@codemirror/view 0.19.19 → 0.19.23
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 +38 -0
- package/dist/index.cjs +290 -162
- package/dist/index.d.ts +52 -2
- package/dist/index.js +290 -162
- package/package.json +1 -1
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;
|
|
@@ -1905,7 +1908,7 @@ class ViewUpdate {
|
|
|
1905
1908
|
Whether the document changed in this update.
|
|
1906
1909
|
*/
|
|
1907
1910
|
get docChanged() {
|
|
1908
|
-
return this.
|
|
1911
|
+
return !this.changes.empty;
|
|
1909
1912
|
}
|
|
1910
1913
|
/**
|
|
1911
1914
|
Whether the selection was explicitly set in this update.
|
|
@@ -1939,6 +1942,10 @@ class DocView extends ContentView {
|
|
|
1939
1942
|
// we don't mess it up when reading it back it
|
|
1940
1943
|
this.impreciseAnchor = null;
|
|
1941
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();
|
|
1942
1949
|
this.setDOM(view.contentDOM);
|
|
1943
1950
|
this.children = [new LineView];
|
|
1944
1951
|
this.children[0].setParent(this);
|
|
@@ -1971,21 +1978,19 @@ class DocView extends ContentView {
|
|
|
1971
1978
|
// getSelection than the one that it actually shows to the user.
|
|
1972
1979
|
// This forces a selection update when lines are joined to work
|
|
1973
1980
|
// around that. Issue #54
|
|
1974
|
-
|
|
1975
|
-
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;
|
|
1976
1984
|
let prevDeco = this.decorations, deco = this.updateDeco();
|
|
1977
1985
|
let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
|
1978
1986
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
1979
|
-
|
|
1980
|
-
if (this.dirty == 0 /* Not */ && changedRanges.length == 0 &&
|
|
1981
|
-
!(update.flags & 4 /* Viewport */) &&
|
|
1982
|
-
update.state.selection.main.from >= this.view.viewport.from &&
|
|
1983
|
-
update.state.selection.main.to <= this.view.viewport.to) {
|
|
1984
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
1987
|
+
if (this.dirty == 0 /* Not */ && changedRanges.length == 0) {
|
|
1985
1988
|
return false;
|
|
1986
1989
|
}
|
|
1987
1990
|
else {
|
|
1988
|
-
this.updateInner(changedRanges, deco, update.startState.doc.length
|
|
1991
|
+
this.updateInner(changedRanges, deco, update.startState.doc.length);
|
|
1992
|
+
if (update.transactions.length)
|
|
1993
|
+
this.lastUpdate = Date.now();
|
|
1989
1994
|
return true;
|
|
1990
1995
|
}
|
|
1991
1996
|
}
|
|
@@ -1993,13 +1998,16 @@ class DocView extends ContentView {
|
|
|
1993
1998
|
if (this.dirty) {
|
|
1994
1999
|
this.view.observer.ignore(() => this.view.docView.sync());
|
|
1995
2000
|
this.dirty = 0 /* Not */;
|
|
2001
|
+
this.updateSelection(true);
|
|
1996
2002
|
}
|
|
1997
|
-
|
|
2003
|
+
else {
|
|
1998
2004
|
this.updateSelection();
|
|
2005
|
+
}
|
|
1999
2006
|
}
|
|
2000
2007
|
// Used both by update and checkLayout do perform the actual DOM
|
|
2001
2008
|
// update
|
|
2002
|
-
updateInner(changes, deco, oldLength
|
|
2009
|
+
updateInner(changes, deco, oldLength) {
|
|
2010
|
+
this.view.viewState.mustMeasureContent = true;
|
|
2003
2011
|
this.updateChildren(changes, deco, oldLength);
|
|
2004
2012
|
let { observer } = this.view;
|
|
2005
2013
|
observer.ignore(() => {
|
|
@@ -2007,7 +2015,7 @@ class DocView extends ContentView {
|
|
|
2007
2015
|
// messes with the scroll position during DOM mutation (though
|
|
2008
2016
|
// no relayout is triggered and I cannot imagine how it can
|
|
2009
2017
|
// recompute the scroll position without a layout)
|
|
2010
|
-
this.dom.style.height = this.view.viewState.
|
|
2018
|
+
this.dom.style.height = this.view.viewState.contentHeight + "px";
|
|
2011
2019
|
this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : "";
|
|
2012
2020
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2013
2021
|
// around the selection, get confused and report a different
|
|
@@ -2017,8 +2025,7 @@ class DocView extends ContentView {
|
|
|
2017
2025
|
this.sync(track);
|
|
2018
2026
|
this.dirty = 0 /* Not */;
|
|
2019
2027
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2020
|
-
forceSelection = true;
|
|
2021
|
-
this.updateSelection(forceSelection, pointerSel);
|
|
2028
|
+
this.forceSelection = true;
|
|
2022
2029
|
this.dom.style.height = "";
|
|
2023
2030
|
});
|
|
2024
2031
|
let gaps = [];
|
|
@@ -2104,10 +2111,14 @@ class DocView extends ContentView {
|
|
|
2104
2111
|
this.replaceChildren(fromI, toI, content);
|
|
2105
2112
|
}
|
|
2106
2113
|
// Sync the DOM selection to this.state.selection
|
|
2107
|
-
updateSelection(
|
|
2114
|
+
updateSelection(mustRead = false, fromPointer = false) {
|
|
2115
|
+
if (mustRead)
|
|
2116
|
+
this.view.observer.readSelectionRange();
|
|
2108
2117
|
if (!(fromPointer || this.mayControlSelection()) ||
|
|
2109
2118
|
browser.ios && this.view.inputState.rapidCompositionStart)
|
|
2110
2119
|
return;
|
|
2120
|
+
let force = this.forceSelection;
|
|
2121
|
+
this.forceSelection = false;
|
|
2111
2122
|
let main = this.view.state.selection.main;
|
|
2112
2123
|
// FIXME need to handle the case where the selection falls inside a block range
|
|
2113
2124
|
let anchor = this.domAtPos(main.anchor);
|
|
@@ -2289,7 +2300,7 @@ class DocView extends ContentView {
|
|
|
2289
2300
|
let next = i == vs.viewports.length ? null : vs.viewports[i];
|
|
2290
2301
|
let end = next ? next.from - 1 : this.length;
|
|
2291
2302
|
if (end > pos) {
|
|
2292
|
-
let height = vs.
|
|
2303
|
+
let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
|
2293
2304
|
deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end));
|
|
2294
2305
|
}
|
|
2295
2306
|
if (!next)
|
|
@@ -2895,13 +2906,14 @@ function domPosInText(node, x, y) {
|
|
|
2895
2906
|
}
|
|
2896
2907
|
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2897
2908
|
var _a;
|
|
2898
|
-
let content = view.contentDOM.getBoundingClientRect(),
|
|
2909
|
+
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
2899
2910
|
let halfLine = view.defaultLineHeight / 2;
|
|
2911
|
+
let block, yOffset = y - docTop;
|
|
2900
2912
|
for (let bounced = false;;) {
|
|
2901
|
-
block = view.
|
|
2902
|
-
if (block.top >
|
|
2903
|
-
bias = block.top >
|
|
2904
|
-
|
|
2913
|
+
block = view.elementAtHeight(yOffset);
|
|
2914
|
+
if (block.top > yOffset || block.bottom < yOffset) {
|
|
2915
|
+
bias = block.top > yOffset ? -1 : 1;
|
|
2916
|
+
yOffset = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, yOffset));
|
|
2905
2917
|
if (bounced)
|
|
2906
2918
|
return precise ? null : 0;
|
|
2907
2919
|
else
|
|
@@ -2909,8 +2921,9 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
2909
2921
|
}
|
|
2910
2922
|
if (block.type == BlockType.Text)
|
|
2911
2923
|
break;
|
|
2912
|
-
|
|
2924
|
+
yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
|
|
2913
2925
|
}
|
|
2926
|
+
y = docTop + yOffset;
|
|
2914
2927
|
let lineStart = block.from;
|
|
2915
2928
|
// Clip x to the viewport sides
|
|
2916
2929
|
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
@@ -3023,17 +3036,17 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3023
3036
|
return EditorSelection.cursor(startPos);
|
|
3024
3037
|
let goal = start.goalColumn, startY;
|
|
3025
3038
|
let rect = view.contentDOM.getBoundingClientRect();
|
|
3026
|
-
let startCoords = view.coordsAtPos(startPos);
|
|
3039
|
+
let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
|
|
3027
3040
|
if (startCoords) {
|
|
3028
3041
|
if (goal == null)
|
|
3029
3042
|
goal = startCoords.left - rect.left;
|
|
3030
3043
|
startY = dir < 0 ? startCoords.top : startCoords.bottom;
|
|
3031
3044
|
}
|
|
3032
3045
|
else {
|
|
3033
|
-
let line = view.viewState.
|
|
3046
|
+
let line = view.viewState.lineBlockAt(startPos - docTop);
|
|
3034
3047
|
if (goal == null)
|
|
3035
3048
|
goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
|
|
3036
|
-
startY = dir < 0 ? line.top : line.bottom;
|
|
3049
|
+
startY = (dir < 0 ? line.top : line.bottom) + docTop;
|
|
3037
3050
|
}
|
|
3038
3051
|
let resolvedGoal = rect.left + goal;
|
|
3039
3052
|
let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
|
@@ -3284,7 +3297,7 @@ class MouseSelection {
|
|
|
3284
3297
|
this.extend = startEvent.shiftKey;
|
|
3285
3298
|
this.multiple = view.state.facet(EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent);
|
|
3286
3299
|
this.dragMove = dragMovesSelection(view, startEvent);
|
|
3287
|
-
this.dragging = isInPrimarySelection(view, startEvent) ? null : false;
|
|
3300
|
+
this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
|
|
3288
3301
|
// When clicking outside of the selection, immediately apply the
|
|
3289
3302
|
// effect of starting the selection
|
|
3290
3303
|
if (this.dragging === false) {
|
|
@@ -3505,7 +3518,7 @@ function basicMouseSelection(view, event) {
|
|
|
3505
3518
|
let last = start, lastEvent = event;
|
|
3506
3519
|
return {
|
|
3507
3520
|
update(update) {
|
|
3508
|
-
if (update.
|
|
3521
|
+
if (update.docChanged) {
|
|
3509
3522
|
if (start)
|
|
3510
3523
|
start.pos = update.changes.mapPos(start.pos);
|
|
3511
3524
|
startSel = startSel.map(update.changes);
|
|
@@ -3769,7 +3782,10 @@ class HeightOracle {
|
|
|
3769
3782
|
return lines * this.lineHeight;
|
|
3770
3783
|
}
|
|
3771
3784
|
setDoc(doc) { this.doc = doc; return this; }
|
|
3772
|
-
|
|
3785
|
+
mustRefreshForStyle(whiteSpace, direction) {
|
|
3786
|
+
return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
|
|
3787
|
+
}
|
|
3788
|
+
mustRefreshForHeights(lineHeights) {
|
|
3773
3789
|
let newHeight = false;
|
|
3774
3790
|
for (let i = 0; i < lineHeights.length; i++) {
|
|
3775
3791
|
let h = lineHeights[i];
|
|
@@ -3781,7 +3797,7 @@ class HeightOracle {
|
|
|
3781
3797
|
this.heightSamples[Math.floor(h * 10)] = true;
|
|
3782
3798
|
}
|
|
3783
3799
|
}
|
|
3784
|
-
return newHeight
|
|
3800
|
+
return newHeight;
|
|
3785
3801
|
}
|
|
3786
3802
|
refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) {
|
|
3787
3803
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
@@ -3835,7 +3851,8 @@ class BlockInfo {
|
|
|
3835
3851
|
*/
|
|
3836
3852
|
length,
|
|
3837
3853
|
/**
|
|
3838
|
-
The top position of the element
|
|
3854
|
+
The top position of the element (relative to the top of the
|
|
3855
|
+
document).
|
|
3839
3856
|
*/
|
|
3840
3857
|
top,
|
|
3841
3858
|
/**
|
|
@@ -3869,13 +3886,19 @@ class BlockInfo {
|
|
|
3869
3886
|
.concat(Array.isArray(other.type) ? other.type : [other]);
|
|
3870
3887
|
return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
|
|
3871
3888
|
}
|
|
3889
|
+
/**
|
|
3890
|
+
FIXME remove on next breaking release @internal
|
|
3891
|
+
*/
|
|
3892
|
+
moveY(offset) {
|
|
3893
|
+
return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type);
|
|
3894
|
+
}
|
|
3872
3895
|
}
|
|
3873
3896
|
var QueryType = /*@__PURE__*/(function (QueryType) {
|
|
3874
3897
|
QueryType[QueryType["ByPos"] = 0] = "ByPos";
|
|
3875
3898
|
QueryType[QueryType["ByHeight"] = 1] = "ByHeight";
|
|
3876
3899
|
QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight";
|
|
3877
3900
|
return QueryType})(QueryType || (QueryType = {}));
|
|
3878
|
-
const Epsilon = 1e-
|
|
3901
|
+
const Epsilon = 1e-3;
|
|
3879
3902
|
class HeightMap {
|
|
3880
3903
|
constructor(length, // The number of characters covered
|
|
3881
3904
|
height, // Height of this part of the document
|
|
@@ -4102,22 +4125,30 @@ class HeightMapGap extends HeightMap {
|
|
|
4102
4125
|
// can't be widgets or collapsed ranges in those lines, because
|
|
4103
4126
|
// they would already have been added to the heightmap (gaps
|
|
4104
4127
|
// only contain plain text).
|
|
4105
|
-
let nodes = [], pos = Math.max(offset, measured.from);
|
|
4128
|
+
let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
|
|
4129
|
+
let wasChanged = oracle.heightChanged;
|
|
4106
4130
|
if (measured.from > offset)
|
|
4107
4131
|
nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
|
|
4108
4132
|
while (pos <= end && measured.more) {
|
|
4109
4133
|
let len = oracle.doc.lineAt(pos).length;
|
|
4110
4134
|
if (nodes.length)
|
|
4111
4135
|
nodes.push(null);
|
|
4112
|
-
let
|
|
4136
|
+
let height = measured.heights[measured.index++];
|
|
4137
|
+
if (singleHeight == -1)
|
|
4138
|
+
singleHeight = height;
|
|
4139
|
+
else if (Math.abs(height - singleHeight) >= Epsilon)
|
|
4140
|
+
singleHeight = -2;
|
|
4141
|
+
let line = new HeightMapText(len, height);
|
|
4113
4142
|
line.outdated = false;
|
|
4114
4143
|
nodes.push(line);
|
|
4115
4144
|
pos += len + 1;
|
|
4116
4145
|
}
|
|
4117
4146
|
if (pos <= end)
|
|
4118
4147
|
nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
|
|
4119
|
-
|
|
4120
|
-
|
|
4148
|
+
let result = HeightMap.of(nodes);
|
|
4149
|
+
oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
|
|
4150
|
+
Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon;
|
|
4151
|
+
return result;
|
|
4121
4152
|
}
|
|
4122
4153
|
else if (force || this.outdated) {
|
|
4123
4154
|
this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length));
|
|
@@ -4475,13 +4506,18 @@ class ViewState {
|
|
|
4475
4506
|
this.inView = true;
|
|
4476
4507
|
this.paddingTop = 0;
|
|
4477
4508
|
this.paddingBottom = 0;
|
|
4478
|
-
this.
|
|
4509
|
+
this.contentDOMWidth = 0;
|
|
4510
|
+
this.contentDOMHeight = 0;
|
|
4511
|
+
this.editorHeight = 0;
|
|
4479
4512
|
this.heightOracle = new HeightOracle;
|
|
4480
4513
|
// See VP.MaxDOMHeight
|
|
4481
4514
|
this.scaler = IdScaler;
|
|
4482
4515
|
this.scrollTarget = null;
|
|
4483
4516
|
// Briefly set to true when printing, to disable viewport limiting
|
|
4484
4517
|
this.printing = false;
|
|
4518
|
+
// Flag set when editor content was redrawn, so that the next
|
|
4519
|
+
// measure stage knows it must read DOM layout
|
|
4520
|
+
this.mustMeasureContent = true;
|
|
4485
4521
|
this.visibleRanges = [];
|
|
4486
4522
|
// Cursor 'assoc' is only significant when the cursor is on a line
|
|
4487
4523
|
// wrap point, where it must stick to the character that it is
|
|
@@ -4494,6 +4530,7 @@ class ViewState {
|
|
|
4494
4530
|
this.mustEnforceCursorAssoc = false;
|
|
4495
4531
|
this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
|
4496
4532
|
this.viewport = this.getViewport(0, null);
|
|
4533
|
+
this.updateViewportLines();
|
|
4497
4534
|
this.updateForViewport();
|
|
4498
4535
|
this.lineGaps = this.ensureLineGaps([]);
|
|
4499
4536
|
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
|
|
@@ -4504,7 +4541,7 @@ class ViewState {
|
|
|
4504
4541
|
for (let i = 0; i <= 1; i++) {
|
|
4505
4542
|
let pos = i ? main.head : main.anchor;
|
|
4506
4543
|
if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) {
|
|
4507
|
-
let { from, to } = this.
|
|
4544
|
+
let { from, to } = this.lineBlockAt(pos);
|
|
4508
4545
|
viewports.push(new Viewport(from, to));
|
|
4509
4546
|
}
|
|
4510
4547
|
}
|
|
@@ -4512,6 +4549,12 @@ class ViewState {
|
|
|
4512
4549
|
this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler :
|
|
4513
4550
|
new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
|
|
4514
4551
|
}
|
|
4552
|
+
updateViewportLines() {
|
|
4553
|
+
this.viewportLines = [];
|
|
4554
|
+
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
|
|
4555
|
+
this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
|
|
4556
|
+
});
|
|
4557
|
+
}
|
|
4515
4558
|
update(update, scrollTarget = null) {
|
|
4516
4559
|
let prev = this.state;
|
|
4517
4560
|
this.state = update.state;
|
|
@@ -4526,7 +4569,11 @@ class ViewState {
|
|
|
4526
4569
|
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
4527
4570
|
!this.viewportIsAppropriate(viewport))
|
|
4528
4571
|
viewport = this.getViewport(0, scrollTarget);
|
|
4572
|
+
let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) ||
|
|
4573
|
+
viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
4529
4574
|
this.viewport = viewport;
|
|
4575
|
+
if (updateLines)
|
|
4576
|
+
this.updateViewportLines();
|
|
4530
4577
|
this.updateForViewport();
|
|
4531
4578
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
|
|
4532
4579
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
@@ -4537,13 +4584,17 @@ class ViewState {
|
|
|
4537
4584
|
update.state.selection.main.empty && update.state.selection.main.assoc)
|
|
4538
4585
|
this.mustEnforceCursorAssoc = true;
|
|
4539
4586
|
}
|
|
4540
|
-
measure(
|
|
4541
|
-
let dom =
|
|
4542
|
-
let
|
|
4543
|
-
|
|
4587
|
+
measure(view) {
|
|
4588
|
+
let dom = view.contentDOM, style = window.getComputedStyle(dom);
|
|
4589
|
+
let oracle = this.heightOracle;
|
|
4590
|
+
let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
|
|
4591
|
+
let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
|
|
4592
|
+
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4593
|
+
let result = 0, bias = 0;
|
|
4594
|
+
if (measureContent) {
|
|
4595
|
+
this.mustMeasureContent = false;
|
|
4596
|
+
this.contentDOMHeight = dom.clientHeight;
|
|
4544
4597
|
// Vertical padding
|
|
4545
|
-
let style = window.getComputedStyle(dom);
|
|
4546
|
-
whiteSpace = style.whiteSpace, direction = (style.direction == "rtl" ? Direction.RTL : Direction.LTR);
|
|
4547
4598
|
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4548
4599
|
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4549
4600
|
result |= 8 /* Geometry */;
|
|
@@ -4558,35 +4609,42 @@ class ViewState {
|
|
|
4558
4609
|
this.inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
|
4559
4610
|
if (!this.inView)
|
|
4560
4611
|
return 0;
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
let { lineHeight, charWidth } = docView.measureTextSize();
|
|
4612
|
+
if (measureContent) {
|
|
4613
|
+
let lineHeights = view.docView.measureVisibleLineHeights();
|
|
4614
|
+
if (oracle.mustRefreshForHeights(lineHeights))
|
|
4615
|
+
refresh = true;
|
|
4616
|
+
let contentWidth = dom.clientWidth;
|
|
4617
|
+
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4618
|
+
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4568
4619
|
refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4569
4620
|
if (refresh) {
|
|
4570
|
-
docView.minWidth = 0;
|
|
4621
|
+
view.docView.minWidth = 0;
|
|
4571
4622
|
result |= 8 /* Geometry */;
|
|
4572
4623
|
}
|
|
4573
4624
|
}
|
|
4574
|
-
if (this.
|
|
4575
|
-
this.
|
|
4625
|
+
if (this.contentDOMWidth != contentWidth) {
|
|
4626
|
+
this.contentDOMWidth = contentWidth;
|
|
4627
|
+
result |= 8 /* Geometry */;
|
|
4628
|
+
}
|
|
4629
|
+
if (this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4630
|
+
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4576
4631
|
result |= 8 /* Geometry */;
|
|
4577
4632
|
}
|
|
4578
4633
|
if (dTop > 0 && dBottom > 0)
|
|
4579
4634
|
bias = Math.max(dTop, dBottom);
|
|
4580
4635
|
else if (dTop < 0 && dBottom < 0)
|
|
4581
4636
|
bias = Math.min(dTop, dBottom);
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to)
|
|
4637
|
+
oracle.heightChanged = false;
|
|
4638
|
+
this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights));
|
|
4639
|
+
if (oracle.heightChanged)
|
|
4640
|
+
result |= 2 /* Height */;
|
|
4641
|
+
}
|
|
4642
|
+
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4643
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
|
|
4644
|
+
if (viewportChange)
|
|
4589
4645
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4646
|
+
if ((result & 2 /* Height */) || viewportChange)
|
|
4647
|
+
this.updateViewportLines();
|
|
4590
4648
|
this.updateForViewport();
|
|
4591
4649
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
|
|
4592
4650
|
this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
|
|
@@ -4597,12 +4655,12 @@ class ViewState {
|
|
|
4597
4655
|
// to a line end is going to trigger a layout anyway, so it
|
|
4598
4656
|
// can't be a pure write. It should be rare that it does any
|
|
4599
4657
|
// writing.
|
|
4600
|
-
docView.enforceCursorAssoc();
|
|
4658
|
+
view.docView.enforceCursorAssoc();
|
|
4601
4659
|
}
|
|
4602
4660
|
return result;
|
|
4603
4661
|
}
|
|
4604
|
-
get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top
|
|
4605
|
-
get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom
|
|
4662
|
+
get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); }
|
|
4663
|
+
get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); }
|
|
4606
4664
|
getViewport(bias, scrollTarget) {
|
|
4607
4665
|
// This will divide VP.Margin between the top and the
|
|
4608
4666
|
// bottom, depending on the bias (the change in viewport position
|
|
@@ -4662,12 +4720,12 @@ class ViewState {
|
|
|
4662
4720
|
// This won't work at all in predominantly right-to-left text.
|
|
4663
4721
|
if (this.heightOracle.direction != Direction.LTR)
|
|
4664
4722
|
return gaps;
|
|
4665
|
-
|
|
4723
|
+
for (let line of this.viewportLines) {
|
|
4666
4724
|
if (line.length < 4000 /* DoubleMargin */)
|
|
4667
|
-
|
|
4725
|
+
continue;
|
|
4668
4726
|
let structure = lineStructure(line.from, line.to, this.state);
|
|
4669
4727
|
if (structure.total < 4000 /* DoubleMargin */)
|
|
4670
|
-
|
|
4728
|
+
continue;
|
|
4671
4729
|
let viewFrom, viewTo;
|
|
4672
4730
|
if (this.heightOracle.lineWrapping) {
|
|
4673
4731
|
let marginHeight = (2000 /* Margin */ / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
|
|
@@ -4697,7 +4755,7 @@ class ViewState {
|
|
|
4697
4755
|
Math.abs(gap.from - from) < 1000 /* HalfMargin */ && Math.abs(gap.to - to) < 1000 /* HalfMargin */) ||
|
|
4698
4756
|
new LineGap(from, to, this.gapSize(line, from, to, structure)));
|
|
4699
4757
|
}
|
|
4700
|
-
}
|
|
4758
|
+
}
|
|
4701
4759
|
return gaps;
|
|
4702
4760
|
}
|
|
4703
4761
|
gapSize(line, from, to, structure) {
|
|
@@ -4729,27 +4787,18 @@ class ViewState {
|
|
|
4729
4787
|
this.visibleRanges = ranges;
|
|
4730
4788
|
return changed ? 4 /* Viewport */ : 0;
|
|
4731
4789
|
}
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
}
|
|
4736
|
-
lineAtHeight(height, editorTop) {
|
|
4737
|
-
editorTop += this.paddingTop;
|
|
4738
|
-
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height, editorTop), QueryType.ByHeight, this.state.doc, editorTop, 0), this.scaler, editorTop);
|
|
4790
|
+
lineBlockAt(pos) {
|
|
4791
|
+
return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to <= pos)) ||
|
|
4792
|
+
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler);
|
|
4739
4793
|
}
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height, editorTop), this.state.doc, editorTop, 0), this.scaler, editorTop);
|
|
4794
|
+
lineBlockAtHeight(height) {
|
|
4795
|
+
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler);
|
|
4743
4796
|
}
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
return this.heightMap.forEachLine(from, to, this.state.doc, editorTop, 0, this.scaler.scale == 1 ? f : b => f(scaleBlock(b, this.scaler, editorTop)));
|
|
4797
|
+
elementAtHeight(height) {
|
|
4798
|
+
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
|
|
4747
4799
|
}
|
|
4748
4800
|
get contentHeight() {
|
|
4749
|
-
return this.
|
|
4750
|
-
}
|
|
4751
|
-
get domHeight() {
|
|
4752
|
-
return this.scaler.toDOM(this.heightMap.height, this.paddingTop);
|
|
4801
|
+
return this.scaler.toDOM(this.heightMap.height) + this.paddingTop + this.paddingBottom;
|
|
4753
4802
|
}
|
|
4754
4803
|
}
|
|
4755
4804
|
class Viewport {
|
|
@@ -4846,36 +4895,34 @@ class BigScaler {
|
|
|
4846
4895
|
base = obj.bottom;
|
|
4847
4896
|
}
|
|
4848
4897
|
}
|
|
4849
|
-
toDOM(n
|
|
4850
|
-
n -= top;
|
|
4898
|
+
toDOM(n) {
|
|
4851
4899
|
for (let i = 0, base = 0, domBase = 0;; i++) {
|
|
4852
4900
|
let vp = i < this.viewports.length ? this.viewports[i] : null;
|
|
4853
4901
|
if (!vp || n < vp.top)
|
|
4854
|
-
return domBase + (n - base) * this.scale
|
|
4902
|
+
return domBase + (n - base) * this.scale;
|
|
4855
4903
|
if (n <= vp.bottom)
|
|
4856
|
-
return vp.domTop + (n - vp.top)
|
|
4904
|
+
return vp.domTop + (n - vp.top);
|
|
4857
4905
|
base = vp.bottom;
|
|
4858
4906
|
domBase = vp.domBottom;
|
|
4859
4907
|
}
|
|
4860
4908
|
}
|
|
4861
|
-
fromDOM(n
|
|
4862
|
-
n -= top;
|
|
4909
|
+
fromDOM(n) {
|
|
4863
4910
|
for (let i = 0, base = 0, domBase = 0;; i++) {
|
|
4864
4911
|
let vp = i < this.viewports.length ? this.viewports[i] : null;
|
|
4865
4912
|
if (!vp || n < vp.domTop)
|
|
4866
|
-
return base + (n - domBase) / this.scale
|
|
4913
|
+
return base + (n - domBase) / this.scale;
|
|
4867
4914
|
if (n <= vp.domBottom)
|
|
4868
|
-
return vp.top + (n - vp.domTop)
|
|
4915
|
+
return vp.top + (n - vp.domTop);
|
|
4869
4916
|
base = vp.bottom;
|
|
4870
4917
|
domBase = vp.domBottom;
|
|
4871
4918
|
}
|
|
4872
4919
|
}
|
|
4873
4920
|
}
|
|
4874
|
-
function scaleBlock(block, scaler
|
|
4921
|
+
function scaleBlock(block, scaler) {
|
|
4875
4922
|
if (scaler.scale == 1)
|
|
4876
4923
|
return block;
|
|
4877
|
-
let bTop = scaler.toDOM(block.top
|
|
4878
|
-
return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler
|
|
4924
|
+
let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom);
|
|
4925
|
+
return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type);
|
|
4879
4926
|
}
|
|
4880
4927
|
|
|
4881
4928
|
const theme = /*@__PURE__*/Facet.define({ combine: strs => strs.join(" ") });
|
|
@@ -5060,24 +5107,30 @@ class DOMObserver {
|
|
|
5060
5107
|
this.onChange = onChange;
|
|
5061
5108
|
this.onScrollChanged = onScrollChanged;
|
|
5062
5109
|
this.active = false;
|
|
5063
|
-
|
|
5110
|
+
// The known selection. Kept in our own object, as opposed to just
|
|
5111
|
+
// directly accessing the selection because:
|
|
5112
|
+
// - Safari doesn't report the right selection in shadow DOM
|
|
5113
|
+
// - Reading from the selection forces a DOM layout
|
|
5114
|
+
// - This way, we can ignore selectionchange events if we have
|
|
5115
|
+
// already seen the 'new' selection
|
|
5116
|
+
this.selectionRange = new DOMSelectionState;
|
|
5117
|
+
// Set when a selection change is detected, cleared on flush
|
|
5118
|
+
this.selectionChanged = false;
|
|
5064
5119
|
this.delayedFlush = -1;
|
|
5120
|
+
this.resizeTimeout = -1;
|
|
5065
5121
|
this.queue = [];
|
|
5066
|
-
this.lastFlush = 0;
|
|
5067
5122
|
this.scrollTargets = [];
|
|
5068
5123
|
this.intersection = null;
|
|
5124
|
+
this.resize = null;
|
|
5069
5125
|
this.intersecting = false;
|
|
5070
5126
|
this.gapIntersection = null;
|
|
5071
5127
|
this.gaps = [];
|
|
5072
|
-
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5073
|
-
this._selectionRange = null;
|
|
5074
5128
|
// Timeout for scheduling check of the parents that need scroll handlers
|
|
5075
5129
|
this.parentCheck = -1;
|
|
5076
5130
|
this.dom = view.contentDOM;
|
|
5077
5131
|
this.observer = new MutationObserver(mutations => {
|
|
5078
5132
|
for (let mut of mutations)
|
|
5079
5133
|
this.queue.push(mut);
|
|
5080
|
-
this._selectionRange = null;
|
|
5081
5134
|
// IE11 will sometimes (on typing over a selection or
|
|
5082
5135
|
// backspacing out a single character text node) call the
|
|
5083
5136
|
// observer callback before actually updating the DOM.
|
|
@@ -5102,6 +5155,16 @@ class DOMObserver {
|
|
|
5102
5155
|
this.flushSoon();
|
|
5103
5156
|
};
|
|
5104
5157
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5158
|
+
if (typeof ResizeObserver == "function") {
|
|
5159
|
+
this.resize = new ResizeObserver(() => {
|
|
5160
|
+
if (this.view.docView.lastUpdate < Date.now() - 75 && this.resizeTimeout < 0)
|
|
5161
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5162
|
+
this.resizeTimeout = -1;
|
|
5163
|
+
this.view.requestMeasure();
|
|
5164
|
+
}, 50);
|
|
5165
|
+
});
|
|
5166
|
+
this.resize.observe(view.scrollDOM);
|
|
5167
|
+
}
|
|
5105
5168
|
this.start();
|
|
5106
5169
|
this.onScroll = this.onScroll.bind(this);
|
|
5107
5170
|
window.addEventListener("scroll", this.onScroll);
|
|
@@ -5122,10 +5185,12 @@ class DOMObserver {
|
|
|
5122
5185
|
}, {});
|
|
5123
5186
|
}
|
|
5124
5187
|
this.listenForScroll();
|
|
5188
|
+
this.readSelectionRange();
|
|
5189
|
+
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5125
5190
|
}
|
|
5126
5191
|
onScroll(e) {
|
|
5127
5192
|
if (this.intersecting)
|
|
5128
|
-
this.flush();
|
|
5193
|
+
this.flush(false);
|
|
5129
5194
|
this.onScrollChanged(e);
|
|
5130
5195
|
}
|
|
5131
5196
|
updateGaps(gaps) {
|
|
@@ -5137,8 +5202,8 @@ class DOMObserver {
|
|
|
5137
5202
|
}
|
|
5138
5203
|
}
|
|
5139
5204
|
onSelectionChange(event) {
|
|
5140
|
-
if (this.
|
|
5141
|
-
|
|
5205
|
+
if (!this.readSelectionRange())
|
|
5206
|
+
return;
|
|
5142
5207
|
let { view } = this, sel = this.selectionRange;
|
|
5143
5208
|
if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel))
|
|
5144
5209
|
return;
|
|
@@ -5153,24 +5218,22 @@ class DOMObserver {
|
|
|
5153
5218
|
sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
5154
5219
|
this.flushSoon();
|
|
5155
5220
|
else
|
|
5156
|
-
this.flush();
|
|
5157
|
-
}
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
return this.
|
|
5221
|
+
this.flush(false);
|
|
5222
|
+
}
|
|
5223
|
+
readSelectionRange() {
|
|
5224
|
+
let { root } = this.view, domSel = getSelection(root);
|
|
5225
|
+
// The Selection object is broken in shadow roots in Safari. See
|
|
5226
|
+
// https://github.com/codemirror/codemirror.next/issues/414
|
|
5227
|
+
let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM &&
|
|
5228
|
+
safariSelectionRangeHack(this.view) || domSel;
|
|
5229
|
+
if (this.selectionRange.eq(range))
|
|
5230
|
+
return false;
|
|
5231
|
+
this.selectionRange.setRange(range);
|
|
5232
|
+
return this.selectionChanged = true;
|
|
5168
5233
|
}
|
|
5169
5234
|
setSelectionRange(anchor, head) {
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
this._selectionRange = { anchorNode: anchor.node, anchorOffset: anchor.offset,
|
|
5173
|
-
focusNode: head.node, focusOffset: head.offset };
|
|
5235
|
+
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
|
5236
|
+
this.selectionChanged = false;
|
|
5174
5237
|
}
|
|
5175
5238
|
listenForScroll() {
|
|
5176
5239
|
this.parentCheck = -1;
|
|
@@ -5217,7 +5280,6 @@ class DOMObserver {
|
|
|
5217
5280
|
if (this.active)
|
|
5218
5281
|
return;
|
|
5219
5282
|
this.observer.observe(this.dom, observeOptions);
|
|
5220
|
-
this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
|
5221
5283
|
if (useCharData)
|
|
5222
5284
|
this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5223
5285
|
this.active = true;
|
|
@@ -5227,18 +5289,14 @@ class DOMObserver {
|
|
|
5227
5289
|
return;
|
|
5228
5290
|
this.active = false;
|
|
5229
5291
|
this.observer.disconnect();
|
|
5230
|
-
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5231
5292
|
if (useCharData)
|
|
5232
5293
|
this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
|
|
5233
5294
|
}
|
|
5234
|
-
clearSelection() {
|
|
5235
|
-
this.ignoreSelection.set(this.selectionRange);
|
|
5236
|
-
}
|
|
5237
5295
|
// Throw away any pending changes
|
|
5238
5296
|
clear() {
|
|
5239
5297
|
this.observer.takeRecords();
|
|
5240
5298
|
this.queue.length = 0;
|
|
5241
|
-
this.
|
|
5299
|
+
this.selectionChanged = false;
|
|
5242
5300
|
}
|
|
5243
5301
|
flushSoon() {
|
|
5244
5302
|
if (this.delayedFlush < 0)
|
|
@@ -5275,24 +5333,24 @@ class DOMObserver {
|
|
|
5275
5333
|
return { from, to, typeOver };
|
|
5276
5334
|
}
|
|
5277
5335
|
// Apply pending changes, if any
|
|
5278
|
-
flush() {
|
|
5336
|
+
flush(readSelection = true) {
|
|
5337
|
+
if (readSelection)
|
|
5338
|
+
this.readSelectionRange();
|
|
5279
5339
|
// Completely hold off flushing when pending keys are set—the code
|
|
5280
5340
|
// managing those will make sure processRecords is called and the
|
|
5281
5341
|
// view is resynchronized after
|
|
5282
5342
|
if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
|
|
5283
5343
|
return;
|
|
5284
|
-
this.lastFlush = Date.now();
|
|
5285
5344
|
let { from, to, typeOver } = this.processRecords();
|
|
5286
|
-
let
|
|
5287
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5345
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
5288
5346
|
if (from < 0 && !newSel)
|
|
5289
5347
|
return;
|
|
5348
|
+
this.selectionChanged = false;
|
|
5290
5349
|
let startState = this.view.state;
|
|
5291
5350
|
this.onChange(from, to, typeOver);
|
|
5292
5351
|
// The view wasn't updated
|
|
5293
5352
|
if (this.view.state == startState)
|
|
5294
5353
|
this.view.docView.reset(newSel);
|
|
5295
|
-
this.clearSelection();
|
|
5296
5354
|
}
|
|
5297
5355
|
readMutation(rec) {
|
|
5298
5356
|
let cView = this.view.docView.nearest(rec.target);
|
|
@@ -5315,15 +5373,16 @@ class DOMObserver {
|
|
|
5315
5373
|
}
|
|
5316
5374
|
}
|
|
5317
5375
|
destroy() {
|
|
5376
|
+
var _a, _b, _c;
|
|
5318
5377
|
this.stop();
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
this.gapIntersection.disconnect();
|
|
5378
|
+
(_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
5379
|
+
(_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
5380
|
+
(_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
5323
5381
|
for (let dom of this.scrollTargets)
|
|
5324
5382
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5325
5383
|
window.removeEventListener("scroll", this.onScroll);
|
|
5326
5384
|
clearTimeout(this.parentCheck);
|
|
5385
|
+
clearTimeout(this.resizeTimeout);
|
|
5327
5386
|
}
|
|
5328
5387
|
}
|
|
5329
5388
|
function findChild(cView, dom, dir) {
|
|
@@ -5336,6 +5395,7 @@ function findChild(cView, dom, dir) {
|
|
|
5336
5395
|
}
|
|
5337
5396
|
return null;
|
|
5338
5397
|
}
|
|
5398
|
+
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
5339
5399
|
function safariSelectionRangeHack(view) {
|
|
5340
5400
|
let found = null;
|
|
5341
5401
|
// Because Safari (at least in 2018-2021) doesn't provide regular
|
|
@@ -5755,6 +5815,7 @@ class EditorView {
|
|
|
5755
5815
|
this.mountStyles();
|
|
5756
5816
|
this.updateAttrs();
|
|
5757
5817
|
this.showAnnouncements(transactions);
|
|
5818
|
+
this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
|
5758
5819
|
}
|
|
5759
5820
|
finally {
|
|
5760
5821
|
this.updateState = 0 /* Idle */;
|
|
@@ -5832,7 +5893,7 @@ class EditorView {
|
|
|
5832
5893
|
return;
|
|
5833
5894
|
if (this.measureScheduled > -1)
|
|
5834
5895
|
cancelAnimationFrame(this.measureScheduled);
|
|
5835
|
-
this.measureScheduled =
|
|
5896
|
+
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
5836
5897
|
if (flush)
|
|
5837
5898
|
this.observer.flush();
|
|
5838
5899
|
let updated = null;
|
|
@@ -5840,11 +5901,11 @@ class EditorView {
|
|
|
5840
5901
|
for (let i = 0;; i++) {
|
|
5841
5902
|
this.updateState = 1 /* Measuring */;
|
|
5842
5903
|
let oldViewport = this.viewport;
|
|
5843
|
-
let changed = this.viewState.measure(this
|
|
5904
|
+
let changed = this.viewState.measure(this);
|
|
5844
5905
|
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
|
5845
5906
|
break;
|
|
5846
5907
|
if (i > 5) {
|
|
5847
|
-
console.warn("Viewport failed to stabilize");
|
|
5908
|
+
console.warn(this.measureRequests.length ? "Measure loop restarted more than 5 times" : "Viewport failed to stabilize");
|
|
5848
5909
|
break;
|
|
5849
5910
|
}
|
|
5850
5911
|
let measuring = [];
|
|
@@ -5860,7 +5921,7 @@ class EditorView {
|
|
|
5860
5921
|
return BadMeasure;
|
|
5861
5922
|
}
|
|
5862
5923
|
});
|
|
5863
|
-
let update = new ViewUpdate(this, this.state);
|
|
5924
|
+
let update = new ViewUpdate(this, this.state), redrawn = false;
|
|
5864
5925
|
update.flags |= changed;
|
|
5865
5926
|
if (!updated)
|
|
5866
5927
|
updated = update;
|
|
@@ -5870,14 +5931,15 @@ class EditorView {
|
|
|
5870
5931
|
if (!update.empty) {
|
|
5871
5932
|
this.updatePlugins(update);
|
|
5872
5933
|
this.inputState.update(update);
|
|
5934
|
+
this.updateAttrs();
|
|
5935
|
+
redrawn = this.docView.update(update);
|
|
5873
5936
|
}
|
|
5874
|
-
this.updateAttrs();
|
|
5875
|
-
if (changed)
|
|
5876
|
-
this.docView.update(update);
|
|
5877
5937
|
for (let i = 0; i < measuring.length; i++)
|
|
5878
5938
|
if (measured[i] != BadMeasure) {
|
|
5879
5939
|
try {
|
|
5880
|
-
measuring[i]
|
|
5940
|
+
let m = measuring[i];
|
|
5941
|
+
if (m.write)
|
|
5942
|
+
m.write(measured[i], this);
|
|
5881
5943
|
}
|
|
5882
5944
|
catch (e) {
|
|
5883
5945
|
logException(this.state, e);
|
|
@@ -5887,14 +5949,16 @@ class EditorView {
|
|
|
5887
5949
|
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5888
5950
|
this.viewState.scrollTarget = null;
|
|
5889
5951
|
}
|
|
5952
|
+
if (redrawn)
|
|
5953
|
+
this.docView.updateSelection(true);
|
|
5890
5954
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5891
5955
|
break;
|
|
5892
5956
|
}
|
|
5893
5957
|
}
|
|
5894
5958
|
finally {
|
|
5895
5959
|
this.updateState = 0 /* Idle */;
|
|
5960
|
+
this.measureScheduled = -1;
|
|
5896
5961
|
}
|
|
5897
|
-
this.measureScheduled = -1;
|
|
5898
5962
|
if (updated && !updated.empty)
|
|
5899
5963
|
for (let listener of this.state.facet(updateListener))
|
|
5900
5964
|
listener(updated);
|
|
@@ -5911,8 +5975,6 @@ class EditorView {
|
|
|
5911
5975
|
let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
|
|
5912
5976
|
class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
|
|
5913
5977
|
});
|
|
5914
|
-
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5915
|
-
this.editorAttrs = editorAttrs;
|
|
5916
5978
|
let contentAttrs = {
|
|
5917
5979
|
spellcheck: "false",
|
|
5918
5980
|
autocorrect: "off",
|
|
@@ -5927,7 +5989,11 @@ class EditorView {
|
|
|
5927
5989
|
if (this.state.readOnly)
|
|
5928
5990
|
contentAttrs["aria-readonly"] = "true";
|
|
5929
5991
|
combineAttrs(this.state.facet(contentAttributes), contentAttrs);
|
|
5930
|
-
|
|
5992
|
+
this.observer.ignore(() => {
|
|
5993
|
+
updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
|
5994
|
+
updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
|
5995
|
+
});
|
|
5996
|
+
this.editorAttrs = editorAttrs;
|
|
5931
5997
|
this.contentAttrs = contentAttrs;
|
|
5932
5998
|
}
|
|
5933
5999
|
showAnnouncements(trs) {
|
|
@@ -5997,6 +6063,20 @@ class EditorView {
|
|
|
5997
6063
|
return null;
|
|
5998
6064
|
}
|
|
5999
6065
|
/**
|
|
6066
|
+
The top position of the document, in screen coordinates. This
|
|
6067
|
+
may be negative when the editor is scrolled down. Points
|
|
6068
|
+
directly to the top of the first line, not above the padding.
|
|
6069
|
+
*/
|
|
6070
|
+
get documentTop() {
|
|
6071
|
+
return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
|
|
6072
|
+
}
|
|
6073
|
+
/**
|
|
6074
|
+
Reports the padding above and below the document.
|
|
6075
|
+
*/
|
|
6076
|
+
get documentPadding() {
|
|
6077
|
+
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
|
6078
|
+
}
|
|
6079
|
+
/**
|
|
6000
6080
|
Find the line or block widget at the given vertical position.
|
|
6001
6081
|
|
|
6002
6082
|
By default, this position is interpreted as a screen position,
|
|
@@ -6006,10 +6086,21 @@ class EditorView {
|
|
|
6006
6086
|
position, or a precomputed document top
|
|
6007
6087
|
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
6008
6088
|
queries.
|
|
6089
|
+
|
|
6090
|
+
*Deprecated: use `blockAtHeight` instead.*
|
|
6009
6091
|
*/
|
|
6010
6092
|
blockAtHeight(height, docTop) {
|
|
6093
|
+
let top = ensureTop(docTop, this);
|
|
6094
|
+
return this.elementAtHeight(height - top).moveY(top);
|
|
6095
|
+
}
|
|
6096
|
+
/**
|
|
6097
|
+
Find the text line or block widget at the given vertical
|
|
6098
|
+
position (which is interpreted as relative to the [top of the
|
|
6099
|
+
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
|
|
6100
|
+
*/
|
|
6101
|
+
elementAtHeight(height) {
|
|
6011
6102
|
this.readMeasured();
|
|
6012
|
-
return this.viewState.
|
|
6103
|
+
return this.viewState.elementAtHeight(height);
|
|
6013
6104
|
}
|
|
6014
6105
|
/**
|
|
6015
6106
|
Find information for the visual line (see
|
|
@@ -6021,20 +6112,43 @@ class EditorView {
|
|
|
6021
6112
|
Defaults to treating `height` as a screen position. See
|
|
6022
6113
|
[`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
|
|
6023
6114
|
interpretation of the `docTop` parameter.
|
|
6115
|
+
|
|
6116
|
+
*Deprecated: use `lineBlockAtHeight` instead.*
|
|
6024
6117
|
*/
|
|
6025
6118
|
visualLineAtHeight(height, docTop) {
|
|
6119
|
+
let top = ensureTop(docTop, this);
|
|
6120
|
+
return this.lineBlockAtHeight(height - top).moveY(top);
|
|
6121
|
+
}
|
|
6122
|
+
/**
|
|
6123
|
+
Find the line block (see
|
|
6124
|
+
[`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
|
|
6125
|
+
height.
|
|
6126
|
+
*/
|
|
6127
|
+
lineBlockAtHeight(height) {
|
|
6026
6128
|
this.readMeasured();
|
|
6027
|
-
return this.viewState.
|
|
6129
|
+
return this.viewState.lineBlockAtHeight(height);
|
|
6028
6130
|
}
|
|
6029
6131
|
/**
|
|
6030
6132
|
Iterate over the height information of the visual lines in the
|
|
6031
6133
|
viewport. The heights of lines are reported relative to the
|
|
6032
6134
|
given document top, which defaults to the screen position of the
|
|
6033
6135
|
document (forcing a layout).
|
|
6136
|
+
|
|
6137
|
+
*Deprecated: use `viewportLineBlocks` instead.*
|
|
6034
6138
|
*/
|
|
6035
6139
|
viewportLines(f, docTop) {
|
|
6036
|
-
let
|
|
6037
|
-
|
|
6140
|
+
let top = ensureTop(docTop, this);
|
|
6141
|
+
for (let line of this.viewportLineBlocks)
|
|
6142
|
+
f(line.moveY(top));
|
|
6143
|
+
}
|
|
6144
|
+
/**
|
|
6145
|
+
Get the extent and vertical position of all [line
|
|
6146
|
+
blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
|
|
6147
|
+
are relative to the [top of the
|
|
6148
|
+
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop);
|
|
6149
|
+
*/
|
|
6150
|
+
get viewportLineBlocks() {
|
|
6151
|
+
return this.viewState.viewportLines;
|
|
6038
6152
|
}
|
|
6039
6153
|
/**
|
|
6040
6154
|
Find the extent and height of the visual line (a range delimited
|
|
@@ -6045,9 +6159,22 @@ class EditorView {
|
|
|
6045
6159
|
argument, which defaults to 0 for this method. You can pass
|
|
6046
6160
|
`view.contentDOM.getBoundingClientRect().top` here to get screen
|
|
6047
6161
|
coordinates.
|
|
6162
|
+
|
|
6163
|
+
*Deprecated: use `lineBlockAt` instead.*
|
|
6048
6164
|
*/
|
|
6049
6165
|
visualLineAt(pos, docTop = 0) {
|
|
6050
|
-
return this.
|
|
6166
|
+
return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
|
|
6167
|
+
}
|
|
6168
|
+
/**
|
|
6169
|
+
Find the line block around the given document position. A line
|
|
6170
|
+
block is a range delimited on both sides by either a
|
|
6171
|
+
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the
|
|
6172
|
+
start/end of the document. It will usually just hold a line of
|
|
6173
|
+
text, but may be broken into multiple textblocks by block
|
|
6174
|
+
widgets.
|
|
6175
|
+
*/
|
|
6176
|
+
lineBlockAt(pos) {
|
|
6177
|
+
return this.viewState.lineBlockAt(pos);
|
|
6051
6178
|
}
|
|
6052
6179
|
/**
|
|
6053
6180
|
The editor's total content height.
|
|
@@ -6380,8 +6507,9 @@ search match).
|
|
|
6380
6507
|
EditorView.announce = /*@__PURE__*/StateEffect.define();
|
|
6381
6508
|
// Maximum line length for which we compute accurate bidi info
|
|
6382
6509
|
const MaxBidiLine = 4096;
|
|
6383
|
-
|
|
6384
|
-
|
|
6510
|
+
// FIXME remove this and its callers on next breaking release
|
|
6511
|
+
function ensureTop(given, view) {
|
|
6512
|
+
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6385
6513
|
}
|
|
6386
6514
|
let resizeDebounce = -1;
|
|
6387
6515
|
function ensureGlobalHandler() {
|
|
@@ -6732,7 +6860,7 @@ function wrappedLine(view, pos, inside) {
|
|
|
6732
6860
|
type: BlockType.Text };
|
|
6733
6861
|
}
|
|
6734
6862
|
function blockAt(view, pos) {
|
|
6735
|
-
let line = view.
|
|
6863
|
+
let line = view.lineBlockAt(pos);
|
|
6736
6864
|
if (Array.isArray(line.type))
|
|
6737
6865
|
for (let l of line.type) {
|
|
6738
6866
|
if (l.to > pos || l.to == pos && (l.to == line.to || l.type == BlockType.Text))
|
|
@@ -7123,7 +7251,7 @@ const activeLineHighlighter = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
7123
7251
|
for (let r of view.state.selection.ranges) {
|
|
7124
7252
|
if (!r.empty)
|
|
7125
7253
|
return Decoration.none;
|
|
7126
|
-
let line = view.
|
|
7254
|
+
let line = view.lineBlockAt(r.head);
|
|
7127
7255
|
if (line.from > lastLineStart) {
|
|
7128
7256
|
deco.push(lineDeco.range(line.from));
|
|
7129
7257
|
lastLineStart = line.from;
|