@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.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
|
|
@@ -3748,9 +3742,16 @@ class InputState {
|
|
|
3748
3742
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3749
3743
|
// avoid messing up the virtual keyboard state.
|
|
3750
3744
|
this.pendingIOSKey = undefined;
|
|
3745
|
+
/**
|
|
3746
|
+
When enabled (>-1), tab presses are not given to key handlers,
|
|
3747
|
+
leaving the browser's default behavior. If >0, the mode expires
|
|
3748
|
+
at that timestamp, and any other keypress clears it.
|
|
3749
|
+
Esc enables temporary tab focus mode for two seconds when not
|
|
3750
|
+
otherwise handled.
|
|
3751
|
+
*/
|
|
3752
|
+
this.tabFocusMode = -1;
|
|
3751
3753
|
this.lastSelectionOrigin = null;
|
|
3752
3754
|
this.lastSelectionTime = 0;
|
|
3753
|
-
this.lastEscPress = 0;
|
|
3754
3755
|
this.lastContextMenu = 0;
|
|
3755
3756
|
this.scrollHandlers = [];
|
|
3756
3757
|
this.handlers = Object.create(null);
|
|
@@ -3830,10 +3831,10 @@ class InputState {
|
|
|
3830
3831
|
// Must always run, even if a custom handler handled the event
|
|
3831
3832
|
this.lastKeyCode = event.keyCode;
|
|
3832
3833
|
this.lastKeyTime = Date.now();
|
|
3833
|
-
if (event.keyCode == 9 && Date.now()
|
|
3834
|
+
if (event.keyCode == 9 && this.tabFocusMode > -1 && (!this.tabFocusMode || Date.now() <= this.tabFocusMode))
|
|
3834
3835
|
return true;
|
|
3835
|
-
if (event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3836
|
-
this.
|
|
3836
|
+
if (this.tabFocusMode > 0 && event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3837
|
+
this.tabFocusMode = -1;
|
|
3837
3838
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3838
3839
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
3839
3840
|
// composition changes. When an enter or backspace key event is
|
|
@@ -3894,7 +3895,6 @@ class InputState {
|
|
|
3894
3895
|
this.mouseSelection = mouseSelection;
|
|
3895
3896
|
}
|
|
3896
3897
|
update(update) {
|
|
3897
|
-
this.view.observer.update(update);
|
|
3898
3898
|
if (this.mouseSelection)
|
|
3899
3899
|
this.mouseSelection.update(update);
|
|
3900
3900
|
if (this.draggedContent && update.docChanged)
|
|
@@ -4073,7 +4073,9 @@ class MouseSelection {
|
|
|
4073
4073
|
this.mustSelect = false;
|
|
4074
4074
|
}
|
|
4075
4075
|
update(update) {
|
|
4076
|
-
if (
|
|
4076
|
+
if (update.transactions.some(tr => tr.isUserEvent("input.type")))
|
|
4077
|
+
this.destroy();
|
|
4078
|
+
else if (this.style.update(update))
|
|
4077
4079
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
4078
4080
|
}
|
|
4079
4081
|
}
|
|
@@ -4170,8 +4172,8 @@ observers.scroll = view => {
|
|
|
4170
4172
|
};
|
|
4171
4173
|
handlers.keydown = (view, event) => {
|
|
4172
4174
|
view.inputState.setSelectionOrigin("select");
|
|
4173
|
-
if (event.keyCode == 27)
|
|
4174
|
-
view.inputState.
|
|
4175
|
+
if (event.keyCode == 27 && view.inputState.tabFocusMode != 0)
|
|
4176
|
+
view.inputState.tabFocusMode = Date.now() + 2000;
|
|
4175
4177
|
return false;
|
|
4176
4178
|
};
|
|
4177
4179
|
observers.touchstart = (view, e) => {
|
|
@@ -4197,7 +4199,12 @@ handlers.mousedown = (view, event) => {
|
|
|
4197
4199
|
let mustFocus = !view.hasFocus;
|
|
4198
4200
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4199
4201
|
if (mustFocus)
|
|
4200
|
-
view.observer.ignore(() =>
|
|
4202
|
+
view.observer.ignore(() => {
|
|
4203
|
+
focusPreventScroll(view.contentDOM);
|
|
4204
|
+
let active = view.root.activeElement;
|
|
4205
|
+
if (active && !active.contains(view.contentDOM))
|
|
4206
|
+
active.blur();
|
|
4207
|
+
});
|
|
4201
4208
|
let mouseSel = view.inputState.mouseSelection;
|
|
4202
4209
|
if (mouseSel) {
|
|
4203
4210
|
mouseSel.start(event);
|
|
@@ -4485,8 +4492,6 @@ observers.blur = view => {
|
|
|
4485
4492
|
updateForFocusChange(view);
|
|
4486
4493
|
};
|
|
4487
4494
|
observers.compositionstart = observers.compositionupdate = view => {
|
|
4488
|
-
if (view.observer.editContext)
|
|
4489
|
-
return; // Composition handled by edit context
|
|
4490
4495
|
if (view.inputState.compositionFirstChange == null)
|
|
4491
4496
|
view.inputState.compositionFirstChange = true;
|
|
4492
4497
|
if (view.inputState.composing < 0) {
|
|
@@ -4495,8 +4500,6 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
4495
4500
|
}
|
|
4496
4501
|
};
|
|
4497
4502
|
observers.compositionend = view => {
|
|
4498
|
-
if (view.observer.editContext)
|
|
4499
|
-
return; // Composition handled by edit context
|
|
4500
4503
|
view.inputState.composing = -1;
|
|
4501
4504
|
view.inputState.compositionEndedAt = Date.now();
|
|
4502
4505
|
view.inputState.compositionPendingKey = true;
|
|
@@ -5416,9 +5419,12 @@ class ViewState {
|
|
|
5416
5419
|
this.heightOracle = new HeightOracle(guessWrapping);
|
|
5417
5420
|
this.stateDeco = state$1.facet(decorations).filter(d => typeof d != "function");
|
|
5418
5421
|
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
|
-
|
|
5422
|
+
for (let i = 0; i < 2; i++) {
|
|
5423
|
+
this.viewport = this.getViewport(0, null);
|
|
5424
|
+
if (!this.updateForViewport())
|
|
5425
|
+
break;
|
|
5426
|
+
}
|
|
5420
5427
|
this.updateViewportLines();
|
|
5421
|
-
this.updateForViewport();
|
|
5422
5428
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5423
5429
|
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5424
5430
|
this.computeVisibleRanges();
|
|
@@ -5433,13 +5439,18 @@ class ViewState {
|
|
|
5433
5439
|
}
|
|
5434
5440
|
}
|
|
5435
5441
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
5442
|
+
return this.updateScaler();
|
|
5443
|
+
}
|
|
5444
|
+
updateScaler() {
|
|
5445
|
+
let scaler = this.scaler;
|
|
5436
5446
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
5437
5447
|
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
5448
|
+
return scaler.eq(this.scaler) ? 0 : 2 /* UpdateFlag.Height */;
|
|
5438
5449
|
}
|
|
5439
5450
|
updateViewportLines() {
|
|
5440
5451
|
this.viewportLines = [];
|
|
5441
5452
|
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
5442
|
-
this.viewportLines.push(
|
|
5453
|
+
this.viewportLines.push(scaleBlock(block, this.scaler));
|
|
5443
5454
|
});
|
|
5444
5455
|
}
|
|
5445
5456
|
update(update, scrollTarget = null) {
|
|
@@ -5465,11 +5476,10 @@ class ViewState {
|
|
|
5465
5476
|
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
5466
5477
|
!this.viewportIsAppropriate(viewport))
|
|
5467
5478
|
viewport = this.getViewport(0, scrollTarget);
|
|
5468
|
-
let
|
|
5469
|
-
viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5479
|
+
let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
|
5470
5480
|
this.viewport = viewport;
|
|
5471
|
-
this.updateForViewport();
|
|
5472
|
-
if (
|
|
5481
|
+
update.flags |= this.updateForViewport();
|
|
5482
|
+
if (viewportChange || !update.changes.empty || (update.flags & 2 /* UpdateFlag.Height */))
|
|
5473
5483
|
this.updateViewportLines();
|
|
5474
5484
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
5475
5485
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
@@ -5567,9 +5577,12 @@ class ViewState {
|
|
|
5567
5577
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
5568
5578
|
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5569
5579
|
this.scrollTarget.range.head > this.viewport.to);
|
|
5570
|
-
if (viewportChange)
|
|
5580
|
+
if (viewportChange) {
|
|
5581
|
+
if (result & 2 /* UpdateFlag.Height */)
|
|
5582
|
+
result |= this.updateScaler();
|
|
5571
5583
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
5572
|
-
|
|
5584
|
+
result |= this.updateForViewport();
|
|
5585
|
+
}
|
|
5573
5586
|
if ((result & 2 /* UpdateFlag.Height */) || viewportChange)
|
|
5574
5587
|
this.updateViewportLines();
|
|
5575
5588
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
|
|
@@ -5758,11 +5771,14 @@ class ViewState {
|
|
|
5758
5771
|
return changed ? 4 /* UpdateFlag.Viewport */ : 0;
|
|
5759
5772
|
}
|
|
5760
5773
|
lineBlockAt(pos) {
|
|
5761
|
-
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5774
|
+
return (pos >= this.viewport.from && pos <= this.viewport.to &&
|
|
5775
|
+
this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5762
5776
|
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5763
5777
|
}
|
|
5764
5778
|
lineBlockAtHeight(height) {
|
|
5765
|
-
return
|
|
5779
|
+
return (height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom &&
|
|
5780
|
+
this.viewportLines.find(l => l.top <= height && l.bottom >= height)) ||
|
|
5781
|
+
scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5766
5782
|
}
|
|
5767
5783
|
scrollAnchorAt(scrollTop) {
|
|
5768
5784
|
let block = this.lineBlockAtHeight(scrollTop + 8);
|
|
@@ -5837,7 +5853,8 @@ function find(array, f) {
|
|
|
5837
5853
|
const IdScaler = {
|
|
5838
5854
|
toDOM(n) { return n; },
|
|
5839
5855
|
fromDOM(n) { return n; },
|
|
5840
|
-
scale: 1
|
|
5856
|
+
scale: 1,
|
|
5857
|
+
eq(other) { return other == this; }
|
|
5841
5858
|
};
|
|
5842
5859
|
// When the height is too big (> VP.MaxDOMHeight), scale down the
|
|
5843
5860
|
// regions outside the viewports so that the total height is
|
|
@@ -5880,6 +5897,12 @@ class BigScaler {
|
|
|
5880
5897
|
domBase = vp.domBottom;
|
|
5881
5898
|
}
|
|
5882
5899
|
}
|
|
5900
|
+
eq(other) {
|
|
5901
|
+
if (!(other instanceof BigScaler))
|
|
5902
|
+
return false;
|
|
5903
|
+
return this.scale == other.scale && this.viewports.length == other.viewports.length &&
|
|
5904
|
+
this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
|
|
5905
|
+
}
|
|
5883
5906
|
}
|
|
5884
5907
|
function scaleBlock(block, scaler) {
|
|
5885
5908
|
if (scaler.scale == 1)
|
|
@@ -6271,6 +6294,7 @@ class DOMChange {
|
|
|
6271
6294
|
this.typeOver = typeOver;
|
|
6272
6295
|
this.bounds = null;
|
|
6273
6296
|
this.text = "";
|
|
6297
|
+
this.domChanged = start > -1;
|
|
6274
6298
|
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
6275
6299
|
if (view.state.readOnly && start > -1) {
|
|
6276
6300
|
// Ignore changes when the editor is read-only
|
|
@@ -6373,7 +6397,35 @@ function applyDOMChange(view, domChange) {
|
|
|
6373
6397
|
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
6374
6398
|
}
|
|
6375
6399
|
if (change) {
|
|
6376
|
-
|
|
6400
|
+
if (browser.ios && view.inputState.flushIOSKey(change))
|
|
6401
|
+
return true;
|
|
6402
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
6403
|
+
// backspace, or delete. So this detects changes that look like
|
|
6404
|
+
// they're caused by those keys, and reinterprets them as key
|
|
6405
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
6406
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
6407
|
+
// reliable in all situations.)
|
|
6408
|
+
if (browser.android &&
|
|
6409
|
+
((change.to == sel.to &&
|
|
6410
|
+
// GBoard will sometimes remove a space it just inserted
|
|
6411
|
+
// after a completion when you press enter
|
|
6412
|
+
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") &&
|
|
6413
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6414
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6415
|
+
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6416
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6417
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6418
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6419
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
6420
|
+
return true;
|
|
6421
|
+
let text = change.insert.toString();
|
|
6422
|
+
if (view.inputState.composing >= 0)
|
|
6423
|
+
view.inputState.composing++;
|
|
6424
|
+
let defaultTr;
|
|
6425
|
+
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
|
|
6426
|
+
if (!view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text, defaultInsert)))
|
|
6427
|
+
view.dispatch(defaultInsert());
|
|
6428
|
+
return true;
|
|
6377
6429
|
}
|
|
6378
6430
|
else if (newSel && !newSel.main.eq(sel)) {
|
|
6379
6431
|
let scrollIntoView = false, userEvent = "select";
|
|
@@ -6389,38 +6441,6 @@ function applyDOMChange(view, domChange) {
|
|
|
6389
6441
|
return false;
|
|
6390
6442
|
}
|
|
6391
6443
|
}
|
|
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
6444
|
function applyDefaultInsert(view, change, newSel) {
|
|
6425
6445
|
let tr, startState = view.state, sel = startState.selection.main;
|
|
6426
6446
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
@@ -6547,7 +6567,6 @@ class DOMObserver {
|
|
|
6547
6567
|
constructor(view) {
|
|
6548
6568
|
this.view = view;
|
|
6549
6569
|
this.active = false;
|
|
6550
|
-
this.editContext = null;
|
|
6551
6570
|
// The known selection. Kept in our own object, as opposed to just
|
|
6552
6571
|
// directly accessing the selection because:
|
|
6553
6572
|
// - Safari doesn't report the right selection in shadow DOM
|
|
@@ -6592,10 +6611,6 @@ class DOMObserver {
|
|
|
6592
6611
|
else
|
|
6593
6612
|
this.flush();
|
|
6594
6613
|
});
|
|
6595
|
-
if (window.EditContext && view.constructor.EDIT_CONTEXT !== false) {
|
|
6596
|
-
this.editContext = new EditContextManager(view);
|
|
6597
|
-
view.contentDOM.editContext = this.editContext.editContext;
|
|
6598
|
-
}
|
|
6599
6614
|
if (useCharData)
|
|
6600
6615
|
this.onCharData = (event) => {
|
|
6601
6616
|
this.queue.push({ target: event.target,
|
|
@@ -6646,8 +6661,6 @@ class DOMObserver {
|
|
|
6646
6661
|
onScroll(e) {
|
|
6647
6662
|
if (this.intersecting)
|
|
6648
6663
|
this.flush(false);
|
|
6649
|
-
if (this.editContext)
|
|
6650
|
-
this.view.requestMeasure(this.editContext.measureReq);
|
|
6651
6664
|
this.onScrollChanged(e);
|
|
6652
6665
|
}
|
|
6653
6666
|
onResize() {
|
|
@@ -6906,8 +6919,9 @@ class DOMObserver {
|
|
|
6906
6919
|
}
|
|
6907
6920
|
let startState = this.view.state;
|
|
6908
6921
|
let handled = applyDOMChange(this.view, domChange);
|
|
6909
|
-
// The view wasn't updated
|
|
6910
|
-
if (this.view.state == startState
|
|
6922
|
+
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
6923
|
+
if (this.view.state == startState &&
|
|
6924
|
+
(domChange.domChanged || domChange.newSel && !domChange.newSel.main.eq(this.view.state.selection.main)))
|
|
6911
6925
|
this.view.update([]);
|
|
6912
6926
|
return handled;
|
|
6913
6927
|
}
|
|
@@ -6956,10 +6970,6 @@ class DOMObserver {
|
|
|
6956
6970
|
win.removeEventListener("beforeprint", this.onPrint);
|
|
6957
6971
|
win.document.removeEventListener("selectionchange", this.onSelectionChange);
|
|
6958
6972
|
}
|
|
6959
|
-
update(update) {
|
|
6960
|
-
if (this.editContext)
|
|
6961
|
-
this.editContext.update(update);
|
|
6962
|
-
}
|
|
6963
6973
|
destroy() {
|
|
6964
6974
|
var _a, _b, _c;
|
|
6965
6975
|
this.stop();
|
|
@@ -7019,161 +7029,6 @@ function safariSelectionRangeHack(view, selection) {
|
|
|
7019
7029
|
view.contentDOM.removeEventListener("beforeinput", read, true);
|
|
7020
7030
|
return found ? buildSelectionRangeFromRange(view, found) : null;
|
|
7021
7031
|
}
|
|
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
7032
|
|
|
7178
7033
|
// The editor's update state machine looks something like this:
|
|
7179
7034
|
//
|
|
@@ -8033,6 +7888,25 @@ class EditorView {
|
|
|
8033
7888
|
return scrollIntoView.of(new ScrollTarget(state.EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
|
|
8034
7889
|
}
|
|
8035
7890
|
/**
|
|
7891
|
+
Enable or disable tab-focus mode, which disables key bindings
|
|
7892
|
+
for Tab and Shift-Tab, letting the browser's default
|
|
7893
|
+
focus-changing behavior go through instead. This is useful to
|
|
7894
|
+
prevent trapping keyboard users in your editor.
|
|
7895
|
+
|
|
7896
|
+
Without argument, this toggles the mode. With a boolean, it
|
|
7897
|
+
enables (true) or disables it (false). Given a number, it
|
|
7898
|
+
temporarily enables the mode until that number of milliseconds
|
|
7899
|
+
have passed or another non-Tab key is pressed.
|
|
7900
|
+
*/
|
|
7901
|
+
setTabFocusMode(to) {
|
|
7902
|
+
if (to == null)
|
|
7903
|
+
this.inputState.tabFocusMode = this.inputState.tabFocusMode < 0 ? 0 : -1;
|
|
7904
|
+
else if (typeof to == "boolean")
|
|
7905
|
+
this.inputState.tabFocusMode = to ? 0 : -1;
|
|
7906
|
+
else if (this.inputState.tabFocusMode != 0)
|
|
7907
|
+
this.inputState.tabFocusMode = Date.now() + to;
|
|
7908
|
+
}
|
|
7909
|
+
/**
|
|
8036
7910
|
Returns an extension that can be used to add DOM event handlers.
|
|
8037
7911
|
The value should be an object mapping event names to handler
|
|
8038
7912
|
functions. For any given event, such functions are ordered by
|
|
@@ -8604,11 +8478,17 @@ function getBase(view) {
|
|
|
8604
8478
|
let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8605
8479
|
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8606
8480
|
}
|
|
8607
|
-
function wrappedLine(view, pos, inside) {
|
|
8608
|
-
let
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8481
|
+
function wrappedLine(view, pos, side, inside) {
|
|
8482
|
+
let coords = view.coordsAtPos(pos, side * 2);
|
|
8483
|
+
if (!coords)
|
|
8484
|
+
return inside;
|
|
8485
|
+
let editorRect = view.dom.getBoundingClientRect();
|
|
8486
|
+
let y = (coords.top + coords.bottom) / 2;
|
|
8487
|
+
let left = view.posAtCoords({ x: editorRect.left + 1, y });
|
|
8488
|
+
let right = view.posAtCoords({ x: editorRect.right - 1, y });
|
|
8489
|
+
if (left == null || right == null)
|
|
8490
|
+
return inside;
|
|
8491
|
+
return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
|
|
8612
8492
|
}
|
|
8613
8493
|
function rectanglesForRange(view, className, range) {
|
|
8614
8494
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -8624,10 +8504,10 @@ function rectanglesForRange(view, className, range) {
|
|
|
8624
8504
|
let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null;
|
|
8625
8505
|
let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null;
|
|
8626
8506
|
if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
|
|
8627
|
-
visualStart = wrappedLine(view, from, visualStart);
|
|
8507
|
+
visualStart = wrappedLine(view, from, 1, visualStart);
|
|
8628
8508
|
if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
|
|
8629
|
-
visualEnd = wrappedLine(view, to, visualEnd);
|
|
8630
|
-
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
8509
|
+
visualEnd = wrappedLine(view, to, -1, visualEnd);
|
|
8510
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
|
|
8631
8511
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
8632
8512
|
}
|
|
8633
8513
|
else {
|
|
@@ -8882,14 +8762,19 @@ const selectionLayer = layer({
|
|
|
8882
8762
|
});
|
|
8883
8763
|
const themeSpec = {
|
|
8884
8764
|
".cm-line": {
|
|
8885
|
-
"& ::selection": { backgroundColor: "transparent !important" },
|
|
8886
|
-
|
|
8765
|
+
"& ::selection, &::selection": { backgroundColor: "transparent !important" },
|
|
8766
|
+
},
|
|
8767
|
+
".cm-content": {
|
|
8768
|
+
"& :focus": {
|
|
8769
|
+
caretColor: "initial !important",
|
|
8770
|
+
"&::selection, & ::selection": {
|
|
8771
|
+
backgroundColor: "Highlight !important"
|
|
8772
|
+
}
|
|
8773
|
+
}
|
|
8887
8774
|
}
|
|
8888
8775
|
};
|
|
8889
|
-
if (CanHidePrimary)
|
|
8890
|
-
themeSpec[".cm-line"].caretColor = "transparent !important";
|
|
8891
|
-
themeSpec[".cm-content"] = { caretColor: "transparent !important" };
|
|
8892
|
-
}
|
|
8776
|
+
if (CanHidePrimary)
|
|
8777
|
+
themeSpec[".cm-line"].caretColor = themeSpec[".cm-content"].caretColor = "transparent !important";
|
|
8893
8778
|
const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
|
|
8894
8779
|
|
|
8895
8780
|
const setDropCursorPos = state.StateEffect.define({
|