@codemirror/view 6.3.0 → 6.3.1
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 +12 -0
- package/dist/index.cjs +341 -260
- package/dist/index.js +341 -260
- 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,59 @@ 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
|
+
if (!view.children.length)
|
|
1058
|
+
return fallbackRect(view);
|
|
1059
|
+
return (side <= 0 ? coordsInChildrenBefore : coordsInChildrenAfter)(view, pos);
|
|
1060
|
+
}
|
|
1061
|
+
function coordsInChildrenBefore(view, pos) {
|
|
1062
|
+
// Find the last leaf in the tree that touches pos and doesn't have getSide() > 0
|
|
1063
|
+
let found = null, foundPos = -1;
|
|
1064
|
+
function scan(view, pos) {
|
|
1065
|
+
for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
|
|
1066
|
+
let child = view.children[i], end = off + child.length;
|
|
1067
|
+
if (end >= pos) {
|
|
1068
|
+
if (child.children.length) {
|
|
1069
|
+
if (scan(child, pos - off))
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
1072
|
+
else if (end >= pos) {
|
|
1073
|
+
if (end == pos && child.getSide() > 0)
|
|
1074
|
+
return true;
|
|
1075
|
+
found = child;
|
|
1076
|
+
foundPos = pos - off;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
off = end;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
scan(view, pos);
|
|
1083
|
+
return found ? found.coordsAt(Math.max(0, foundPos), -1) : coordsInChildrenAfter(view, pos);
|
|
1084
|
+
}
|
|
1085
|
+
function coordsInChildrenAfter(view, pos) {
|
|
1086
|
+
// Find the first leaf in the tree that touches pos and doesn't have getSide() < 0
|
|
1087
|
+
let found = null, foundPos = -1;
|
|
1088
|
+
function scan(view, pos) {
|
|
1089
|
+
for (let i = view.children.length - 1, off = view.length; i >= 0 && off >= pos; i--) {
|
|
1090
|
+
let child = view.children[i];
|
|
1091
|
+
off -= child.length;
|
|
1092
|
+
if (off <= pos) {
|
|
1093
|
+
if (child.children.length) {
|
|
1094
|
+
if (scan(child, pos - off))
|
|
1095
|
+
return true;
|
|
1096
|
+
}
|
|
1097
|
+
else if (off <= pos) {
|
|
1098
|
+
if (off == pos && child.getSide() < 0)
|
|
1099
|
+
return true;
|
|
1100
|
+
found = child;
|
|
1101
|
+
foundPos = pos - off;
|
|
1102
|
+
}
|
|
1067
1103
|
}
|
|
1068
|
-
let rect = child.coordsAt(Math.max(0, pos - off), side);
|
|
1069
|
-
return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
|
1070
1104
|
}
|
|
1071
|
-
off = end;
|
|
1072
1105
|
}
|
|
1106
|
+
scan(view, pos);
|
|
1107
|
+
return found ? found.coordsAt(Math.max(0, foundPos), 1) : coordsInChildrenBefore(view, pos);
|
|
1108
|
+
}
|
|
1109
|
+
function fallbackRect(view) {
|
|
1073
1110
|
let last = view.dom.lastChild;
|
|
1074
1111
|
if (!last)
|
|
1075
1112
|
return view.dom.getBoundingClientRect();
|
|
@@ -1688,7 +1725,7 @@ class ContentBuilder {
|
|
|
1688
1725
|
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1689
1726
|
}
|
|
1690
1727
|
else {
|
|
1691
|
-
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1728
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
1692
1729
|
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1693
1730
|
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1694
1731
|
let line = this.getLine();
|
|
@@ -4883,7 +4920,7 @@ class ViewState {
|
|
|
4883
4920
|
refresh = true;
|
|
4884
4921
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4885
4922
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4886
|
-
refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4923
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4887
4924
|
if (refresh) {
|
|
4888
4925
|
view.docView.minWidth = 0;
|
|
4889
4926
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
@@ -5027,8 +5064,10 @@ class ViewState {
|
|
|
5027
5064
|
let marginHeight = (margin / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
|
|
5028
5065
|
let top, bot;
|
|
5029
5066
|
if (target != null) {
|
|
5030
|
-
|
|
5031
|
-
|
|
5067
|
+
let targetFrac = findFraction(structure, target);
|
|
5068
|
+
let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.height;
|
|
5069
|
+
top = targetFrac - spaceFrac;
|
|
5070
|
+
bot = targetFrac + spaceFrac;
|
|
5032
5071
|
}
|
|
5033
5072
|
else {
|
|
5034
5073
|
top = (this.visibleTop - line.top - marginHeight) / line.height;
|
|
@@ -5038,14 +5077,16 @@ class ViewState {
|
|
|
5038
5077
|
viewTo = findPosition(structure, bot);
|
|
5039
5078
|
}
|
|
5040
5079
|
else {
|
|
5080
|
+
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5081
|
+
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5041
5082
|
let left, right;
|
|
5042
5083
|
if (target != null) {
|
|
5043
|
-
|
|
5044
|
-
|
|
5084
|
+
let targetFrac = findFraction(structure, target);
|
|
5085
|
+
let spaceFrac = ((this.pixelViewport.right - this.pixelViewport.left) / 2 + marginWidth) / totalWidth;
|
|
5086
|
+
left = targetFrac - spaceFrac;
|
|
5087
|
+
right = targetFrac + spaceFrac;
|
|
5045
5088
|
}
|
|
5046
5089
|
else {
|
|
5047
|
-
let totalWidth = structure.total * this.heightOracle.charWidth;
|
|
5048
|
-
let marginWidth = margin * this.heightOracle.charWidth;
|
|
5049
5090
|
left = (this.pixelViewport.left - marginWidth) / totalWidth;
|
|
5050
5091
|
right = (this.pixelViewport.right + marginWidth) / totalWidth;
|
|
5051
5092
|
}
|
|
@@ -5452,6 +5493,227 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
|
|
|
5452
5493
|
}
|
|
5453
5494
|
}, lightDarkIDs);
|
|
5454
5495
|
|
|
5496
|
+
class DOMChange {
|
|
5497
|
+
constructor(view, start, end, typeOver) {
|
|
5498
|
+
this.typeOver = typeOver;
|
|
5499
|
+
this.bounds = null;
|
|
5500
|
+
this.text = "";
|
|
5501
|
+
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
|
5502
|
+
if (start > -1 && !view.state.readOnly && (this.bounds = view.docView.domBoundsAround(start, end, 0))) {
|
|
5503
|
+
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
|
|
5504
|
+
let reader = new DOMReader(selPoints, view.state);
|
|
5505
|
+
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
|
|
5506
|
+
this.text = reader.text;
|
|
5507
|
+
this.newSel = selectionFromPoints(selPoints, this.bounds.from);
|
|
5508
|
+
}
|
|
5509
|
+
else {
|
|
5510
|
+
let domSel = view.observer.selectionRange;
|
|
5511
|
+
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
|
5512
|
+
!contains(view.contentDOM, domSel.focusNode)
|
|
5513
|
+
? view.state.selection.main.head
|
|
5514
|
+
: view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
|
5515
|
+
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
|
5516
|
+
!contains(view.contentDOM, domSel.anchorNode)
|
|
5517
|
+
? view.state.selection.main.anchor
|
|
5518
|
+
: view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
|
5519
|
+
this.newSel = state.EditorSelection.single(anchor, head);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5523
|
+
function applyDOMChange(view, domChange) {
|
|
5524
|
+
let change;
|
|
5525
|
+
let { newSel } = domChange, sel = view.state.selection.main;
|
|
5526
|
+
if (domChange.bounds) {
|
|
5527
|
+
let { from, to } = domChange.bounds;
|
|
5528
|
+
let preferredPos = sel.from, preferredSide = null;
|
|
5529
|
+
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5530
|
+
// Android, when something was deleted)
|
|
5531
|
+
if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
|
5532
|
+
browser.android && domChange.text.length < to - from) {
|
|
5533
|
+
preferredPos = sel.to;
|
|
5534
|
+
preferredSide = "end";
|
|
5535
|
+
}
|
|
5536
|
+
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), domChange.text, preferredPos - from, preferredSide);
|
|
5537
|
+
if (diff) {
|
|
5538
|
+
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5539
|
+
// end of a line. DomChange drops one of those.
|
|
5540
|
+
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5541
|
+
diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5542
|
+
diff.toB--;
|
|
5543
|
+
change = { from: from + diff.from, to: from + diff.toA,
|
|
5544
|
+
insert: state.Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
else if (newSel && (!view.hasFocus || !view.state.facet(editable) || newSel.main.eq(sel))) {
|
|
5548
|
+
newSel = null;
|
|
5549
|
+
}
|
|
5550
|
+
if (!change && !newSel)
|
|
5551
|
+
return false;
|
|
5552
|
+
if (!change && domChange.typeOver && !sel.empty && newSel && newSel.main.empty) {
|
|
5553
|
+
// Heuristic to notice typing over a selected character
|
|
5554
|
+
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
5555
|
+
}
|
|
5556
|
+
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
5557
|
+
(change.from != sel.from || change.to != sel.to) &&
|
|
5558
|
+
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
5559
|
+
// If the change is inside the selection and covers most of it,
|
|
5560
|
+
// assume it is a selection replace (with identical characters at
|
|
5561
|
+
// the start/end not included in the diff)
|
|
5562
|
+
change = {
|
|
5563
|
+
from: sel.from, to: sel.to,
|
|
5564
|
+
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5568
|
+
/^\. ?$/.test(change.insert.toString())) {
|
|
5569
|
+
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5570
|
+
// and transform it into a regular space insert.
|
|
5571
|
+
if (newSel && change.insert.length == 2)
|
|
5572
|
+
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
5573
|
+
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
5574
|
+
}
|
|
5575
|
+
if (change) {
|
|
5576
|
+
let startState = view.state;
|
|
5577
|
+
if (browser.ios && view.inputState.flushIOSKey(view))
|
|
5578
|
+
return true;
|
|
5579
|
+
// Android browsers don't fire reasonable key events for enter,
|
|
5580
|
+
// backspace, or delete. So this detects changes that look like
|
|
5581
|
+
// they're caused by those keys, and reinterprets them as key
|
|
5582
|
+
// events. (Some of these keys are also handled by beforeinput
|
|
5583
|
+
// events and the pendingAndroidKey mechanism, but that's not
|
|
5584
|
+
// reliable in all situations.)
|
|
5585
|
+
if (browser.android &&
|
|
5586
|
+
((change.from == sel.from && change.to == sel.to &&
|
|
5587
|
+
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
5588
|
+
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
5589
|
+
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5590
|
+
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5591
|
+
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5592
|
+
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
5593
|
+
return true;
|
|
5594
|
+
let text = change.insert.toString();
|
|
5595
|
+
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5596
|
+
return true;
|
|
5597
|
+
if (view.inputState.composing >= 0)
|
|
5598
|
+
view.inputState.composing++;
|
|
5599
|
+
let tr;
|
|
5600
|
+
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5601
|
+
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5602
|
+
view.inputState.composing < 0) {
|
|
5603
|
+
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5604
|
+
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5605
|
+
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5606
|
+
}
|
|
5607
|
+
else {
|
|
5608
|
+
let changes = startState.changes(change);
|
|
5609
|
+
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5610
|
+
? newSel.main : undefined;
|
|
5611
|
+
// Try to apply a composition change to all cursors
|
|
5612
|
+
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5613
|
+
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5614
|
+
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5615
|
+
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5616
|
+
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5617
|
+
tr = startState.changeByRange(range => {
|
|
5618
|
+
if (range.from == sel.from && range.to == sel.to)
|
|
5619
|
+
return { changes, range: mainSel || range.map(changes) };
|
|
5620
|
+
let to = range.to - offset, from = to - replaced.length;
|
|
5621
|
+
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5622
|
+
// Unfortunately, there's no way to make multiple
|
|
5623
|
+
// changes in the same node work without aborting
|
|
5624
|
+
// composition, so cursors in the composition range are
|
|
5625
|
+
// ignored.
|
|
5626
|
+
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5627
|
+
return { range };
|
|
5628
|
+
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5629
|
+
return {
|
|
5630
|
+
changes: rangeChanges,
|
|
5631
|
+
range: !mainSel ? range.map(rangeChanges) :
|
|
5632
|
+
state.EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
5633
|
+
};
|
|
5634
|
+
});
|
|
5635
|
+
}
|
|
5636
|
+
else {
|
|
5637
|
+
tr = {
|
|
5638
|
+
changes,
|
|
5639
|
+
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
5640
|
+
};
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
let userEvent = "input.type";
|
|
5644
|
+
if (view.composing) {
|
|
5645
|
+
userEvent += ".compose";
|
|
5646
|
+
if (view.inputState.compositionFirstChange) {
|
|
5647
|
+
userEvent += ".start";
|
|
5648
|
+
view.inputState.compositionFirstChange = false;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
view.dispatch(tr, { scrollIntoView: true, userEvent });
|
|
5652
|
+
return true;
|
|
5653
|
+
}
|
|
5654
|
+
else if (newSel && !newSel.main.eq(sel)) {
|
|
5655
|
+
let scrollIntoView = false, userEvent = "select";
|
|
5656
|
+
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
5657
|
+
if (view.inputState.lastSelectionOrigin == "select")
|
|
5658
|
+
scrollIntoView = true;
|
|
5659
|
+
userEvent = view.inputState.lastSelectionOrigin;
|
|
5660
|
+
}
|
|
5661
|
+
view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
|
5662
|
+
return true;
|
|
5663
|
+
}
|
|
5664
|
+
else {
|
|
5665
|
+
return false;
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
function findDiff(a, b, preferredPos, preferredSide) {
|
|
5669
|
+
let minLen = Math.min(a.length, b.length);
|
|
5670
|
+
let from = 0;
|
|
5671
|
+
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
|
5672
|
+
from++;
|
|
5673
|
+
if (from == minLen && a.length == b.length)
|
|
5674
|
+
return null;
|
|
5675
|
+
let toA = a.length, toB = b.length;
|
|
5676
|
+
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
|
5677
|
+
toA--;
|
|
5678
|
+
toB--;
|
|
5679
|
+
}
|
|
5680
|
+
if (preferredSide == "end") {
|
|
5681
|
+
let adjust = Math.max(0, from - Math.min(toA, toB));
|
|
5682
|
+
preferredPos -= toA + adjust - from;
|
|
5683
|
+
}
|
|
5684
|
+
if (toA < from && a.length < b.length) {
|
|
5685
|
+
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
|
5686
|
+
from -= move;
|
|
5687
|
+
toB = from + (toB - toA);
|
|
5688
|
+
toA = from;
|
|
5689
|
+
}
|
|
5690
|
+
else if (toB < from) {
|
|
5691
|
+
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
|
5692
|
+
from -= move;
|
|
5693
|
+
toA = from + (toA - toB);
|
|
5694
|
+
toB = from;
|
|
5695
|
+
}
|
|
5696
|
+
return { from, toA, toB };
|
|
5697
|
+
}
|
|
5698
|
+
function selectionPoints(view) {
|
|
5699
|
+
let result = [];
|
|
5700
|
+
if (view.root.activeElement != view.contentDOM)
|
|
5701
|
+
return result;
|
|
5702
|
+
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
|
5703
|
+
if (anchorNode) {
|
|
5704
|
+
result.push(new DOMPoint(anchorNode, anchorOffset));
|
|
5705
|
+
if (focusNode != anchorNode || focusOffset != anchorOffset)
|
|
5706
|
+
result.push(new DOMPoint(focusNode, focusOffset));
|
|
5707
|
+
}
|
|
5708
|
+
return result;
|
|
5709
|
+
}
|
|
5710
|
+
function selectionFromPoints(points, base) {
|
|
5711
|
+
if (points.length == 0)
|
|
5712
|
+
return null;
|
|
5713
|
+
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
5714
|
+
return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null;
|
|
5715
|
+
}
|
|
5716
|
+
|
|
5455
5717
|
const observeOptions = {
|
|
5456
5718
|
childList: true,
|
|
5457
5719
|
characterData: true,
|
|
@@ -5463,10 +5725,8 @@ const observeOptions = {
|
|
|
5463
5725
|
// DOMCharacterDataModified there
|
|
5464
5726
|
const useCharData = browser.ie && browser.ie_version <= 11;
|
|
5465
5727
|
class DOMObserver {
|
|
5466
|
-
constructor(view
|
|
5728
|
+
constructor(view) {
|
|
5467
5729
|
this.view = view;
|
|
5468
|
-
this.onChange = onChange;
|
|
5469
|
-
this.onScrollChanged = onScrollChanged;
|
|
5470
5730
|
this.active = false;
|
|
5471
5731
|
// The known selection. Kept in our own object, as opposed to just
|
|
5472
5732
|
// directly accessing the selection because:
|
|
@@ -5481,6 +5741,7 @@ class DOMObserver {
|
|
|
5481
5741
|
this.resizeTimeout = -1;
|
|
5482
5742
|
this.queue = [];
|
|
5483
5743
|
this.delayedAndroidKey = null;
|
|
5744
|
+
this.flushingAndroidKey = -1;
|
|
5484
5745
|
this.lastChange = 0;
|
|
5485
5746
|
this.scrollTargets = [];
|
|
5486
5747
|
this.intersection = null;
|
|
@@ -5549,6 +5810,11 @@ class DOMObserver {
|
|
|
5549
5810
|
this.listenForScroll();
|
|
5550
5811
|
this.readSelectionRange();
|
|
5551
5812
|
}
|
|
5813
|
+
onScrollChanged(e) {
|
|
5814
|
+
this.view.inputState.runScrollHandlers(this.view, e);
|
|
5815
|
+
if (this.intersecting)
|
|
5816
|
+
this.view.measure();
|
|
5817
|
+
}
|
|
5552
5818
|
onScroll(e) {
|
|
5553
5819
|
if (this.intersecting)
|
|
5554
5820
|
this.flush(false);
|
|
@@ -5708,14 +5974,17 @@ class DOMObserver {
|
|
|
5708
5974
|
// them or, if that has no effect, dispatches the given key.
|
|
5709
5975
|
delayAndroidKey(key, keyCode) {
|
|
5710
5976
|
var _a;
|
|
5711
|
-
if (!this.delayedAndroidKey)
|
|
5712
|
-
|
|
5977
|
+
if (!this.delayedAndroidKey) {
|
|
5978
|
+
let flush = () => {
|
|
5713
5979
|
let key = this.delayedAndroidKey;
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5980
|
+
if (key) {
|
|
5981
|
+
this.clearDelayedAndroidKey();
|
|
5982
|
+
if (!this.flush() && key.force)
|
|
5983
|
+
dispatchKey(this.dom, key.key, key.keyCode);
|
|
5984
|
+
}
|
|
5985
|
+
};
|
|
5986
|
+
this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush);
|
|
5987
|
+
}
|
|
5719
5988
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5720
5989
|
// Enter always takes precedence.
|
|
5721
5990
|
if (!this.delayedAndroidKey || key == "Enter")
|
|
@@ -5728,6 +5997,11 @@ class DOMObserver {
|
|
|
5728
5997
|
force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force)
|
|
5729
5998
|
};
|
|
5730
5999
|
}
|
|
6000
|
+
clearDelayedAndroidKey() {
|
|
6001
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
6002
|
+
this.delayedAndroidKey = null;
|
|
6003
|
+
this.flushingAndroidKey = -1;
|
|
6004
|
+
}
|
|
5731
6005
|
flushSoon() {
|
|
5732
6006
|
if (this.delayedFlush < 0)
|
|
5733
6007
|
this.delayedFlush = this.view.win.requestAnimationFrame(() => { this.delayedFlush = -1; this.flush(); });
|
|
@@ -5762,6 +6036,17 @@ class DOMObserver {
|
|
|
5762
6036
|
}
|
|
5763
6037
|
return { from, to, typeOver };
|
|
5764
6038
|
}
|
|
6039
|
+
readChange() {
|
|
6040
|
+
let { from, to, typeOver } = this.processRecords();
|
|
6041
|
+
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
6042
|
+
if (from < 0 && !newSel)
|
|
6043
|
+
return null;
|
|
6044
|
+
if (from > -1)
|
|
6045
|
+
this.lastChange = Date.now();
|
|
6046
|
+
this.view.inputState.lastFocusTime = 0;
|
|
6047
|
+
this.selectionChanged = false;
|
|
6048
|
+
return new DOMChange(this.view, from, to, typeOver);
|
|
6049
|
+
}
|
|
5765
6050
|
// Apply pending changes, if any
|
|
5766
6051
|
flush(readSelection = true) {
|
|
5767
6052
|
// Completely hold off flushing when pending keys are set—the code
|
|
@@ -5771,16 +6056,11 @@ class DOMObserver {
|
|
|
5771
6056
|
return false;
|
|
5772
6057
|
if (readSelection)
|
|
5773
6058
|
this.readSelectionRange();
|
|
5774
|
-
let
|
|
5775
|
-
|
|
5776
|
-
if (from < 0 && !newSel)
|
|
6059
|
+
let domChange = this.readChange();
|
|
6060
|
+
if (!domChange)
|
|
5777
6061
|
return false;
|
|
5778
|
-
if (from > -1)
|
|
5779
|
-
this.lastChange = Date.now();
|
|
5780
|
-
this.view.inputState.lastFocusTime = 0;
|
|
5781
|
-
this.selectionChanged = false;
|
|
5782
6062
|
let startState = this.view.state;
|
|
5783
|
-
let handled = this.
|
|
6063
|
+
let handled = applyDOMChange(this.view, domChange);
|
|
5784
6064
|
// The view wasn't updated
|
|
5785
6065
|
if (this.view.state == startState)
|
|
5786
6066
|
this.view.update([]);
|
|
@@ -5836,6 +6116,8 @@ class DOMObserver {
|
|
|
5836
6116
|
this.removeWindowListeners(this.win);
|
|
5837
6117
|
clearTimeout(this.parentCheck);
|
|
5838
6118
|
clearTimeout(this.resizeTimeout);
|
|
6119
|
+
this.win.cancelAnimationFrame(this.delayedFlush);
|
|
6120
|
+
this.win.cancelAnimationFrame(this.flushingAndroidKey);
|
|
5839
6121
|
}
|
|
5840
6122
|
}
|
|
5841
6123
|
function findChild(cView, dom, dir) {
|
|
@@ -5877,218 +6159,6 @@ function safariSelectionRangeHack(view) {
|
|
|
5877
6159
|
return { anchorNode, anchorOffset, focusNode, focusOffset };
|
|
5878
6160
|
}
|
|
5879
6161
|
|
|
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
6162
|
// The editor's update state machine looks something like this:
|
|
6093
6163
|
//
|
|
6094
6164
|
// Idle → Updating ⇆ Idle (unchecked) → Measuring → Idle
|
|
@@ -6151,13 +6221,7 @@ class EditorView {
|
|
|
6151
6221
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
|
6152
6222
|
for (let plugin of this.plugins)
|
|
6153
6223
|
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
|
-
});
|
|
6224
|
+
this.observer = new DOMObserver(this);
|
|
6161
6225
|
this.inputState = new InputState(this);
|
|
6162
6226
|
this.inputState.ensureHandlers(this, this.plugins);
|
|
6163
6227
|
this.docView = new DocView(this);
|
|
@@ -6241,7 +6305,20 @@ class EditorView {
|
|
|
6241
6305
|
this.viewState.state = state$1;
|
|
6242
6306
|
return;
|
|
6243
6307
|
}
|
|
6244
|
-
|
|
6308
|
+
// If there was a pending DOM change, eagerly read it and try to
|
|
6309
|
+
// apply it after the given transactions.
|
|
6310
|
+
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
|
|
6311
|
+
if (pendingKey) {
|
|
6312
|
+
this.observer.clearDelayedAndroidKey();
|
|
6313
|
+
domChange = this.observer.readChange();
|
|
6314
|
+
// Only try to apply DOM changes if the transactions didn't
|
|
6315
|
+
// change the doc or selection.
|
|
6316
|
+
if (domChange && !this.state.doc.eq(state$1.doc) || !this.state.selection.eq(state$1.selection))
|
|
6317
|
+
domChange = null;
|
|
6318
|
+
}
|
|
6319
|
+
else {
|
|
6320
|
+
this.observer.clear();
|
|
6321
|
+
}
|
|
6245
6322
|
// When the phrases change, redraw the editor
|
|
6246
6323
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
6247
6324
|
return this.setState(state$1);
|
|
@@ -6283,6 +6360,10 @@ class EditorView {
|
|
|
6283
6360
|
if (!update.empty)
|
|
6284
6361
|
for (let listener of this.state.facet(updateListener))
|
|
6285
6362
|
listener(update);
|
|
6363
|
+
if (domChange) {
|
|
6364
|
+
if (!applyDOMChange(this, domChange) && pendingKey.force)
|
|
6365
|
+
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
|
|
6366
|
+
}
|
|
6286
6367
|
}
|
|
6287
6368
|
/**
|
|
6288
6369
|
Reset the view to the given state. (This will cause the entire
|