@codemirror/view 0.19.17 → 0.19.21
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 +24 -0
- package/dist/index.cjs +106 -65
- package/dist/index.js +106 -65
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 0.19.21 (2021-11-26)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a problem where the DOM update would unnecessarily trigger browser relayouts.
|
|
6
|
+
|
|
7
|
+
## 0.19.20 (2021-11-19)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Run a measure cycle when the editor's size spontaneously changes.
|
|
12
|
+
|
|
13
|
+
## 0.19.19 (2021-11-17)
|
|
14
|
+
|
|
15
|
+
### Bug fixes
|
|
16
|
+
|
|
17
|
+
Fix a bug that caused the precedence of `editorAttributes` and `contentAttributes` to be inverted, making lower-precedence extensions override higher-precedence ones.
|
|
18
|
+
|
|
19
|
+
## 0.19.18 (2021-11-16)
|
|
20
|
+
|
|
21
|
+
### Bug fixes
|
|
22
|
+
|
|
23
|
+
Fix an issue where the editor wasn't aware it was line-wrapping with its own `lineWrapping` extension enabled.
|
|
24
|
+
|
|
1
25
|
## 0.19.17 (2021-11-16)
|
|
2
26
|
|
|
3
27
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -186,7 +186,7 @@ function scrollRectIntoView(dom, rect, side, center) {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
-
class
|
|
189
|
+
class DOMSelectionState {
|
|
190
190
|
constructor() {
|
|
191
191
|
this.anchorNode = null;
|
|
192
192
|
this.anchorOffset = 0;
|
|
@@ -197,11 +197,14 @@ class DOMSelection {
|
|
|
197
197
|
return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
|
|
198
198
|
this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
|
|
199
199
|
}
|
|
200
|
-
|
|
201
|
-
this.anchorNode
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this.
|
|
200
|
+
setRange(range) {
|
|
201
|
+
this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset);
|
|
202
|
+
}
|
|
203
|
+
set(anchorNode, anchorOffset, focusNode, focusOffset) {
|
|
204
|
+
this.anchorNode = anchorNode;
|
|
205
|
+
this.anchorOffset = anchorOffset;
|
|
206
|
+
this.focusNode = focusNode;
|
|
207
|
+
this.focusOffset = focusOffset;
|
|
205
208
|
}
|
|
206
209
|
}
|
|
207
210
|
let preventScrollSupported = null;
|
|
@@ -1771,11 +1774,17 @@ class PluginInstance {
|
|
|
1771
1774
|
}
|
|
1772
1775
|
}
|
|
1773
1776
|
PluginInstance.dummy = new PluginInstance(ViewPlugin.define(() => ({})));
|
|
1777
|
+
function combineFacetAttrs(values) {
|
|
1778
|
+
let result = {};
|
|
1779
|
+
for (let i = values.length - 1; i >= 0; i--)
|
|
1780
|
+
combineAttrs(values[i], result);
|
|
1781
|
+
return result;
|
|
1782
|
+
}
|
|
1774
1783
|
const editorAttributes = state.Facet.define({
|
|
1775
|
-
combine:
|
|
1784
|
+
combine: combineFacetAttrs
|
|
1776
1785
|
});
|
|
1777
1786
|
const contentAttributes = state.Facet.define({
|
|
1778
|
-
combine:
|
|
1787
|
+
combine: combineFacetAttrs
|
|
1779
1788
|
});
|
|
1780
1789
|
// Provide decorations
|
|
1781
1790
|
const decorations = state.Facet.define();
|
|
@@ -1937,6 +1946,10 @@ class DocView extends ContentView {
|
|
|
1937
1946
|
// we don't mess it up when reading it back it
|
|
1938
1947
|
this.impreciseAnchor = null;
|
|
1939
1948
|
this.impreciseHead = null;
|
|
1949
|
+
this.forceSelection = false;
|
|
1950
|
+
// Used by the resize observer to ignore resizes that we caused
|
|
1951
|
+
// ourselves
|
|
1952
|
+
this.lastUpdate = Date.now();
|
|
1940
1953
|
this.setDOM(view.contentDOM);
|
|
1941
1954
|
this.children = [new LineView];
|
|
1942
1955
|
this.children[0].setParent(this);
|
|
@@ -1969,21 +1982,22 @@ class DocView extends ContentView {
|
|
|
1969
1982
|
// getSelection than the one that it actually shows to the user.
|
|
1970
1983
|
// This forces a selection update when lines are joined to work
|
|
1971
1984
|
// around that. Issue #54
|
|
1972
|
-
|
|
1973
|
-
update.state.doc.lines != update.startState.doc.lines
|
|
1985
|
+
if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update &&
|
|
1986
|
+
update.state.doc.lines != update.startState.doc.lines)
|
|
1987
|
+
this.forceSelection = true;
|
|
1974
1988
|
let prevDeco = this.decorations, deco = this.updateDeco();
|
|
1975
1989
|
let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
|
1976
1990
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
1977
|
-
let pointerSel = update.transactions.some(tr => tr.isUserEvent("select.pointer"));
|
|
1978
1991
|
if (this.dirty == 0 /* Not */ && changedRanges.length == 0 &&
|
|
1979
1992
|
!(update.flags & 4 /* Viewport */) &&
|
|
1980
1993
|
update.state.selection.main.from >= this.view.viewport.from &&
|
|
1981
1994
|
update.state.selection.main.to <= this.view.viewport.to) {
|
|
1982
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
1983
1995
|
return false;
|
|
1984
1996
|
}
|
|
1985
1997
|
else {
|
|
1986
|
-
this.updateInner(changedRanges, deco, update.startState.doc.length
|
|
1998
|
+
this.updateInner(changedRanges, deco, update.startState.doc.length);
|
|
1999
|
+
if (update.transactions.length)
|
|
2000
|
+
this.lastUpdate = Date.now();
|
|
1987
2001
|
return true;
|
|
1988
2002
|
}
|
|
1989
2003
|
}
|
|
@@ -1991,13 +2005,15 @@ class DocView extends ContentView {
|
|
|
1991
2005
|
if (this.dirty) {
|
|
1992
2006
|
this.view.observer.ignore(() => this.view.docView.sync());
|
|
1993
2007
|
this.dirty = 0 /* Not */;
|
|
2008
|
+
this.updateSelection(true);
|
|
1994
2009
|
}
|
|
1995
|
-
|
|
2010
|
+
else {
|
|
1996
2011
|
this.updateSelection();
|
|
2012
|
+
}
|
|
1997
2013
|
}
|
|
1998
2014
|
// Used both by update and checkLayout do perform the actual DOM
|
|
1999
2015
|
// update
|
|
2000
|
-
updateInner(changes, deco, oldLength
|
|
2016
|
+
updateInner(changes, deco, oldLength) {
|
|
2001
2017
|
this.updateChildren(changes, deco, oldLength);
|
|
2002
2018
|
let { observer } = this.view;
|
|
2003
2019
|
observer.ignore(() => {
|
|
@@ -2015,8 +2031,7 @@ class DocView extends ContentView {
|
|
|
2015
2031
|
this.sync(track);
|
|
2016
2032
|
this.dirty = 0 /* Not */;
|
|
2017
2033
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2018
|
-
forceSelection = true;
|
|
2019
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
2034
|
+
this.forceSelection = true;
|
|
2020
2035
|
this.dom.style.height = "";
|
|
2021
2036
|
});
|
|
2022
2037
|
let gaps = [];
|
|
@@ -2102,10 +2117,14 @@ class DocView extends ContentView {
|
|
|
2102
2117
|
this.replaceChildren(fromI, toI, content);
|
|
2103
2118
|
}
|
|
2104
2119
|
// Sync the DOM selection to this.state.selection
|
|
2105
|
-
updateSelection(
|
|
2120
|
+
updateSelection(mustRead = false, fromPointer = false) {
|
|
2121
|
+
if (mustRead)
|
|
2122
|
+
this.view.observer.readSelectionRange();
|
|
2106
2123
|
if (!(fromPointer || this.mayControlSelection()) ||
|
|
2107
2124
|
browser.ios && this.view.inputState.rapidCompositionStart)
|
|
2108
2125
|
return;
|
|
2126
|
+
let force = this.forceSelection;
|
|
2127
|
+
this.forceSelection = false;
|
|
2109
2128
|
let main = this.view.state.selection.main;
|
|
2110
2129
|
// FIXME need to handle the case where the selection falls inside a block range
|
|
2111
2130
|
let anchor = this.domAtPos(main.anchor);
|
|
@@ -3742,7 +3761,7 @@ handlers.beforeinput = (view, event) => {
|
|
|
3742
3761
|
}
|
|
3743
3762
|
};
|
|
3744
3763
|
|
|
3745
|
-
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line"];
|
|
3764
|
+
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
3746
3765
|
class HeightOracle {
|
|
3747
3766
|
constructor() {
|
|
3748
3767
|
this.doc = text.Text.empty;
|
|
@@ -4476,6 +4495,7 @@ class ViewState {
|
|
|
4476
4495
|
this.paddingTop = 0;
|
|
4477
4496
|
this.paddingBottom = 0;
|
|
4478
4497
|
this.contentWidth = 0;
|
|
4498
|
+
this.editorHeight = 0;
|
|
4479
4499
|
this.heightOracle = new HeightOracle;
|
|
4480
4500
|
// See VP.MaxDOMHeight
|
|
4481
4501
|
this.scaler = IdScaler;
|
|
@@ -4575,6 +4595,10 @@ class ViewState {
|
|
|
4575
4595
|
this.contentWidth = contentWidth;
|
|
4576
4596
|
result |= 8 /* Geometry */;
|
|
4577
4597
|
}
|
|
4598
|
+
if (this.editorHeight != docView.view.scrollDOM.clientHeight) {
|
|
4599
|
+
this.editorHeight = docView.view.scrollDOM.clientHeight;
|
|
4600
|
+
result |= 8 /* Geometry */;
|
|
4601
|
+
}
|
|
4578
4602
|
if (dTop > 0 && dBottom > 0)
|
|
4579
4603
|
bias = Math.max(dTop, dBottom);
|
|
4580
4604
|
else if (dTop < 0 && dBottom < 0)
|
|
@@ -5060,24 +5084,30 @@ class DOMObserver {
|
|
|
5060
5084
|
this.onChange = onChange;
|
|
5061
5085
|
this.onScrollChanged = onScrollChanged;
|
|
5062
5086
|
this.active = false;
|
|
5063
|
-
|
|
5087
|
+
// The known selection. Kept in our own object, as opposed to just
|
|
5088
|
+
// directly accessing the selection because:
|
|
5089
|
+
// - Safari doesn't report the right selection in shadow DOM
|
|
5090
|
+
// - Reading from the selection forces a DOM layout
|
|
5091
|
+
// - This way, we can ignore selectionchange events if we have
|
|
5092
|
+
// already seen the 'new' selection
|
|
5093
|
+
this.selectionRange = new DOMSelectionState;
|
|
5094
|
+
// Set when a selection change is detected, cleared on flush
|
|
5095
|
+
this.selectionChanged = false;
|
|
5064
5096
|
this.delayedFlush = -1;
|
|
5097
|
+
this.resizeTimeout = -1;
|
|
5065
5098
|
this.queue = [];
|
|
5066
|
-
this.lastFlush = 0;
|
|
5067
5099
|
this.scrollTargets = [];
|
|
5068
5100
|
this.intersection = null;
|
|
5101
|
+
this.resize = null;
|
|
5069
5102
|
this.intersecting = false;
|
|
5070
5103
|
this.gapIntersection = null;
|
|
5071
5104
|
this.gaps = [];
|
|
5072
|
-
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5073
|
-
this._selectionRange = null;
|
|
5074
5105
|
// Timeout for scheduling check of the parents that need scroll handlers
|
|
5075
5106
|
this.parentCheck = -1;
|
|
5076
5107
|
this.dom = view.contentDOM;
|
|
5077
5108
|
this.observer = new MutationObserver(mutations => {
|
|
5078
5109
|
for (let mut of mutations)
|
|
5079
5110
|
this.queue.push(mut);
|
|
5080
|
-
this._selectionRange = null;
|
|
5081
5111
|
// IE11 will sometimes (on typing over a selection or
|
|
5082
5112
|
// backspacing out a single character text node) call the
|
|
5083
5113
|
// observer callback before actually updating the DOM.
|
|
@@ -5102,6 +5132,16 @@ class DOMObserver {
|
|
|
5102
5132
|
this.flushSoon();
|
|
5103
5133
|
};
|
|
5104
5134
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5135
|
+
if (typeof ResizeObserver == "function") {
|
|
5136
|
+
this.resize = new ResizeObserver(() => {
|
|
5137
|
+
if (this.view.docView.lastUpdate < Date.now() - 75 && this.resizeTimeout < 0)
|
|
5138
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5139
|
+
this.resizeTimeout = -1;
|
|
5140
|
+
this.view.requestMeasure();
|
|
5141
|
+
}, 50);
|
|
5142
|
+
});
|
|
5143
|
+
this.resize.observe(view.scrollDOM);
|
|
5144
|
+
}
|
|
5105
5145
|
this.start();
|
|
5106
5146
|
this.onScroll = this.onScroll.bind(this);
|
|
5107
5147
|
window.addEventListener("scroll", this.onScroll);
|
|
@@ -5122,10 +5162,12 @@ class DOMObserver {
|
|
|
5122
5162
|
}, {});
|
|
5123
5163
|
}
|
|
5124
5164
|
this.listenForScroll();
|
|
5165
|
+
this.readSelectionRange();
|
|
5166
|
+
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5125
5167
|
}
|
|
5126
5168
|
onScroll(e) {
|
|
5127
5169
|
if (this.intersecting)
|
|
5128
|
-
this.flush();
|
|
5170
|
+
this.flush(false);
|
|
5129
5171
|
this.onScrollChanged(e);
|
|
5130
5172
|
}
|
|
5131
5173
|
updateGaps(gaps) {
|
|
@@ -5137,8 +5179,8 @@ class DOMObserver {
|
|
|
5137
5179
|
}
|
|
5138
5180
|
}
|
|
5139
5181
|
onSelectionChange(event) {
|
|
5140
|
-
if (this.
|
|
5141
|
-
|
|
5182
|
+
if (!this.readSelectionRange())
|
|
5183
|
+
return;
|
|
5142
5184
|
let { view } = this, sel = this.selectionRange;
|
|
5143
5185
|
if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel))
|
|
5144
5186
|
return;
|
|
@@ -5153,24 +5195,22 @@ class DOMObserver {
|
|
|
5153
5195
|
sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
5154
5196
|
this.flushSoon();
|
|
5155
5197
|
else
|
|
5156
|
-
this.flush();
|
|
5157
|
-
}
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
return this.
|
|
5198
|
+
this.flush(false);
|
|
5199
|
+
}
|
|
5200
|
+
readSelectionRange() {
|
|
5201
|
+
let { root } = this.view, domSel = getSelection(root);
|
|
5202
|
+
// The Selection object is broken in shadow roots in Safari. See
|
|
5203
|
+
// https://github.com/codemirror/codemirror.next/issues/414
|
|
5204
|
+
let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM &&
|
|
5205
|
+
safariSelectionRangeHack(this.view) || domSel;
|
|
5206
|
+
if (this.selectionRange.eq(range))
|
|
5207
|
+
return false;
|
|
5208
|
+
this.selectionRange.setRange(range);
|
|
5209
|
+
return this.selectionChanged = true;
|
|
5168
5210
|
}
|
|
5169
5211
|
setSelectionRange(anchor, head) {
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
this._selectionRange = { anchorNode: anchor.node, anchorOffset: anchor.offset,
|
|
5173
|
-
focusNode: head.node, focusOffset: head.offset };
|
|
5212
|
+
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
|
5213
|
+
this.selectionChanged = false;
|
|
5174
5214
|
}
|
|
5175
5215
|
listenForScroll() {
|
|
5176
5216
|
this.parentCheck = -1;
|
|
@@ -5217,7 +5257,6 @@ class DOMObserver {
|
|
|
5217
5257
|
if (this.active)
|
|
5218
5258
|
return;
|
|
5219
5259
|
this.observer.observe(this.dom, observeOptions);
|
|
5220
|
-
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5221
5260
|
if (useCharData)
|
|
5222
5261
|
this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5223
5262
|
this.active = true;
|
|
@@ -5227,18 +5266,14 @@ class DOMObserver {
|
|
|
5227
5266
|
return;
|
|
5228
5267
|
this.active = false;
|
|
5229
5268
|
this.observer.disconnect();
|
|
5230
|
-
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5231
5269
|
if (useCharData)
|
|
5232
5270
|
this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5233
5271
|
}
|
|
5234
|
-
clearSelection() {
|
|
5235
|
-
this.ignoreSelection.set(this.selectionRange);
|
|
5236
|
-
}
|
|
5237
5272
|
// Throw away any pending changes
|
|
5238
5273
|
clear() {
|
|
5239
5274
|
this.observer.takeRecords();
|
|
5240
5275
|
this.queue.length = 0;
|
|
5241
|
-
this.
|
|
5276
|
+
this.selectionChanged = false;
|
|
5242
5277
|
}
|
|
5243
5278
|
flushSoon() {
|
|
5244
5279
|
if (this.delayedFlush < 0)
|
|
@@ -5275,24 +5310,24 @@ class DOMObserver {
|
|
|
5275
5310
|
return { from, to, typeOver };
|
|
5276
5311
|
}
|
|
5277
5312
|
// Apply pending changes, if any
|
|
5278
|
-
flush() {
|
|
5313
|
+
flush(readSelection = true) {
|
|
5314
|
+
if (readSelection)
|
|
5315
|
+
this.readSelectionRange();
|
|
5279
5316
|
// Completely hold off flushing when pending keys are set—the code
|
|
5280
5317
|
// managing those will make sure processRecords is called and the
|
|
5281
5318
|
// view is resynchronized after
|
|
5282
5319
|
if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
|
|
5283
5320
|
return;
|
|
5284
|
-
this.lastFlush = Date.now();
|
|
5285
5321
|
let { from, to, typeOver } = this.processRecords();
|
|
5286
|
-
let
|
|
5287
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5322
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
5288
5323
|
if (from < 0 && !newSel)
|
|
5289
5324
|
return;
|
|
5325
|
+
this.selectionChanged = false;
|
|
5290
5326
|
let startState = this.view.state;
|
|
5291
5327
|
this.onChange(from, to, typeOver);
|
|
5292
5328
|
// The view wasn't updated
|
|
5293
5329
|
if (this.view.state == startState)
|
|
5294
5330
|
this.view.docView.reset(newSel);
|
|
5295
|
-
this.clearSelection();
|
|
5296
5331
|
}
|
|
5297
5332
|
readMutation(rec) {
|
|
5298
5333
|
let cView = this.view.docView.nearest(rec.target);
|
|
@@ -5315,15 +5350,16 @@ class DOMObserver {
|
|
|
5315
5350
|
}
|
|
5316
5351
|
}
|
|
5317
5352
|
destroy() {
|
|
5353
|
+
var _a, _b, _c;
|
|
5318
5354
|
this.stop();
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
this.gapIntersection.disconnect();
|
|
5355
|
+
(_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
5356
|
+
(_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
5357
|
+
(_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
5323
5358
|
for (let dom of this.scrollTargets)
|
|
5324
5359
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5325
5360
|
window.removeEventListener("scroll", this.onScroll);
|
|
5326
5361
|
clearTimeout(this.parentCheck);
|
|
5362
|
+
clearTimeout(this.resizeTimeout);
|
|
5327
5363
|
}
|
|
5328
5364
|
}
|
|
5329
5365
|
function findChild(cView, dom, dir) {
|
|
@@ -5336,6 +5372,7 @@ function findChild(cView, dom, dir) {
|
|
|
5336
5372
|
}
|
|
5337
5373
|
return null;
|
|
5338
5374
|
}
|
|
5375
|
+
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5339
5376
|
function safariSelectionRangeHack(view) {
|
|
5340
5377
|
let found = null;
|
|
5341
5378
|
// Because Safari (at least in 2018-2021) doesn't provide regular
|
|
@@ -5755,6 +5792,7 @@ class EditorView {
|
|
|
5755
5792
|
this.mountStyles();
|
|
5756
5793
|
this.updateAttrs();
|
|
5757
5794
|
this.showAnnouncements(transactions);
|
|
5795
|
+
this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
|
5758
5796
|
}
|
|
5759
5797
|
finally {
|
|
5760
5798
|
this.updateState = 0 /* Idle */;
|
|
@@ -5832,7 +5870,7 @@ class EditorView {
|
|
|
5832
5870
|
return;
|
|
5833
5871
|
if (this.measureScheduled > -1)
|
|
5834
5872
|
cancelAnimationFrame(this.measureScheduled);
|
|
5835
|
-
this.measureScheduled =
|
|
5873
|
+
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
5836
5874
|
if (flush)
|
|
5837
5875
|
this.observer.flush();
|
|
5838
5876
|
let updated = null;
|
|
@@ -5872,8 +5910,7 @@ class EditorView {
|
|
|
5872
5910
|
this.inputState.update(update);
|
|
5873
5911
|
}
|
|
5874
5912
|
this.updateAttrs();
|
|
5875
|
-
|
|
5876
|
-
this.docView.update(update);
|
|
5913
|
+
let redrawn = changed > 0 && this.docView.update(update);
|
|
5877
5914
|
for (let i = 0; i < measuring.length; i++)
|
|
5878
5915
|
if (measured[i] != BadMeasure) {
|
|
5879
5916
|
try {
|
|
@@ -5887,14 +5924,16 @@ class EditorView {
|
|
|
5887
5924
|
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5888
5925
|
this.viewState.scrollTarget = null;
|
|
5889
5926
|
}
|
|
5927
|
+
if (changed)
|
|
5928
|
+
this.docView.updateSelection(redrawn);
|
|
5890
5929
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5891
5930
|
break;
|
|
5892
5931
|
}
|
|
5893
5932
|
}
|
|
5894
5933
|
finally {
|
|
5895
5934
|
this.updateState = 0 /* Idle */;
|
|
5935
|
+
this.measureScheduled = -1;
|
|
5896
5936
|
}
|
|
5897
|
-
this.measureScheduled = -1;
|
|
5898
5937
|
if (updated && !updated.empty)
|
|
5899
5938
|
for (let listener of this.state.facet(updateListener))
|
|
5900
5939
|
listener(updated);
|
|
@@ -5911,8 +5950,6 @@ class EditorView {
|
|
|
5911
5950
|
let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
|
|
5912
5951
|
class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
|
|
5913
5952
|
});
|
|
5914
|
-
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5915
|
-
this.editorAttrs = editorAttrs;
|
|
5916
5953
|
let contentAttrs = {
|
|
5917
5954
|
spellcheck: "false",
|
|
5918
5955
|
autocorrect: "off",
|
|
@@ -5927,7 +5964,11 @@ class EditorView {
|
|
|
5927
5964
|
if (this.state.readOnly)
|
|
5928
5965
|
contentAttrs["aria-readonly"] = "true";
|
|
5929
5966
|
combineAttrs(this.state.facet(contentAttributes), contentAttrs);
|
|
5930
|
-
|
|
5967
|
+
this.observer.ignore(() => {
|
|
5968
|
+
updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
5969
|
+
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5970
|
+
});
|
|
5971
|
+
this.editorAttrs = editorAttrs;
|
|
5931
5972
|
this.contentAttrs = contentAttrs;
|
|
5932
5973
|
}
|
|
5933
5974
|
showAnnouncements(trs) {
|
package/dist/index.js
CHANGED
|
@@ -183,7 +183,7 @@ function scrollRectIntoView(dom, rect, side, center) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
|
-
class
|
|
186
|
+
class DOMSelectionState {
|
|
187
187
|
constructor() {
|
|
188
188
|
this.anchorNode = null;
|
|
189
189
|
this.anchorOffset = 0;
|
|
@@ -194,11 +194,14 @@ class DOMSelection {
|
|
|
194
194
|
return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
|
|
195
195
|
this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
|
|
196
196
|
}
|
|
197
|
-
|
|
198
|
-
this.anchorNode
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
197
|
+
setRange(range) {
|
|
198
|
+
this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset);
|
|
199
|
+
}
|
|
200
|
+
set(anchorNode, anchorOffset, focusNode, focusOffset) {
|
|
201
|
+
this.anchorNode = anchorNode;
|
|
202
|
+
this.anchorOffset = anchorOffset;
|
|
203
|
+
this.focusNode = focusNode;
|
|
204
|
+
this.focusOffset = focusOffset;
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
let preventScrollSupported = null;
|
|
@@ -1767,11 +1770,17 @@ class PluginInstance {
|
|
|
1767
1770
|
}
|
|
1768
1771
|
}
|
|
1769
1772
|
PluginInstance.dummy = /*@__PURE__*/new PluginInstance(/*@__PURE__*/ViewPlugin.define(() => ({})));
|
|
1773
|
+
function combineFacetAttrs(values) {
|
|
1774
|
+
let result = {};
|
|
1775
|
+
for (let i = values.length - 1; i >= 0; i--)
|
|
1776
|
+
combineAttrs(values[i], result);
|
|
1777
|
+
return result;
|
|
1778
|
+
}
|
|
1770
1779
|
const editorAttributes = /*@__PURE__*/Facet.define({
|
|
1771
|
-
combine:
|
|
1780
|
+
combine: combineFacetAttrs
|
|
1772
1781
|
});
|
|
1773
1782
|
const contentAttributes = /*@__PURE__*/Facet.define({
|
|
1774
|
-
combine:
|
|
1783
|
+
combine: combineFacetAttrs
|
|
1775
1784
|
});
|
|
1776
1785
|
// Provide decorations
|
|
1777
1786
|
const decorations = /*@__PURE__*/Facet.define();
|
|
@@ -1933,6 +1942,10 @@ class DocView extends ContentView {
|
|
|
1933
1942
|
// we don't mess it up when reading it back it
|
|
1934
1943
|
this.impreciseAnchor = null;
|
|
1935
1944
|
this.impreciseHead = null;
|
|
1945
|
+
this.forceSelection = false;
|
|
1946
|
+
// Used by the resize observer to ignore resizes that we caused
|
|
1947
|
+
// ourselves
|
|
1948
|
+
this.lastUpdate = Date.now();
|
|
1936
1949
|
this.setDOM(view.contentDOM);
|
|
1937
1950
|
this.children = [new LineView];
|
|
1938
1951
|
this.children[0].setParent(this);
|
|
@@ -1965,21 +1978,22 @@ class DocView extends ContentView {
|
|
|
1965
1978
|
// getSelection than the one that it actually shows to the user.
|
|
1966
1979
|
// This forces a selection update when lines are joined to work
|
|
1967
1980
|
// around that. Issue #54
|
|
1968
|
-
|
|
1969
|
-
update.state.doc.lines != update.startState.doc.lines
|
|
1981
|
+
if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update &&
|
|
1982
|
+
update.state.doc.lines != update.startState.doc.lines)
|
|
1983
|
+
this.forceSelection = true;
|
|
1970
1984
|
let prevDeco = this.decorations, deco = this.updateDeco();
|
|
1971
1985
|
let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
|
1972
1986
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
1973
|
-
let pointerSel = update.transactions.some(tr => tr.isUserEvent("select.pointer"));
|
|
1974
1987
|
if (this.dirty == 0 /* Not */ && changedRanges.length == 0 &&
|
|
1975
1988
|
!(update.flags & 4 /* Viewport */) &&
|
|
1976
1989
|
update.state.selection.main.from >= this.view.viewport.from &&
|
|
1977
1990
|
update.state.selection.main.to <= this.view.viewport.to) {
|
|
1978
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
1979
1991
|
return false;
|
|
1980
1992
|
}
|
|
1981
1993
|
else {
|
|
1982
|
-
this.updateInner(changedRanges, deco, update.startState.doc.length
|
|
1994
|
+
this.updateInner(changedRanges, deco, update.startState.doc.length);
|
|
1995
|
+
if (update.transactions.length)
|
|
1996
|
+
this.lastUpdate = Date.now();
|
|
1983
1997
|
return true;
|
|
1984
1998
|
}
|
|
1985
1999
|
}
|
|
@@ -1987,13 +2001,15 @@ class DocView extends ContentView {
|
|
|
1987
2001
|
if (this.dirty) {
|
|
1988
2002
|
this.view.observer.ignore(() => this.view.docView.sync());
|
|
1989
2003
|
this.dirty = 0 /* Not */;
|
|
2004
|
+
this.updateSelection(true);
|
|
1990
2005
|
}
|
|
1991
|
-
|
|
2006
|
+
else {
|
|
1992
2007
|
this.updateSelection();
|
|
2008
|
+
}
|
|
1993
2009
|
}
|
|
1994
2010
|
// Used both by update and checkLayout do perform the actual DOM
|
|
1995
2011
|
// update
|
|
1996
|
-
updateInner(changes, deco, oldLength
|
|
2012
|
+
updateInner(changes, deco, oldLength) {
|
|
1997
2013
|
this.updateChildren(changes, deco, oldLength);
|
|
1998
2014
|
let { observer } = this.view;
|
|
1999
2015
|
observer.ignore(() => {
|
|
@@ -2011,8 +2027,7 @@ class DocView extends ContentView {
|
|
|
2011
2027
|
this.sync(track);
|
|
2012
2028
|
this.dirty = 0 /* Not */;
|
|
2013
2029
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2014
|
-
forceSelection = true;
|
|
2015
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
2030
|
+
this.forceSelection = true;
|
|
2016
2031
|
this.dom.style.height = "";
|
|
2017
2032
|
});
|
|
2018
2033
|
let gaps = [];
|
|
@@ -2098,10 +2113,14 @@ class DocView extends ContentView {
|
|
|
2098
2113
|
this.replaceChildren(fromI, toI, content);
|
|
2099
2114
|
}
|
|
2100
2115
|
// Sync the DOM selection to this.state.selection
|
|
2101
|
-
updateSelection(
|
|
2116
|
+
updateSelection(mustRead = false, fromPointer = false) {
|
|
2117
|
+
if (mustRead)
|
|
2118
|
+
this.view.observer.readSelectionRange();
|
|
2102
2119
|
if (!(fromPointer || this.mayControlSelection()) ||
|
|
2103
2120
|
browser.ios && this.view.inputState.rapidCompositionStart)
|
|
2104
2121
|
return;
|
|
2122
|
+
let force = this.forceSelection;
|
|
2123
|
+
this.forceSelection = false;
|
|
2105
2124
|
let main = this.view.state.selection.main;
|
|
2106
2125
|
// FIXME need to handle the case where the selection falls inside a block range
|
|
2107
2126
|
let anchor = this.domAtPos(main.anchor);
|
|
@@ -3737,7 +3756,7 @@ handlers.beforeinput = (view, event) => {
|
|
|
3737
3756
|
}
|
|
3738
3757
|
};
|
|
3739
3758
|
|
|
3740
|
-
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line"];
|
|
3759
|
+
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
3741
3760
|
class HeightOracle {
|
|
3742
3761
|
constructor() {
|
|
3743
3762
|
this.doc = Text.empty;
|
|
@@ -4470,6 +4489,7 @@ class ViewState {
|
|
|
4470
4489
|
this.paddingTop = 0;
|
|
4471
4490
|
this.paddingBottom = 0;
|
|
4472
4491
|
this.contentWidth = 0;
|
|
4492
|
+
this.editorHeight = 0;
|
|
4473
4493
|
this.heightOracle = new HeightOracle;
|
|
4474
4494
|
// See VP.MaxDOMHeight
|
|
4475
4495
|
this.scaler = IdScaler;
|
|
@@ -4569,6 +4589,10 @@ class ViewState {
|
|
|
4569
4589
|
this.contentWidth = contentWidth;
|
|
4570
4590
|
result |= 8 /* Geometry */;
|
|
4571
4591
|
}
|
|
4592
|
+
if (this.editorHeight != docView.view.scrollDOM.clientHeight) {
|
|
4593
|
+
this.editorHeight = docView.view.scrollDOM.clientHeight;
|
|
4594
|
+
result |= 8 /* Geometry */;
|
|
4595
|
+
}
|
|
4572
4596
|
if (dTop > 0 && dBottom > 0)
|
|
4573
4597
|
bias = Math.max(dTop, dBottom);
|
|
4574
4598
|
else if (dTop < 0 && dBottom < 0)
|
|
@@ -5054,24 +5078,30 @@ class DOMObserver {
|
|
|
5054
5078
|
this.onChange = onChange;
|
|
5055
5079
|
this.onScrollChanged = onScrollChanged;
|
|
5056
5080
|
this.active = false;
|
|
5057
|
-
|
|
5081
|
+
// The known selection. Kept in our own object, as opposed to just
|
|
5082
|
+
// directly accessing the selection because:
|
|
5083
|
+
// - Safari doesn't report the right selection in shadow DOM
|
|
5084
|
+
// - Reading from the selection forces a DOM layout
|
|
5085
|
+
// - This way, we can ignore selectionchange events if we have
|
|
5086
|
+
// already seen the 'new' selection
|
|
5087
|
+
this.selectionRange = new DOMSelectionState;
|
|
5088
|
+
// Set when a selection change is detected, cleared on flush
|
|
5089
|
+
this.selectionChanged = false;
|
|
5058
5090
|
this.delayedFlush = -1;
|
|
5091
|
+
this.resizeTimeout = -1;
|
|
5059
5092
|
this.queue = [];
|
|
5060
|
-
this.lastFlush = 0;
|
|
5061
5093
|
this.scrollTargets = [];
|
|
5062
5094
|
this.intersection = null;
|
|
5095
|
+
this.resize = null;
|
|
5063
5096
|
this.intersecting = false;
|
|
5064
5097
|
this.gapIntersection = null;
|
|
5065
5098
|
this.gaps = [];
|
|
5066
|
-
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5067
|
-
this._selectionRange = null;
|
|
5068
5099
|
// Timeout for scheduling check of the parents that need scroll handlers
|
|
5069
5100
|
this.parentCheck = -1;
|
|
5070
5101
|
this.dom = view.contentDOM;
|
|
5071
5102
|
this.observer = new MutationObserver(mutations => {
|
|
5072
5103
|
for (let mut of mutations)
|
|
5073
5104
|
this.queue.push(mut);
|
|
5074
|
-
this._selectionRange = null;
|
|
5075
5105
|
// IE11 will sometimes (on typing over a selection or
|
|
5076
5106
|
// backspacing out a single character text node) call the
|
|
5077
5107
|
// observer callback before actually updating the DOM.
|
|
@@ -5096,6 +5126,16 @@ class DOMObserver {
|
|
|
5096
5126
|
this.flushSoon();
|
|
5097
5127
|
};
|
|
5098
5128
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5129
|
+
if (typeof ResizeObserver == "function") {
|
|
5130
|
+
this.resize = new ResizeObserver(() => {
|
|
5131
|
+
if (this.view.docView.lastUpdate < Date.now() - 75 && this.resizeTimeout < 0)
|
|
5132
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5133
|
+
this.resizeTimeout = -1;
|
|
5134
|
+
this.view.requestMeasure();
|
|
5135
|
+
}, 50);
|
|
5136
|
+
});
|
|
5137
|
+
this.resize.observe(view.scrollDOM);
|
|
5138
|
+
}
|
|
5099
5139
|
this.start();
|
|
5100
5140
|
this.onScroll = this.onScroll.bind(this);
|
|
5101
5141
|
window.addEventListener("scroll", this.onScroll);
|
|
@@ -5116,10 +5156,12 @@ class DOMObserver {
|
|
|
5116
5156
|
}, {});
|
|
5117
5157
|
}
|
|
5118
5158
|
this.listenForScroll();
|
|
5159
|
+
this.readSelectionRange();
|
|
5160
|
+
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5119
5161
|
}
|
|
5120
5162
|
onScroll(e) {
|
|
5121
5163
|
if (this.intersecting)
|
|
5122
|
-
this.flush();
|
|
5164
|
+
this.flush(false);
|
|
5123
5165
|
this.onScrollChanged(e);
|
|
5124
5166
|
}
|
|
5125
5167
|
updateGaps(gaps) {
|
|
@@ -5131,8 +5173,8 @@ class DOMObserver {
|
|
|
5131
5173
|
}
|
|
5132
5174
|
}
|
|
5133
5175
|
onSelectionChange(event) {
|
|
5134
|
-
if (this.
|
|
5135
|
-
|
|
5176
|
+
if (!this.readSelectionRange())
|
|
5177
|
+
return;
|
|
5136
5178
|
let { view } = this, sel = this.selectionRange;
|
|
5137
5179
|
if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel))
|
|
5138
5180
|
return;
|
|
@@ -5147,24 +5189,22 @@ class DOMObserver {
|
|
|
5147
5189
|
sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
5148
5190
|
this.flushSoon();
|
|
5149
5191
|
else
|
|
5150
|
-
this.flush();
|
|
5151
|
-
}
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
return this.
|
|
5192
|
+
this.flush(false);
|
|
5193
|
+
}
|
|
5194
|
+
readSelectionRange() {
|
|
5195
|
+
let { root } = this.view, domSel = getSelection(root);
|
|
5196
|
+
// The Selection object is broken in shadow roots in Safari. See
|
|
5197
|
+
// https://github.com/codemirror/codemirror.next/issues/414
|
|
5198
|
+
let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM &&
|
|
5199
|
+
safariSelectionRangeHack(this.view) || domSel;
|
|
5200
|
+
if (this.selectionRange.eq(range))
|
|
5201
|
+
return false;
|
|
5202
|
+
this.selectionRange.setRange(range);
|
|
5203
|
+
return this.selectionChanged = true;
|
|
5162
5204
|
}
|
|
5163
5205
|
setSelectionRange(anchor, head) {
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
this._selectionRange = { anchorNode: anchor.node, anchorOffset: anchor.offset,
|
|
5167
|
-
focusNode: head.node, focusOffset: head.offset };
|
|
5206
|
+
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
|
5207
|
+
this.selectionChanged = false;
|
|
5168
5208
|
}
|
|
5169
5209
|
listenForScroll() {
|
|
5170
5210
|
this.parentCheck = -1;
|
|
@@ -5211,7 +5251,6 @@ class DOMObserver {
|
|
|
5211
5251
|
if (this.active)
|
|
5212
5252
|
return;
|
|
5213
5253
|
this.observer.observe(this.dom, observeOptions);
|
|
5214
|
-
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5215
5254
|
if (useCharData)
|
|
5216
5255
|
this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5217
5256
|
this.active = true;
|
|
@@ -5221,18 +5260,14 @@ class DOMObserver {
|
|
|
5221
5260
|
return;
|
|
5222
5261
|
this.active = false;
|
|
5223
5262
|
this.observer.disconnect();
|
|
5224
|
-
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5225
5263
|
if (useCharData)
|
|
5226
5264
|
this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5227
5265
|
}
|
|
5228
|
-
clearSelection() {
|
|
5229
|
-
this.ignoreSelection.set(this.selectionRange);
|
|
5230
|
-
}
|
|
5231
5266
|
// Throw away any pending changes
|
|
5232
5267
|
clear() {
|
|
5233
5268
|
this.observer.takeRecords();
|
|
5234
5269
|
this.queue.length = 0;
|
|
5235
|
-
this.
|
|
5270
|
+
this.selectionChanged = false;
|
|
5236
5271
|
}
|
|
5237
5272
|
flushSoon() {
|
|
5238
5273
|
if (this.delayedFlush < 0)
|
|
@@ -5269,24 +5304,24 @@ class DOMObserver {
|
|
|
5269
5304
|
return { from, to, typeOver };
|
|
5270
5305
|
}
|
|
5271
5306
|
// Apply pending changes, if any
|
|
5272
|
-
flush() {
|
|
5307
|
+
flush(readSelection = true) {
|
|
5308
|
+
if (readSelection)
|
|
5309
|
+
this.readSelectionRange();
|
|
5273
5310
|
// Completely hold off flushing when pending keys are set—the code
|
|
5274
5311
|
// managing those will make sure processRecords is called and the
|
|
5275
5312
|
// view is resynchronized after
|
|
5276
5313
|
if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
|
|
5277
5314
|
return;
|
|
5278
|
-
this.lastFlush = Date.now();
|
|
5279
5315
|
let { from, to, typeOver } = this.processRecords();
|
|
5280
|
-
let
|
|
5281
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5316
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
5282
5317
|
if (from < 0 && !newSel)
|
|
5283
5318
|
return;
|
|
5319
|
+
this.selectionChanged = false;
|
|
5284
5320
|
let startState = this.view.state;
|
|
5285
5321
|
this.onChange(from, to, typeOver);
|
|
5286
5322
|
// The view wasn't updated
|
|
5287
5323
|
if (this.view.state == startState)
|
|
5288
5324
|
this.view.docView.reset(newSel);
|
|
5289
|
-
this.clearSelection();
|
|
5290
5325
|
}
|
|
5291
5326
|
readMutation(rec) {
|
|
5292
5327
|
let cView = this.view.docView.nearest(rec.target);
|
|
@@ -5309,15 +5344,16 @@ class DOMObserver {
|
|
|
5309
5344
|
}
|
|
5310
5345
|
}
|
|
5311
5346
|
destroy() {
|
|
5347
|
+
var _a, _b, _c;
|
|
5312
5348
|
this.stop();
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
this.gapIntersection.disconnect();
|
|
5349
|
+
(_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
5350
|
+
(_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
5351
|
+
(_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
5317
5352
|
for (let dom of this.scrollTargets)
|
|
5318
5353
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5319
5354
|
window.removeEventListener("scroll", this.onScroll);
|
|
5320
5355
|
clearTimeout(this.parentCheck);
|
|
5356
|
+
clearTimeout(this.resizeTimeout);
|
|
5321
5357
|
}
|
|
5322
5358
|
}
|
|
5323
5359
|
function findChild(cView, dom, dir) {
|
|
@@ -5330,6 +5366,7 @@ function findChild(cView, dom, dir) {
|
|
|
5330
5366
|
}
|
|
5331
5367
|
return null;
|
|
5332
5368
|
}
|
|
5369
|
+
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5333
5370
|
function safariSelectionRangeHack(view) {
|
|
5334
5371
|
let found = null;
|
|
5335
5372
|
// Because Safari (at least in 2018-2021) doesn't provide regular
|
|
@@ -5749,6 +5786,7 @@ class EditorView {
|
|
|
5749
5786
|
this.mountStyles();
|
|
5750
5787
|
this.updateAttrs();
|
|
5751
5788
|
this.showAnnouncements(transactions);
|
|
5789
|
+
this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
|
5752
5790
|
}
|
|
5753
5791
|
finally {
|
|
5754
5792
|
this.updateState = 0 /* Idle */;
|
|
@@ -5826,7 +5864,7 @@ class EditorView {
|
|
|
5826
5864
|
return;
|
|
5827
5865
|
if (this.measureScheduled > -1)
|
|
5828
5866
|
cancelAnimationFrame(this.measureScheduled);
|
|
5829
|
-
this.measureScheduled =
|
|
5867
|
+
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
5830
5868
|
if (flush)
|
|
5831
5869
|
this.observer.flush();
|
|
5832
5870
|
let updated = null;
|
|
@@ -5866,8 +5904,7 @@ class EditorView {
|
|
|
5866
5904
|
this.inputState.update(update);
|
|
5867
5905
|
}
|
|
5868
5906
|
this.updateAttrs();
|
|
5869
|
-
|
|
5870
|
-
this.docView.update(update);
|
|
5907
|
+
let redrawn = changed > 0 && this.docView.update(update);
|
|
5871
5908
|
for (let i = 0; i < measuring.length; i++)
|
|
5872
5909
|
if (measured[i] != BadMeasure) {
|
|
5873
5910
|
try {
|
|
@@ -5881,14 +5918,16 @@ class EditorView {
|
|
|
5881
5918
|
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5882
5919
|
this.viewState.scrollTarget = null;
|
|
5883
5920
|
}
|
|
5921
|
+
if (changed)
|
|
5922
|
+
this.docView.updateSelection(redrawn);
|
|
5884
5923
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5885
5924
|
break;
|
|
5886
5925
|
}
|
|
5887
5926
|
}
|
|
5888
5927
|
finally {
|
|
5889
5928
|
this.updateState = 0 /* Idle */;
|
|
5929
|
+
this.measureScheduled = -1;
|
|
5890
5930
|
}
|
|
5891
|
-
this.measureScheduled = -1;
|
|
5892
5931
|
if (updated && !updated.empty)
|
|
5893
5932
|
for (let listener of this.state.facet(updateListener))
|
|
5894
5933
|
listener(updated);
|
|
@@ -5905,8 +5944,6 @@ class EditorView {
|
|
|
5905
5944
|
let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
|
|
5906
5945
|
class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
|
|
5907
5946
|
});
|
|
5908
|
-
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5909
|
-
this.editorAttrs = editorAttrs;
|
|
5910
5947
|
let contentAttrs = {
|
|
5911
5948
|
spellcheck: "false",
|
|
5912
5949
|
autocorrect: "off",
|
|
@@ -5921,7 +5958,11 @@ class EditorView {
|
|
|
5921
5958
|
if (this.state.readOnly)
|
|
5922
5959
|
contentAttrs["aria-readonly"] = "true";
|
|
5923
5960
|
combineAttrs(this.state.facet(contentAttributes), contentAttrs);
|
|
5924
|
-
|
|
5961
|
+
this.observer.ignore(() => {
|
|
5962
|
+
updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
5963
|
+
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5964
|
+
});
|
|
5965
|
+
this.editorAttrs = editorAttrs;
|
|
5925
5966
|
this.contentAttrs = contentAttrs;
|
|
5926
5967
|
}
|
|
5927
5968
|
showAnnouncements(trs) {
|