@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.js
CHANGED
|
@@ -871,7 +871,7 @@ class WidgetView extends ContentView {
|
|
|
871
871
|
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
|
872
872
|
break;
|
|
873
873
|
}
|
|
874
|
-
return (
|
|
874
|
+
return flattenRect(rect, this.side > 0);
|
|
875
875
|
}
|
|
876
876
|
get isEditable() { return false; }
|
|
877
877
|
destroy() {
|
|
@@ -1024,7 +1024,6 @@ function inlineDOMAtPos(parent, pos) {
|
|
|
1024
1024
|
break;
|
|
1025
1025
|
off = end;
|
|
1026
1026
|
}
|
|
1027
|
-
// if (i) return DOMPos.after(children[i - 1].dom!)
|
|
1028
1027
|
for (let j = i; j > 0; j--) {
|
|
1029
1028
|
let prev = children[j - 1];
|
|
1030
1029
|
if (prev.dom.parentNode == dom)
|
|
@@ -1051,21 +1050,33 @@ function joinInlineInto(parent, view, open) {
|
|
|
1051
1050
|
parent.length += view.length;
|
|
1052
1051
|
}
|
|
1053
1052
|
function coordsInChildren(view, pos, side) {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1053
|
+
let before = null, beforePos = -1, after = null, afterPos = -1;
|
|
1054
|
+
function scan(view, pos) {
|
|
1055
|
+
for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
|
|
1056
|
+
let child = view.children[i], end = off + child.length;
|
|
1057
|
+
if (end >= pos) {
|
|
1058
|
+
if (child.children.length) {
|
|
1059
|
+
scan(child, pos - off);
|
|
1060
|
+
}
|
|
1061
|
+
else if (!after && (end > pos || off == end && child.getSide() > 0)) {
|
|
1062
|
+
after = child;
|
|
1063
|
+
afterPos = pos - off;
|
|
1064
|
+
}
|
|
1065
|
+
else if (off < pos || (off == end && child.getSide() < 0)) {
|
|
1066
|
+
before = child;
|
|
1067
|
+
beforePos = pos - off;
|
|
1068
|
+
}
|
|
1063
1069
|
}
|
|
1064
|
-
|
|
1065
|
-
return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
|
1070
|
+
off = end;
|
|
1066
1071
|
}
|
|
1067
|
-
off = end;
|
|
1068
1072
|
}
|
|
1073
|
+
scan(view, pos);
|
|
1074
|
+
let target = (side < 0 ? before : after) || before || after;
|
|
1075
|
+
if (target)
|
|
1076
|
+
return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side);
|
|
1077
|
+
return fallbackRect(view);
|
|
1078
|
+
}
|
|
1079
|
+
function fallbackRect(view) {
|
|
1069
1080
|
let last = view.dom.lastChild;
|
|
1070
1081
|
if (!last)
|
|
1071
1082
|
return view.dom.getBoundingClientRect();
|
|
@@ -1683,7 +1694,7 @@ class ContentBuilder {
|
|
|
1683
1694
|
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1684
1695
|
}
|
|
1685
1696
|
else {
|
|
1686
|
-
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1697
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
1687
1698
|
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1688
1699
|
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1689
1700
|
let line = this.getLine();
|
|
@@ -4876,7 +4887,7 @@ class ViewState {
|
|
|
4876
4887
|
refresh = true;
|
|
4877
4888
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4878
4889
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4879
|
-
refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4890
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4880
4891
|
if (refresh) {
|
|
4881
4892
|
view.docView.minWidth = 0;
|
|
4882
4893
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
@@ -5020,8 +5031,10 @@ class ViewState {
|
|
|
5020
5031
|
let marginHeight = (margin / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
|
|
5021
5032
|
let top, bot;
|
|
5022
5033
|
if (target != null) {
|
|
5023
|
-
|
|
5024
|
-
|
|
5034
|
+
let targetFrac = findFraction(structure, target);
|
|
5035
|
+
let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.height;
|
|
5036
|
+
top = targetFrac - spaceFrac;
|
|
5037
|
+
bot = targetFrac + spaceFrac;
|
|
5025
5038
|
}
|
|
5026
5039
|
else {
|
|
5027
5040
|
top = (this.visibleTop - line.top - marginHeight) / line.height;
|
|
@@ -5031,14 +5044,16 @@ class ViewState {
|
|
|
5031
5044
|
viewTo = findPosition(structure, bot);
|
|
5032
5045
|
}
|
|
5033
5046
|
else {
|
|
5047
|
+
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5048
|
+
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5034
5049
|
let left, right;
|
|
5035
5050
|
if (target != null) {
|
|
5036
|
-
|
|
5037
|
-
|
|
5051
|
+
let targetFrac = findFraction(structure, target);
|
|
5052
|
+
let spaceFrac = ((this.pixelViewport.right - this.pixelViewport.left) / 2 + marginWidth) / totalWidth;
|
|
5053
|
+
left = targetFrac - spaceFrac;
|
|
5054
|
+
right = targetFrac + spaceFrac;
|
|
5038
5055
|
}
|
|
5039
5056
|
else {
|
|
5040
|
-
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5041
|
-
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5042
5057
|
left = (this.pixelViewport.left - marginWidth) / totalWidth;
|
|
5043
5058
|
right = (this.pixelViewport.right + marginWidth) / totalWidth;
|
|
5044
5059
|
}
|
|
@@ -5445,6 +5460,236 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
5445
5460
|
}
|
|
5446
5461
|
}, lightDarkIDs);
|
|
5447
5462
|
|
|
5463
|
+
class DOMChange {
|
|
5464
|
+
constructor(view, start, end, typeOver) {
|
|
5465
|
+
this.typeOver = typeOver;
|
|
5466
|
+
this.bounds = null;
|
|
5467
|
+
this.text = "";
|
|
5468
|
+
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
5469
|
+
if (start > -1 && !view.state.readOnly && (this.bounds = view.docView.domBoundsAround(start, end, 0))) {
|
|
5470
|
+
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
|
|
5471
|
+
let reader = new DOMReader(selPoints, view.state);
|
|
5472
|
+
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
|
|
5473
|
+
this.text = reader.text;
|
|
5474
|
+
this.newSel = selectionFromPoints(selPoints, this.bounds.from);
|
|
5475
|
+
}
|
|
5476
|
+
else {
|
|
5477
|
+
let domSel = view.observer.selectionRange;
|
|
5478
|
+
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
|
5479
|
+
!contains(view.contentDOM, domSel.focusNode)
|
|
5480
|
+
? view.state.selection.main.head
|
|
5481
|
+
: view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
|
5482
|
+
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
|
5483
|
+
!contains(view.contentDOM, domSel.anchorNode)
|
|
5484
|
+
? view.state.selection.main.anchor
|
|
5485
|
+
: view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
|
5486
|
+
this.newSel = EditorSelection.single(anchor, head);
|
|
5487
|
+
}
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
function applyDOMChange(view, domChange) {
|
|
5491
|
+
let change;
|
|
5492
|
+
let { newSel } = domChange, sel = view.state.selection.main;
|
|
5493
|
+
if (domChange.bounds) {
|
|
5494
|
+
let { from, to } = domChange.bounds;
|
|
5495
|
+
let preferredPos = sel.from, preferredSide = null;
|
|
5496
|
+
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5497
|
+
// Android, when something was deleted)
|
|
5498
|
+
if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
|
5499
|
+
browser.android && domChange.text.length < to - from) {
|
|
5500
|
+
preferredPos = sel.to;
|
|
5501
|
+
preferredSide = "end";
|
|
5502
|
+
}
|
|
5503
|
+
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), domChange.text, preferredPos - from, preferredSide);
|
|
5504
|
+
if (diff) {
|
|
5505
|
+
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5506
|
+
// end of a line. DomChange drops one of those.
|
|
5507
|
+
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5508
|
+
diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5509
|
+
diff.toB--;
|
|
5510
|
+
change = { from: from + diff.from, to: from + diff.toA,
|
|
5511
|
+
insert: Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5514
|
+
else if (newSel && (!view.hasFocus || !view.state.facet(editable) || newSel.main.eq(sel))) {
|
|
5515
|
+
newSel = null;
|
|
5516
|
+
}
|
|
5517
|
+
if (!change && !newSel)
|
|
5518
|
+
return false;
|
|
5519
|
+
if (!change && domChange.typeOver && !sel.empty && newSel && newSel.main.empty) {
|
|
5520
|
+
// Heuristic to notice typing over a selected character
|
|
5521
|
+
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
5522
|
+
}
|
|
5523
|
+
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
5524
|
+
(change.from != sel.from || change.to != sel.to) &&
|
|
5525
|
+
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
5526
|
+
// If the change is inside the selection and covers most of it,
|
|
5527
|
+
// assume it is a selection replace (with identical characters at
|
|
5528
|
+
// the start/end not included in the diff)
|
|
5529
|
+
change = {
|
|
5530
|
+
from: sel.from, to: sel.to,
|
|
5531
|
+
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
5532
|
+
};
|
|
5533
|
+
}
|
|
5534
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5535
|
+
/^\. ?$/.test(change.insert.toString())) {
|
|
5536
|
+
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5537
|
+
// and transform it into a regular space insert.
|
|
5538
|
+
if (newSel && change.insert.length == 2)
|
|
5539
|
+
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5540
|
+
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
5541
|
+
}
|
|
5542
|
+
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
5543
|
+
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
5544
|
+
// In Chrome, if you insert a space at the start of a wrapped
|
|
5545
|
+
// line, it will actually insert a newline and a space, causing a
|
|
5546
|
+
// bogus new line to be created in CodeMirror (#968)
|
|
5547
|
+
if (newSel)
|
|
5548
|
+
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5549
|
+
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
5550
|
+
}
|
|
5551
|
+
if (change) {
|
|
5552
|
+
let startState = view.state;
|
|
5553
|
+
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5554
|
+
return true;
|
|
5555
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
5556
|
+
// backspace, or delete. So this detects changes that look like
|
|
5557
|
+
// they're caused by those keys, and reinterprets them as key
|
|
5558
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
5559
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
5560
|
+
// reliable in all situations.)
|
|
5561
|
+
if (browser.android &&
|
|
5562
|
+
((change.from == sel.from && change.to == sel.to &&
|
|
5563
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
5564
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
5565
|
+
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5566
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5567
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5568
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5569
|
+
return true;
|
|
5570
|
+
let text = change.insert.toString();
|
|
5571
|
+
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5572
|
+
return true;
|
|
5573
|
+
if (view.inputState.composing >= 0)
|
|
5574
|
+
view.inputState.composing++;
|
|
5575
|
+
let tr;
|
|
5576
|
+
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5577
|
+
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5578
|
+
view.inputState.composing < 0) {
|
|
5579
|
+
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5580
|
+
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5581
|
+
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5582
|
+
}
|
|
5583
|
+
else {
|
|
5584
|
+
let changes = startState.changes(change);
|
|
5585
|
+
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5586
|
+
? newSel.main : undefined;
|
|
5587
|
+
// Try to apply a composition change to all cursors
|
|
5588
|
+
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5589
|
+
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5590
|
+
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5591
|
+
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5592
|
+
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5593
|
+
tr = startState.changeByRange(range => {
|
|
5594
|
+
if (range.from == sel.from && range.to == sel.to)
|
|
5595
|
+
return { changes, range: mainSel || range.map(changes) };
|
|
5596
|
+
let to = range.to - offset, from = to - replaced.length;
|
|
5597
|
+
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5598
|
+
// Unfortunately, there's no way to make multiple
|
|
5599
|
+
// changes in the same node work without aborting
|
|
5600
|
+
// composition, so cursors in the composition range are
|
|
5601
|
+
// ignored.
|
|
5602
|
+
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5603
|
+
return { range };
|
|
5604
|
+
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5605
|
+
return {
|
|
5606
|
+
changes: rangeChanges,
|
|
5607
|
+
range: !mainSel ? range.map(rangeChanges) :
|
|
5608
|
+
EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
5609
|
+
};
|
|
5610
|
+
});
|
|
5611
|
+
}
|
|
5612
|
+
else {
|
|
5613
|
+
tr = {
|
|
5614
|
+
changes,
|
|
5615
|
+
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
5616
|
+
};
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
let userEvent = "input.type";
|
|
5620
|
+
if (view.composing) {
|
|
5621
|
+
userEvent += ".compose";
|
|
5622
|
+
if (view.inputState.compositionFirstChange) {
|
|
5623
|
+
userEvent += ".start";
|
|
5624
|
+
view.inputState.compositionFirstChange = false;
|
|
5625
|
+
}
|
|
5626
|
+
}
|
|
5627
|
+
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
5628
|
+
return true;
|
|
5629
|
+
}
|
|
5630
|
+
else if (newSel && !newSel.main.eq(sel)) {
|
|
5631
|
+
let scrollIntoView = false, userEvent = "select";
|
|
5632
|
+
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
5633
|
+
if (view.inputState.lastSelectionOrigin == "select")
|
|
5634
|
+
scrollIntoView = true;
|
|
5635
|
+
userEvent = view.inputState.lastSelectionOrigin;
|
|
5636
|
+
}
|
|
5637
|
+
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
5638
|
+
return true;
|
|
5639
|
+
}
|
|
5640
|
+
else {
|
|
5641
|
+
return false;
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
5644
|
+
function findDiff(a, b, preferredPos, preferredSide) {
|
|
5645
|
+
let minLen = Math.min(a.length, b.length);
|
|
5646
|
+
let from = 0;
|
|
5647
|
+
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
|
5648
|
+
from++;
|
|
5649
|
+
if (from == minLen && a.length == b.length)
|
|
5650
|
+
return null;
|
|
5651
|
+
let toA = a.length, toB = b.length;
|
|
5652
|
+
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
|
5653
|
+
toA--;
|
|
5654
|
+
toB--;
|
|
5655
|
+
}
|
|
5656
|
+
if (preferredSide == "end") {
|
|
5657
|
+
let adjust = Math.max(0, from - Math.min(toA, toB));
|
|
5658
|
+
preferredPos -= toA + adjust - from;
|
|
5659
|
+
}
|
|
5660
|
+
if (toA < from && a.length < b.length) {
|
|
5661
|
+
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
|
5662
|
+
from -= move;
|
|
5663
|
+
toB = from + (toB - toA);
|
|
5664
|
+
toA = from;
|
|
5665
|
+
}
|
|
5666
|
+
else if (toB < from) {
|
|
5667
|
+
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
|
5668
|
+
from -= move;
|
|
5669
|
+
toA = from + (toA - toB);
|
|
5670
|
+
toB = from;
|
|
5671
|
+
}
|
|
5672
|
+
return { from, toA, toB };
|
|
5673
|
+
}
|
|
5674
|
+
function selectionPoints(view) {
|
|
5675
|
+
let result = [];
|
|
5676
|
+
if (view.root.activeElement != view.contentDOM)
|
|
5677
|
+
return result;
|
|
5678
|
+
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
|
5679
|
+
if (anchorNode) {
|
|
5680
|
+
result.push(new DOMPoint(anchorNode, anchorOffset));
|
|
5681
|
+
if (focusNode != anchorNode || focusOffset != anchorOffset)
|
|
5682
|
+
result.push(new DOMPoint(focusNode, focusOffset));
|
|
5683
|
+
}
|
|
5684
|
+
return result;
|
|
5685
|
+
}
|
|
5686
|
+
function selectionFromPoints(points, base) {
|
|
5687
|
+
if (points.length == 0)
|
|
5688
|
+
return null;
|
|
5689
|
+
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
5690
|
+
return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
|
|
5691
|
+
}
|
|
5692
|
+
|
|
5448
5693
|
const observeOptions = {
|
|
5449
5694
|
childList: true,
|
|
5450
5695
|
characterData: true,
|
|
@@ -5456,10 +5701,8 @@ const observeOptions = {
|
|
|
5456
5701
|
// DOMCharacterDataModified there
|
|
5457
5702
|
const useCharData = browser.ie && browser.ie_version <= 11;
|
|
5458
5703
|
class DOMObserver {
|
|
5459
|
-
constructor(view
|
|
5704
|
+
constructor(view) {
|
|
5460
5705
|
this.view = view;
|
|
5461
|
-
this.onChange = onChange;
|
|
5462
|
-
this.onScrollChanged = onScrollChanged;
|
|
5463
5706
|
this.active = false;
|
|
5464
5707
|
// The known selection. Kept in our own object, as opposed to just
|
|
5465
5708
|
// directly accessing the selection because:
|
|
@@ -5474,6 +5717,7 @@ class DOMObserver {
|
|
|
5474
5717
|
this.resizeTimeout = -1;
|
|
5475
5718
|
this.queue = [];
|
|
5476
5719
|
this.delayedAndroidKey = null;
|
|
5720
|
+
this.flushingAndroidKey = -1;
|
|
5477
5721
|
this.lastChange = 0;
|
|
5478
5722
|
this.scrollTargets = [];
|
|
5479
5723
|
this.intersection = null;
|
|
@@ -5542,6 +5786,11 @@ class DOMObserver {
|
|
|
5542
5786
|
this.listenForScroll();
|
|
5543
5787
|
this.readSelectionRange();
|
|
5544
5788
|
}
|
|
5789
|
+
onScrollChanged(e) {
|
|
5790
|
+
this.view.inputState.runScrollHandlers(this.view, e);
|
|
5791
|
+
if (this.intersecting)
|
|
5792
|
+
this.view.measure();
|
|
5793
|
+
}
|
|
5545
5794
|
onScroll(e) {
|
|
5546
5795
|
if (this.intersecting)
|
|
5547
5796
|
this.flush(false);
|
|
@@ -5701,14 +5950,17 @@ class DOMObserver {
|
|
|
5701
5950
|
// them or, if that has no effect, dispatches the given key.
|
|
5702
5951
|
delayAndroidKey(key, keyCode) {
|
|
5703
5952
|
var _a;
|
|
5704
|
-
if (!this.delayedAndroidKey)
|
|
5705
|
-
|
|
5953
|
+
if (!this.delayedAndroidKey) {
|
|
5954
|
+
let flush = () => {
|
|
5706
5955
|
let key = this.delayedAndroidKey;
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5956
|
+
if (key) {
|
|
5957
|
+
this.clearDelayedAndroidKey();
|
|
5958
|
+
if (!this.flush() && key.force)
|
|
5959
|
+
dispatchKey(this.dom, key.key, key.keyCode);
|
|
5960
|
+
}
|
|
5961
|
+
};
|
|
5962
|
+
this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush);
|
|
5963
|
+
}
|
|
5712
5964
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5713
5965
|
// Enter always takes precedence.
|
|
5714
5966
|
if (!this.delayedAndroidKey || key == "Enter")
|
|
@@ -5721,6 +5973,11 @@ class DOMObserver {
|
|
|
5721
5973
|
force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force)
|
|
5722
5974
|
};
|
|
5723
5975
|
}
|
|
5976
|
+
clearDelayedAndroidKey() {
|
|
5977
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
5978
|
+
this.delayedAndroidKey = null;
|
|
5979
|
+
this.flushingAndroidKey = -1;
|
|
5980
|
+
}
|
|
5724
5981
|
flushSoon() {
|
|
5725
5982
|
if (this.delayedFlush < 0)
|
|
5726
5983
|
this.delayedFlush = this.view.win.requestAnimationFrame(() => { this.delayedFlush = -1; this.flush(); });
|
|
@@ -5755,6 +6012,17 @@ class DOMObserver {
|
|
|
5755
6012
|
}
|
|
5756
6013
|
return { from, to, typeOver };
|
|
5757
6014
|
}
|
|
6015
|
+
readChange() {
|
|
6016
|
+
let { from, to, typeOver } = this.processRecords();
|
|
6017
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
6018
|
+
if (from < 0 && !newSel)
|
|
6019
|
+
return null;
|
|
6020
|
+
if (from > -1)
|
|
6021
|
+
this.lastChange = Date.now();
|
|
6022
|
+
this.view.inputState.lastFocusTime = 0;
|
|
6023
|
+
this.selectionChanged = false;
|
|
6024
|
+
return new DOMChange(this.view, from, to, typeOver);
|
|
6025
|
+
}
|
|
5758
6026
|
// Apply pending changes, if any
|
|
5759
6027
|
flush(readSelection = true) {
|
|
5760
6028
|
// Completely hold off flushing when pending keys are set—the code
|
|
@@ -5764,16 +6032,11 @@ class DOMObserver {
|
|
|
5764
6032
|
return false;
|
|
5765
6033
|
if (readSelection)
|
|
5766
6034
|
this.readSelectionRange();
|
|
5767
|
-
let
|
|
5768
|
-
|
|
5769
|
-
if (from < 0 && !newSel)
|
|
6035
|
+
let domChange = this.readChange();
|
|
6036
|
+
if (!domChange)
|
|
5770
6037
|
return false;
|
|
5771
|
-
if (from > -1)
|
|
5772
|
-
this.lastChange = Date.now();
|
|
5773
|
-
this.view.inputState.lastFocusTime = 0;
|
|
5774
|
-
this.selectionChanged = false;
|
|
5775
6038
|
let startState = this.view.state;
|
|
5776
|
-
let handled = this.
|
|
6039
|
+
let handled = applyDOMChange(this.view, domChange);
|
|
5777
6040
|
// The view wasn't updated
|
|
5778
6041
|
if (this.view.state == startState)
|
|
5779
6042
|
this.view.update([]);
|
|
@@ -5829,6 +6092,8 @@ class DOMObserver {
|
|
|
5829
6092
|
this.removeWindowListeners(this.win);
|
|
5830
6093
|
clearTimeout(this.parentCheck);
|
|
5831
6094
|
clearTimeout(this.resizeTimeout);
|
|
6095
|
+
this.win.cancelAnimationFrame(this.delayedFlush);
|
|
6096
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
5832
6097
|
}
|
|
5833
6098
|
}
|
|
5834
6099
|
function findChild(cView, dom, dir) {
|
|
@@ -5870,218 +6135,6 @@ function safariSelectionRangeHack(view) {
|
|
|
5870
6135
|
return { anchorNode, anchorOffset, focusNode, focusOffset };
|
|
5871
6136
|
}
|
|
5872
6137
|
|
|
5873
|
-
function applyDOMChange(view, start, end, typeOver) {
|
|
5874
|
-
let change, newSel;
|
|
5875
|
-
let sel = view.state.selection.main;
|
|
5876
|
-
if (start > -1) {
|
|
5877
|
-
let bounds = view.docView.domBoundsAround(start, end, 0);
|
|
5878
|
-
if (!bounds || view.state.readOnly)
|
|
5879
|
-
return false;
|
|
5880
|
-
let { from, to } = bounds;
|
|
5881
|
-
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5882
|
-
let reader = new DOMReader(selPoints, view.state);
|
|
5883
|
-
reader.readRange(bounds.startDOM, bounds.endDOM);
|
|
5884
|
-
let preferredPos = sel.from, preferredSide = null;
|
|
5885
|
-
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5886
|
-
// Android, when something was deleted)
|
|
5887
|
-
if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
|
5888
|
-
browser.android && reader.text.length < to - from) {
|
|
5889
|
-
preferredPos = sel.to;
|
|
5890
|
-
preferredSide = "end";
|
|
5891
|
-
}
|
|
5892
|
-
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5893
|
-
if (diff) {
|
|
5894
|
-
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5895
|
-
// end of a line. This drops one of those.
|
|
5896
|
-
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5897
|
-
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5898
|
-
diff.toB--;
|
|
5899
|
-
change = { from: from + diff.from, to: from + diff.toA,
|
|
5900
|
-
insert: Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5901
|
-
}
|
|
5902
|
-
newSel = selectionFromPoints(selPoints, from);
|
|
5903
|
-
}
|
|
5904
|
-
else if (view.hasFocus || !view.state.facet(editable)) {
|
|
5905
|
-
let domSel = view.observer.selectionRange;
|
|
5906
|
-
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
5907
|
-
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
|
5908
|
-
!contains(view.contentDOM, domSel.focusNode)
|
|
5909
|
-
? view.state.selection.main.head
|
|
5910
|
-
: view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
|
5911
|
-
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
|
5912
|
-
!contains(view.contentDOM, domSel.anchorNode)
|
|
5913
|
-
? view.state.selection.main.anchor
|
|
5914
|
-
: view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
|
5915
|
-
if (head != sel.head || anchor != sel.anchor)
|
|
5916
|
-
newSel = EditorSelection.single(anchor, head);
|
|
5917
|
-
}
|
|
5918
|
-
if (!change && !newSel)
|
|
5919
|
-
return false;
|
|
5920
|
-
if (!change && typeOver && !sel.empty && newSel && newSel.main.empty) {
|
|
5921
|
-
// Heuristic to notice typing over a selected character
|
|
5922
|
-
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
5923
|
-
}
|
|
5924
|
-
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
5925
|
-
(change.from != sel.from || change.to != sel.to) &&
|
|
5926
|
-
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
5927
|
-
// If the change is inside the selection and covers most of it,
|
|
5928
|
-
// assume it is a selection replace (with identical characters at
|
|
5929
|
-
// the start/end not included in the diff)
|
|
5930
|
-
change = {
|
|
5931
|
-
from: sel.from, to: sel.to,
|
|
5932
|
-
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
5933
|
-
};
|
|
5934
|
-
}
|
|
5935
|
-
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5936
|
-
/^\. ?$/.test(change.insert.toString())) {
|
|
5937
|
-
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5938
|
-
// and transform it into a regular space insert.
|
|
5939
|
-
if (newSel && change.insert.length == 2)
|
|
5940
|
-
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5941
|
-
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
5942
|
-
}
|
|
5943
|
-
if (change) {
|
|
5944
|
-
let startState = view.state;
|
|
5945
|
-
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5946
|
-
return true;
|
|
5947
|
-
// Android browsers don't fire reasonable key events for enter,
|
|
5948
|
-
// backspace, or delete. So this detects changes that look like
|
|
5949
|
-
// they're caused by those keys, and reinterprets them as key
|
|
5950
|
-
// events. (Some of these keys are also handled by beforeinput
|
|
5951
|
-
// events and the pendingAndroidKey mechanism, but that's not
|
|
5952
|
-
// reliable in all situations.)
|
|
5953
|
-
if (browser.android &&
|
|
5954
|
-
((change.from == sel.from && change.to == sel.to &&
|
|
5955
|
-
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
5956
|
-
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
5957
|
-
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5958
|
-
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5959
|
-
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5960
|
-
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5961
|
-
return true;
|
|
5962
|
-
let text = change.insert.toString();
|
|
5963
|
-
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5964
|
-
return true;
|
|
5965
|
-
if (view.inputState.composing >= 0)
|
|
5966
|
-
view.inputState.composing++;
|
|
5967
|
-
let tr;
|
|
5968
|
-
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5969
|
-
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5970
|
-
view.inputState.composing < 0) {
|
|
5971
|
-
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5972
|
-
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5973
|
-
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5974
|
-
}
|
|
5975
|
-
else {
|
|
5976
|
-
let changes = startState.changes(change);
|
|
5977
|
-
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5978
|
-
? newSel.main : undefined;
|
|
5979
|
-
// Try to apply a composition change to all cursors
|
|
5980
|
-
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5981
|
-
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5982
|
-
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5983
|
-
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5984
|
-
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5985
|
-
tr = startState.changeByRange(range => {
|
|
5986
|
-
if (range.from == sel.from && range.to == sel.to)
|
|
5987
|
-
return { changes, range: mainSel || range.map(changes) };
|
|
5988
|
-
let to = range.to - offset, from = to - replaced.length;
|
|
5989
|
-
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5990
|
-
// Unfortunately, there's no way to make multiple
|
|
5991
|
-
// changes in the same node work without aborting
|
|
5992
|
-
// composition, so cursors in the composition range are
|
|
5993
|
-
// ignored.
|
|
5994
|
-
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5995
|
-
return { range };
|
|
5996
|
-
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5997
|
-
return {
|
|
5998
|
-
changes: rangeChanges,
|
|
5999
|
-
range: !mainSel ? range.map(rangeChanges) :
|
|
6000
|
-
EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
6001
|
-
};
|
|
6002
|
-
});
|
|
6003
|
-
}
|
|
6004
|
-
else {
|
|
6005
|
-
tr = {
|
|
6006
|
-
changes,
|
|
6007
|
-
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
6008
|
-
};
|
|
6009
|
-
}
|
|
6010
|
-
}
|
|
6011
|
-
let userEvent = "input.type";
|
|
6012
|
-
if (view.composing) {
|
|
6013
|
-
userEvent += ".compose";
|
|
6014
|
-
if (view.inputState.compositionFirstChange) {
|
|
6015
|
-
userEvent += ".start";
|
|
6016
|
-
view.inputState.compositionFirstChange = false;
|
|
6017
|
-
}
|
|
6018
|
-
}
|
|
6019
|
-
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
6020
|
-
return true;
|
|
6021
|
-
}
|
|
6022
|
-
else if (newSel && !newSel.main.eq(sel)) {
|
|
6023
|
-
let scrollIntoView = false, userEvent = "select";
|
|
6024
|
-
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
6025
|
-
if (view.inputState.lastSelectionOrigin == "select")
|
|
6026
|
-
scrollIntoView = true;
|
|
6027
|
-
userEvent = view.inputState.lastSelectionOrigin;
|
|
6028
|
-
}
|
|
6029
|
-
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
6030
|
-
return true;
|
|
6031
|
-
}
|
|
6032
|
-
else {
|
|
6033
|
-
return false;
|
|
6034
|
-
}
|
|
6035
|
-
}
|
|
6036
|
-
function findDiff(a, b, preferredPos, preferredSide) {
|
|
6037
|
-
let minLen = Math.min(a.length, b.length);
|
|
6038
|
-
let from = 0;
|
|
6039
|
-
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
|
6040
|
-
from++;
|
|
6041
|
-
if (from == minLen && a.length == b.length)
|
|
6042
|
-
return null;
|
|
6043
|
-
let toA = a.length, toB = b.length;
|
|
6044
|
-
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
|
6045
|
-
toA--;
|
|
6046
|
-
toB--;
|
|
6047
|
-
}
|
|
6048
|
-
if (preferredSide == "end") {
|
|
6049
|
-
let adjust = Math.max(0, from - Math.min(toA, toB));
|
|
6050
|
-
preferredPos -= toA + adjust - from;
|
|
6051
|
-
}
|
|
6052
|
-
if (toA < from && a.length < b.length) {
|
|
6053
|
-
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
|
6054
|
-
from -= move;
|
|
6055
|
-
toB = from + (toB - toA);
|
|
6056
|
-
toA = from;
|
|
6057
|
-
}
|
|
6058
|
-
else if (toB < from) {
|
|
6059
|
-
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
|
6060
|
-
from -= move;
|
|
6061
|
-
toA = from + (toA - toB);
|
|
6062
|
-
toB = from;
|
|
6063
|
-
}
|
|
6064
|
-
return { from, toA, toB };
|
|
6065
|
-
}
|
|
6066
|
-
function selectionPoints(view) {
|
|
6067
|
-
let result = [];
|
|
6068
|
-
if (view.root.activeElement != view.contentDOM)
|
|
6069
|
-
return result;
|
|
6070
|
-
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
|
6071
|
-
if (anchorNode) {
|
|
6072
|
-
result.push(new DOMPoint(anchorNode, anchorOffset));
|
|
6073
|
-
if (focusNode != anchorNode || focusOffset != anchorOffset)
|
|
6074
|
-
result.push(new DOMPoint(focusNode, focusOffset));
|
|
6075
|
-
}
|
|
6076
|
-
return result;
|
|
6077
|
-
}
|
|
6078
|
-
function selectionFromPoints(points, base) {
|
|
6079
|
-
if (points.length == 0)
|
|
6080
|
-
return null;
|
|
6081
|
-
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
6082
|
-
return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
|
|
6083
|
-
}
|
|
6084
|
-
|
|
6085
6138
|
// The editor's update state machine looks something like this:
|
|
6086
6139
|
//
|
|
6087
6140
|
// Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle
|
|
@@ -6144,13 +6197,7 @@ class EditorView {
|
|
|
6144
6197
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
|
6145
6198
|
for (let plugin of this.plugins)
|
|
6146
6199
|
plugin.update(this);
|
|
6147
|
-
this.observer = new DOMObserver(this
|
|
6148
|
-
return applyDOMChange(this, from, to, typeOver);
|
|
6149
|
-
}, event => {
|
|
6150
|
-
this.inputState.runScrollHandlers(this, event);
|
|
6151
|
-
if (this.observer.intersecting)
|
|
6152
|
-
this.measure();
|
|
6153
|
-
});
|
|
6200
|
+
this.observer = new DOMObserver(this);
|
|
6154
6201
|
this.inputState = new InputState(this);
|
|
6155
6202
|
this.inputState.ensureHandlers(this, this.plugins);
|
|
6156
6203
|
this.docView = new DocView(this);
|
|
@@ -6234,7 +6281,20 @@ class EditorView {
|
|
|
6234
6281
|
this.viewState.state = state;
|
|
6235
6282
|
return;
|
|
6236
6283
|
}
|
|
6237
|
-
|
|
6284
|
+
// If there was a pending DOM change, eagerly read it and try to
|
|
6285
|
+
// apply it after the given transactions.
|
|
6286
|
+
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
|
|
6287
|
+
if (pendingKey) {
|
|
6288
|
+
this.observer.clearDelayedAndroidKey();
|
|
6289
|
+
domChange = this.observer.readChange();
|
|
6290
|
+
// Only try to apply DOM changes if the transactions didn't
|
|
6291
|
+
// change the doc or selection.
|
|
6292
|
+
if (domChange && !this.state.doc.eq(state.doc) || !this.state.selection.eq(state.selection))
|
|
6293
|
+
domChange = null;
|
|
6294
|
+
}
|
|
6295
|
+
else {
|
|
6296
|
+
this.observer.clear();
|
|
6297
|
+
}
|
|
6238
6298
|
// When the phrases change, redraw the editor
|
|
6239
6299
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
6240
6300
|
return this.setState(state);
|
|
@@ -6276,6 +6336,10 @@ class EditorView {
|
|
|
6276
6336
|
if (!update.empty)
|
|
6277
6337
|
for (let listener of this.state.facet(updateListener))
|
|
6278
6338
|
listener(update);
|
|
6339
|
+
if (domChange) {
|
|
6340
|
+
if (!applyDOMChange(this, domChange) && pendingKey.force)
|
|
6341
|
+
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
|
|
6342
|
+
}
|
|
6279
6343
|
}
|
|
6280
6344
|
/**
|
|
6281
6345
|
Reset the view to the given state. (This will cause the entire
|
|
@@ -6408,17 +6472,19 @@ class EditorView {
|
|
|
6408
6472
|
logException(this.state, e);
|
|
6409
6473
|
}
|
|
6410
6474
|
}
|
|
6411
|
-
if (this.viewState.
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
}
|
|
6416
|
-
else {
|
|
6417
|
-
let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
|
|
6418
|
-
if (diff > 1 || diff < -1) {
|
|
6419
|
-
this.scrollDOM.scrollTop += diff;
|
|
6475
|
+
if (this.viewState.editorHeight) {
|
|
6476
|
+
if (this.viewState.scrollTarget) {
|
|
6477
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6478
|
+
this.viewState.scrollTarget = null;
|
|
6420
6479
|
scrolled = true;
|
|
6421
6480
|
}
|
|
6481
|
+
else {
|
|
6482
|
+
let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
|
|
6483
|
+
if (diff > 1 || diff < -1) {
|
|
6484
|
+
this.scrollDOM.scrollTop += diff;
|
|
6485
|
+
scrolled = true;
|
|
6486
|
+
}
|
|
6487
|
+
}
|
|
6422
6488
|
}
|
|
6423
6489
|
if (redrawn)
|
|
6424
6490
|
this.docView.updateSelection(true);
|
|
@@ -7824,7 +7890,8 @@ const plugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
7824
7890
|
this.attrs = { style: "padding-bottom: 1000px" };
|
|
7825
7891
|
}
|
|
7826
7892
|
update(update) {
|
|
7827
|
-
let
|
|
7893
|
+
let { view } = update;
|
|
7894
|
+
let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
|
|
7828
7895
|
if (height != this.height) {
|
|
7829
7896
|
this.height = height;
|
|
7830
7897
|
this.attrs = { style: `padding-bottom: ${height}px` };
|
|
@@ -7926,7 +7993,10 @@ function rectangleFor(state, a, b) {
|
|
|
7926
7993
|
for (let i = startLine; i <= endLine; i++) {
|
|
7927
7994
|
let line = state.doc.line(i);
|
|
7928
7995
|
let start = findColumn(line.text, startCol, state.tabSize, true);
|
|
7929
|
-
if (start
|
|
7996
|
+
if (start < 0) {
|
|
7997
|
+
ranges.push(EditorSelection.cursor(line.to));
|
|
7998
|
+
}
|
|
7999
|
+
else {
|
|
7930
8000
|
let end = findColumn(line.text, endCol, state.tabSize);
|
|
7931
8001
|
ranges.push(EditorSelection.range(line.from + start, line.from + end));
|
|
7932
8002
|
}
|
|
@@ -8038,6 +8108,7 @@ class TooltipViewManager {
|
|
|
8038
8108
|
this.tooltipViews = this.tooltips.map(createTooltipView);
|
|
8039
8109
|
}
|
|
8040
8110
|
update(update) {
|
|
8111
|
+
var _a;
|
|
8041
8112
|
let input = update.state.facet(this.facet);
|
|
8042
8113
|
let tooltips = input.filter(x => x);
|
|
8043
8114
|
if (input === this.input) {
|
|
@@ -8066,8 +8137,10 @@ class TooltipViewManager {
|
|
|
8066
8137
|
}
|
|
8067
8138
|
}
|
|
8068
8139
|
for (let t of this.tooltipViews)
|
|
8069
|
-
if (tooltipViews.indexOf(t) < 0)
|
|
8140
|
+
if (tooltipViews.indexOf(t) < 0) {
|
|
8070
8141
|
t.dom.remove();
|
|
8142
|
+
(_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
|
|
8143
|
+
}
|
|
8071
8144
|
this.input = input;
|
|
8072
8145
|
this.tooltips = tooltips;
|
|
8073
8146
|
this.tooltipViews = tooltipViews;
|
|
@@ -8186,11 +8259,13 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
8186
8259
|
return tooltipView;
|
|
8187
8260
|
}
|
|
8188
8261
|
destroy() {
|
|
8189
|
-
var _a;
|
|
8262
|
+
var _a, _b;
|
|
8190
8263
|
this.view.win.removeEventListener("resize", this.measureSoon);
|
|
8191
|
-
for (let
|
|
8192
|
-
dom.remove();
|
|
8193
|
-
|
|
8264
|
+
for (let tooltipView of this.manager.tooltipViews) {
|
|
8265
|
+
tooltipView.dom.remove();
|
|
8266
|
+
(_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
|
|
8267
|
+
}
|
|
8268
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
8194
8269
|
clearTimeout(this.measureTimeout);
|
|
8195
8270
|
}
|
|
8196
8271
|
readMeasure() {
|