@codemirror/view 0.20.4 → 0.20.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/index.cjs +64 -42
- package/dist/index.js +64 -42
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## 0.20.7 (2022-05-30)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue on Chrome Android where the DOM could fail to display the actual document after backspace.
|
|
6
|
+
|
|
7
|
+
Avoid an issue on Chrome Android where DOM changes were sometimes inappropriately replace by a backspace key effect due to spurious beforeinput events.
|
|
8
|
+
|
|
9
|
+
Fix a problem where the content element's width didn't cover the width of the actual content.
|
|
10
|
+
|
|
11
|
+
Work around a bug in Chrome 102 which caused wheel scrolling of the editor to be interrupted every few lines.
|
|
12
|
+
|
|
13
|
+
## 0.20.6 (2022-05-20)
|
|
14
|
+
|
|
15
|
+
### Bug fixes
|
|
16
|
+
|
|
17
|
+
Make sure the editor re-measures itself when its attributes are updated.
|
|
18
|
+
|
|
19
|
+
## 0.20.5 (2022-05-18)
|
|
20
|
+
|
|
21
|
+
### Bug fixes
|
|
22
|
+
|
|
23
|
+
Fix an issue where gutter elements without any markers in them would not get the `cm-gutterElement` class assigned.
|
|
24
|
+
|
|
25
|
+
Fix an issue where DOM event handlers registered by plugins were retained indefinitely, even after the editor was reconfigured.
|
|
26
|
+
|
|
1
27
|
## 0.20.4 (2022-05-03)
|
|
2
28
|
|
|
3
29
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -754,7 +754,7 @@ function textCoords(text, pos, side) {
|
|
|
754
754
|
from--;
|
|
755
755
|
flatten = 1;
|
|
756
756
|
} // FIXME this is wrong in RTL text
|
|
757
|
-
else {
|
|
757
|
+
else if (to < length) {
|
|
758
758
|
to++;
|
|
759
759
|
flatten = -1;
|
|
760
760
|
}
|
|
@@ -763,7 +763,7 @@ function textCoords(text, pos, side) {
|
|
|
763
763
|
else {
|
|
764
764
|
if (side < 0)
|
|
765
765
|
from--;
|
|
766
|
-
else
|
|
766
|
+
else if (to < length)
|
|
767
767
|
to++;
|
|
768
768
|
}
|
|
769
769
|
let rects = textRange(text, from, to).getClientRects();
|
|
@@ -1063,14 +1063,16 @@ function attrsEq(a, b) {
|
|
|
1063
1063
|
return true;
|
|
1064
1064
|
}
|
|
1065
1065
|
function updateAttrs(dom, prev, attrs) {
|
|
1066
|
+
let changed = null;
|
|
1066
1067
|
if (prev)
|
|
1067
1068
|
for (let name in prev)
|
|
1068
1069
|
if (!(attrs && name in attrs))
|
|
1069
|
-
dom.removeAttribute(name);
|
|
1070
|
+
dom.removeAttribute(changed = name);
|
|
1070
1071
|
if (attrs)
|
|
1071
1072
|
for (let name in attrs)
|
|
1072
1073
|
if (!(prev && prev[name] == attrs[name]))
|
|
1073
|
-
dom.setAttribute(name, attrs[name]);
|
|
1074
|
+
dom.setAttribute(changed = name, attrs[name]);
|
|
1075
|
+
return !!changed;
|
|
1074
1076
|
}
|
|
1075
1077
|
|
|
1076
1078
|
/**
|
|
@@ -1377,6 +1379,7 @@ class LineView extends ContentView {
|
|
|
1377
1379
|
transferDOM(other) {
|
|
1378
1380
|
if (!this.dom)
|
|
1379
1381
|
return;
|
|
1382
|
+
this.markDirty();
|
|
1380
1383
|
other.setDOM(this.dom);
|
|
1381
1384
|
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1382
1385
|
this.prevAttrs = undefined;
|
|
@@ -2508,7 +2511,7 @@ class DocView extends ContentView {
|
|
|
2508
2511
|
// no relayout is triggered and I cannot imagine how it can
|
|
2509
2512
|
// recompute the scroll position without a layout)
|
|
2510
2513
|
this.dom.style.height = this.view.viewState.contentHeight + "px";
|
|
2511
|
-
this.dom.style.
|
|
2514
|
+
this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2512
2515
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2513
2516
|
// around the selection, get confused and report a different
|
|
2514
2517
|
// selection from the one it displays (issue #218). This tries
|
|
@@ -3266,6 +3269,7 @@ class InputState {
|
|
|
3266
3269
|
constructor(view) {
|
|
3267
3270
|
this.lastKeyCode = 0;
|
|
3268
3271
|
this.lastKeyTime = 0;
|
|
3272
|
+
this.chromeScrollHack = -1;
|
|
3269
3273
|
// On iOS, some keys need to have their default behavior happen
|
|
3270
3274
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3271
3275
|
// avoid messing up the virtual keyboard state.
|
|
@@ -3306,6 +3310,21 @@ class InputState {
|
|
|
3306
3310
|
});
|
|
3307
3311
|
this.registeredEvents.push(type);
|
|
3308
3312
|
}
|
|
3313
|
+
if (browser.chrome && browser.chrome_version >= 102) {
|
|
3314
|
+
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
3315
|
+
// scrolling. Turning off pointer events during the scroll seems
|
|
3316
|
+
// to avoid the issue.
|
|
3317
|
+
view.scrollDOM.addEventListener("wheel", () => {
|
|
3318
|
+
if (this.chromeScrollHack < 0)
|
|
3319
|
+
view.contentDOM.style.pointerEvents = "none";
|
|
3320
|
+
else
|
|
3321
|
+
window.clearTimeout(this.chromeScrollHack);
|
|
3322
|
+
this.chromeScrollHack = setTimeout(() => {
|
|
3323
|
+
this.chromeScrollHack = -1;
|
|
3324
|
+
view.contentDOM.style.pointerEvents = "";
|
|
3325
|
+
}, 100);
|
|
3326
|
+
}, { passive: true });
|
|
3327
|
+
}
|
|
3309
3328
|
this.notifiedFocused = view.hasFocus;
|
|
3310
3329
|
// On Safari adding an input event handler somehow prevents an
|
|
3311
3330
|
// issue where the composition vanishes when you press enter.
|
|
@@ -3319,6 +3338,7 @@ class InputState {
|
|
|
3319
3338
|
ensureHandlers(view, plugins) {
|
|
3320
3339
|
var _a;
|
|
3321
3340
|
let handlers;
|
|
3341
|
+
this.customHandlers = [];
|
|
3322
3342
|
for (let plugin of plugins)
|
|
3323
3343
|
if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
|
|
3324
3344
|
this.customHandlers.push({ plugin: plugin.value, handlers });
|
|
@@ -4746,24 +4766,22 @@ class ViewState {
|
|
|
4746
4766
|
this.defaultTextDirection = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
|
|
4747
4767
|
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4748
4768
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4769
|
+
this.contentDOMHeight = dom.clientHeight;
|
|
4770
|
+
this.mustMeasureContent = false;
|
|
4749
4771
|
let result = 0, bias = 0;
|
|
4772
|
+
// Vertical padding
|
|
4773
|
+
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4774
|
+
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4775
|
+
this.paddingTop = paddingTop;
|
|
4776
|
+
this.paddingBottom = paddingBottom;
|
|
4777
|
+
result |= 8 /* Geometry */ | 2 /* Height */;
|
|
4778
|
+
}
|
|
4750
4779
|
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
4751
4780
|
if (oracle.lineWrapping)
|
|
4752
4781
|
measureContent = true;
|
|
4753
4782
|
this.editorWidth = view.scrollDOM.clientWidth;
|
|
4754
4783
|
result |= 8 /* Geometry */;
|
|
4755
4784
|
}
|
|
4756
|
-
if (measureContent) {
|
|
4757
|
-
this.mustMeasureContent = false;
|
|
4758
|
-
this.contentDOMHeight = dom.clientHeight;
|
|
4759
|
-
// Vertical padding
|
|
4760
|
-
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4761
|
-
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4762
|
-
result |= 8 /* Geometry */;
|
|
4763
|
-
this.paddingTop = paddingTop;
|
|
4764
|
-
this.paddingBottom = paddingBottom;
|
|
4765
|
-
}
|
|
4766
|
-
}
|
|
4767
4785
|
// Pixel viewport
|
|
4768
4786
|
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
|
4769
4787
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
@@ -5563,21 +5581,16 @@ class DOMObserver {
|
|
|
5563
5581
|
// composition events that, when interrupted, cause text duplication
|
|
5564
5582
|
// or other kinds of corruption. This hack makes the editor back off
|
|
5565
5583
|
// from handling DOM changes for a moment when such a key is
|
|
5566
|
-
// detected (via beforeinput or keydown), and then
|
|
5567
|
-
//
|
|
5584
|
+
// detected (via beforeinput or keydown), and then tries to flush
|
|
5585
|
+
// them or, if that has no effect, dispatches the given key.
|
|
5568
5586
|
delayAndroidKey(key, keyCode) {
|
|
5569
5587
|
if (!this.delayedAndroidKey)
|
|
5570
5588
|
requestAnimationFrame(() => {
|
|
5571
5589
|
let key = this.delayedAndroidKey;
|
|
5572
5590
|
this.delayedAndroidKey = null;
|
|
5573
|
-
|
|
5574
|
-
this.
|
|
5575
|
-
|
|
5576
|
-
this.processRecords();
|
|
5577
|
-
else
|
|
5578
|
-
this.flush();
|
|
5579
|
-
if (this.view.state == startState)
|
|
5580
|
-
this.view.update([]);
|
|
5591
|
+
this.delayedFlush = -1;
|
|
5592
|
+
if (!this.flush())
|
|
5593
|
+
dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
|
5581
5594
|
});
|
|
5582
5595
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5583
5596
|
// Enter always takes precedence.
|
|
@@ -5633,10 +5646,11 @@ class DOMObserver {
|
|
|
5633
5646
|
return;
|
|
5634
5647
|
this.selectionChanged = false;
|
|
5635
5648
|
let startState = this.view.state;
|
|
5636
|
-
this.onChange(from, to, typeOver);
|
|
5649
|
+
let handled = this.onChange(from, to, typeOver);
|
|
5637
5650
|
// The view wasn't updated
|
|
5638
5651
|
if (this.view.state == startState)
|
|
5639
5652
|
this.view.update([]);
|
|
5653
|
+
return handled;
|
|
5640
5654
|
}
|
|
5641
5655
|
readMutation(rec) {
|
|
5642
5656
|
let cView = this.view.docView.nearest(rec.target);
|
|
@@ -5719,7 +5733,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5719
5733
|
if (start > -1) {
|
|
5720
5734
|
let bounds = view.docView.domBoundsAround(start, end, 0);
|
|
5721
5735
|
if (!bounds || view.state.readOnly)
|
|
5722
|
-
return;
|
|
5736
|
+
return false;
|
|
5723
5737
|
let { from, to } = bounds;
|
|
5724
5738
|
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5725
5739
|
let reader = new DOMReader(selPoints, view.state);
|
|
@@ -5759,7 +5773,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5759
5773
|
newSel = state.EditorSelection.single(anchor, head);
|
|
5760
5774
|
}
|
|
5761
5775
|
if (!change && !newSel)
|
|
5762
|
-
return;
|
|
5776
|
+
return false;
|
|
5763
5777
|
// Heuristic to notice typing over a selected character
|
|
5764
5778
|
if (!change && typeOver && !sel.empty && newSel && newSel.main.empty)
|
|
5765
5779
|
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
@@ -5775,13 +5789,13 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5775
5789
|
};
|
|
5776
5790
|
// Detect insert-period-on-double-space Mac behavior, and transform
|
|
5777
5791
|
// it into a regular space insert.
|
|
5778
|
-
else if (browser.mac && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5792
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5779
5793
|
change.insert.toString() == ".")
|
|
5780
5794
|
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
5781
5795
|
if (change) {
|
|
5782
5796
|
let startState = view.state;
|
|
5783
5797
|
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5784
|
-
return;
|
|
5798
|
+
return true;
|
|
5785
5799
|
// Android browsers don't fire reasonable key events for enter,
|
|
5786
5800
|
// backspace, or delete. So this detects changes that look like
|
|
5787
5801
|
// they're caused by those keys, and reinterprets them as key
|
|
@@ -5796,10 +5810,10 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5796
5810
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5797
5811
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5798
5812
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5799
|
-
return;
|
|
5813
|
+
return true;
|
|
5800
5814
|
let text = change.insert.toString();
|
|
5801
5815
|
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5802
|
-
return;
|
|
5816
|
+
return true;
|
|
5803
5817
|
if (view.inputState.composing >= 0)
|
|
5804
5818
|
view.inputState.composing++;
|
|
5805
5819
|
let tr;
|
|
@@ -5855,6 +5869,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5855
5869
|
}
|
|
5856
5870
|
}
|
|
5857
5871
|
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
5872
|
+
return true;
|
|
5858
5873
|
}
|
|
5859
5874
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
5860
5875
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -5864,6 +5879,10 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5864
5879
|
userEvent = view.inputState.lastSelectionOrigin;
|
|
5865
5880
|
}
|
|
5866
5881
|
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
5882
|
+
return true;
|
|
5883
|
+
}
|
|
5884
|
+
else {
|
|
5885
|
+
return false;
|
|
5867
5886
|
}
|
|
5868
5887
|
}
|
|
5869
5888
|
function findDiff(a, b, preferredPos, preferredSide) {
|
|
@@ -5982,7 +6001,7 @@ class EditorView {
|
|
|
5982
6001
|
for (let plugin of this.plugins)
|
|
5983
6002
|
plugin.update(this);
|
|
5984
6003
|
this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
|
5985
|
-
applyDOMChange(this, from, to, typeOver);
|
|
6004
|
+
return applyDOMChange(this, from, to, typeOver);
|
|
5986
6005
|
}, event => {
|
|
5987
6006
|
this.inputState.runScrollHandlers(this, event);
|
|
5988
6007
|
if (this.observer.intersecting)
|
|
@@ -6052,7 +6071,7 @@ class EditorView {
|
|
|
6052
6071
|
update(transactions) {
|
|
6053
6072
|
if (this.updateState != 0 /* Idle */)
|
|
6054
6073
|
throw new Error("Calls to EditorView.update are not allowed while an update is in progress");
|
|
6055
|
-
let redrawn = false, update;
|
|
6074
|
+
let redrawn = false, attrsChanged = false, update;
|
|
6056
6075
|
let state$1 = this.state;
|
|
6057
6076
|
for (let tr of transactions) {
|
|
6058
6077
|
if (tr.startState != state$1)
|
|
@@ -6063,6 +6082,7 @@ class EditorView {
|
|
|
6063
6082
|
this.viewState.state = state$1;
|
|
6064
6083
|
return;
|
|
6065
6084
|
}
|
|
6085
|
+
this.observer.clear();
|
|
6066
6086
|
// When the phrases change, redraw the editor
|
|
6067
6087
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
6068
6088
|
return this.setState(state$1);
|
|
@@ -6090,7 +6110,7 @@ class EditorView {
|
|
|
6090
6110
|
redrawn = this.docView.update(update);
|
|
6091
6111
|
if (this.state.facet(styleModule) != this.styleModules)
|
|
6092
6112
|
this.mountStyles();
|
|
6093
|
-
this.updateAttrs();
|
|
6113
|
+
attrsChanged = this.updateAttrs();
|
|
6094
6114
|
this.showAnnouncements(transactions);
|
|
6095
6115
|
this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
|
6096
6116
|
}
|
|
@@ -6099,7 +6119,7 @@ class EditorView {
|
|
|
6099
6119
|
}
|
|
6100
6120
|
if (update.startState.facet(theme) != update.state.facet(theme))
|
|
6101
6121
|
this.viewState.mustMeasureContent = true;
|
|
6102
|
-
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
6122
|
+
if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
6103
6123
|
this.requestMeasure();
|
|
6104
6124
|
if (!update.empty)
|
|
6105
6125
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -6279,12 +6299,14 @@ class EditorView {
|
|
|
6279
6299
|
if (this.state.readOnly)
|
|
6280
6300
|
contentAttrs["aria-readonly"] = "true";
|
|
6281
6301
|
attrsFromFacet(this, contentAttributes, contentAttrs);
|
|
6282
|
-
this.observer.ignore(() => {
|
|
6283
|
-
updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
6284
|
-
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
6302
|
+
let changed = this.observer.ignore(() => {
|
|
6303
|
+
let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
6304
|
+
let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
6305
|
+
return changedContent || changedEditor;
|
|
6285
6306
|
});
|
|
6286
6307
|
this.editorAttrs = editorAttrs;
|
|
6287
6308
|
this.contentAttrs = contentAttrs;
|
|
6309
|
+
return changed;
|
|
6288
6310
|
}
|
|
6289
6311
|
showAnnouncements(trs) {
|
|
6290
6312
|
let first = true;
|
|
@@ -8181,7 +8203,6 @@ class HoverPlugin {
|
|
|
8181
8203
|
this.startHover();
|
|
8182
8204
|
}
|
|
8183
8205
|
startHover() {
|
|
8184
|
-
var _a;
|
|
8185
8206
|
clearTimeout(this.restartTimeout);
|
|
8186
8207
|
let { lastMove } = this;
|
|
8187
8208
|
let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
|
|
@@ -8195,7 +8216,7 @@ class HoverPlugin {
|
|
|
8195
8216
|
let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
|
|
8196
8217
|
let rtl = bidi && bidi.dir == exports.Direction.RTL ? -1 : 1;
|
|
8197
8218
|
let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
|
|
8198
|
-
if (
|
|
8219
|
+
if (open === null || open === void 0 ? void 0 : open.then) {
|
|
8199
8220
|
let pending = this.pending = { pos };
|
|
8200
8221
|
open.then(result => {
|
|
8201
8222
|
if (this.pending == pending) {
|
|
@@ -8795,6 +8816,7 @@ class GutterElement {
|
|
|
8795
8816
|
this.above = 0;
|
|
8796
8817
|
this.markers = [];
|
|
8797
8818
|
this.dom = document.createElement("div");
|
|
8819
|
+
this.dom.className = "cm-gutterElement";
|
|
8798
8820
|
this.update(view, height, above, markers);
|
|
8799
8821
|
}
|
|
8800
8822
|
update(view, height, above, markers) {
|
package/dist/index.js
CHANGED
|
@@ -750,7 +750,7 @@ function textCoords(text, pos, side) {
|
|
|
750
750
|
from--;
|
|
751
751
|
flatten = 1;
|
|
752
752
|
} // FIXME this is wrong in RTL text
|
|
753
|
-
else {
|
|
753
|
+
else if (to < length) {
|
|
754
754
|
to++;
|
|
755
755
|
flatten = -1;
|
|
756
756
|
}
|
|
@@ -759,7 +759,7 @@ function textCoords(text, pos, side) {
|
|
|
759
759
|
else {
|
|
760
760
|
if (side < 0)
|
|
761
761
|
from--;
|
|
762
|
-
else
|
|
762
|
+
else if (to < length)
|
|
763
763
|
to++;
|
|
764
764
|
}
|
|
765
765
|
let rects = textRange(text, from, to).getClientRects();
|
|
@@ -1059,14 +1059,16 @@ function attrsEq(a, b) {
|
|
|
1059
1059
|
return true;
|
|
1060
1060
|
}
|
|
1061
1061
|
function updateAttrs(dom, prev, attrs) {
|
|
1062
|
+
let changed = null;
|
|
1062
1063
|
if (prev)
|
|
1063
1064
|
for (let name in prev)
|
|
1064
1065
|
if (!(attrs && name in attrs))
|
|
1065
|
-
dom.removeAttribute(name);
|
|
1066
|
+
dom.removeAttribute(changed = name);
|
|
1066
1067
|
if (attrs)
|
|
1067
1068
|
for (let name in attrs)
|
|
1068
1069
|
if (!(prev && prev[name] == attrs[name]))
|
|
1069
|
-
dom.setAttribute(name, attrs[name]);
|
|
1070
|
+
dom.setAttribute(changed = name, attrs[name]);
|
|
1071
|
+
return !!changed;
|
|
1070
1072
|
}
|
|
1071
1073
|
|
|
1072
1074
|
/**
|
|
@@ -1372,6 +1374,7 @@ class LineView extends ContentView {
|
|
|
1372
1374
|
transferDOM(other) {
|
|
1373
1375
|
if (!this.dom)
|
|
1374
1376
|
return;
|
|
1377
|
+
this.markDirty();
|
|
1375
1378
|
other.setDOM(this.dom);
|
|
1376
1379
|
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1377
1380
|
this.prevAttrs = undefined;
|
|
@@ -2502,7 +2505,7 @@ class DocView extends ContentView {
|
|
|
2502
2505
|
// no relayout is triggered and I cannot imagine how it can
|
|
2503
2506
|
// recompute the scroll position without a layout)
|
|
2504
2507
|
this.dom.style.height = this.view.viewState.contentHeight + "px";
|
|
2505
|
-
this.dom.style.
|
|
2508
|
+
this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2506
2509
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2507
2510
|
// around the selection, get confused and report a different
|
|
2508
2511
|
// selection from the one it displays (issue #218). This tries
|
|
@@ -3260,6 +3263,7 @@ class InputState {
|
|
|
3260
3263
|
constructor(view) {
|
|
3261
3264
|
this.lastKeyCode = 0;
|
|
3262
3265
|
this.lastKeyTime = 0;
|
|
3266
|
+
this.chromeScrollHack = -1;
|
|
3263
3267
|
// On iOS, some keys need to have their default behavior happen
|
|
3264
3268
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3265
3269
|
// avoid messing up the virtual keyboard state.
|
|
@@ -3300,6 +3304,21 @@ class InputState {
|
|
|
3300
3304
|
});
|
|
3301
3305
|
this.registeredEvents.push(type);
|
|
3302
3306
|
}
|
|
3307
|
+
if (browser.chrome && browser.chrome_version >= 102) {
|
|
3308
|
+
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
3309
|
+
// scrolling. Turning off pointer events during the scroll seems
|
|
3310
|
+
// to avoid the issue.
|
|
3311
|
+
view.scrollDOM.addEventListener("wheel", () => {
|
|
3312
|
+
if (this.chromeScrollHack < 0)
|
|
3313
|
+
view.contentDOM.style.pointerEvents = "none";
|
|
3314
|
+
else
|
|
3315
|
+
window.clearTimeout(this.chromeScrollHack);
|
|
3316
|
+
this.chromeScrollHack = setTimeout(() => {
|
|
3317
|
+
this.chromeScrollHack = -1;
|
|
3318
|
+
view.contentDOM.style.pointerEvents = "";
|
|
3319
|
+
}, 100);
|
|
3320
|
+
}, { passive: true });
|
|
3321
|
+
}
|
|
3303
3322
|
this.notifiedFocused = view.hasFocus;
|
|
3304
3323
|
// On Safari adding an input event handler somehow prevents an
|
|
3305
3324
|
// issue where the composition vanishes when you press enter.
|
|
@@ -3313,6 +3332,7 @@ class InputState {
|
|
|
3313
3332
|
ensureHandlers(view, plugins) {
|
|
3314
3333
|
var _a;
|
|
3315
3334
|
let handlers;
|
|
3335
|
+
this.customHandlers = [];
|
|
3316
3336
|
for (let plugin of plugins)
|
|
3317
3337
|
if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
|
|
3318
3338
|
this.customHandlers.push({ plugin: plugin.value, handlers });
|
|
@@ -4739,24 +4759,22 @@ class ViewState {
|
|
|
4739
4759
|
this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
|
|
4740
4760
|
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4741
4761
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4762
|
+
this.contentDOMHeight = dom.clientHeight;
|
|
4763
|
+
this.mustMeasureContent = false;
|
|
4742
4764
|
let result = 0, bias = 0;
|
|
4765
|
+
// Vertical padding
|
|
4766
|
+
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4767
|
+
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4768
|
+
this.paddingTop = paddingTop;
|
|
4769
|
+
this.paddingBottom = paddingBottom;
|
|
4770
|
+
result |= 8 /* Geometry */ | 2 /* Height */;
|
|
4771
|
+
}
|
|
4743
4772
|
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
4744
4773
|
if (oracle.lineWrapping)
|
|
4745
4774
|
measureContent = true;
|
|
4746
4775
|
this.editorWidth = view.scrollDOM.clientWidth;
|
|
4747
4776
|
result |= 8 /* Geometry */;
|
|
4748
4777
|
}
|
|
4749
|
-
if (measureContent) {
|
|
4750
|
-
this.mustMeasureContent = false;
|
|
4751
|
-
this.contentDOMHeight = dom.clientHeight;
|
|
4752
|
-
// Vertical padding
|
|
4753
|
-
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4754
|
-
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4755
|
-
result |= 8 /* Geometry */;
|
|
4756
|
-
this.paddingTop = paddingTop;
|
|
4757
|
-
this.paddingBottom = paddingBottom;
|
|
4758
|
-
}
|
|
4759
|
-
}
|
|
4760
4778
|
// Pixel viewport
|
|
4761
4779
|
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
|
4762
4780
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
@@ -5556,21 +5574,16 @@ class DOMObserver {
|
|
|
5556
5574
|
// composition events that, when interrupted, cause text duplication
|
|
5557
5575
|
// or other kinds of corruption. This hack makes the editor back off
|
|
5558
5576
|
// from handling DOM changes for a moment when such a key is
|
|
5559
|
-
// detected (via beforeinput or keydown), and then
|
|
5560
|
-
//
|
|
5577
|
+
// detected (via beforeinput or keydown), and then tries to flush
|
|
5578
|
+
// them or, if that has no effect, dispatches the given key.
|
|
5561
5579
|
delayAndroidKey(key, keyCode) {
|
|
5562
5580
|
if (!this.delayedAndroidKey)
|
|
5563
5581
|
requestAnimationFrame(() => {
|
|
5564
5582
|
let key = this.delayedAndroidKey;
|
|
5565
5583
|
this.delayedAndroidKey = null;
|
|
5566
|
-
|
|
5567
|
-
this.
|
|
5568
|
-
|
|
5569
|
-
this.processRecords();
|
|
5570
|
-
else
|
|
5571
|
-
this.flush();
|
|
5572
|
-
if (this.view.state == startState)
|
|
5573
|
-
this.view.update([]);
|
|
5584
|
+
this.delayedFlush = -1;
|
|
5585
|
+
if (!this.flush())
|
|
5586
|
+
dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
|
5574
5587
|
});
|
|
5575
5588
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5576
5589
|
// Enter always takes precedence.
|
|
@@ -5626,10 +5639,11 @@ class DOMObserver {
|
|
|
5626
5639
|
return;
|
|
5627
5640
|
this.selectionChanged = false;
|
|
5628
5641
|
let startState = this.view.state;
|
|
5629
|
-
this.onChange(from, to, typeOver);
|
|
5642
|
+
let handled = this.onChange(from, to, typeOver);
|
|
5630
5643
|
// The view wasn't updated
|
|
5631
5644
|
if (this.view.state == startState)
|
|
5632
5645
|
this.view.update([]);
|
|
5646
|
+
return handled;
|
|
5633
5647
|
}
|
|
5634
5648
|
readMutation(rec) {
|
|
5635
5649
|
let cView = this.view.docView.nearest(rec.target);
|
|
@@ -5712,7 +5726,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5712
5726
|
if (start > -1) {
|
|
5713
5727
|
let bounds = view.docView.domBoundsAround(start, end, 0);
|
|
5714
5728
|
if (!bounds || view.state.readOnly)
|
|
5715
|
-
return;
|
|
5729
|
+
return false;
|
|
5716
5730
|
let { from, to } = bounds;
|
|
5717
5731
|
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5718
5732
|
let reader = new DOMReader(selPoints, view.state);
|
|
@@ -5752,7 +5766,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5752
5766
|
newSel = EditorSelection.single(anchor, head);
|
|
5753
5767
|
}
|
|
5754
5768
|
if (!change && !newSel)
|
|
5755
|
-
return;
|
|
5769
|
+
return false;
|
|
5756
5770
|
// Heuristic to notice typing over a selected character
|
|
5757
5771
|
if (!change && typeOver && !sel.empty && newSel && newSel.main.empty)
|
|
5758
5772
|
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
@@ -5768,13 +5782,13 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5768
5782
|
};
|
|
5769
5783
|
// Detect insert-period-on-double-space Mac behavior, and transform
|
|
5770
5784
|
// it into a regular space insert.
|
|
5771
|
-
else if (browser.mac && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5785
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5772
5786
|
change.insert.toString() == ".")
|
|
5773
5787
|
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
5774
5788
|
if (change) {
|
|
5775
5789
|
let startState = view.state;
|
|
5776
5790
|
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5777
|
-
return;
|
|
5791
|
+
return true;
|
|
5778
5792
|
// Android browsers don't fire reasonable key events for enter,
|
|
5779
5793
|
// backspace, or delete. So this detects changes that look like
|
|
5780
5794
|
// they're caused by those keys, and reinterprets them as key
|
|
@@ -5789,10 +5803,10 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5789
5803
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5790
5804
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5791
5805
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5792
|
-
return;
|
|
5806
|
+
return true;
|
|
5793
5807
|
let text = change.insert.toString();
|
|
5794
5808
|
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5795
|
-
return;
|
|
5809
|
+
return true;
|
|
5796
5810
|
if (view.inputState.composing >= 0)
|
|
5797
5811
|
view.inputState.composing++;
|
|
5798
5812
|
let tr;
|
|
@@ -5848,6 +5862,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5848
5862
|
}
|
|
5849
5863
|
}
|
|
5850
5864
|
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
5865
|
+
return true;
|
|
5851
5866
|
}
|
|
5852
5867
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
5853
5868
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -5857,6 +5872,10 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5857
5872
|
userEvent = view.inputState.lastSelectionOrigin;
|
|
5858
5873
|
}
|
|
5859
5874
|
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
5875
|
+
return true;
|
|
5876
|
+
}
|
|
5877
|
+
else {
|
|
5878
|
+
return false;
|
|
5860
5879
|
}
|
|
5861
5880
|
}
|
|
5862
5881
|
function findDiff(a, b, preferredPos, preferredSide) {
|
|
@@ -5975,7 +5994,7 @@ class EditorView {
|
|
|
5975
5994
|
for (let plugin of this.plugins)
|
|
5976
5995
|
plugin.update(this);
|
|
5977
5996
|
this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
|
5978
|
-
applyDOMChange(this, from, to, typeOver);
|
|
5997
|
+
return applyDOMChange(this, from, to, typeOver);
|
|
5979
5998
|
}, event => {
|
|
5980
5999
|
this.inputState.runScrollHandlers(this, event);
|
|
5981
6000
|
if (this.observer.intersecting)
|
|
@@ -6045,7 +6064,7 @@ class EditorView {
|
|
|
6045
6064
|
update(transactions) {
|
|
6046
6065
|
if (this.updateState != 0 /* Idle */)
|
|
6047
6066
|
throw new Error("Calls to EditorView.update are not allowed while an update is in progress");
|
|
6048
|
-
let redrawn = false, update;
|
|
6067
|
+
let redrawn = false, attrsChanged = false, update;
|
|
6049
6068
|
let state = this.state;
|
|
6050
6069
|
for (let tr of transactions) {
|
|
6051
6070
|
if (tr.startState != state)
|
|
@@ -6056,6 +6075,7 @@ class EditorView {
|
|
|
6056
6075
|
this.viewState.state = state;
|
|
6057
6076
|
return;
|
|
6058
6077
|
}
|
|
6078
|
+
this.observer.clear();
|
|
6059
6079
|
// When the phrases change, redraw the editor
|
|
6060
6080
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
6061
6081
|
return this.setState(state);
|
|
@@ -6083,7 +6103,7 @@ class EditorView {
|
|
|
6083
6103
|
redrawn = this.docView.update(update);
|
|
6084
6104
|
if (this.state.facet(styleModule) != this.styleModules)
|
|
6085
6105
|
this.mountStyles();
|
|
6086
|
-
this.updateAttrs();
|
|
6106
|
+
attrsChanged = this.updateAttrs();
|
|
6087
6107
|
this.showAnnouncements(transactions);
|
|
6088
6108
|
this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
|
6089
6109
|
}
|
|
@@ -6092,7 +6112,7 @@ class EditorView {
|
|
|
6092
6112
|
}
|
|
6093
6113
|
if (update.startState.facet(theme) != update.state.facet(theme))
|
|
6094
6114
|
this.viewState.mustMeasureContent = true;
|
|
6095
|
-
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
6115
|
+
if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
6096
6116
|
this.requestMeasure();
|
|
6097
6117
|
if (!update.empty)
|
|
6098
6118
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -6272,12 +6292,14 @@ class EditorView {
|
|
|
6272
6292
|
if (this.state.readOnly)
|
|
6273
6293
|
contentAttrs["aria-readonly"] = "true";
|
|
6274
6294
|
attrsFromFacet(this, contentAttributes, contentAttrs);
|
|
6275
|
-
this.observer.ignore(() => {
|
|
6276
|
-
updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
6277
|
-
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
6295
|
+
let changed = this.observer.ignore(() => {
|
|
6296
|
+
let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
6297
|
+
let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
6298
|
+
return changedContent || changedEditor;
|
|
6278
6299
|
});
|
|
6279
6300
|
this.editorAttrs = editorAttrs;
|
|
6280
6301
|
this.contentAttrs = contentAttrs;
|
|
6302
|
+
return changed;
|
|
6281
6303
|
}
|
|
6282
6304
|
showAnnouncements(trs) {
|
|
6283
6305
|
let first = true;
|
|
@@ -8174,7 +8196,6 @@ class HoverPlugin {
|
|
|
8174
8196
|
this.startHover();
|
|
8175
8197
|
}
|
|
8176
8198
|
startHover() {
|
|
8177
|
-
var _a;
|
|
8178
8199
|
clearTimeout(this.restartTimeout);
|
|
8179
8200
|
let { lastMove } = this;
|
|
8180
8201
|
let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
|
|
@@ -8188,7 +8209,7 @@ class HoverPlugin {
|
|
|
8188
8209
|
let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
|
|
8189
8210
|
let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
|
|
8190
8211
|
let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
|
|
8191
|
-
if (
|
|
8212
|
+
if (open === null || open === void 0 ? void 0 : open.then) {
|
|
8192
8213
|
let pending = this.pending = { pos };
|
|
8193
8214
|
open.then(result => {
|
|
8194
8215
|
if (this.pending == pending) {
|
|
@@ -8788,6 +8809,7 @@ class GutterElement {
|
|
|
8788
8809
|
this.above = 0;
|
|
8789
8810
|
this.markers = [];
|
|
8790
8811
|
this.dom = document.createElement("div");
|
|
8812
|
+
this.dom.className = "cm-gutterElement";
|
|
8791
8813
|
this.update(view, height, above, markers);
|
|
8792
8814
|
}
|
|
8793
8815
|
update(view, height, above, markers) {
|