@codemirror/view 6.3.0 → 6.4.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 +30 -0
- package/dist/index.cjs +351 -276
- package/dist/index.d.ts +5 -0
- package/dist/index.js +351 -276
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -875,7 +875,7 @@ class WidgetView extends ContentView {
|
|
|
875
875
|
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
|
876
876
|
break;
|
|
877
877
|
}
|
|
878
|
-
return (
|
|
878
|
+
return flattenRect(rect, this.side > 0);
|
|
879
879
|
}
|
|
880
880
|
get isEditable() { return false; }
|
|
881
881
|
destroy() {
|
|
@@ -1028,7 +1028,6 @@ function inlineDOMAtPos(parent, pos) {
|
|
|
1028
1028
|
break;
|
|
1029
1029
|
off = end;
|
|
1030
1030
|
}
|
|
1031
|
-
// if (i) return DOMPos.after(children[i - 1].dom!)
|
|
1032
1031
|
for (let j = i; j > 0; j--) {
|
|
1033
1032
|
let prev = children[j - 1];
|
|
1034
1033
|
if (prev.dom.parentNode == dom)
|
|
@@ -1055,21 +1054,33 @@ function joinInlineInto(parent, view, open) {
|
|
|
1055
1054
|
parent.length += view.length;
|
|
1056
1055
|
}
|
|
1057
1056
|
function coordsInChildren(view, pos, side) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1057
|
+
let before = null, beforePos = -1, after = null, afterPos = -1;
|
|
1058
|
+
function scan(view, pos) {
|
|
1059
|
+
for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
|
|
1060
|
+
let child = view.children[i], end = off + child.length;
|
|
1061
|
+
if (end >= pos) {
|
|
1062
|
+
if (child.children.length) {
|
|
1063
|
+
scan(child, pos - off);
|
|
1064
|
+
}
|
|
1065
|
+
else if (!after && (end > pos || off == end && child.getSide() > 0)) {
|
|
1066
|
+
after = child;
|
|
1067
|
+
afterPos = pos - off;
|
|
1068
|
+
}
|
|
1069
|
+
else if (off < pos || (off == end && child.getSide() < 0)) {
|
|
1070
|
+
before = child;
|
|
1071
|
+
beforePos = pos - off;
|
|
1072
|
+
}
|
|
1067
1073
|
}
|
|
1068
|
-
|
|
1069
|
-
return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
|
1074
|
+
off = end;
|
|
1070
1075
|
}
|
|
1071
|
-
off = end;
|
|
1072
1076
|
}
|
|
1077
|
+
scan(view, pos);
|
|
1078
|
+
let target = (side < 0 ? before : after) || before || after;
|
|
1079
|
+
if (target)
|
|
1080
|
+
return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side);
|
|
1081
|
+
return fallbackRect(view);
|
|
1082
|
+
}
|
|
1083
|
+
function fallbackRect(view) {
|
|
1073
1084
|
let last = view.dom.lastChild;
|
|
1074
1085
|
if (!last)
|
|
1075
1086
|
return view.dom.getBoundingClientRect();
|
|
@@ -1688,7 +1699,7 @@ class ContentBuilder {
|
|
|
1688
1699
|
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1689
1700
|
}
|
|
1690
1701
|
else {
|
|
1691
|
-
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1702
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
1692
1703
|
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1693
1704
|
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1694
1705
|
let line = this.getLine();
|
|
@@ -4883,7 +4894,7 @@ class ViewState {
|
|
|
4883
4894
|
refresh = true;
|
|
4884
4895
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4885
4896
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4886
|
-
refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4897
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4887
4898
|
if (refresh) {
|
|
4888
4899
|
view.docView.minWidth = 0;
|
|
4889
4900
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
@@ -5027,8 +5038,10 @@ class ViewState {
|
|
|
5027
5038
|
let marginHeight = (margin / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
|
|
5028
5039
|
let top, bot;
|
|
5029
5040
|
if (target != null) {
|
|
5030
|
-
|
|
5031
|
-
|
|
5041
|
+
let targetFrac = findFraction(structure, target);
|
|
5042
|
+
let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.height;
|
|
5043
|
+
top = targetFrac - spaceFrac;
|
|
5044
|
+
bot = targetFrac + spaceFrac;
|
|
5032
5045
|
}
|
|
5033
5046
|
else {
|
|
5034
5047
|
top = (this.visibleTop - line.top - marginHeight) / line.height;
|
|
@@ -5038,14 +5051,16 @@ class ViewState {
|
|
|
5038
5051
|
viewTo = findPosition(structure, bot);
|
|
5039
5052
|
}
|
|
5040
5053
|
else {
|
|
5054
|
+
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5055
|
+
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5041
5056
|
let left, right;
|
|
5042
5057
|
if (target != null) {
|
|
5043
|
-
|
|
5044
|
-
|
|
5058
|
+
let targetFrac = findFraction(structure, target);
|
|
5059
|
+
let spaceFrac = ((this.pixelViewport.right - this.pixelViewport.left) / 2 + marginWidth) / totalWidth;
|
|
5060
|
+
left = targetFrac - spaceFrac;
|
|
5061
|
+
right = targetFrac + spaceFrac;
|
|
5045
5062
|
}
|
|
5046
5063
|
else {
|
|
5047
|
-
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5048
|
-
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5049
5064
|
left = (this.pixelViewport.left - marginWidth) / totalWidth;
|
|
5050
5065
|
right = (this.pixelViewport.right + marginWidth) / totalWidth;
|
|
5051
5066
|
}
|
|
@@ -5452,6 +5467,236 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
|
|
|
5452
5467
|
}
|
|
5453
5468
|
}, lightDarkIDs);
|
|
5454
5469
|
|
|
5470
|
+
class DOMChange {
|
|
5471
|
+
constructor(view, start, end, typeOver) {
|
|
5472
|
+
this.typeOver = typeOver;
|
|
5473
|
+
this.bounds = null;
|
|
5474
|
+
this.text = "";
|
|
5475
|
+
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
5476
|
+
if (start > -1 && !view.state.readOnly && (this.bounds = view.docView.domBoundsAround(start, end, 0))) {
|
|
5477
|
+
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
|
|
5478
|
+
let reader = new DOMReader(selPoints, view.state);
|
|
5479
|
+
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
|
|
5480
|
+
this.text = reader.text;
|
|
5481
|
+
this.newSel = selectionFromPoints(selPoints, this.bounds.from);
|
|
5482
|
+
}
|
|
5483
|
+
else {
|
|
5484
|
+
let domSel = view.observer.selectionRange;
|
|
5485
|
+
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
|
5486
|
+
!contains(view.contentDOM, domSel.focusNode)
|
|
5487
|
+
? view.state.selection.main.head
|
|
5488
|
+
: view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
|
5489
|
+
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
|
5490
|
+
!contains(view.contentDOM, domSel.anchorNode)
|
|
5491
|
+
? view.state.selection.main.anchor
|
|
5492
|
+
: view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
|
5493
|
+
this.newSel = state.EditorSelection.single(anchor, head);
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
function applyDOMChange(view, domChange) {
|
|
5498
|
+
let change;
|
|
5499
|
+
let { newSel } = domChange, sel = view.state.selection.main;
|
|
5500
|
+
if (domChange.bounds) {
|
|
5501
|
+
let { from, to } = domChange.bounds;
|
|
5502
|
+
let preferredPos = sel.from, preferredSide = null;
|
|
5503
|
+
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5504
|
+
// Android, when something was deleted)
|
|
5505
|
+
if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
|
5506
|
+
browser.android && domChange.text.length < to - from) {
|
|
5507
|
+
preferredPos = sel.to;
|
|
5508
|
+
preferredSide = "end";
|
|
5509
|
+
}
|
|
5510
|
+
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), domChange.text, preferredPos - from, preferredSide);
|
|
5511
|
+
if (diff) {
|
|
5512
|
+
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5513
|
+
// end of a line. DomChange drops one of those.
|
|
5514
|
+
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5515
|
+
diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5516
|
+
diff.toB--;
|
|
5517
|
+
change = { from: from + diff.from, to: from + diff.toA,
|
|
5518
|
+
insert: state.Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
else if (newSel && (!view.hasFocus || !view.state.facet(editable) || newSel.main.eq(sel))) {
|
|
5522
|
+
newSel = null;
|
|
5523
|
+
}
|
|
5524
|
+
if (!change && !newSel)
|
|
5525
|
+
return false;
|
|
5526
|
+
if (!change && domChange.typeOver && !sel.empty && newSel && newSel.main.empty) {
|
|
5527
|
+
// Heuristic to notice typing over a selected character
|
|
5528
|
+
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
5529
|
+
}
|
|
5530
|
+
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
5531
|
+
(change.from != sel.from || change.to != sel.to) &&
|
|
5532
|
+
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
5533
|
+
// If the change is inside the selection and covers most of it,
|
|
5534
|
+
// assume it is a selection replace (with identical characters at
|
|
5535
|
+
// the start/end not included in the diff)
|
|
5536
|
+
change = {
|
|
5537
|
+
from: sel.from, to: sel.to,
|
|
5538
|
+
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5541
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5542
|
+
/^\. ?$/.test(change.insert.toString())) {
|
|
5543
|
+
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5544
|
+
// and transform it into a regular space insert.
|
|
5545
|
+
if (newSel && change.insert.length == 2)
|
|
5546
|
+
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5547
|
+
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
5548
|
+
}
|
|
5549
|
+
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
5550
|
+
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
5551
|
+
// In Chrome, if you insert a space at the start of a wrapped
|
|
5552
|
+
// line, it will actually insert a newline and a space, causing a
|
|
5553
|
+
// bogus new line to be created in CodeMirror (#968)
|
|
5554
|
+
if (newSel)
|
|
5555
|
+
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5556
|
+
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
5557
|
+
}
|
|
5558
|
+
if (change) {
|
|
5559
|
+
let startState = view.state;
|
|
5560
|
+
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5561
|
+
return true;
|
|
5562
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
5563
|
+
// backspace, or delete. So this detects changes that look like
|
|
5564
|
+
// they're caused by those keys, and reinterprets them as key
|
|
5565
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
5566
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
5567
|
+
// reliable in all situations.)
|
|
5568
|
+
if (browser.android &&
|
|
5569
|
+
((change.from == sel.from && change.to == sel.to &&
|
|
5570
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
5571
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
5572
|
+
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5573
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5574
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5575
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5576
|
+
return true;
|
|
5577
|
+
let text = change.insert.toString();
|
|
5578
|
+
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5579
|
+
return true;
|
|
5580
|
+
if (view.inputState.composing >= 0)
|
|
5581
|
+
view.inputState.composing++;
|
|
5582
|
+
let tr;
|
|
5583
|
+
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5584
|
+
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5585
|
+
view.inputState.composing < 0) {
|
|
5586
|
+
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5587
|
+
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5588
|
+
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5589
|
+
}
|
|
5590
|
+
else {
|
|
5591
|
+
let changes = startState.changes(change);
|
|
5592
|
+
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5593
|
+
? newSel.main : undefined;
|
|
5594
|
+
// Try to apply a composition change to all cursors
|
|
5595
|
+
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5596
|
+
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5597
|
+
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5598
|
+
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5599
|
+
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5600
|
+
tr = startState.changeByRange(range => {
|
|
5601
|
+
if (range.from == sel.from && range.to == sel.to)
|
|
5602
|
+
return { changes, range: mainSel || range.map(changes) };
|
|
5603
|
+
let to = range.to - offset, from = to - replaced.length;
|
|
5604
|
+
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5605
|
+
// Unfortunately, there's no way to make multiple
|
|
5606
|
+
// changes in the same node work without aborting
|
|
5607
|
+
// composition, so cursors in the composition range are
|
|
5608
|
+
// ignored.
|
|
5609
|
+
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5610
|
+
return { range };
|
|
5611
|
+
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5612
|
+
return {
|
|
5613
|
+
changes: rangeChanges,
|
|
5614
|
+
range: !mainSel ? range.map(rangeChanges) :
|
|
5615
|
+
state.EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
5616
|
+
};
|
|
5617
|
+
});
|
|
5618
|
+
}
|
|
5619
|
+
else {
|
|
5620
|
+
tr = {
|
|
5621
|
+
changes,
|
|
5622
|
+
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
5623
|
+
};
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
let userEvent = "input.type";
|
|
5627
|
+
if (view.composing) {
|
|
5628
|
+
userEvent += ".compose";
|
|
5629
|
+
if (view.inputState.compositionFirstChange) {
|
|
5630
|
+
userEvent += ".start";
|
|
5631
|
+
view.inputState.compositionFirstChange = false;
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
5635
|
+
return true;
|
|
5636
|
+
}
|
|
5637
|
+
else if (newSel && !newSel.main.eq(sel)) {
|
|
5638
|
+
let scrollIntoView = false, userEvent = "select";
|
|
5639
|
+
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
5640
|
+
if (view.inputState.lastSelectionOrigin == "select")
|
|
5641
|
+
scrollIntoView = true;
|
|
5642
|
+
userEvent = view.inputState.lastSelectionOrigin;
|
|
5643
|
+
}
|
|
5644
|
+
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
5645
|
+
return true;
|
|
5646
|
+
}
|
|
5647
|
+
else {
|
|
5648
|
+
return false;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
function findDiff(a, b, preferredPos, preferredSide) {
|
|
5652
|
+
let minLen = Math.min(a.length, b.length);
|
|
5653
|
+
let from = 0;
|
|
5654
|
+
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
|
5655
|
+
from++;
|
|
5656
|
+
if (from == minLen && a.length == b.length)
|
|
5657
|
+
return null;
|
|
5658
|
+
let toA = a.length, toB = b.length;
|
|
5659
|
+
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
|
5660
|
+
toA--;
|
|
5661
|
+
toB--;
|
|
5662
|
+
}
|
|
5663
|
+
if (preferredSide == "end") {
|
|
5664
|
+
let adjust = Math.max(0, from - Math.min(toA, toB));
|
|
5665
|
+
preferredPos -= toA + adjust - from;
|
|
5666
|
+
}
|
|
5667
|
+
if (toA < from && a.length < b.length) {
|
|
5668
|
+
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
|
5669
|
+
from -= move;
|
|
5670
|
+
toB = from + (toB - toA);
|
|
5671
|
+
toA = from;
|
|
5672
|
+
}
|
|
5673
|
+
else if (toB < from) {
|
|
5674
|
+
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
|
5675
|
+
from -= move;
|
|
5676
|
+
toA = from + (toA - toB);
|
|
5677
|
+
toB = from;
|
|
5678
|
+
}
|
|
5679
|
+
return { from, toA, toB };
|
|
5680
|
+
}
|
|
5681
|
+
function selectionPoints(view) {
|
|
5682
|
+
let result = [];
|
|
5683
|
+
if (view.root.activeElement != view.contentDOM)
|
|
5684
|
+
return result;
|
|
5685
|
+
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
|
5686
|
+
if (anchorNode) {
|
|
5687
|
+
result.push(new DOMPoint(anchorNode, anchorOffset));
|
|
5688
|
+
if (focusNode != anchorNode || focusOffset != anchorOffset)
|
|
5689
|
+
result.push(new DOMPoint(focusNode, focusOffset));
|
|
5690
|
+
}
|
|
5691
|
+
return result;
|
|
5692
|
+
}
|
|
5693
|
+
function selectionFromPoints(points, base) {
|
|
5694
|
+
if (points.length == 0)
|
|
5695
|
+
return null;
|
|
5696
|
+
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
5697
|
+
return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null;
|
|
5698
|
+
}
|
|
5699
|
+
|
|
5455
5700
|
const observeOptions = {
|
|
5456
5701
|
childList: true,
|
|
5457
5702
|
characterData: true,
|
|
@@ -5463,10 +5708,8 @@ const observeOptions = {
|
|
|
5463
5708
|
// DOMCharacterDataModified there
|
|
5464
5709
|
const useCharData = browser.ie && browser.ie_version <= 11;
|
|
5465
5710
|
class DOMObserver {
|
|
5466
|
-
constructor(view
|
|
5711
|
+
constructor(view) {
|
|
5467
5712
|
this.view = view;
|
|
5468
|
-
this.onChange = onChange;
|
|
5469
|
-
this.onScrollChanged = onScrollChanged;
|
|
5470
5713
|
this.active = false;
|
|
5471
5714
|
// The known selection. Kept in our own object, as opposed to just
|
|
5472
5715
|
// directly accessing the selection because:
|
|
@@ -5481,6 +5724,7 @@ class DOMObserver {
|
|
|
5481
5724
|
this.resizeTimeout = -1;
|
|
5482
5725
|
this.queue = [];
|
|
5483
5726
|
this.delayedAndroidKey = null;
|
|
5727
|
+
this.flushingAndroidKey = -1;
|
|
5484
5728
|
this.lastChange = 0;
|
|
5485
5729
|
this.scrollTargets = [];
|
|
5486
5730
|
this.intersection = null;
|
|
@@ -5549,6 +5793,11 @@ class DOMObserver {
|
|
|
5549
5793
|
this.listenForScroll();
|
|
5550
5794
|
this.readSelectionRange();
|
|
5551
5795
|
}
|
|
5796
|
+
onScrollChanged(e) {
|
|
5797
|
+
this.view.inputState.runScrollHandlers(this.view, e);
|
|
5798
|
+
if (this.intersecting)
|
|
5799
|
+
this.view.measure();
|
|
5800
|
+
}
|
|
5552
5801
|
onScroll(e) {
|
|
5553
5802
|
if (this.intersecting)
|
|
5554
5803
|
this.flush(false);
|
|
@@ -5708,14 +5957,17 @@ class DOMObserver {
|
|
|
5708
5957
|
// them or, if that has no effect, dispatches the given key.
|
|
5709
5958
|
delayAndroidKey(key, keyCode) {
|
|
5710
5959
|
var _a;
|
|
5711
|
-
if (!this.delayedAndroidKey)
|
|
5712
|
-
|
|
5960
|
+
if (!this.delayedAndroidKey) {
|
|
5961
|
+
let flush = () => {
|
|
5713
5962
|
let key = this.delayedAndroidKey;
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5963
|
+
if (key) {
|
|
5964
|
+
this.clearDelayedAndroidKey();
|
|
5965
|
+
if (!this.flush() && key.force)
|
|
5966
|
+
dispatchKey(this.dom, key.key, key.keyCode);
|
|
5967
|
+
}
|
|
5968
|
+
};
|
|
5969
|
+
this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush);
|
|
5970
|
+
}
|
|
5719
5971
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5720
5972
|
// Enter always takes precedence.
|
|
5721
5973
|
if (!this.delayedAndroidKey || key == "Enter")
|
|
@@ -5728,6 +5980,11 @@ class DOMObserver {
|
|
|
5728
5980
|
force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force)
|
|
5729
5981
|
};
|
|
5730
5982
|
}
|
|
5983
|
+
clearDelayedAndroidKey() {
|
|
5984
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
5985
|
+
this.delayedAndroidKey = null;
|
|
5986
|
+
this.flushingAndroidKey = -1;
|
|
5987
|
+
}
|
|
5731
5988
|
flushSoon() {
|
|
5732
5989
|
if (this.delayedFlush < 0)
|
|
5733
5990
|
this.delayedFlush = this.view.win.requestAnimationFrame(() => { this.delayedFlush = -1; this.flush(); });
|
|
@@ -5762,6 +6019,17 @@ class DOMObserver {
|
|
|
5762
6019
|
}
|
|
5763
6020
|
return { from, to, typeOver };
|
|
5764
6021
|
}
|
|
6022
|
+
readChange() {
|
|
6023
|
+
let { from, to, typeOver } = this.processRecords();
|
|
6024
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
6025
|
+
if (from < 0 && !newSel)
|
|
6026
|
+
return null;
|
|
6027
|
+
if (from > -1)
|
|
6028
|
+
this.lastChange = Date.now();
|
|
6029
|
+
this.view.inputState.lastFocusTime = 0;
|
|
6030
|
+
this.selectionChanged = false;
|
|
6031
|
+
return new DOMChange(this.view, from, to, typeOver);
|
|
6032
|
+
}
|
|
5765
6033
|
// Apply pending changes, if any
|
|
5766
6034
|
flush(readSelection = true) {
|
|
5767
6035
|
// Completely hold off flushing when pending keys are set—the code
|
|
@@ -5771,16 +6039,11 @@ class DOMObserver {
|
|
|
5771
6039
|
return false;
|
|
5772
6040
|
if (readSelection)
|
|
5773
6041
|
this.readSelectionRange();
|
|
5774
|
-
let
|
|
5775
|
-
|
|
5776
|
-
if (from < 0 && !newSel)
|
|
6042
|
+
let domChange = this.readChange();
|
|
6043
|
+
if (!domChange)
|
|
5777
6044
|
return false;
|
|
5778
|
-
if (from > -1)
|
|
5779
|
-
this.lastChange = Date.now();
|
|
5780
|
-
this.view.inputState.lastFocusTime = 0;
|
|
5781
|
-
this.selectionChanged = false;
|
|
5782
6045
|
let startState = this.view.state;
|
|
5783
|
-
let handled = this.
|
|
6046
|
+
let handled = applyDOMChange(this.view, domChange);
|
|
5784
6047
|
// The view wasn't updated
|
|
5785
6048
|
if (this.view.state == startState)
|
|
5786
6049
|
this.view.update([]);
|
|
@@ -5836,6 +6099,8 @@ class DOMObserver {
|
|
|
5836
6099
|
this.removeWindowListeners(this.win);
|
|
5837
6100
|
clearTimeout(this.parentCheck);
|
|
5838
6101
|
clearTimeout(this.resizeTimeout);
|
|
6102
|
+
this.win.cancelAnimationFrame(this.delayedFlush);
|
|
6103
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
5839
6104
|
}
|
|
5840
6105
|
}
|
|
5841
6106
|
function findChild(cView, dom, dir) {
|
|
@@ -5877,218 +6142,6 @@ function safariSelectionRangeHack(view) {
|
|
|
5877
6142
|
return { anchorNode, anchorOffset, focusNode, focusOffset };
|
|
5878
6143
|
}
|
|
5879
6144
|
|
|
5880
|
-
function applyDOMChange(view, start, end, typeOver) {
|
|
5881
|
-
let change, newSel;
|
|
5882
|
-
let sel = view.state.selection.main;
|
|
5883
|
-
if (start > -1) {
|
|
5884
|
-
let bounds = view.docView.domBoundsAround(start, end, 0);
|
|
5885
|
-
if (!bounds || view.state.readOnly)
|
|
5886
|
-
return false;
|
|
5887
|
-
let { from, to } = bounds;
|
|
5888
|
-
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5889
|
-
let reader = new DOMReader(selPoints, view.state);
|
|
5890
|
-
reader.readRange(bounds.startDOM, bounds.endDOM);
|
|
5891
|
-
let preferredPos = sel.from, preferredSide = null;
|
|
5892
|
-
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5893
|
-
// Android, when something was deleted)
|
|
5894
|
-
if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
|
5895
|
-
browser.android && reader.text.length < to - from) {
|
|
5896
|
-
preferredPos = sel.to;
|
|
5897
|
-
preferredSide = "end";
|
|
5898
|
-
}
|
|
5899
|
-
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5900
|
-
if (diff) {
|
|
5901
|
-
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5902
|
-
// end of a line. This drops one of those.
|
|
5903
|
-
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5904
|
-
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5905
|
-
diff.toB--;
|
|
5906
|
-
change = { from: from + diff.from, to: from + diff.toA,
|
|
5907
|
-
insert: state.Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5908
|
-
}
|
|
5909
|
-
newSel = selectionFromPoints(selPoints, from);
|
|
5910
|
-
}
|
|
5911
|
-
else if (view.hasFocus || !view.state.facet(editable)) {
|
|
5912
|
-
let domSel = view.observer.selectionRange;
|
|
5913
|
-
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
5914
|
-
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
|
5915
|
-
!contains(view.contentDOM, domSel.focusNode)
|
|
5916
|
-
? view.state.selection.main.head
|
|
5917
|
-
: view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
|
5918
|
-
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
|
5919
|
-
!contains(view.contentDOM, domSel.anchorNode)
|
|
5920
|
-
? view.state.selection.main.anchor
|
|
5921
|
-
: view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
|
5922
|
-
if (head != sel.head || anchor != sel.anchor)
|
|
5923
|
-
newSel = state.EditorSelection.single(anchor, head);
|
|
5924
|
-
}
|
|
5925
|
-
if (!change && !newSel)
|
|
5926
|
-
return false;
|
|
5927
|
-
if (!change && typeOver && !sel.empty && newSel && newSel.main.empty) {
|
|
5928
|
-
// Heuristic to notice typing over a selected character
|
|
5929
|
-
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
5930
|
-
}
|
|
5931
|
-
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
5932
|
-
(change.from != sel.from || change.to != sel.to) &&
|
|
5933
|
-
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
5934
|
-
// If the change is inside the selection and covers most of it,
|
|
5935
|
-
// assume it is a selection replace (with identical characters at
|
|
5936
|
-
// the start/end not included in the diff)
|
|
5937
|
-
change = {
|
|
5938
|
-
from: sel.from, to: sel.to,
|
|
5939
|
-
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
5940
|
-
};
|
|
5941
|
-
}
|
|
5942
|
-
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5943
|
-
/^\. ?$/.test(change.insert.toString())) {
|
|
5944
|
-
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5945
|
-
// and transform it into a regular space insert.
|
|
5946
|
-
if (newSel && change.insert.length == 2)
|
|
5947
|
-
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5948
|
-
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
5949
|
-
}
|
|
5950
|
-
if (change) {
|
|
5951
|
-
let startState = view.state;
|
|
5952
|
-
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5953
|
-
return true;
|
|
5954
|
-
// Android browsers don't fire reasonable key events for enter,
|
|
5955
|
-
// backspace, or delete. So this detects changes that look like
|
|
5956
|
-
// they're caused by those keys, and reinterprets them as key
|
|
5957
|
-
// events. (Some of these keys are also handled by beforeinput
|
|
5958
|
-
// events and the pendingAndroidKey mechanism, but that's not
|
|
5959
|
-
// reliable in all situations.)
|
|
5960
|
-
if (browser.android &&
|
|
5961
|
-
((change.from == sel.from && change.to == sel.to &&
|
|
5962
|
-
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
5963
|
-
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
5964
|
-
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5965
|
-
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5966
|
-
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5967
|
-
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5968
|
-
return true;
|
|
5969
|
-
let text = change.insert.toString();
|
|
5970
|
-
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5971
|
-
return true;
|
|
5972
|
-
if (view.inputState.composing >= 0)
|
|
5973
|
-
view.inputState.composing++;
|
|
5974
|
-
let tr;
|
|
5975
|
-
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5976
|
-
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5977
|
-
view.inputState.composing < 0) {
|
|
5978
|
-
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5979
|
-
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5980
|
-
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5981
|
-
}
|
|
5982
|
-
else {
|
|
5983
|
-
let changes = startState.changes(change);
|
|
5984
|
-
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5985
|
-
? newSel.main : undefined;
|
|
5986
|
-
// Try to apply a composition change to all cursors
|
|
5987
|
-
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5988
|
-
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5989
|
-
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5990
|
-
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5991
|
-
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5992
|
-
tr = startState.changeByRange(range => {
|
|
5993
|
-
if (range.from == sel.from && range.to == sel.to)
|
|
5994
|
-
return { changes, range: mainSel || range.map(changes) };
|
|
5995
|
-
let to = range.to - offset, from = to - replaced.length;
|
|
5996
|
-
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5997
|
-
// Unfortunately, there's no way to make multiple
|
|
5998
|
-
// changes in the same node work without aborting
|
|
5999
|
-
// composition, so cursors in the composition range are
|
|
6000
|
-
// ignored.
|
|
6001
|
-
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
6002
|
-
return { range };
|
|
6003
|
-
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
6004
|
-
return {
|
|
6005
|
-
changes: rangeChanges,
|
|
6006
|
-
range: !mainSel ? range.map(rangeChanges) :
|
|
6007
|
-
state.EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
6008
|
-
};
|
|
6009
|
-
});
|
|
6010
|
-
}
|
|
6011
|
-
else {
|
|
6012
|
-
tr = {
|
|
6013
|
-
changes,
|
|
6014
|
-
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
6015
|
-
};
|
|
6016
|
-
}
|
|
6017
|
-
}
|
|
6018
|
-
let userEvent = "input.type";
|
|
6019
|
-
if (view.composing) {
|
|
6020
|
-
userEvent += ".compose";
|
|
6021
|
-
if (view.inputState.compositionFirstChange) {
|
|
6022
|
-
userEvent += ".start";
|
|
6023
|
-
view.inputState.compositionFirstChange = false;
|
|
6024
|
-
}
|
|
6025
|
-
}
|
|
6026
|
-
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
6027
|
-
return true;
|
|
6028
|
-
}
|
|
6029
|
-
else if (newSel && !newSel.main.eq(sel)) {
|
|
6030
|
-
let scrollIntoView = false, userEvent = "select";
|
|
6031
|
-
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
6032
|
-
if (view.inputState.lastSelectionOrigin == "select")
|
|
6033
|
-
scrollIntoView = true;
|
|
6034
|
-
userEvent = view.inputState.lastSelectionOrigin;
|
|
6035
|
-
}
|
|
6036
|
-
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
6037
|
-
return true;
|
|
6038
|
-
}
|
|
6039
|
-
else {
|
|
6040
|
-
return false;
|
|
6041
|
-
}
|
|
6042
|
-
}
|
|
6043
|
-
function findDiff(a, b, preferredPos, preferredSide) {
|
|
6044
|
-
let minLen = Math.min(a.length, b.length);
|
|
6045
|
-
let from = 0;
|
|
6046
|
-
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
|
6047
|
-
from++;
|
|
6048
|
-
if (from == minLen && a.length == b.length)
|
|
6049
|
-
return null;
|
|
6050
|
-
let toA = a.length, toB = b.length;
|
|
6051
|
-
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
|
6052
|
-
toA--;
|
|
6053
|
-
toB--;
|
|
6054
|
-
}
|
|
6055
|
-
if (preferredSide == "end") {
|
|
6056
|
-
let adjust = Math.max(0, from - Math.min(toA, toB));
|
|
6057
|
-
preferredPos -= toA + adjust - from;
|
|
6058
|
-
}
|
|
6059
|
-
if (toA < from && a.length < b.length) {
|
|
6060
|
-
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
|
6061
|
-
from -= move;
|
|
6062
|
-
toB = from + (toB - toA);
|
|
6063
|
-
toA = from;
|
|
6064
|
-
}
|
|
6065
|
-
else if (toB < from) {
|
|
6066
|
-
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
|
6067
|
-
from -= move;
|
|
6068
|
-
toA = from + (toA - toB);
|
|
6069
|
-
toB = from;
|
|
6070
|
-
}
|
|
6071
|
-
return { from, toA, toB };
|
|
6072
|
-
}
|
|
6073
|
-
function selectionPoints(view) {
|
|
6074
|
-
let result = [];
|
|
6075
|
-
if (view.root.activeElement != view.contentDOM)
|
|
6076
|
-
return result;
|
|
6077
|
-
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
|
6078
|
-
if (anchorNode) {
|
|
6079
|
-
result.push(new DOMPoint(anchorNode, anchorOffset));
|
|
6080
|
-
if (focusNode != anchorNode || focusOffset != anchorOffset)
|
|
6081
|
-
result.push(new DOMPoint(focusNode, focusOffset));
|
|
6082
|
-
}
|
|
6083
|
-
return result;
|
|
6084
|
-
}
|
|
6085
|
-
function selectionFromPoints(points, base) {
|
|
6086
|
-
if (points.length == 0)
|
|
6087
|
-
return null;
|
|
6088
|
-
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
6089
|
-
return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null;
|
|
6090
|
-
}
|
|
6091
|
-
|
|
6092
6145
|
// The editor's update state machine looks something like this:
|
|
6093
6146
|
//
|
|
6094
6147
|
// Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle
|
|
@@ -6151,13 +6204,7 @@ class EditorView {
|
|
|
6151
6204
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
|
6152
6205
|
for (let plugin of this.plugins)
|
|
6153
6206
|
plugin.update(this);
|
|
6154
|
-
this.observer = new DOMObserver(this
|
|
6155
|
-
return applyDOMChange(this, from, to, typeOver);
|
|
6156
|
-
}, event => {
|
|
6157
|
-
this.inputState.runScrollHandlers(this, event);
|
|
6158
|
-
if (this.observer.intersecting)
|
|
6159
|
-
this.measure();
|
|
6160
|
-
});
|
|
6207
|
+
this.observer = new DOMObserver(this);
|
|
6161
6208
|
this.inputState = new InputState(this);
|
|
6162
6209
|
this.inputState.ensureHandlers(this, this.plugins);
|
|
6163
6210
|
this.docView = new DocView(this);
|
|
@@ -6241,7 +6288,20 @@ class EditorView {
|
|
|
6241
6288
|
this.viewState.state = state$1;
|
|
6242
6289
|
return;
|
|
6243
6290
|
}
|
|
6244
|
-
|
|
6291
|
+
// If there was a pending DOM change, eagerly read it and try to
|
|
6292
|
+
// apply it after the given transactions.
|
|
6293
|
+
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
|
|
6294
|
+
if (pendingKey) {
|
|
6295
|
+
this.observer.clearDelayedAndroidKey();
|
|
6296
|
+
domChange = this.observer.readChange();
|
|
6297
|
+
// Only try to apply DOM changes if the transactions didn't
|
|
6298
|
+
// change the doc or selection.
|
|
6299
|
+
if (domChange && !this.state.doc.eq(state$1.doc) || !this.state.selection.eq(state$1.selection))
|
|
6300
|
+
domChange = null;
|
|
6301
|
+
}
|
|
6302
|
+
else {
|
|
6303
|
+
this.observer.clear();
|
|
6304
|
+
}
|
|
6245
6305
|
// When the phrases change, redraw the editor
|
|
6246
6306
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
6247
6307
|
return this.setState(state$1);
|
|
@@ -6283,6 +6343,10 @@ class EditorView {
|
|
|
6283
6343
|
if (!update.empty)
|
|
6284
6344
|
for (let listener of this.state.facet(updateListener))
|
|
6285
6345
|
listener(update);
|
|
6346
|
+
if (domChange) {
|
|
6347
|
+
if (!applyDOMChange(this, domChange) && pendingKey.force)
|
|
6348
|
+
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
|
|
6349
|
+
}
|
|
6286
6350
|
}
|
|
6287
6351
|
/**
|
|
6288
6352
|
Reset the view to the given state. (This will cause the entire
|
|
@@ -6415,17 +6479,19 @@ class EditorView {
|
|
|
6415
6479
|
logException(this.state, e);
|
|
6416
6480
|
}
|
|
6417
6481
|
}
|
|
6418
|
-
if (this.viewState.
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
}
|
|
6423
|
-
else {
|
|
6424
|
-
let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
|
|
6425
|
-
if (diff > 1 || diff < -1) {
|
|
6426
|
-
this.scrollDOM.scrollTop += diff;
|
|
6482
|
+
if (this.viewState.editorHeight) {
|
|
6483
|
+
if (this.viewState.scrollTarget) {
|
|
6484
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6485
|
+
this.viewState.scrollTarget = null;
|
|
6427
6486
|
scrolled = true;
|
|
6428
6487
|
}
|
|
6488
|
+
else {
|
|
6489
|
+
let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
|
|
6490
|
+
if (diff > 1 || diff < -1) {
|
|
6491
|
+
this.scrollDOM.scrollTop += diff;
|
|
6492
|
+
scrolled = true;
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6429
6495
|
}
|
|
6430
6496
|
if (redrawn)
|
|
6431
6497
|
this.docView.updateSelection(true);
|
|
@@ -7831,7 +7897,8 @@ const plugin = ViewPlugin.fromClass(class {
|
|
|
7831
7897
|
this.attrs = { style: "padding-bottom: 1000px" };
|
|
7832
7898
|
}
|
|
7833
7899
|
update(update) {
|
|
7834
|
-
let
|
|
7900
|
+
let { view } = update;
|
|
7901
|
+
let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
|
|
7835
7902
|
if (height != this.height) {
|
|
7836
7903
|
this.height = height;
|
|
7837
7904
|
this.attrs = { style: `padding-bottom: ${height}px` };
|
|
@@ -7933,7 +8000,10 @@ function rectangleFor(state$1, a, b) {
|
|
|
7933
8000
|
for (let i = startLine; i <= endLine; i++) {
|
|
7934
8001
|
let line = state$1.doc.line(i);
|
|
7935
8002
|
let start = state.findColumn(line.text, startCol, state$1.tabSize, true);
|
|
7936
|
-
if (start
|
|
8003
|
+
if (start < 0) {
|
|
8004
|
+
ranges.push(state.EditorSelection.cursor(line.to));
|
|
8005
|
+
}
|
|
8006
|
+
else {
|
|
7937
8007
|
let end = state.findColumn(line.text, endCol, state$1.tabSize);
|
|
7938
8008
|
ranges.push(state.EditorSelection.range(line.from + start, line.from + end));
|
|
7939
8009
|
}
|
|
@@ -8045,6 +8115,7 @@ class TooltipViewManager {
|
|
|
8045
8115
|
this.tooltipViews = this.tooltips.map(createTooltipView);
|
|
8046
8116
|
}
|
|
8047
8117
|
update(update) {
|
|
8118
|
+
var _a;
|
|
8048
8119
|
let input = update.state.facet(this.facet);
|
|
8049
8120
|
let tooltips = input.filter(x => x);
|
|
8050
8121
|
if (input === this.input) {
|
|
@@ -8073,8 +8144,10 @@ class TooltipViewManager {
|
|
|
8073
8144
|
}
|
|
8074
8145
|
}
|
|
8075
8146
|
for (let t of this.tooltipViews)
|
|
8076
|
-
if (tooltipViews.indexOf(t) < 0)
|
|
8147
|
+
if (tooltipViews.indexOf(t) < 0) {
|
|
8077
8148
|
t.dom.remove();
|
|
8149
|
+
(_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
|
|
8150
|
+
}
|
|
8078
8151
|
this.input = input;
|
|
8079
8152
|
this.tooltips = tooltips;
|
|
8080
8153
|
this.tooltipViews = tooltipViews;
|
|
@@ -8193,11 +8266,13 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
8193
8266
|
return tooltipView;
|
|
8194
8267
|
}
|
|
8195
8268
|
destroy() {
|
|
8196
|
-
var _a;
|
|
8269
|
+
var _a, _b;
|
|
8197
8270
|
this.view.win.removeEventListener("resize", this.measureSoon);
|
|
8198
|
-
for (let
|
|
8199
|
-
dom.remove();
|
|
8200
|
-
|
|
8271
|
+
for (let tooltipView of this.manager.tooltipViews) {
|
|
8272
|
+
tooltipView.dom.remove();
|
|
8273
|
+
(_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
|
|
8274
|
+
}
|
|
8275
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
8201
8276
|
clearTimeout(this.measureTimeout);
|
|
8202
8277
|
}
|
|
8203
8278
|
readMeasure() {
|