@codemirror/view 6.26.4-edit-context.1 → 6.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/index.cjs +141 -256
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +141 -256
- package/package.json +1 -1
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
|
|
@@ -3744,9 +3738,16 @@ class InputState {
|
|
|
3744
3738
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3745
3739
|
// avoid messing up the virtual keyboard state.
|
|
3746
3740
|
this.pendingIOSKey = undefined;
|
|
3741
|
+
/**
|
|
3742
|
+
When enabled (>-1), tab presses are not given to key handlers,
|
|
3743
|
+
leaving the browser's default behavior. If >0, the mode expires
|
|
3744
|
+
at that timestamp, and any other keypress clears it.
|
|
3745
|
+
Esc enables temporary tab focus mode for two seconds when not
|
|
3746
|
+
otherwise handled.
|
|
3747
|
+
*/
|
|
3748
|
+
this.tabFocusMode = -1;
|
|
3747
3749
|
this.lastSelectionOrigin = null;
|
|
3748
3750
|
this.lastSelectionTime = 0;
|
|
3749
|
-
this.lastEscPress = 0;
|
|
3750
3751
|
this.lastContextMenu = 0;
|
|
3751
3752
|
this.scrollHandlers = [];
|
|
3752
3753
|
this.handlers = Object.create(null);
|
|
@@ -3826,10 +3827,10 @@ class InputState {
|
|
|
3826
3827
|
// Must always run, even if a custom handler handled the event
|
|
3827
3828
|
this.lastKeyCode = event.keyCode;
|
|
3828
3829
|
this.lastKeyTime = Date.now();
|
|
3829
|
-
if (event.keyCode == 9 && Date.now()
|
|
3830
|
+
if (event.keyCode == 9 && this.tabFocusMode > -1 && (!this.tabFocusMode || Date.now() <= this.tabFocusMode))
|
|
3830
3831
|
return true;
|
|
3831
|
-
if (event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3832
|
-
this.
|
|
3832
|
+
if (this.tabFocusMode > 0 && event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3833
|
+
this.tabFocusMode = -1;
|
|
3833
3834
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3834
3835
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
3835
3836
|
// composition changes. When an enter or backspace key event is
|
|
@@ -3890,7 +3891,6 @@ class InputState {
|
|
|
3890
3891
|
this.mouseSelection = mouseSelection;
|
|
3891
3892
|
}
|
|
3892
3893
|
update(update) {
|
|
3893
|
-
this.view.observer.update(update);
|
|
3894
3894
|
if (this.mouseSelection)
|
|
3895
3895
|
this.mouseSelection.update(update);
|
|
3896
3896
|
if (this.draggedContent && update.docChanged)
|
|
@@ -4069,7 +4069,9 @@ class MouseSelection {
|
|
|
4069
4069
|
this.mustSelect = false;
|
|
4070
4070
|
}
|
|
4071
4071
|
update(update) {
|
|
4072
|
-
if (
|
|
4072
|
+
if (update.transactions.some(tr => tr.isUserEvent("input.type")))
|
|
4073
|
+
this.destroy();
|
|
4074
|
+
else if (this.style.update(update))
|
|
4073
4075
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
4074
4076
|
}
|
|
4075
4077
|
}
|
|
@@ -4166,8 +4168,8 @@ observers.scroll = view => {
|
|
|
4166
4168
|
};
|
|
4167
4169
|
handlers.keydown = (view, event) => {
|
|
4168
4170
|
view.inputState.setSelectionOrigin("select");
|
|
4169
|
-
if (event.keyCode == 27)
|
|
4170
|
-
view.inputState.
|
|
4171
|
+
if (event.keyCode == 27 && view.inputState.tabFocusMode != 0)
|
|
4172
|
+
view.inputState.tabFocusMode = Date.now() + 2000;
|
|
4171
4173
|
return false;
|
|
4172
4174
|
};
|
|
4173
4175
|
observers.touchstart = (view, e) => {
|
|
@@ -4193,7 +4195,12 @@ handlers.mousedown = (view, event) => {
|
|
|
4193
4195
|
let mustFocus = !view.hasFocus;
|
|
4194
4196
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4195
4197
|
if (mustFocus)
|
|
4196
|
-
view.observer.ignore(() =>
|
|
4198
|
+
view.observer.ignore(() => {
|
|
4199
|
+
focusPreventScroll(view.contentDOM);
|
|
4200
|
+
let active = view.root.activeElement;
|
|
4201
|
+
if (active && !active.contains(view.contentDOM))
|
|
4202
|
+
active.blur();
|
|
4203
|
+
});
|
|
4197
4204
|
let mouseSel = view.inputState.mouseSelection;
|
|
4198
4205
|
if (mouseSel) {
|
|
4199
4206
|
mouseSel.start(event);
|
|
@@ -4481,8 +4488,6 @@ observers.blur = view => {
|
|
|
4481
4488
|
updateForFocusChange(view);
|
|
4482
4489
|
};
|
|
4483
4490
|
observers.compositionstart = observers.compositionupdate = view => {
|
|
4484
|
-
if (view.observer.editContext)
|
|
4485
|
-
return; // Composition handled by edit context
|
|
4486
4491
|
if (view.inputState.compositionFirstChange == null)
|
|
4487
4492
|
view.inputState.compositionFirstChange = true;
|
|
4488
4493
|
if (view.inputState.composing < 0) {
|
|
@@ -4491,8 +4496,6 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
4491
4496
|
}
|
|
4492
4497
|
};
|
|
4493
4498
|
observers.compositionend = view => {
|
|
4494
|
-
if (view.observer.editContext)
|
|
4495
|
-
return; // Composition handled by edit context
|
|
4496
4499
|
view.inputState.composing = -1;
|
|
4497
4500
|
view.inputState.compositionEndedAt = Date.now();
|
|
4498
4501
|
view.inputState.compositionPendingKey = true;
|
|
@@ -5411,9 +5414,12 @@ class ViewState {
|
|
|
5411
5414
|
this.heightOracle = new HeightOracle(guessWrapping);
|
|
5412
5415
|
this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
|
|
5413
5416
|
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
|
5414
|
-
|
|
5417
|
+
for (let i = 0; i < 2; i++) {
|
|
5418
|
+
this.viewport = this.getViewport(0, null);
|
|
5419
|
+
if (!this.updateForViewport())
|
|
5420
|
+
break;
|
|
5421
|
+
}
|
|
5415
5422
|
this.updateViewportLines();
|
|
5416
|
-
this.updateForViewport();
|
|
5417
5423
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5418
5424
|
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5419
5425
|
this.computeVisibleRanges();
|
|
@@ -5428,13 +5434,18 @@ class ViewState {
|
|
|
5428
5434
|
}
|
|
5429
5435
|
}
|
|
5430
5436
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
5437
|
+
return this.updateScaler();
|
|
5438
|
+
}
|
|
5439
|
+
updateScaler() {
|
|
5440
|
+
let scaler = this.scaler;
|
|
5431
5441
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
5432
5442
|
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
5443
|
+
return scaler.eq(this.scaler) ? 0 : 2 /* UpdateFlag.Height */;
|
|
5433
5444
|
}
|
|
5434
5445
|
updateViewportLines() {
|
|
5435
5446
|
this.viewportLines = [];
|
|
5436
5447
|
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
5437
|
-
this.viewportLines.push(
|
|
5448
|
+
this.viewportLines.push(scaleBlock(block, this.scaler));
|
|
5438
5449
|
});
|
|
5439
5450
|
}
|
|
5440
5451
|
update(update, scrollTarget = null) {
|
|
@@ -5460,11 +5471,10 @@ class ViewState {
|
|
|
5460
5471
|
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
5461
5472
|
!this.viewportIsAppropriate(viewport))
|
|
5462
5473
|
viewport = this.getViewport(0, scrollTarget);
|
|
5463
|
-
let
|
|
5464
|
-
viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5474
|
+
let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5465
5475
|
this.viewport = viewport;
|
|
5466
|
-
this.updateForViewport();
|
|
5467
|
-
if (
|
|
5476
|
+
update.flags |= this.updateForViewport();
|
|
5477
|
+
if (viewportChange || !update.changes.empty || (update.flags & 2 /* UpdateFlag.Height */))
|
|
5468
5478
|
this.updateViewportLines();
|
|
5469
5479
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
5470
5480
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
@@ -5562,9 +5572,12 @@ class ViewState {
|
|
|
5562
5572
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
5563
5573
|
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5564
5574
|
this.scrollTarget.range.head > this.viewport.to);
|
|
5565
|
-
if (viewportChange)
|
|
5575
|
+
if (viewportChange) {
|
|
5576
|
+
if (result & 2 /* UpdateFlag.Height */)
|
|
5577
|
+
result |= this.updateScaler();
|
|
5566
5578
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
5567
|
-
|
|
5579
|
+
result |= this.updateForViewport();
|
|
5580
|
+
}
|
|
5568
5581
|
if ((result & 2 /* UpdateFlag.Height */) || viewportChange)
|
|
5569
5582
|
this.updateViewportLines();
|
|
5570
5583
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
@@ -5753,11 +5766,14 @@ class ViewState {
|
|
|
5753
5766
|
return changed ? 4 /* UpdateFlag.Viewport */ : 0;
|
|
5754
5767
|
}
|
|
5755
5768
|
lineBlockAt(pos) {
|
|
5756
|
-
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5769
|
+
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5770
|
+
this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5757
5771
|
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5758
5772
|
}
|
|
5759
5773
|
lineBlockAtHeight(height) {
|
|
5760
|
-
return
|
|
5774
|
+
return (height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom &&
|
|
5775
|
+
this.viewportLines.find(l => l.top <= height && l.bottom >= height)) ||
|
|
5776
|
+
scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5761
5777
|
}
|
|
5762
5778
|
scrollAnchorAt(scrollTop) {
|
|
5763
5779
|
let block = this.lineBlockAtHeight(scrollTop + 8);
|
|
@@ -5832,7 +5848,8 @@ function find(array, f) {
|
|
|
5832
5848
|
const IdScaler = {
|
|
5833
5849
|
toDOM(n) { return n; },
|
|
5834
5850
|
fromDOM(n) { return n; },
|
|
5835
|
-
scale: 1
|
|
5851
|
+
scale: 1,
|
|
5852
|
+
eq(other) { return other == this; }
|
|
5836
5853
|
};
|
|
5837
5854
|
// When the height is too big (> VP.MaxDOMHeight), scale down the
|
|
5838
5855
|
// regions outside the viewports so that the total height is
|
|
@@ -5875,6 +5892,12 @@ class BigScaler {
|
|
|
5875
5892
|
domBase = vp.domBottom;
|
|
5876
5893
|
}
|
|
5877
5894
|
}
|
|
5895
|
+
eq(other) {
|
|
5896
|
+
if (!(other instanceof BigScaler))
|
|
5897
|
+
return false;
|
|
5898
|
+
return this.scale == other.scale && this.viewports.length == other.viewports.length &&
|
|
5899
|
+
this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
|
|
5900
|
+
}
|
|
5878
5901
|
}
|
|
5879
5902
|
function scaleBlock(block, scaler) {
|
|
5880
5903
|
if (scaler.scale == 1)
|
|
@@ -6266,6 +6289,7 @@ class DOMChange {
|
|
|
6266
6289
|
this.typeOver = typeOver;
|
|
6267
6290
|
this.bounds = null;
|
|
6268
6291
|
this.text = "";
|
|
6292
|
+
this.domChanged = start > -1;
|
|
6269
6293
|
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
6270
6294
|
if (view.state.readOnly && start > -1) {
|
|
6271
6295
|
// Ignore changes when the editor is read-only
|
|
@@ -6368,7 +6392,35 @@ function applyDOMChange(view, domChange) {
|
|
|
6368
6392
|
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
6369
6393
|
}
|
|
6370
6394
|
if (change) {
|
|
6371
|
-
|
|
6395
|
+
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6396
|
+
return true;
|
|
6397
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
6398
|
+
// backspace, or delete. So this detects changes that look like
|
|
6399
|
+
// they're caused by those keys, and reinterprets them as key
|
|
6400
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
6401
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
6402
|
+
// reliable in all situations.)
|
|
6403
|
+
if (browser.android &&
|
|
6404
|
+
((change.to == sel.to &&
|
|
6405
|
+
// GBoard will sometimes remove a space it just inserted
|
|
6406
|
+
// after a completion when you press enter
|
|
6407
|
+
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6408
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6409
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6410
|
+
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6411
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6412
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6413
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6414
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6415
|
+
return true;
|
|
6416
|
+
let text = change.insert.toString();
|
|
6417
|
+
if (view.inputState.composing >= 0)
|
|
6418
|
+
view.inputState.composing++;
|
|
6419
|
+
let defaultTr;
|
|
6420
|
+
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6421
|
+
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6422
|
+
view.dispatch(defaultInsert());
|
|
6423
|
+
return true;
|
|
6372
6424
|
}
|
|
6373
6425
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
6374
6426
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -6384,38 +6436,6 @@ function applyDOMChange(view, domChange) {
|
|
|
6384
6436
|
return false;
|
|
6385
6437
|
}
|
|
6386
6438
|
}
|
|
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
6439
|
function applyDefaultInsert(view, change, newSel) {
|
|
6420
6440
|
let tr, startState = view.state, sel = startState.selection.main;
|
|
6421
6441
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
@@ -6542,7 +6562,6 @@ class DOMObserver {
|
|
|
6542
6562
|
constructor(view) {
|
|
6543
6563
|
this.view = view;
|
|
6544
6564
|
this.active = false;
|
|
6545
|
-
this.editContext = null;
|
|
6546
6565
|
// The known selection. Kept in our own object, as opposed to just
|
|
6547
6566
|
// directly accessing the selection because:
|
|
6548
6567
|
// - Safari doesn't report the right selection in shadow DOM
|
|
@@ -6587,10 +6606,6 @@ class DOMObserver {
|
|
|
6587
6606
|
else
|
|
6588
6607
|
this.flush();
|
|
6589
6608
|
});
|
|
6590
|
-
if (window.EditContext && view.constructor.EDIT_CONTEXT !== false) {
|
|
6591
|
-
this.editContext = new EditContextManager(view);
|
|
6592
|
-
view.contentDOM.editContext = this.editContext.editContext;
|
|
6593
|
-
}
|
|
6594
6609
|
if (useCharData)
|
|
6595
6610
|
this.onCharData = (event) => {
|
|
6596
6611
|
this.queue.push({ target: event.target,
|
|
@@ -6641,8 +6656,6 @@ class DOMObserver {
|
|
|
6641
6656
|
onScroll(e) {
|
|
6642
6657
|
if (this.intersecting)
|
|
6643
6658
|
this.flush(false);
|
|
6644
|
-
if (this.editContext)
|
|
6645
|
-
this.view.requestMeasure(this.editContext.measureReq);
|
|
6646
6659
|
this.onScrollChanged(e);
|
|
6647
6660
|
}
|
|
6648
6661
|
onResize() {
|
|
@@ -6901,8 +6914,9 @@ class DOMObserver {
|
|
|
6901
6914
|
}
|
|
6902
6915
|
let startState = this.view.state;
|
|
6903
6916
|
let handled = applyDOMChange(this.view, domChange);
|
|
6904
|
-
// The view wasn't updated
|
|
6905
|
-
if (this.view.state == startState
|
|
6917
|
+
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
6918
|
+
if (this.view.state == startState &&
|
|
6919
|
+
(domChange.domChanged || domChange.newSel && !domChange.newSel.main.eq(this.view.state.selection.main)))
|
|
6906
6920
|
this.view.update([]);
|
|
6907
6921
|
return handled;
|
|
6908
6922
|
}
|
|
@@ -6951,10 +6965,6 @@ class DOMObserver {
|
|
|
6951
6965
|
win.removeEventListener("beforeprint", this.onPrint);
|
|
6952
6966
|
win.document.removeEventListener("selectionchange", this.onSelectionChange);
|
|
6953
6967
|
}
|
|
6954
|
-
update(update) {
|
|
6955
|
-
if (this.editContext)
|
|
6956
|
-
this.editContext.update(update);
|
|
6957
|
-
}
|
|
6958
6968
|
destroy() {
|
|
6959
6969
|
var _a, _b, _c;
|
|
6960
6970
|
this.stop();
|
|
@@ -7014,161 +7024,6 @@ function safariSelectionRangeHack(view, selection) {
|
|
|
7014
7024
|
view.contentDOM.removeEventListener("beforeinput", read, true);
|
|
7015
7025
|
return found ? buildSelectionRangeFromRange(view, found) : null;
|
|
7016
7026
|
}
|
|
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
7027
|
|
|
7173
7028
|
// The editor's update state machine looks something like this:
|
|
7174
7029
|
//
|
|
@@ -8028,6 +7883,25 @@ class EditorView {
|
|
|
8028
7883
|
return scrollIntoView.of(new ScrollTarget(EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
|
|
8029
7884
|
}
|
|
8030
7885
|
/**
|
|
7886
|
+
Enable or disable tab-focus mode, which disables key bindings
|
|
7887
|
+
for Tab and Shift-Tab, letting the browser's default
|
|
7888
|
+
focus-changing behavior go through instead. This is useful to
|
|
7889
|
+
prevent trapping keyboard users in your editor.
|
|
7890
|
+
|
|
7891
|
+
Without argument, this toggles the mode. With a boolean, it
|
|
7892
|
+
enables (true) or disables it (false). Given a number, it
|
|
7893
|
+
temporarily enables the mode until that number of milliseconds
|
|
7894
|
+
have passed or another non-Tab key is pressed.
|
|
7895
|
+
*/
|
|
7896
|
+
setTabFocusMode(to) {
|
|
7897
|
+
if (to == null)
|
|
7898
|
+
this.inputState.tabFocusMode = this.inputState.tabFocusMode < 0 ? 0 : -1;
|
|
7899
|
+
else if (typeof to == "boolean")
|
|
7900
|
+
this.inputState.tabFocusMode = to ? 0 : -1;
|
|
7901
|
+
else if (this.inputState.tabFocusMode != 0)
|
|
7902
|
+
this.inputState.tabFocusMode = Date.now() + to;
|
|
7903
|
+
}
|
|
7904
|
+
/**
|
|
8031
7905
|
Returns an extension that can be used to add DOM event handlers.
|
|
8032
7906
|
The value should be an object mapping event names to handler
|
|
8033
7907
|
functions. For any given event, such functions are ordered by
|
|
@@ -8599,11 +8473,17 @@ function getBase(view) {
|
|
|
8599
8473
|
let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8600
8474
|
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8601
8475
|
}
|
|
8602
|
-
function wrappedLine(view, pos, inside) {
|
|
8603
|
-
let
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8476
|
+
function wrappedLine(view, pos, side, inside) {
|
|
8477
|
+
let coords = view.coordsAtPos(pos, side * 2);
|
|
8478
|
+
if (!coords)
|
|
8479
|
+
return inside;
|
|
8480
|
+
let editorRect = view.dom.getBoundingClientRect();
|
|
8481
|
+
let y = (coords.top + coords.bottom) / 2;
|
|
8482
|
+
let left = view.posAtCoords({ x: editorRect.left + 1, y });
|
|
8483
|
+
let right = view.posAtCoords({ x: editorRect.right - 1, y });
|
|
8484
|
+
if (left == null || right == null)
|
|
8485
|
+
return inside;
|
|
8486
|
+
return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
|
|
8607
8487
|
}
|
|
8608
8488
|
function rectanglesForRange(view, className, range) {
|
|
8609
8489
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -8619,10 +8499,10 @@ function rectanglesForRange(view, className, range) {
|
|
|
8619
8499
|
let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
|
|
8620
8500
|
let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
|
|
8621
8501
|
if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
|
|
8622
|
-
visualStart = wrappedLine(view, from, visualStart);
|
|
8502
|
+
visualStart = wrappedLine(view, from, 1, visualStart);
|
|
8623
8503
|
if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
|
|
8624
|
-
visualEnd = wrappedLine(view, to, visualEnd);
|
|
8625
|
-
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
8504
|
+
visualEnd = wrappedLine(view, to, -1, visualEnd);
|
|
8505
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
|
|
8626
8506
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
8627
8507
|
}
|
|
8628
8508
|
else {
|
|
@@ -8877,14 +8757,19 @@ const selectionLayer = /*@__PURE__*/layer({
|
|
|
8877
8757
|
});
|
|
8878
8758
|
const themeSpec = {
|
|
8879
8759
|
".cm-line": {
|
|
8880
|
-
"& ::selection": { backgroundColor: "transparent !important" },
|
|
8881
|
-
|
|
8760
|
+
"& ::selection, &::selection": { backgroundColor: "transparent !important" },
|
|
8761
|
+
},
|
|
8762
|
+
".cm-content": {
|
|
8763
|
+
"& :focus": {
|
|
8764
|
+
caretColor: "initial !important",
|
|
8765
|
+
"&::selection, & ::selection": {
|
|
8766
|
+
backgroundColor: "Highlight !important"
|
|
8767
|
+
}
|
|
8768
|
+
}
|
|
8882
8769
|
}
|
|
8883
8770
|
};
|
|
8884
|
-
if (CanHidePrimary)
|
|
8885
|
-
themeSpec[".cm-line"].caretColor = "transparent !important";
|
|
8886
|
-
themeSpec[".cm-content"] = { caretColor: "transparent !important" };
|
|
8887
|
-
}
|
|
8771
|
+
if (CanHidePrimary)
|
|
8772
|
+
themeSpec[".cm-line"].caretColor = themeSpec[".cm-content"].caretColor = "transparent !important";
|
|
8888
8773
|
const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
|
|
8889
8774
|
|
|
8890
8775
|
const setDropCursorPos = /*@__PURE__*/StateEffect.define({
|