@codemirror/view 6.26.4-edit-context → 6.26.4
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 +18 -0
- package/dist/index.cjs +109 -250
- package/dist/index.js +109 -250
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 6.26.4 (2024-06-04)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where commands with an optional second argument would get the keyboard event in that argument when called from a keymap.
|
|
6
|
+
|
|
7
|
+
Fix an issue that could cause the cursor to be rendered on the wrong side of a zero-length block widget.
|
|
8
|
+
|
|
9
|
+
Fix an issue where `drawSelection` got confused by block widgets in line-wrapped editors in some situations.
|
|
10
|
+
|
|
11
|
+
Don't hide the native selection in widgets that have focus.
|
|
12
|
+
|
|
13
|
+
Make sure that clicking an unfocusable editor still remove focus from any other focused elements.
|
|
14
|
+
|
|
15
|
+
Fix a crash when loading the package in a non-browser environment.
|
|
16
|
+
|
|
17
|
+
Stop mouse selection when the user types.
|
|
18
|
+
|
|
1
19
|
## 6.26.3 (2024-04-12)
|
|
2
20
|
|
|
3
21
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -745,7 +745,7 @@ var browser = {
|
|
|
745
745
|
android: /Android\b/.test(nav.userAgent),
|
|
746
746
|
webkit,
|
|
747
747
|
safari,
|
|
748
|
-
webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(
|
|
748
|
+
webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
|
749
749
|
tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
|
|
750
750
|
};
|
|
751
751
|
|
|
@@ -2368,7 +2368,6 @@ class ScrollTarget {
|
|
|
2368
2368
|
}
|
|
2369
2369
|
}
|
|
2370
2370
|
const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) });
|
|
2371
|
-
const setEditContextFormatting = state.StateEffect.define();
|
|
2372
2371
|
/**
|
|
2373
2372
|
Log or report an unhandled exception in client code. Should
|
|
2374
2373
|
probably only be used by extension code that allows client code to
|
|
@@ -2705,11 +2704,10 @@ class DocView extends ContentView {
|
|
|
2705
2704
|
super();
|
|
2706
2705
|
this.view = view;
|
|
2707
2706
|
this.decorations = [];
|
|
2708
|
-
this.dynamicDecorationMap = [
|
|
2707
|
+
this.dynamicDecorationMap = [];
|
|
2709
2708
|
this.domChanged = null;
|
|
2710
2709
|
this.hasComposition = null;
|
|
2711
2710
|
this.markedForComposition = new Set;
|
|
2712
|
-
this.editContextFormatting = Decoration.none;
|
|
2713
2711
|
this.lastCompositionAfterCursor = false;
|
|
2714
2712
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2715
2713
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
@@ -2748,9 +2746,8 @@ class DocView extends ContentView {
|
|
|
2748
2746
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2749
2747
|
}
|
|
2750
2748
|
}
|
|
2751
|
-
this.updateEditContextFormatting(update);
|
|
2752
2749
|
let readCompositionAt = -1;
|
|
2753
|
-
if (this.view.inputState.composing >= 0
|
|
2750
|
+
if (this.view.inputState.composing >= 0) {
|
|
2754
2751
|
if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
|
|
2755
2752
|
readCompositionAt = this.domChanged.newSel.head;
|
|
2756
2753
|
else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
|
|
@@ -2858,14 +2855,6 @@ class DocView extends ContentView {
|
|
|
2858
2855
|
if (composition)
|
|
2859
2856
|
this.fixCompositionDOM(composition);
|
|
2860
2857
|
}
|
|
2861
|
-
updateEditContextFormatting(update) {
|
|
2862
|
-
this.editContextFormatting = this.editContextFormatting.map(update.changes);
|
|
2863
|
-
for (let tr of update.transactions)
|
|
2864
|
-
for (let effect of tr.effects)
|
|
2865
|
-
if (effect.is(setEditContextFormatting)) {
|
|
2866
|
-
this.editContextFormatting = effect.value;
|
|
2867
|
-
}
|
|
2868
|
-
}
|
|
2869
2858
|
compositionView(composition) {
|
|
2870
2859
|
let cur = new TextView(composition.text.nodeValue);
|
|
2871
2860
|
cur.flags |= 8 /* ViewFlag.Composition */;
|
|
@@ -3071,6 +3060,12 @@ class DocView extends ContentView {
|
|
|
3071
3060
|
best = child;
|
|
3072
3061
|
bestPos = start;
|
|
3073
3062
|
}
|
|
3063
|
+
else if (best && start == pos && end == pos && child instanceof BlockWidgetView && Math.abs(side) < 2) {
|
|
3064
|
+
if (child.deco.startSide < 0)
|
|
3065
|
+
break;
|
|
3066
|
+
else if (i)
|
|
3067
|
+
best = null;
|
|
3068
|
+
}
|
|
3074
3069
|
off = start;
|
|
3075
3070
|
}
|
|
3076
3071
|
return best ? best.coordsAt(pos - bestPos, side) : null;
|
|
@@ -3191,7 +3186,7 @@ class DocView extends ContentView {
|
|
|
3191
3186
|
return Decoration.set(deco);
|
|
3192
3187
|
}
|
|
3193
3188
|
updateDeco() {
|
|
3194
|
-
let i =
|
|
3189
|
+
let i = 0;
|
|
3195
3190
|
let allDeco = this.view.state.facet(decorations).map(d => {
|
|
3196
3191
|
let dynamic = this.dynamicDecorationMap[i++] = typeof d == "function";
|
|
3197
3192
|
return dynamic ? d(this.view) : d;
|
|
@@ -3207,7 +3202,6 @@ class DocView extends ContentView {
|
|
|
3207
3202
|
allDeco.push(state.RangeSet.join(outerDeco));
|
|
3208
3203
|
}
|
|
3209
3204
|
this.decorations = [
|
|
3210
|
-
this.editContextFormatting,
|
|
3211
3205
|
...allDeco,
|
|
3212
3206
|
this.computeBlockGapDeco(),
|
|
3213
3207
|
this.view.viewState.lineGapDeco
|
|
@@ -3894,7 +3888,6 @@ class InputState {
|
|
|
3894
3888
|
this.mouseSelection = mouseSelection;
|
|
3895
3889
|
}
|
|
3896
3890
|
update(update) {
|
|
3897
|
-
this.view.observer.update(update);
|
|
3898
3891
|
if (this.mouseSelection)
|
|
3899
3892
|
this.mouseSelection.update(update);
|
|
3900
3893
|
if (this.draggedContent && update.docChanged)
|
|
@@ -4073,7 +4066,9 @@ class MouseSelection {
|
|
|
4073
4066
|
this.mustSelect = false;
|
|
4074
4067
|
}
|
|
4075
4068
|
update(update) {
|
|
4076
|
-
if (
|
|
4069
|
+
if (update.transactions.some(tr => tr.isUserEvent("input.type")))
|
|
4070
|
+
this.destroy();
|
|
4071
|
+
else if (this.style.update(update))
|
|
4077
4072
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
4078
4073
|
}
|
|
4079
4074
|
}
|
|
@@ -4197,7 +4192,12 @@ handlers.mousedown = (view, event) => {
|
|
|
4197
4192
|
let mustFocus = !view.hasFocus;
|
|
4198
4193
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4199
4194
|
if (mustFocus)
|
|
4200
|
-
view.observer.ignore(() =>
|
|
4195
|
+
view.observer.ignore(() => {
|
|
4196
|
+
focusPreventScroll(view.contentDOM);
|
|
4197
|
+
let active = view.root.activeElement;
|
|
4198
|
+
if (active && !active.contains(view.contentDOM))
|
|
4199
|
+
active.blur();
|
|
4200
|
+
});
|
|
4201
4201
|
let mouseSel = view.inputState.mouseSelection;
|
|
4202
4202
|
if (mouseSel) {
|
|
4203
4203
|
mouseSel.start(event);
|
|
@@ -4485,8 +4485,6 @@ observers.blur = view => {
|
|
|
4485
4485
|
updateForFocusChange(view);
|
|
4486
4486
|
};
|
|
4487
4487
|
observers.compositionstart = observers.compositionupdate = view => {
|
|
4488
|
-
if (view.observer.editContext)
|
|
4489
|
-
return; // Composition handled by edit context
|
|
4490
4488
|
if (view.inputState.compositionFirstChange == null)
|
|
4491
4489
|
view.inputState.compositionFirstChange = true;
|
|
4492
4490
|
if (view.inputState.composing < 0) {
|
|
@@ -4495,8 +4493,6 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
4495
4493
|
}
|
|
4496
4494
|
};
|
|
4497
4495
|
observers.compositionend = view => {
|
|
4498
|
-
if (view.observer.editContext)
|
|
4499
|
-
return; // Composition handled by edit context
|
|
4500
4496
|
view.inputState.composing = -1;
|
|
4501
4497
|
view.inputState.compositionEndedAt = Date.now();
|
|
4502
4498
|
view.inputState.compositionPendingKey = true;
|
|
@@ -5416,9 +5412,12 @@ class ViewState {
|
|
|
5416
5412
|
this.heightOracle = new HeightOracle(guessWrapping);
|
|
5417
5413
|
this.stateDeco = state$1.facet(decorations).filter(d => typeof d != "function");
|
|
5418
5414
|
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, state.Text.empty, this.heightOracle.setDoc(state$1.doc), [new ChangedRange(0, 0, 0, state$1.doc.length)]);
|
|
5419
|
-
|
|
5415
|
+
for (let i = 0; i < 2; i++) {
|
|
5416
|
+
this.viewport = this.getViewport(0, null);
|
|
5417
|
+
if (!this.updateForViewport())
|
|
5418
|
+
break;
|
|
5419
|
+
}
|
|
5420
5420
|
this.updateViewportLines();
|
|
5421
|
-
this.updateForViewport();
|
|
5422
5421
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5423
5422
|
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5424
5423
|
this.computeVisibleRanges();
|
|
@@ -5433,13 +5432,18 @@ class ViewState {
|
|
|
5433
5432
|
}
|
|
5434
5433
|
}
|
|
5435
5434
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
5435
|
+
return this.updateScaler();
|
|
5436
|
+
}
|
|
5437
|
+
updateScaler() {
|
|
5438
|
+
let scaler = this.scaler;
|
|
5436
5439
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
5437
5440
|
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
5441
|
+
return scaler.eq(this.scaler) ? 0 : 2 /* UpdateFlag.Height */;
|
|
5438
5442
|
}
|
|
5439
5443
|
updateViewportLines() {
|
|
5440
5444
|
this.viewportLines = [];
|
|
5441
5445
|
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
5442
|
-
this.viewportLines.push(
|
|
5446
|
+
this.viewportLines.push(scaleBlock(block, this.scaler));
|
|
5443
5447
|
});
|
|
5444
5448
|
}
|
|
5445
5449
|
update(update, scrollTarget = null) {
|
|
@@ -5465,11 +5469,10 @@ class ViewState {
|
|
|
5465
5469
|
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
5466
5470
|
!this.viewportIsAppropriate(viewport))
|
|
5467
5471
|
viewport = this.getViewport(0, scrollTarget);
|
|
5468
|
-
let
|
|
5469
|
-
viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5472
|
+
let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5470
5473
|
this.viewport = viewport;
|
|
5471
|
-
this.updateForViewport();
|
|
5472
|
-
if (
|
|
5474
|
+
update.flags |= this.updateForViewport();
|
|
5475
|
+
if (viewportChange || !update.changes.empty || (update.flags & 2 /* UpdateFlag.Height */))
|
|
5473
5476
|
this.updateViewportLines();
|
|
5474
5477
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
5475
5478
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
@@ -5567,9 +5570,12 @@ class ViewState {
|
|
|
5567
5570
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
5568
5571
|
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5569
5572
|
this.scrollTarget.range.head > this.viewport.to);
|
|
5570
|
-
if (viewportChange)
|
|
5573
|
+
if (viewportChange) {
|
|
5574
|
+
if (result & 2 /* UpdateFlag.Height */)
|
|
5575
|
+
result |= this.updateScaler();
|
|
5571
5576
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
5572
|
-
|
|
5577
|
+
result |= this.updateForViewport();
|
|
5578
|
+
}
|
|
5573
5579
|
if ((result & 2 /* UpdateFlag.Height */) || viewportChange)
|
|
5574
5580
|
this.updateViewportLines();
|
|
5575
5581
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
@@ -5758,11 +5764,14 @@ class ViewState {
|
|
|
5758
5764
|
return changed ? 4 /* UpdateFlag.Viewport */ : 0;
|
|
5759
5765
|
}
|
|
5760
5766
|
lineBlockAt(pos) {
|
|
5761
|
-
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5767
|
+
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5768
|
+
this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5762
5769
|
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5763
5770
|
}
|
|
5764
5771
|
lineBlockAtHeight(height) {
|
|
5765
|
-
return
|
|
5772
|
+
return (height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom &&
|
|
5773
|
+
this.viewportLines.find(l => l.top <= height && l.bottom >= height)) ||
|
|
5774
|
+
scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5766
5775
|
}
|
|
5767
5776
|
scrollAnchorAt(scrollTop) {
|
|
5768
5777
|
let block = this.lineBlockAtHeight(scrollTop + 8);
|
|
@@ -5837,7 +5846,8 @@ function find(array, f) {
|
|
|
5837
5846
|
const IdScaler = {
|
|
5838
5847
|
toDOM(n) { return n; },
|
|
5839
5848
|
fromDOM(n) { return n; },
|
|
5840
|
-
scale: 1
|
|
5849
|
+
scale: 1,
|
|
5850
|
+
eq(other) { return other == this; }
|
|
5841
5851
|
};
|
|
5842
5852
|
// When the height is too big (> VP.MaxDOMHeight), scale down the
|
|
5843
5853
|
// regions outside the viewports so that the total height is
|
|
@@ -5880,6 +5890,12 @@ class BigScaler {
|
|
|
5880
5890
|
domBase = vp.domBottom;
|
|
5881
5891
|
}
|
|
5882
5892
|
}
|
|
5893
|
+
eq(other) {
|
|
5894
|
+
if (!(other instanceof BigScaler))
|
|
5895
|
+
return false;
|
|
5896
|
+
return this.scale == other.scale && this.viewports.length == other.viewports.length &&
|
|
5897
|
+
this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
|
|
5898
|
+
}
|
|
5883
5899
|
}
|
|
5884
5900
|
function scaleBlock(block, scaler) {
|
|
5885
5901
|
if (scaler.scale == 1)
|
|
@@ -6271,6 +6287,7 @@ class DOMChange {
|
|
|
6271
6287
|
this.typeOver = typeOver;
|
|
6272
6288
|
this.bounds = null;
|
|
6273
6289
|
this.text = "";
|
|
6290
|
+
this.domChanged = start > -1;
|
|
6274
6291
|
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
6275
6292
|
if (view.state.readOnly && start > -1) {
|
|
6276
6293
|
// Ignore changes when the editor is read-only
|
|
@@ -6373,7 +6390,35 @@ function applyDOMChange(view, domChange) {
|
|
|
6373
6390
|
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
6374
6391
|
}
|
|
6375
6392
|
if (change) {
|
|
6376
|
-
|
|
6393
|
+
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6394
|
+
return true;
|
|
6395
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
6396
|
+
// backspace, or delete. So this detects changes that look like
|
|
6397
|
+
// they're caused by those keys, and reinterprets them as key
|
|
6398
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
6399
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
6400
|
+
// reliable in all situations.)
|
|
6401
|
+
if (browser.android &&
|
|
6402
|
+
((change.to == sel.to &&
|
|
6403
|
+
// GBoard will sometimes remove a space it just inserted
|
|
6404
|
+
// after a completion when you press enter
|
|
6405
|
+
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6406
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6407
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6408
|
+
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6409
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6410
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6411
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6412
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6413
|
+
return true;
|
|
6414
|
+
let text = change.insert.toString();
|
|
6415
|
+
if (view.inputState.composing >= 0)
|
|
6416
|
+
view.inputState.composing++;
|
|
6417
|
+
let defaultTr;
|
|
6418
|
+
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6419
|
+
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6420
|
+
view.dispatch(defaultInsert());
|
|
6421
|
+
return true;
|
|
6377
6422
|
}
|
|
6378
6423
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
6379
6424
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -6389,38 +6434,6 @@ function applyDOMChange(view, domChange) {
|
|
|
6389
6434
|
return false;
|
|
6390
6435
|
}
|
|
6391
6436
|
}
|
|
6392
|
-
function applyDOMChangeInner(view, change, newSel, lastKey = -1) {
|
|
6393
|
-
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6394
|
-
return true;
|
|
6395
|
-
let sel = view.state.selection.main;
|
|
6396
|
-
// Android browsers don't fire reasonable key events for enter,
|
|
6397
|
-
// backspace, or delete. So this detects changes that look like
|
|
6398
|
-
// they're caused by those keys, and reinterprets them as key
|
|
6399
|
-
// events. (Some of these keys are also handled by beforeinput
|
|
6400
|
-
// events and the pendingAndroidKey mechanism, but that's not
|
|
6401
|
-
// reliable in all situations.)
|
|
6402
|
-
if (browser.android &&
|
|
6403
|
-
((change.to == sel.to &&
|
|
6404
|
-
// GBoard will sometimes remove a space it just inserted
|
|
6405
|
-
// after a completion when you press enter
|
|
6406
|
-
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6407
|
-
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6408
|
-
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6409
|
-
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6410
|
-
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6411
|
-
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6412
|
-
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6413
|
-
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6414
|
-
return true;
|
|
6415
|
-
let text = change.insert.toString();
|
|
6416
|
-
if (view.inputState.composing >= 0)
|
|
6417
|
-
view.inputState.composing++;
|
|
6418
|
-
let defaultTr;
|
|
6419
|
-
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6420
|
-
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6421
|
-
view.dispatch(defaultInsert());
|
|
6422
|
-
return true;
|
|
6423
|
-
}
|
|
6424
6437
|
function applyDefaultInsert(view, change, newSel) {
|
|
6425
6438
|
let tr, startState = view.state, sel = startState.selection.main;
|
|
6426
6439
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
@@ -6547,7 +6560,6 @@ class DOMObserver {
|
|
|
6547
6560
|
constructor(view) {
|
|
6548
6561
|
this.view = view;
|
|
6549
6562
|
this.active = false;
|
|
6550
|
-
this.editContext = null;
|
|
6551
6563
|
// The known selection. Kept in our own object, as opposed to just
|
|
6552
6564
|
// directly accessing the selection because:
|
|
6553
6565
|
// - Safari doesn't report the right selection in shadow DOM
|
|
@@ -6592,10 +6604,6 @@ class DOMObserver {
|
|
|
6592
6604
|
else
|
|
6593
6605
|
this.flush();
|
|
6594
6606
|
});
|
|
6595
|
-
if (window.EditContext) {
|
|
6596
|
-
this.editContext = new EditContextManager(view);
|
|
6597
|
-
view.contentDOM.editContext = this.editContext.editContext;
|
|
6598
|
-
}
|
|
6599
6607
|
if (useCharData)
|
|
6600
6608
|
this.onCharData = (event) => {
|
|
6601
6609
|
this.queue.push({ target: event.target,
|
|
@@ -6646,8 +6654,6 @@ class DOMObserver {
|
|
|
6646
6654
|
onScroll(e) {
|
|
6647
6655
|
if (this.intersecting)
|
|
6648
6656
|
this.flush(false);
|
|
6649
|
-
if (this.editContext)
|
|
6650
|
-
this.view.requestMeasure(this.editContext.measureReq);
|
|
6651
6657
|
this.onScrollChanged(e);
|
|
6652
6658
|
}
|
|
6653
6659
|
onResize() {
|
|
@@ -6906,8 +6912,9 @@ class DOMObserver {
|
|
|
6906
6912
|
}
|
|
6907
6913
|
let startState = this.view.state;
|
|
6908
6914
|
let handled = applyDOMChange(this.view, domChange);
|
|
6909
|
-
// The view wasn't updated
|
|
6910
|
-
if (this.view.state == startState
|
|
6915
|
+
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
6916
|
+
if (this.view.state == startState &&
|
|
6917
|
+
(domChange.domChanged || domChange.newSel && !domChange.newSel.main.eq(this.view.state.selection.main)))
|
|
6911
6918
|
this.view.update([]);
|
|
6912
6919
|
return handled;
|
|
6913
6920
|
}
|
|
@@ -6956,10 +6963,6 @@ class DOMObserver {
|
|
|
6956
6963
|
win.removeEventListener("beforeprint", this.onPrint);
|
|
6957
6964
|
win.document.removeEventListener("selectionchange", this.onSelectionChange);
|
|
6958
6965
|
}
|
|
6959
|
-
update(update) {
|
|
6960
|
-
if (this.editContext)
|
|
6961
|
-
this.editContext.update(update);
|
|
6962
|
-
}
|
|
6963
6966
|
destroy() {
|
|
6964
6967
|
var _a, _b, _c;
|
|
6965
6968
|
this.stop();
|
|
@@ -7019,161 +7022,6 @@ function safariSelectionRangeHack(view, selection) {
|
|
|
7019
7022
|
view.contentDOM.removeEventListener("beforeinput", read, true);
|
|
7020
7023
|
return found ? buildSelectionRangeFromRange(view, found) : null;
|
|
7021
7024
|
}
|
|
7022
|
-
class EditContextManager {
|
|
7023
|
-
constructor(view) {
|
|
7024
|
-
// The document window for which the text in the context is
|
|
7025
|
-
// maintained. For large documents, this may be smaller than the
|
|
7026
|
-
// editor document. This window always includes the selection head.
|
|
7027
|
-
this.from = 0;
|
|
7028
|
-
this.to = 0;
|
|
7029
|
-
// When applying a transaction, this is used to compare the change
|
|
7030
|
-
// made to the context content to the change in the transaction in
|
|
7031
|
-
// order to make the minimal changes to the context (since touching
|
|
7032
|
-
// that sometimes breaks series of multiple edits made for a single
|
|
7033
|
-
// user action on some Android keyboards)
|
|
7034
|
-
this.pendingContextChange = null;
|
|
7035
|
-
this.resetRange(view.state);
|
|
7036
|
-
let context = this.editContext = new window.EditContext({
|
|
7037
|
-
text: view.state.doc.sliceString(this.from, this.to),
|
|
7038
|
-
selectionStart: this.toContextPos(Math.max(this.from, Math.min(this.to, view.state.selection.main.anchor))),
|
|
7039
|
-
selectionEnd: this.toContextPos(view.state.selection.main.head)
|
|
7040
|
-
});
|
|
7041
|
-
context.addEventListener("textupdate", e => {
|
|
7042
|
-
let { anchor } = view.state.selection.main;
|
|
7043
|
-
let change = { from: this.toEditorPos(e.updateRangeStart),
|
|
7044
|
-
to: this.toEditorPos(e.updateRangeEnd),
|
|
7045
|
-
insert: state.Text.of(e.text.split("\n")) };
|
|
7046
|
-
// If the window doesn't include the anchor, assume changes
|
|
7047
|
-
// adjacent to a side go up to the anchor.
|
|
7048
|
-
if (change.from == this.from && anchor < this.from)
|
|
7049
|
-
change.from = anchor;
|
|
7050
|
-
else if (change.to == this.to && anchor > this.to)
|
|
7051
|
-
change.to = anchor;
|
|
7052
|
-
// Edit context sometimes fire empty changes
|
|
7053
|
-
if (change.from == change.to && !change.insert.length)
|
|
7054
|
-
return;
|
|
7055
|
-
this.pendingContextChange = change;
|
|
7056
|
-
applyDOMChangeInner(view, change, state.EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd)));
|
|
7057
|
-
// If the transaction didn't flush our change, revert it so
|
|
7058
|
-
// that the context is in sync with the editor state again.
|
|
7059
|
-
if (this.pendingContextChange)
|
|
7060
|
-
this.revertPending(view.state);
|
|
7061
|
-
});
|
|
7062
|
-
context.addEventListener("characterboundsupdate", e => {
|
|
7063
|
-
let rects = [], prev = null;
|
|
7064
|
-
for (let i = this.toEditorPos(e.rangeStart), end = this.toEditorPos(e.rangeEnd); i < end; i++) {
|
|
7065
|
-
let rect = view.coordsForChar(i);
|
|
7066
|
-
prev = (rect && new DOMRect(rect.left, rect.right, rect.right - rect.left, rect.bottom - rect.top))
|
|
7067
|
-
|| prev || new DOMRect;
|
|
7068
|
-
rects.push(prev);
|
|
7069
|
-
}
|
|
7070
|
-
context.updateCharacterBounds(e.rangeStart, rects);
|
|
7071
|
-
});
|
|
7072
|
-
context.addEventListener("textformatupdate", e => {
|
|
7073
|
-
let deco = [];
|
|
7074
|
-
for (let format of e.getTextFormats()) {
|
|
7075
|
-
let lineStyle = format.underlineStyle, thickness = format.underlineThickness;
|
|
7076
|
-
if (lineStyle != "None" && thickness != "None") {
|
|
7077
|
-
let style = `text-decoration: underline ${lineStyle == "Dashed" ? "dashed " : lineStyle == "Squiggle" ? "wavy " : ""}${thickness == "Thin" ? 1 : 2}px`;
|
|
7078
|
-
deco.push(Decoration.mark({ attributes: { style } })
|
|
7079
|
-
.range(this.toEditorPos(format.rangeStart), this.toEditorPos(format.rangeEnd)));
|
|
7080
|
-
}
|
|
7081
|
-
}
|
|
7082
|
-
view.dispatch({ effects: setEditContextFormatting.of(Decoration.set(deco)) });
|
|
7083
|
-
});
|
|
7084
|
-
context.addEventListener("compositionstart", () => {
|
|
7085
|
-
if (view.inputState.composing < 0) {
|
|
7086
|
-
view.inputState.composing = 0;
|
|
7087
|
-
view.inputState.compositionFirstChange = true;
|
|
7088
|
-
}
|
|
7089
|
-
});
|
|
7090
|
-
context.addEventListener("compositionend", () => {
|
|
7091
|
-
view.inputState.composing = -1;
|
|
7092
|
-
view.inputState.compositionFirstChange = null;
|
|
7093
|
-
});
|
|
7094
|
-
this.measureReq = { read: view => {
|
|
7095
|
-
this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
|
|
7096
|
-
let sel = getSelection(view.root);
|
|
7097
|
-
if (sel && sel.rangeCount)
|
|
7098
|
-
this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
|
|
7099
|
-
} };
|
|
7100
|
-
}
|
|
7101
|
-
applyEdits(update) {
|
|
7102
|
-
let off = 0, abort = false, pending = this.pendingContextChange;
|
|
7103
|
-
update.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
7104
|
-
if (abort)
|
|
7105
|
-
return;
|
|
7106
|
-
let dLen = insert.length - (toA - fromA);
|
|
7107
|
-
if (pending && toA >= pending.to) {
|
|
7108
|
-
if (pending.from == fromA && pending.to == toA && pending.insert.eq(insert)) {
|
|
7109
|
-
pending = this.pendingContextChange = null; // Match
|
|
7110
|
-
off += dLen;
|
|
7111
|
-
return;
|
|
7112
|
-
}
|
|
7113
|
-
else { // Mismatch, revert
|
|
7114
|
-
pending = null;
|
|
7115
|
-
this.revertPending(update.state);
|
|
7116
|
-
}
|
|
7117
|
-
}
|
|
7118
|
-
fromA += off;
|
|
7119
|
-
toA += off;
|
|
7120
|
-
if (toA <= this.from) { // Before the window
|
|
7121
|
-
this.from += dLen;
|
|
7122
|
-
this.to += dLen;
|
|
7123
|
-
}
|
|
7124
|
-
else if (fromA < this.to) { // Overlaps with window
|
|
7125
|
-
if (fromA < this.from || toA > this.to || (this.to - this.from) + insert.length > 30000 /* CxVp.MaxSize */) {
|
|
7126
|
-
abort = true;
|
|
7127
|
-
return;
|
|
7128
|
-
}
|
|
7129
|
-
this.editContext.updateText(this.toContextPos(fromA), this.toContextPos(toA), insert.toString());
|
|
7130
|
-
this.to += dLen;
|
|
7131
|
-
}
|
|
7132
|
-
off += dLen;
|
|
7133
|
-
});
|
|
7134
|
-
if (pending && !abort)
|
|
7135
|
-
this.revertPending(update.state);
|
|
7136
|
-
return !abort;
|
|
7137
|
-
}
|
|
7138
|
-
update(update) {
|
|
7139
|
-
if (!this.applyEdits(update) || !this.rangeIsValid(update.state)) {
|
|
7140
|
-
this.pendingContextChange = null;
|
|
7141
|
-
this.resetRange(update.state);
|
|
7142
|
-
this.editContext.updateText(0, this.editContext.text.length, update.state.doc.sliceString(this.from, this.to));
|
|
7143
|
-
this.setSelection(update.state);
|
|
7144
|
-
}
|
|
7145
|
-
else if (update.docChanged || update.selectionSet) {
|
|
7146
|
-
this.setSelection(update.state);
|
|
7147
|
-
}
|
|
7148
|
-
if (update.geometryChanged || update.docChanged || update.selectionSet)
|
|
7149
|
-
update.view.requestMeasure(this.measureReq);
|
|
7150
|
-
}
|
|
7151
|
-
resetRange(state) {
|
|
7152
|
-
let { head } = state.selection.main;
|
|
7153
|
-
this.from = Math.max(0, head - 10000 /* CxVp.Margin */);
|
|
7154
|
-
this.to = Math.min(state.doc.length, head + 10000 /* CxVp.Margin */);
|
|
7155
|
-
}
|
|
7156
|
-
revertPending(state) {
|
|
7157
|
-
let pending = this.pendingContextChange;
|
|
7158
|
-
this.pendingContextChange = null;
|
|
7159
|
-
this.editContext.updateText(this.toContextPos(pending.from), this.toContextPos(pending.to + pending.insert.length), state.doc.sliceString(pending.from, pending.to));
|
|
7160
|
-
}
|
|
7161
|
-
setSelection(state) {
|
|
7162
|
-
let { main } = state.selection;
|
|
7163
|
-
let start = this.toContextPos(Math.max(this.from, Math.min(this.to, main.anchor)));
|
|
7164
|
-
let end = this.toContextPos(main.head);
|
|
7165
|
-
if (this.editContext.selectionStart != start || this.editContext.selectionEnd != end)
|
|
7166
|
-
this.editContext.updateSelection(start, end);
|
|
7167
|
-
}
|
|
7168
|
-
rangeIsValid(state) {
|
|
7169
|
-
let { head } = state.selection.main;
|
|
7170
|
-
return !(this.from > 0 && head - this.from < 500 /* CxVp.MinMargin */ ||
|
|
7171
|
-
this.to < state.doc.length && this.to - head < 500 /* CxVp.MinMargin */ ||
|
|
7172
|
-
this.to - this.from > 10000 /* CxVp.Margin */ * 3);
|
|
7173
|
-
}
|
|
7174
|
-
toEditorPos(contextPos) { return contextPos + this.from; }
|
|
7175
|
-
toContextPos(editorPos) { return editorPos - this.from; }
|
|
7176
|
-
}
|
|
7177
7025
|
|
|
7178
7026
|
// The editor's update state machine looks something like this:
|
|
7179
7027
|
//
|
|
@@ -8604,11 +8452,17 @@ function getBase(view) {
|
|
|
8604
8452
|
let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8605
8453
|
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8606
8454
|
}
|
|
8607
|
-
function wrappedLine(view, pos, inside) {
|
|
8608
|
-
let
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8455
|
+
function wrappedLine(view, pos, side, inside) {
|
|
8456
|
+
let coords = view.coordsAtPos(pos, side * 2);
|
|
8457
|
+
if (!coords)
|
|
8458
|
+
return inside;
|
|
8459
|
+
let editorRect = view.dom.getBoundingClientRect();
|
|
8460
|
+
let y = (coords.top + coords.bottom) / 2;
|
|
8461
|
+
let left = view.posAtCoords({ x: editorRect.left + 1, y });
|
|
8462
|
+
let right = view.posAtCoords({ x: editorRect.right - 1, y });
|
|
8463
|
+
if (left == null || right == null)
|
|
8464
|
+
return inside;
|
|
8465
|
+
return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
|
|
8612
8466
|
}
|
|
8613
8467
|
function rectanglesForRange(view, className, range) {
|
|
8614
8468
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -8624,10 +8478,10 @@ function rectanglesForRange(view, className, range) {
|
|
|
8624
8478
|
let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null;
|
|
8625
8479
|
let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null;
|
|
8626
8480
|
if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
|
|
8627
|
-
visualStart = wrappedLine(view, from, visualStart);
|
|
8481
|
+
visualStart = wrappedLine(view, from, 1, visualStart);
|
|
8628
8482
|
if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
|
|
8629
|
-
visualEnd = wrappedLine(view, to, visualEnd);
|
|
8630
|
-
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
8483
|
+
visualEnd = wrappedLine(view, to, -1, visualEnd);
|
|
8484
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
|
|
8631
8485
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
8632
8486
|
}
|
|
8633
8487
|
else {
|
|
@@ -8882,14 +8736,19 @@ const selectionLayer = layer({
|
|
|
8882
8736
|
});
|
|
8883
8737
|
const themeSpec = {
|
|
8884
8738
|
".cm-line": {
|
|
8885
|
-
"& ::selection": { backgroundColor: "transparent !important" },
|
|
8886
|
-
|
|
8739
|
+
"& ::selection, &::selection": { backgroundColor: "transparent !important" },
|
|
8740
|
+
},
|
|
8741
|
+
".cm-content": {
|
|
8742
|
+
"& :focus": {
|
|
8743
|
+
caretColor: "initial !important",
|
|
8744
|
+
"&::selection, & ::selection": {
|
|
8745
|
+
backgroundColor: "Highlight !important"
|
|
8746
|
+
}
|
|
8747
|
+
}
|
|
8887
8748
|
}
|
|
8888
8749
|
};
|
|
8889
|
-
if (CanHidePrimary)
|
|
8890
|
-
themeSpec[".cm-line"].caretColor = "transparent !important";
|
|
8891
|
-
themeSpec[".cm-content"] = { caretColor: "transparent !important" };
|
|
8892
|
-
}
|
|
8750
|
+
if (CanHidePrimary)
|
|
8751
|
+
themeSpec[".cm-line"].caretColor = themeSpec[".cm-content"].caretColor = "transparent !important";
|
|
8893
8752
|
const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
|
|
8894
8753
|
|
|
8895
8754
|
const setDropCursorPos = state.StateEffect.define({
|
package/dist/index.js
CHANGED
|
@@ -743,7 +743,7 @@ var browser = {
|
|
|
743
743
|
android: /*@__PURE__*//Android\b/.test(nav.userAgent),
|
|
744
744
|
webkit,
|
|
745
745
|
safari,
|
|
746
|
-
webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(
|
|
746
|
+
webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
|
747
747
|
tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
|
|
748
748
|
};
|
|
749
749
|
|
|
@@ -2364,7 +2364,6 @@ class ScrollTarget {
|
|
|
2364
2364
|
}
|
|
2365
2365
|
}
|
|
2366
2366
|
const scrollIntoView = /*@__PURE__*/StateEffect.define({ map: (t, ch) => t.map(ch) });
|
|
2367
|
-
const setEditContextFormatting = /*@__PURE__*/StateEffect.define();
|
|
2368
2367
|
/**
|
|
2369
2368
|
Log or report an unhandled exception in client code. Should
|
|
2370
2369
|
probably only be used by extension code that allows client code to
|
|
@@ -2701,11 +2700,10 @@ class DocView extends ContentView {
|
|
|
2701
2700
|
super();
|
|
2702
2701
|
this.view = view;
|
|
2703
2702
|
this.decorations = [];
|
|
2704
|
-
this.dynamicDecorationMap = [
|
|
2703
|
+
this.dynamicDecorationMap = [];
|
|
2705
2704
|
this.domChanged = null;
|
|
2706
2705
|
this.hasComposition = null;
|
|
2707
2706
|
this.markedForComposition = new Set;
|
|
2708
|
-
this.editContextFormatting = Decoration.none;
|
|
2709
2707
|
this.lastCompositionAfterCursor = false;
|
|
2710
2708
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2711
2709
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
@@ -2744,9 +2742,8 @@ class DocView extends ContentView {
|
|
|
2744
2742
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2745
2743
|
}
|
|
2746
2744
|
}
|
|
2747
|
-
this.updateEditContextFormatting(update);
|
|
2748
2745
|
let readCompositionAt = -1;
|
|
2749
|
-
if (this.view.inputState.composing >= 0
|
|
2746
|
+
if (this.view.inputState.composing >= 0) {
|
|
2750
2747
|
if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
|
|
2751
2748
|
readCompositionAt = this.domChanged.newSel.head;
|
|
2752
2749
|
else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
|
|
@@ -2854,14 +2851,6 @@ class DocView extends ContentView {
|
|
|
2854
2851
|
if (composition)
|
|
2855
2852
|
this.fixCompositionDOM(composition);
|
|
2856
2853
|
}
|
|
2857
|
-
updateEditContextFormatting(update) {
|
|
2858
|
-
this.editContextFormatting = this.editContextFormatting.map(update.changes);
|
|
2859
|
-
for (let tr of update.transactions)
|
|
2860
|
-
for (let effect of tr.effects)
|
|
2861
|
-
if (effect.is(setEditContextFormatting)) {
|
|
2862
|
-
this.editContextFormatting = effect.value;
|
|
2863
|
-
}
|
|
2864
|
-
}
|
|
2865
2854
|
compositionView(composition) {
|
|
2866
2855
|
let cur = new TextView(composition.text.nodeValue);
|
|
2867
2856
|
cur.flags |= 8 /* ViewFlag.Composition */;
|
|
@@ -3067,6 +3056,12 @@ class DocView extends ContentView {
|
|
|
3067
3056
|
best = child;
|
|
3068
3057
|
bestPos = start;
|
|
3069
3058
|
}
|
|
3059
|
+
else if (best && start == pos && end == pos && child instanceof BlockWidgetView && Math.abs(side) < 2) {
|
|
3060
|
+
if (child.deco.startSide < 0)
|
|
3061
|
+
break;
|
|
3062
|
+
else if (i)
|
|
3063
|
+
best = null;
|
|
3064
|
+
}
|
|
3070
3065
|
off = start;
|
|
3071
3066
|
}
|
|
3072
3067
|
return best ? best.coordsAt(pos - bestPos, side) : null;
|
|
@@ -3187,7 +3182,7 @@ class DocView extends ContentView {
|
|
|
3187
3182
|
return Decoration.set(deco);
|
|
3188
3183
|
}
|
|
3189
3184
|
updateDeco() {
|
|
3190
|
-
let i =
|
|
3185
|
+
let i = 0;
|
|
3191
3186
|
let allDeco = this.view.state.facet(decorations).map(d => {
|
|
3192
3187
|
let dynamic = this.dynamicDecorationMap[i++] = typeof d == "function";
|
|
3193
3188
|
return dynamic ? d(this.view) : d;
|
|
@@ -3203,7 +3198,6 @@ class DocView extends ContentView {
|
|
|
3203
3198
|
allDeco.push(RangeSet.join(outerDeco));
|
|
3204
3199
|
}
|
|
3205
3200
|
this.decorations = [
|
|
3206
|
-
this.editContextFormatting,
|
|
3207
3201
|
...allDeco,
|
|
3208
3202
|
this.computeBlockGapDeco(),
|
|
3209
3203
|
this.view.viewState.lineGapDeco
|
|
@@ -3890,7 +3884,6 @@ class InputState {
|
|
|
3890
3884
|
this.mouseSelection = mouseSelection;
|
|
3891
3885
|
}
|
|
3892
3886
|
update(update) {
|
|
3893
|
-
this.view.observer.update(update);
|
|
3894
3887
|
if (this.mouseSelection)
|
|
3895
3888
|
this.mouseSelection.update(update);
|
|
3896
3889
|
if (this.draggedContent && update.docChanged)
|
|
@@ -4069,7 +4062,9 @@ class MouseSelection {
|
|
|
4069
4062
|
this.mustSelect = false;
|
|
4070
4063
|
}
|
|
4071
4064
|
update(update) {
|
|
4072
|
-
if (
|
|
4065
|
+
if (update.transactions.some(tr => tr.isUserEvent("input.type")))
|
|
4066
|
+
this.destroy();
|
|
4067
|
+
else if (this.style.update(update))
|
|
4073
4068
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
4074
4069
|
}
|
|
4075
4070
|
}
|
|
@@ -4193,7 +4188,12 @@ handlers.mousedown = (view, event) => {
|
|
|
4193
4188
|
let mustFocus = !view.hasFocus;
|
|
4194
4189
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4195
4190
|
if (mustFocus)
|
|
4196
|
-
view.observer.ignore(() =>
|
|
4191
|
+
view.observer.ignore(() => {
|
|
4192
|
+
focusPreventScroll(view.contentDOM);
|
|
4193
|
+
let active = view.root.activeElement;
|
|
4194
|
+
if (active && !active.contains(view.contentDOM))
|
|
4195
|
+
active.blur();
|
|
4196
|
+
});
|
|
4197
4197
|
let mouseSel = view.inputState.mouseSelection;
|
|
4198
4198
|
if (mouseSel) {
|
|
4199
4199
|
mouseSel.start(event);
|
|
@@ -4481,8 +4481,6 @@ observers.blur = view => {
|
|
|
4481
4481
|
updateForFocusChange(view);
|
|
4482
4482
|
};
|
|
4483
4483
|
observers.compositionstart = observers.compositionupdate = view => {
|
|
4484
|
-
if (view.observer.editContext)
|
|
4485
|
-
return; // Composition handled by edit context
|
|
4486
4484
|
if (view.inputState.compositionFirstChange == null)
|
|
4487
4485
|
view.inputState.compositionFirstChange = true;
|
|
4488
4486
|
if (view.inputState.composing < 0) {
|
|
@@ -4491,8 +4489,6 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
4491
4489
|
}
|
|
4492
4490
|
};
|
|
4493
4491
|
observers.compositionend = view => {
|
|
4494
|
-
if (view.observer.editContext)
|
|
4495
|
-
return; // Composition handled by edit context
|
|
4496
4492
|
view.inputState.composing = -1;
|
|
4497
4493
|
view.inputState.compositionEndedAt = Date.now();
|
|
4498
4494
|
view.inputState.compositionPendingKey = true;
|
|
@@ -5411,9 +5407,12 @@ class ViewState {
|
|
|
5411
5407
|
this.heightOracle = new HeightOracle(guessWrapping);
|
|
5412
5408
|
this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
|
|
5413
5409
|
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
|
5414
|
-
|
|
5410
|
+
for (let i = 0; i < 2; i++) {
|
|
5411
|
+
this.viewport = this.getViewport(0, null);
|
|
5412
|
+
if (!this.updateForViewport())
|
|
5413
|
+
break;
|
|
5414
|
+
}
|
|
5415
5415
|
this.updateViewportLines();
|
|
5416
|
-
this.updateForViewport();
|
|
5417
5416
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5418
5417
|
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5419
5418
|
this.computeVisibleRanges();
|
|
@@ -5428,13 +5427,18 @@ class ViewState {
|
|
|
5428
5427
|
}
|
|
5429
5428
|
}
|
|
5430
5429
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
5430
|
+
return this.updateScaler();
|
|
5431
|
+
}
|
|
5432
|
+
updateScaler() {
|
|
5433
|
+
let scaler = this.scaler;
|
|
5431
5434
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
5432
5435
|
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
5436
|
+
return scaler.eq(this.scaler) ? 0 : 2 /* UpdateFlag.Height */;
|
|
5433
5437
|
}
|
|
5434
5438
|
updateViewportLines() {
|
|
5435
5439
|
this.viewportLines = [];
|
|
5436
5440
|
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
5437
|
-
this.viewportLines.push(
|
|
5441
|
+
this.viewportLines.push(scaleBlock(block, this.scaler));
|
|
5438
5442
|
});
|
|
5439
5443
|
}
|
|
5440
5444
|
update(update, scrollTarget = null) {
|
|
@@ -5460,11 +5464,10 @@ class ViewState {
|
|
|
5460
5464
|
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
5461
5465
|
!this.viewportIsAppropriate(viewport))
|
|
5462
5466
|
viewport = this.getViewport(0, scrollTarget);
|
|
5463
|
-
let
|
|
5464
|
-
viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5467
|
+
let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5465
5468
|
this.viewport = viewport;
|
|
5466
|
-
this.updateForViewport();
|
|
5467
|
-
if (
|
|
5469
|
+
update.flags |= this.updateForViewport();
|
|
5470
|
+
if (viewportChange || !update.changes.empty || (update.flags & 2 /* UpdateFlag.Height */))
|
|
5468
5471
|
this.updateViewportLines();
|
|
5469
5472
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
5470
5473
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
@@ -5562,9 +5565,12 @@ class ViewState {
|
|
|
5562
5565
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
5563
5566
|
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5564
5567
|
this.scrollTarget.range.head > this.viewport.to);
|
|
5565
|
-
if (viewportChange)
|
|
5568
|
+
if (viewportChange) {
|
|
5569
|
+
if (result & 2 /* UpdateFlag.Height */)
|
|
5570
|
+
result |= this.updateScaler();
|
|
5566
5571
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
5567
|
-
|
|
5572
|
+
result |= this.updateForViewport();
|
|
5573
|
+
}
|
|
5568
5574
|
if ((result & 2 /* UpdateFlag.Height */) || viewportChange)
|
|
5569
5575
|
this.updateViewportLines();
|
|
5570
5576
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
@@ -5753,11 +5759,14 @@ class ViewState {
|
|
|
5753
5759
|
return changed ? 4 /* UpdateFlag.Viewport */ : 0;
|
|
5754
5760
|
}
|
|
5755
5761
|
lineBlockAt(pos) {
|
|
5756
|
-
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5762
|
+
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5763
|
+
this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5757
5764
|
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5758
5765
|
}
|
|
5759
5766
|
lineBlockAtHeight(height) {
|
|
5760
|
-
return
|
|
5767
|
+
return (height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom &&
|
|
5768
|
+
this.viewportLines.find(l => l.top <= height && l.bottom >= height)) ||
|
|
5769
|
+
scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5761
5770
|
}
|
|
5762
5771
|
scrollAnchorAt(scrollTop) {
|
|
5763
5772
|
let block = this.lineBlockAtHeight(scrollTop + 8);
|
|
@@ -5832,7 +5841,8 @@ function find(array, f) {
|
|
|
5832
5841
|
const IdScaler = {
|
|
5833
5842
|
toDOM(n) { return n; },
|
|
5834
5843
|
fromDOM(n) { return n; },
|
|
5835
|
-
scale: 1
|
|
5844
|
+
scale: 1,
|
|
5845
|
+
eq(other) { return other == this; }
|
|
5836
5846
|
};
|
|
5837
5847
|
// When the height is too big (> VP.MaxDOMHeight), scale down the
|
|
5838
5848
|
// regions outside the viewports so that the total height is
|
|
@@ -5875,6 +5885,12 @@ class BigScaler {
|
|
|
5875
5885
|
domBase = vp.domBottom;
|
|
5876
5886
|
}
|
|
5877
5887
|
}
|
|
5888
|
+
eq(other) {
|
|
5889
|
+
if (!(other instanceof BigScaler))
|
|
5890
|
+
return false;
|
|
5891
|
+
return this.scale == other.scale && this.viewports.length == other.viewports.length &&
|
|
5892
|
+
this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
|
|
5893
|
+
}
|
|
5878
5894
|
}
|
|
5879
5895
|
function scaleBlock(block, scaler) {
|
|
5880
5896
|
if (scaler.scale == 1)
|
|
@@ -6266,6 +6282,7 @@ class DOMChange {
|
|
|
6266
6282
|
this.typeOver = typeOver;
|
|
6267
6283
|
this.bounds = null;
|
|
6268
6284
|
this.text = "";
|
|
6285
|
+
this.domChanged = start > -1;
|
|
6269
6286
|
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
6270
6287
|
if (view.state.readOnly && start > -1) {
|
|
6271
6288
|
// Ignore changes when the editor is read-only
|
|
@@ -6368,7 +6385,35 @@ function applyDOMChange(view, domChange) {
|
|
|
6368
6385
|
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
6369
6386
|
}
|
|
6370
6387
|
if (change) {
|
|
6371
|
-
|
|
6388
|
+
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6389
|
+
return true;
|
|
6390
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
6391
|
+
// backspace, or delete. So this detects changes that look like
|
|
6392
|
+
// they're caused by those keys, and reinterprets them as key
|
|
6393
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
6394
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
6395
|
+
// reliable in all situations.)
|
|
6396
|
+
if (browser.android &&
|
|
6397
|
+
((change.to == sel.to &&
|
|
6398
|
+
// GBoard will sometimes remove a space it just inserted
|
|
6399
|
+
// after a completion when you press enter
|
|
6400
|
+
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6401
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6402
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6403
|
+
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6404
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6405
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6406
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6407
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6408
|
+
return true;
|
|
6409
|
+
let text = change.insert.toString();
|
|
6410
|
+
if (view.inputState.composing >= 0)
|
|
6411
|
+
view.inputState.composing++;
|
|
6412
|
+
let defaultTr;
|
|
6413
|
+
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6414
|
+
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6415
|
+
view.dispatch(defaultInsert());
|
|
6416
|
+
return true;
|
|
6372
6417
|
}
|
|
6373
6418
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
6374
6419
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -6384,38 +6429,6 @@ function applyDOMChange(view, domChange) {
|
|
|
6384
6429
|
return false;
|
|
6385
6430
|
}
|
|
6386
6431
|
}
|
|
6387
|
-
function applyDOMChangeInner(view, change, newSel, lastKey = -1) {
|
|
6388
|
-
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6389
|
-
return true;
|
|
6390
|
-
let sel = view.state.selection.main;
|
|
6391
|
-
// Android browsers don't fire reasonable key events for enter,
|
|
6392
|
-
// backspace, or delete. So this detects changes that look like
|
|
6393
|
-
// they're caused by those keys, and reinterprets them as key
|
|
6394
|
-
// events. (Some of these keys are also handled by beforeinput
|
|
6395
|
-
// events and the pendingAndroidKey mechanism, but that's not
|
|
6396
|
-
// reliable in all situations.)
|
|
6397
|
-
if (browser.android &&
|
|
6398
|
-
((change.to == sel.to &&
|
|
6399
|
-
// GBoard will sometimes remove a space it just inserted
|
|
6400
|
-
// after a completion when you press enter
|
|
6401
|
-
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6402
|
-
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6403
|
-
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6404
|
-
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6405
|
-
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6406
|
-
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6407
|
-
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6408
|
-
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6409
|
-
return true;
|
|
6410
|
-
let text = change.insert.toString();
|
|
6411
|
-
if (view.inputState.composing >= 0)
|
|
6412
|
-
view.inputState.composing++;
|
|
6413
|
-
let defaultTr;
|
|
6414
|
-
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6415
|
-
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6416
|
-
view.dispatch(defaultInsert());
|
|
6417
|
-
return true;
|
|
6418
|
-
}
|
|
6419
6432
|
function applyDefaultInsert(view, change, newSel) {
|
|
6420
6433
|
let tr, startState = view.state, sel = startState.selection.main;
|
|
6421
6434
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
@@ -6542,7 +6555,6 @@ class DOMObserver {
|
|
|
6542
6555
|
constructor(view) {
|
|
6543
6556
|
this.view = view;
|
|
6544
6557
|
this.active = false;
|
|
6545
|
-
this.editContext = null;
|
|
6546
6558
|
// The known selection. Kept in our own object, as opposed to just
|
|
6547
6559
|
// directly accessing the selection because:
|
|
6548
6560
|
// - Safari doesn't report the right selection in shadow DOM
|
|
@@ -6587,10 +6599,6 @@ class DOMObserver {
|
|
|
6587
6599
|
else
|
|
6588
6600
|
this.flush();
|
|
6589
6601
|
});
|
|
6590
|
-
if (window.EditContext) {
|
|
6591
|
-
this.editContext = new EditContextManager(view);
|
|
6592
|
-
view.contentDOM.editContext = this.editContext.editContext;
|
|
6593
|
-
}
|
|
6594
6602
|
if (useCharData)
|
|
6595
6603
|
this.onCharData = (event) => {
|
|
6596
6604
|
this.queue.push({ target: event.target,
|
|
@@ -6641,8 +6649,6 @@ class DOMObserver {
|
|
|
6641
6649
|
onScroll(e) {
|
|
6642
6650
|
if (this.intersecting)
|
|
6643
6651
|
this.flush(false);
|
|
6644
|
-
if (this.editContext)
|
|
6645
|
-
this.view.requestMeasure(this.editContext.measureReq);
|
|
6646
6652
|
this.onScrollChanged(e);
|
|
6647
6653
|
}
|
|
6648
6654
|
onResize() {
|
|
@@ -6901,8 +6907,9 @@ class DOMObserver {
|
|
|
6901
6907
|
}
|
|
6902
6908
|
let startState = this.view.state;
|
|
6903
6909
|
let handled = applyDOMChange(this.view, domChange);
|
|
6904
|
-
// The view wasn't updated
|
|
6905
|
-
if (this.view.state == startState
|
|
6910
|
+
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
6911
|
+
if (this.view.state == startState &&
|
|
6912
|
+
(domChange.domChanged || domChange.newSel && !domChange.newSel.main.eq(this.view.state.selection.main)))
|
|
6906
6913
|
this.view.update([]);
|
|
6907
6914
|
return handled;
|
|
6908
6915
|
}
|
|
@@ -6951,10 +6958,6 @@ class DOMObserver {
|
|
|
6951
6958
|
win.removeEventListener("beforeprint", this.onPrint);
|
|
6952
6959
|
win.document.removeEventListener("selectionchange", this.onSelectionChange);
|
|
6953
6960
|
}
|
|
6954
|
-
update(update) {
|
|
6955
|
-
if (this.editContext)
|
|
6956
|
-
this.editContext.update(update);
|
|
6957
|
-
}
|
|
6958
6961
|
destroy() {
|
|
6959
6962
|
var _a, _b, _c;
|
|
6960
6963
|
this.stop();
|
|
@@ -7014,161 +7017,6 @@ function safariSelectionRangeHack(view, selection) {
|
|
|
7014
7017
|
view.contentDOM.removeEventListener("beforeinput", read, true);
|
|
7015
7018
|
return found ? buildSelectionRangeFromRange(view, found) : null;
|
|
7016
7019
|
}
|
|
7017
|
-
class EditContextManager {
|
|
7018
|
-
constructor(view) {
|
|
7019
|
-
// The document window for which the text in the context is
|
|
7020
|
-
// maintained. For large documents, this may be smaller than the
|
|
7021
|
-
// editor document. This window always includes the selection head.
|
|
7022
|
-
this.from = 0;
|
|
7023
|
-
this.to = 0;
|
|
7024
|
-
// When applying a transaction, this is used to compare the change
|
|
7025
|
-
// made to the context content to the change in the transaction in
|
|
7026
|
-
// order to make the minimal changes to the context (since touching
|
|
7027
|
-
// that sometimes breaks series of multiple edits made for a single
|
|
7028
|
-
// user action on some Android keyboards)
|
|
7029
|
-
this.pendingContextChange = null;
|
|
7030
|
-
this.resetRange(view.state);
|
|
7031
|
-
let context = this.editContext = new window.EditContext({
|
|
7032
|
-
text: view.state.doc.sliceString(this.from, this.to),
|
|
7033
|
-
selectionStart: this.toContextPos(Math.max(this.from, Math.min(this.to, view.state.selection.main.anchor))),
|
|
7034
|
-
selectionEnd: this.toContextPos(view.state.selection.main.head)
|
|
7035
|
-
});
|
|
7036
|
-
context.addEventListener("textupdate", e => {
|
|
7037
|
-
let { anchor } = view.state.selection.main;
|
|
7038
|
-
let change = { from: this.toEditorPos(e.updateRangeStart),
|
|
7039
|
-
to: this.toEditorPos(e.updateRangeEnd),
|
|
7040
|
-
insert: Text.of(e.text.split("\n")) };
|
|
7041
|
-
// If the window doesn't include the anchor, assume changes
|
|
7042
|
-
// adjacent to a side go up to the anchor.
|
|
7043
|
-
if (change.from == this.from && anchor < this.from)
|
|
7044
|
-
change.from = anchor;
|
|
7045
|
-
else if (change.to == this.to && anchor > this.to)
|
|
7046
|
-
change.to = anchor;
|
|
7047
|
-
// Edit context sometimes fire empty changes
|
|
7048
|
-
if (change.from == change.to && !change.insert.length)
|
|
7049
|
-
return;
|
|
7050
|
-
this.pendingContextChange = change;
|
|
7051
|
-
applyDOMChangeInner(view, change, EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd)));
|
|
7052
|
-
// If the transaction didn't flush our change, revert it so
|
|
7053
|
-
// that the context is in sync with the editor state again.
|
|
7054
|
-
if (this.pendingContextChange)
|
|
7055
|
-
this.revertPending(view.state);
|
|
7056
|
-
});
|
|
7057
|
-
context.addEventListener("characterboundsupdate", e => {
|
|
7058
|
-
let rects = [], prev = null;
|
|
7059
|
-
for (let i = this.toEditorPos(e.rangeStart), end = this.toEditorPos(e.rangeEnd); i < end; i++) {
|
|
7060
|
-
let rect = view.coordsForChar(i);
|
|
7061
|
-
prev = (rect && new DOMRect(rect.left, rect.right, rect.right - rect.left, rect.bottom - rect.top))
|
|
7062
|
-
|| prev || new DOMRect;
|
|
7063
|
-
rects.push(prev);
|
|
7064
|
-
}
|
|
7065
|
-
context.updateCharacterBounds(e.rangeStart, rects);
|
|
7066
|
-
});
|
|
7067
|
-
context.addEventListener("textformatupdate", e => {
|
|
7068
|
-
let deco = [];
|
|
7069
|
-
for (let format of e.getTextFormats()) {
|
|
7070
|
-
let lineStyle = format.underlineStyle, thickness = format.underlineThickness;
|
|
7071
|
-
if (lineStyle != "None" && thickness != "None") {
|
|
7072
|
-
let style = `text-decoration: underline ${lineStyle == "Dashed" ? "dashed " : lineStyle == "Squiggle" ? "wavy " : ""}${thickness == "Thin" ? 1 : 2}px`;
|
|
7073
|
-
deco.push(Decoration.mark({ attributes: { style } })
|
|
7074
|
-
.range(this.toEditorPos(format.rangeStart), this.toEditorPos(format.rangeEnd)));
|
|
7075
|
-
}
|
|
7076
|
-
}
|
|
7077
|
-
view.dispatch({ effects: setEditContextFormatting.of(Decoration.set(deco)) });
|
|
7078
|
-
});
|
|
7079
|
-
context.addEventListener("compositionstart", () => {
|
|
7080
|
-
if (view.inputState.composing < 0) {
|
|
7081
|
-
view.inputState.composing = 0;
|
|
7082
|
-
view.inputState.compositionFirstChange = true;
|
|
7083
|
-
}
|
|
7084
|
-
});
|
|
7085
|
-
context.addEventListener("compositionend", () => {
|
|
7086
|
-
view.inputState.composing = -1;
|
|
7087
|
-
view.inputState.compositionFirstChange = null;
|
|
7088
|
-
});
|
|
7089
|
-
this.measureReq = { read: view => {
|
|
7090
|
-
this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
|
|
7091
|
-
let sel = getSelection(view.root);
|
|
7092
|
-
if (sel && sel.rangeCount)
|
|
7093
|
-
this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
|
|
7094
|
-
} };
|
|
7095
|
-
}
|
|
7096
|
-
applyEdits(update) {
|
|
7097
|
-
let off = 0, abort = false, pending = this.pendingContextChange;
|
|
7098
|
-
update.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
|
|
7099
|
-
if (abort)
|
|
7100
|
-
return;
|
|
7101
|
-
let dLen = insert.length - (toA - fromA);
|
|
7102
|
-
if (pending && toA >= pending.to) {
|
|
7103
|
-
if (pending.from == fromA && pending.to == toA && pending.insert.eq(insert)) {
|
|
7104
|
-
pending = this.pendingContextChange = null; // Match
|
|
7105
|
-
off += dLen;
|
|
7106
|
-
return;
|
|
7107
|
-
}
|
|
7108
|
-
else { // Mismatch, revert
|
|
7109
|
-
pending = null;
|
|
7110
|
-
this.revertPending(update.state);
|
|
7111
|
-
}
|
|
7112
|
-
}
|
|
7113
|
-
fromA += off;
|
|
7114
|
-
toA += off;
|
|
7115
|
-
if (toA <= this.from) { // Before the window
|
|
7116
|
-
this.from += dLen;
|
|
7117
|
-
this.to += dLen;
|
|
7118
|
-
}
|
|
7119
|
-
else if (fromA < this.to) { // Overlaps with window
|
|
7120
|
-
if (fromA < this.from || toA > this.to || (this.to - this.from) + insert.length > 30000 /* CxVp.MaxSize */) {
|
|
7121
|
-
abort = true;
|
|
7122
|
-
return;
|
|
7123
|
-
}
|
|
7124
|
-
this.editContext.updateText(this.toContextPos(fromA), this.toContextPos(toA), insert.toString());
|
|
7125
|
-
this.to += dLen;
|
|
7126
|
-
}
|
|
7127
|
-
off += dLen;
|
|
7128
|
-
});
|
|
7129
|
-
if (pending && !abort)
|
|
7130
|
-
this.revertPending(update.state);
|
|
7131
|
-
return !abort;
|
|
7132
|
-
}
|
|
7133
|
-
update(update) {
|
|
7134
|
-
if (!this.applyEdits(update) || !this.rangeIsValid(update.state)) {
|
|
7135
|
-
this.pendingContextChange = null;
|
|
7136
|
-
this.resetRange(update.state);
|
|
7137
|
-
this.editContext.updateText(0, this.editContext.text.length, update.state.doc.sliceString(this.from, this.to));
|
|
7138
|
-
this.setSelection(update.state);
|
|
7139
|
-
}
|
|
7140
|
-
else if (update.docChanged || update.selectionSet) {
|
|
7141
|
-
this.setSelection(update.state);
|
|
7142
|
-
}
|
|
7143
|
-
if (update.geometryChanged || update.docChanged || update.selectionSet)
|
|
7144
|
-
update.view.requestMeasure(this.measureReq);
|
|
7145
|
-
}
|
|
7146
|
-
resetRange(state) {
|
|
7147
|
-
let { head } = state.selection.main;
|
|
7148
|
-
this.from = Math.max(0, head - 10000 /* CxVp.Margin */);
|
|
7149
|
-
this.to = Math.min(state.doc.length, head + 10000 /* CxVp.Margin */);
|
|
7150
|
-
}
|
|
7151
|
-
revertPending(state) {
|
|
7152
|
-
let pending = this.pendingContextChange;
|
|
7153
|
-
this.pendingContextChange = null;
|
|
7154
|
-
this.editContext.updateText(this.toContextPos(pending.from), this.toContextPos(pending.to + pending.insert.length), state.doc.sliceString(pending.from, pending.to));
|
|
7155
|
-
}
|
|
7156
|
-
setSelection(state) {
|
|
7157
|
-
let { main } = state.selection;
|
|
7158
|
-
let start = this.toContextPos(Math.max(this.from, Math.min(this.to, main.anchor)));
|
|
7159
|
-
let end = this.toContextPos(main.head);
|
|
7160
|
-
if (this.editContext.selectionStart != start || this.editContext.selectionEnd != end)
|
|
7161
|
-
this.editContext.updateSelection(start, end);
|
|
7162
|
-
}
|
|
7163
|
-
rangeIsValid(state) {
|
|
7164
|
-
let { head } = state.selection.main;
|
|
7165
|
-
return !(this.from > 0 && head - this.from < 500 /* CxVp.MinMargin */ ||
|
|
7166
|
-
this.to < state.doc.length && this.to - head < 500 /* CxVp.MinMargin */ ||
|
|
7167
|
-
this.to - this.from > 10000 /* CxVp.Margin */ * 3);
|
|
7168
|
-
}
|
|
7169
|
-
toEditorPos(contextPos) { return contextPos + this.from; }
|
|
7170
|
-
toContextPos(editorPos) { return editorPos - this.from; }
|
|
7171
|
-
}
|
|
7172
7020
|
|
|
7173
7021
|
// The editor's update state machine looks something like this:
|
|
7174
7022
|
//
|
|
@@ -8599,11 +8447,17 @@ function getBase(view) {
|
|
|
8599
8447
|
let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8600
8448
|
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8601
8449
|
}
|
|
8602
|
-
function wrappedLine(view, pos, inside) {
|
|
8603
|
-
let
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8450
|
+
function wrappedLine(view, pos, side, inside) {
|
|
8451
|
+
let coords = view.coordsAtPos(pos, side * 2);
|
|
8452
|
+
if (!coords)
|
|
8453
|
+
return inside;
|
|
8454
|
+
let editorRect = view.dom.getBoundingClientRect();
|
|
8455
|
+
let y = (coords.top + coords.bottom) / 2;
|
|
8456
|
+
let left = view.posAtCoords({ x: editorRect.left + 1, y });
|
|
8457
|
+
let right = view.posAtCoords({ x: editorRect.right - 1, y });
|
|
8458
|
+
if (left == null || right == null)
|
|
8459
|
+
return inside;
|
|
8460
|
+
return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
|
|
8607
8461
|
}
|
|
8608
8462
|
function rectanglesForRange(view, className, range) {
|
|
8609
8463
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -8619,10 +8473,10 @@ function rectanglesForRange(view, className, range) {
|
|
|
8619
8473
|
let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
|
|
8620
8474
|
let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
|
|
8621
8475
|
if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
|
|
8622
|
-
visualStart = wrappedLine(view, from, visualStart);
|
|
8476
|
+
visualStart = wrappedLine(view, from, 1, visualStart);
|
|
8623
8477
|
if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
|
|
8624
|
-
visualEnd = wrappedLine(view, to, visualEnd);
|
|
8625
|
-
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
8478
|
+
visualEnd = wrappedLine(view, to, -1, visualEnd);
|
|
8479
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
|
|
8626
8480
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
8627
8481
|
}
|
|
8628
8482
|
else {
|
|
@@ -8877,14 +8731,19 @@ const selectionLayer = /*@__PURE__*/layer({
|
|
|
8877
8731
|
});
|
|
8878
8732
|
const themeSpec = {
|
|
8879
8733
|
".cm-line": {
|
|
8880
|
-
"& ::selection": { backgroundColor: "transparent !important" },
|
|
8881
|
-
|
|
8734
|
+
"& ::selection, &::selection": { backgroundColor: "transparent !important" },
|
|
8735
|
+
},
|
|
8736
|
+
".cm-content": {
|
|
8737
|
+
"& :focus": {
|
|
8738
|
+
caretColor: "initial !important",
|
|
8739
|
+
"&::selection, & ::selection": {
|
|
8740
|
+
backgroundColor: "Highlight !important"
|
|
8741
|
+
}
|
|
8742
|
+
}
|
|
8882
8743
|
}
|
|
8883
8744
|
};
|
|
8884
|
-
if (CanHidePrimary)
|
|
8885
|
-
themeSpec[".cm-line"].caretColor = "transparent !important";
|
|
8886
|
-
themeSpec[".cm-content"] = { caretColor: "transparent !important" };
|
|
8887
|
-
}
|
|
8745
|
+
if (CanHidePrimary)
|
|
8746
|
+
themeSpec[".cm-line"].caretColor = themeSpec[".cm-content"].caretColor = "transparent !important";
|
|
8888
8747
|
const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
|
|
8889
8748
|
|
|
8890
8749
|
const setDropCursorPos = /*@__PURE__*/StateEffect.define({
|