prosemirror-view 1.28.2 → 1.28.3
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 +6 -0
- package/dist/index.cjs +134 -67
- package/dist/index.js +112 -68
- package/package.json +1 -1
- package/src/capturekeys.ts +9 -8
- package/src/dom.ts +14 -8
- package/src/domchange.ts +1 -1
- package/src/domcoords.ts +8 -5
- package/src/domobserver.ts +47 -11
- package/src/index.ts +12 -5
- package/src/input.ts +3 -3
- package/src/selection.ts +6 -6
- package/src/viewdesc.ts +6 -10
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -36,28 +36,6 @@ var prosemirrorModel = require('prosemirror-model');
|
|
|
36
36
|
|
|
37
37
|
var prosemirrorTransform = require('prosemirror-transform');
|
|
38
38
|
|
|
39
|
-
var nav = typeof navigator != "undefined" ? navigator : null;
|
|
40
|
-
var doc = typeof document != "undefined" ? document : null;
|
|
41
|
-
var agent = nav && nav.userAgent || "";
|
|
42
|
-
var ie_edge = /Edge\/(\d+)/.exec(agent);
|
|
43
|
-
var ie_upto10 = /MSIE \d/.exec(agent);
|
|
44
|
-
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
|
|
45
|
-
var ie = !!(ie_upto10 || ie_11up || ie_edge);
|
|
46
|
-
var ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
|
|
47
|
-
var gecko = !ie && /gecko\/(\d+)/i.test(agent);
|
|
48
|
-
gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
|
|
49
|
-
|
|
50
|
-
var _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
|
|
51
|
-
|
|
52
|
-
var chrome = !!_chrome;
|
|
53
|
-
var chrome_version = _chrome ? +_chrome[1] : 0;
|
|
54
|
-
var safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
|
|
55
|
-
var ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
|
|
56
|
-
var mac = ios || (nav ? /Mac/.test(nav.platform) : false);
|
|
57
|
-
var android = /Android \d/.test(agent);
|
|
58
|
-
var webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
|
|
59
|
-
var webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;
|
|
60
|
-
|
|
61
39
|
var domIndex = function domIndex(node) {
|
|
62
40
|
for (var index = 0;; index++) {
|
|
63
41
|
node = node.previousSibling;
|
|
@@ -130,9 +108,7 @@ function hasBlockDesc(dom) {
|
|
|
130
108
|
}
|
|
131
109
|
|
|
132
110
|
var selectionCollapsed = function selectionCollapsed(domSel) {
|
|
133
|
-
|
|
134
|
-
if (collapsed && chrome && domSel.rangeCount && !domSel.getRangeAt(0).collapsed) collapsed = false;
|
|
135
|
-
return collapsed;
|
|
111
|
+
return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);
|
|
136
112
|
};
|
|
137
113
|
|
|
138
114
|
function keyEvent(keyCode, key) {
|
|
@@ -143,6 +119,38 @@ function keyEvent(keyCode, key) {
|
|
|
143
119
|
return event;
|
|
144
120
|
}
|
|
145
121
|
|
|
122
|
+
function deepActiveElement(doc) {
|
|
123
|
+
var elt = doc.activeElement;
|
|
124
|
+
|
|
125
|
+
while (elt && elt.shadowRoot) {
|
|
126
|
+
elt = elt.shadowRoot.activeElement;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return elt;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var nav = typeof navigator != "undefined" ? navigator : null;
|
|
133
|
+
var doc = typeof document != "undefined" ? document : null;
|
|
134
|
+
var agent = nav && nav.userAgent || "";
|
|
135
|
+
var ie_edge = /Edge\/(\d+)/.exec(agent);
|
|
136
|
+
var ie_upto10 = /MSIE \d/.exec(agent);
|
|
137
|
+
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
|
|
138
|
+
var ie = !!(ie_upto10 || ie_11up || ie_edge);
|
|
139
|
+
var ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
|
|
140
|
+
var gecko = !ie && /gecko\/(\d+)/i.test(agent);
|
|
141
|
+
gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
|
|
142
|
+
|
|
143
|
+
var _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
|
|
144
|
+
|
|
145
|
+
var chrome = !!_chrome;
|
|
146
|
+
var chrome_version = _chrome ? +_chrome[1] : 0;
|
|
147
|
+
var safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
|
|
148
|
+
var ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
|
|
149
|
+
var mac = ios || (nav ? /Mac/.test(nav.platform) : false);
|
|
150
|
+
var android = /Android \d/.test(agent);
|
|
151
|
+
var webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
|
|
152
|
+
var webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;
|
|
153
|
+
|
|
146
154
|
function windowRect(doc) {
|
|
147
155
|
return {
|
|
148
156
|
left: 0,
|
|
@@ -654,15 +662,27 @@ function endOfTextblockHorizontal(view, state, dir) {
|
|
|
654
662
|
var sel = view.domSelection();
|
|
655
663
|
if (!maybeRTL.test($head.parent.textContent) || !sel.modify) return dir == "left" || dir == "backward" ? atStart : atEnd;
|
|
656
664
|
return withFlushedState(view, state, function () {
|
|
657
|
-
var
|
|
658
|
-
oldNode =
|
|
659
|
-
oldOff =
|
|
665
|
+
var _view$domSelectionRan = view.domSelectionRange(),
|
|
666
|
+
oldNode = _view$domSelectionRan.focusNode,
|
|
667
|
+
oldOff = _view$domSelectionRan.focusOffset,
|
|
668
|
+
anchorNode = _view$domSelectionRan.anchorNode,
|
|
669
|
+
anchorOffset = _view$domSelectionRan.anchorOffset;
|
|
670
|
+
|
|
660
671
|
var oldBidiLevel = sel.caretBidiLevel;
|
|
661
672
|
sel.modify("move", dir, "character");
|
|
662
673
|
var parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
674
|
+
|
|
675
|
+
var _view$domSelectionRan2 = view.domSelectionRange(),
|
|
676
|
+
newNode = _view$domSelectionRan2.focusNode,
|
|
677
|
+
newOff = _view$domSelectionRan2.focusOffset;
|
|
678
|
+
|
|
679
|
+
var result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) || oldNode == newNode && oldOff == newOff;
|
|
680
|
+
|
|
681
|
+
try {
|
|
682
|
+
sel.collapse(anchorNode, anchorOffset);
|
|
683
|
+
if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend) sel.extend(oldNode, oldOff);
|
|
684
|
+
} catch (_) {}
|
|
685
|
+
|
|
666
686
|
if (oldBidiLevel != null) sel.caretBidiLevel = oldBidiLevel;
|
|
667
687
|
return result;
|
|
668
688
|
});
|
|
@@ -1102,16 +1122,9 @@ var ViewDesc = function () {
|
|
|
1102
1122
|
domSel.collapse(anchorDOM.node, anchorDOM.offset);
|
|
1103
1123
|
|
|
1104
1124
|
try {
|
|
1105
|
-
if (anchor != head)
|
|
1106
|
-
try {
|
|
1107
|
-
domSel.extend(headDOM.node, headDOM.offset);
|
|
1108
|
-
} catch (_) {}
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1125
|
+
if (anchor != head) domSel.extend(headDOM.node, headDOM.offset);
|
|
1111
1126
|
domSelExtended = true;
|
|
1112
|
-
} catch (
|
|
1113
|
-
if (!(err instanceof DOMException)) throw err;
|
|
1114
|
-
}
|
|
1127
|
+
} catch (_) {}
|
|
1115
1128
|
}
|
|
1116
1129
|
|
|
1117
1130
|
if (!domSelExtended) {
|
|
@@ -1496,7 +1509,7 @@ var NodeViewDesc = function (_ViewDesc4) {
|
|
|
1496
1509
|
from = _view$state$selection.from,
|
|
1497
1510
|
to = _view$state$selection.to;
|
|
1498
1511
|
if (!(view.state.selection instanceof prosemirrorState.TextSelection) || from < pos || to > pos + this.node.content.size) return null;
|
|
1499
|
-
var sel = view.
|
|
1512
|
+
var sel = view.domSelectionRange();
|
|
1500
1513
|
var textNode = nearbyTextNode(sel.focusNode, sel.focusOffset);
|
|
1501
1514
|
if (!textNode || !this.dom.contains(textNode.parentNode)) return null;
|
|
1502
1515
|
|
|
@@ -2406,7 +2419,7 @@ function replaceNodes(nodes, from, to, view, replacement) {
|
|
|
2406
2419
|
|
|
2407
2420
|
function selectionFromDOM(view) {
|
|
2408
2421
|
var origin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
2409
|
-
var domSel = view.
|
|
2422
|
+
var domSel = view.domSelectionRange(),
|
|
2410
2423
|
doc = view.state.doc;
|
|
2411
2424
|
if (!domSel.focusNode) return null;
|
|
2412
2425
|
var nearestDesc = view.docView.nearestDesc(domSel.focusNode),
|
|
@@ -2455,7 +2468,7 @@ function selectionToDOM(view) {
|
|
|
2455
2468
|
if (!editorOwnsSelection(view)) return;
|
|
2456
2469
|
|
|
2457
2470
|
if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
|
|
2458
|
-
var domSel = view.
|
|
2471
|
+
var domSel = view.domSelectionRange(),
|
|
2459
2472
|
curSel = view.domObserver.currentSelection;
|
|
2460
2473
|
|
|
2461
2474
|
if (domSel.anchorNode && curSel.anchorNode && isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
|
|
@@ -2538,7 +2551,7 @@ function resetEditable(element) {
|
|
|
2538
2551
|
function removeClassOnSelectionChange(view) {
|
|
2539
2552
|
var doc = view.dom.ownerDocument;
|
|
2540
2553
|
doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
|
|
2541
|
-
var domSel = view.
|
|
2554
|
+
var domSel = view.domSelectionRange();
|
|
2542
2555
|
var node = domSel.anchorNode,
|
|
2543
2556
|
offset = domSel.anchorOffset;
|
|
2544
2557
|
doc.addEventListener("selectionchange", view.input.hideSelectionGuard = function () {
|
|
@@ -2600,7 +2613,7 @@ function hasFocusAndSelection(view) {
|
|
|
2600
2613
|
}
|
|
2601
2614
|
|
|
2602
2615
|
function hasSelection(view) {
|
|
2603
|
-
var sel = view.
|
|
2616
|
+
var sel = view.domSelectionRange();
|
|
2604
2617
|
if (!sel.anchorNode) return false;
|
|
2605
2618
|
|
|
2606
2619
|
try {
|
|
@@ -2612,7 +2625,7 @@ function hasSelection(view) {
|
|
|
2612
2625
|
|
|
2613
2626
|
function anchorInRightPlace(view) {
|
|
2614
2627
|
var anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);
|
|
2615
|
-
var domSel = view.
|
|
2628
|
+
var domSel = view.domSelectionRange();
|
|
2616
2629
|
return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);
|
|
2617
2630
|
}
|
|
2618
2631
|
|
|
@@ -2676,7 +2689,7 @@ function isIgnorable(dom) {
|
|
|
2676
2689
|
}
|
|
2677
2690
|
|
|
2678
2691
|
function skipIgnoredNodesLeft(view) {
|
|
2679
|
-
var sel = view.
|
|
2692
|
+
var sel = view.domSelectionRange();
|
|
2680
2693
|
var node = sel.focusNode,
|
|
2681
2694
|
offset = sel.focusOffset;
|
|
2682
2695
|
if (!node) return;
|
|
@@ -2722,11 +2735,11 @@ function skipIgnoredNodesLeft(view) {
|
|
|
2722
2735
|
}
|
|
2723
2736
|
}
|
|
2724
2737
|
|
|
2725
|
-
if (force) setSelFocus(view,
|
|
2738
|
+
if (force) setSelFocus(view, node, offset);else if (moveNode) setSelFocus(view, moveNode, moveOffset);
|
|
2726
2739
|
}
|
|
2727
2740
|
|
|
2728
2741
|
function skipIgnoredNodesRight(view) {
|
|
2729
|
-
var sel = view.
|
|
2742
|
+
var sel = view.domSelectionRange();
|
|
2730
2743
|
var node = sel.focusNode,
|
|
2731
2744
|
offset = sel.focusOffset;
|
|
2732
2745
|
if (!node) return;
|
|
@@ -2765,7 +2778,7 @@ function skipIgnoredNodesRight(view) {
|
|
|
2765
2778
|
}
|
|
2766
2779
|
}
|
|
2767
2780
|
|
|
2768
|
-
if (moveNode) setSelFocus(view,
|
|
2781
|
+
if (moveNode) setSelFocus(view, moveNode, moveOffset);
|
|
2769
2782
|
}
|
|
2770
2783
|
|
|
2771
2784
|
function isBlockNode(dom) {
|
|
@@ -2773,7 +2786,9 @@ function isBlockNode(dom) {
|
|
|
2773
2786
|
return desc && desc.node && desc.node.isBlock;
|
|
2774
2787
|
}
|
|
2775
2788
|
|
|
2776
|
-
function setSelFocus(view,
|
|
2789
|
+
function setSelFocus(view, node, offset) {
|
|
2790
|
+
var sel = view.domSelection();
|
|
2791
|
+
|
|
2777
2792
|
if (selectionCollapsed(sel)) {
|
|
2778
2793
|
var range = document.createRange();
|
|
2779
2794
|
range.setEnd(node, offset);
|
|
@@ -2842,9 +2857,9 @@ function switchEditable(view, node, state) {
|
|
|
2842
2857
|
function safariDownArrowBug(view) {
|
|
2843
2858
|
if (!safari || view.state.selection.$head.parentOffset > 0) return false;
|
|
2844
2859
|
|
|
2845
|
-
var _view$
|
|
2846
|
-
focusNode = _view$
|
|
2847
|
-
focusOffset = _view$
|
|
2860
|
+
var _view$domSelectionRan3 = view.domSelectionRange(),
|
|
2861
|
+
focusNode = _view$domSelectionRan3.focusNode,
|
|
2862
|
+
focusOffset = _view$domSelectionRan3.focusOffset;
|
|
2848
2863
|
|
|
2849
2864
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 && focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
2850
2865
|
var child = focusNode.firstChild;
|
|
@@ -3639,14 +3654,14 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
|
|
|
3639
3654
|
endComposition(view);
|
|
3640
3655
|
|
|
3641
3656
|
if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
|
|
3642
|
-
var sel = view.
|
|
3657
|
+
var sel = view.domSelectionRange();
|
|
3643
3658
|
|
|
3644
3659
|
for (var node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
3645
3660
|
var before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
|
|
3646
3661
|
if (!before) break;
|
|
3647
3662
|
|
|
3648
3663
|
if (before.nodeType == 3) {
|
|
3649
|
-
|
|
3664
|
+
view.domSelection().collapse(before, before.nodeValue.length);
|
|
3650
3665
|
break;
|
|
3651
3666
|
} else {
|
|
3652
3667
|
node = before;
|
|
@@ -3898,7 +3913,7 @@ handlers.focus = function (view) {
|
|
|
3898
3913
|
view.domObserver.start();
|
|
3899
3914
|
view.focused = true;
|
|
3900
3915
|
setTimeout(function () {
|
|
3901
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
3916
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange())) selectionToDOM(view);
|
|
3902
3917
|
}, 20);
|
|
3903
3918
|
}
|
|
3904
3919
|
};
|
|
@@ -4826,7 +4841,7 @@ var DOMObserver = function () {
|
|
|
4826
4841
|
if (this.suppressingSelectionUpdates) return selectionToDOM(this.view);
|
|
4827
4842
|
|
|
4828
4843
|
if (ie && ie_version <= 11 && !this.view.state.selection.empty) {
|
|
4829
|
-
var sel = this.view.
|
|
4844
|
+
var sel = this.view.domSelectionRange();
|
|
4830
4845
|
if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) return this.flushSoon();
|
|
4831
4846
|
}
|
|
4832
4847
|
|
|
@@ -4835,14 +4850,27 @@ var DOMObserver = function () {
|
|
|
4835
4850
|
}, {
|
|
4836
4851
|
key: "setCurSelection",
|
|
4837
4852
|
value: function setCurSelection() {
|
|
4838
|
-
this.currentSelection.set(this.view.
|
|
4853
|
+
this.currentSelection.set(this.view.domSelectionRange());
|
|
4839
4854
|
}
|
|
4840
4855
|
}, {
|
|
4841
4856
|
key: "ignoreSelectionChange",
|
|
4842
4857
|
value: function ignoreSelectionChange(sel) {
|
|
4843
|
-
if (sel.
|
|
4844
|
-
var
|
|
4845
|
-
|
|
4858
|
+
if (!sel.focusNode) return true;
|
|
4859
|
+
var ancestors = new Set(),
|
|
4860
|
+
container;
|
|
4861
|
+
|
|
4862
|
+
for (var scan = sel.focusNode; scan; scan = parentNode(scan)) {
|
|
4863
|
+
ancestors.add(scan);
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4866
|
+
for (var _scan = sel.anchorNode; _scan; _scan = parentNode(_scan)) {
|
|
4867
|
+
if (ancestors.has(_scan)) {
|
|
4868
|
+
container = _scan;
|
|
4869
|
+
break;
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
|
|
4873
|
+
var desc = container && this.view.docView.nearestDesc(container);
|
|
4846
4874
|
|
|
4847
4875
|
if (desc && desc.ignoreMutation({
|
|
4848
4876
|
type: "selection",
|
|
@@ -4864,7 +4892,7 @@ var DOMObserver = function () {
|
|
|
4864
4892
|
this.queue.length = 0;
|
|
4865
4893
|
}
|
|
4866
4894
|
|
|
4867
|
-
var sel = view.
|
|
4895
|
+
var sel = view.domSelectionRange();
|
|
4868
4896
|
var newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4869
4897
|
var from = -1,
|
|
4870
4898
|
to = -1,
|
|
@@ -4984,6 +5012,40 @@ function checkCSS(view) {
|
|
|
4984
5012
|
}
|
|
4985
5013
|
}
|
|
4986
5014
|
|
|
5015
|
+
function safariShadowSelectionRange(view) {
|
|
5016
|
+
var found;
|
|
5017
|
+
|
|
5018
|
+
function read(event) {
|
|
5019
|
+
event.preventDefault();
|
|
5020
|
+
event.stopImmediatePropagation();
|
|
5021
|
+
found = event.getTargetRanges()[0];
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
view.dom.addEventListener("beforeinput", read, true);
|
|
5025
|
+
document.execCommand("indent");
|
|
5026
|
+
view.dom.removeEventListener("beforeinput", read, true);
|
|
5027
|
+
var anchorNode = found.startContainer,
|
|
5028
|
+
anchorOffset = found.startOffset;
|
|
5029
|
+
var focusNode = found.endContainer,
|
|
5030
|
+
focusOffset = found.endOffset;
|
|
5031
|
+
var currentAnchor = view.domAtPos(view.state.selection.anchor);
|
|
5032
|
+
|
|
5033
|
+
if (isEquivalentPosition(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset)) {
|
|
5034
|
+
var _ref3 = [focusNode, focusOffset, anchorNode, anchorOffset];
|
|
5035
|
+
anchorNode = _ref3[0];
|
|
5036
|
+
anchorOffset = _ref3[1];
|
|
5037
|
+
focusNode = _ref3[2];
|
|
5038
|
+
focusOffset = _ref3[3];
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
return {
|
|
5042
|
+
anchorNode: anchorNode,
|
|
5043
|
+
anchorOffset: anchorOffset,
|
|
5044
|
+
focusNode: focusNode,
|
|
5045
|
+
focusOffset: focusOffset
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
5048
|
+
|
|
4987
5049
|
function parseBetween(view, from_, to_) {
|
|
4988
5050
|
var _view$docView$parseRa = view.docView.parseRange(from_, to_),
|
|
4989
5051
|
parent = _view$docView$parseRa.node,
|
|
@@ -4992,7 +5054,7 @@ function parseBetween(view, from_, to_) {
|
|
|
4992
5054
|
from = _view$docView$parseRa.from,
|
|
4993
5055
|
to = _view$docView$parseRa.to;
|
|
4994
5056
|
|
|
4995
|
-
var domSel = view.
|
|
5057
|
+
var domSel = view.domSelectionRange();
|
|
4996
5058
|
var find;
|
|
4997
5059
|
var anchor = domSel.anchorNode;
|
|
4998
5060
|
|
|
@@ -5502,7 +5564,7 @@ var EditorView = function () {
|
|
|
5502
5564
|
var forceSelUpdate = updateDoc && (ie || chrome) && !this.composing && !prev.selection.empty && !state.selection.empty && selectionContextChanged(prev.selection, state.selection);
|
|
5503
5565
|
|
|
5504
5566
|
if (updateDoc) {
|
|
5505
|
-
var chromeKludge = chrome ? this.trackWrites = this.
|
|
5567
|
+
var chromeKludge = chrome ? this.trackWrites = this.domSelectionRange().focusNode : null;
|
|
5506
5568
|
|
|
5507
5569
|
if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
|
|
5508
5570
|
this.docView.updateOuterDeco([]);
|
|
@@ -5513,7 +5575,7 @@ var EditorView = function () {
|
|
|
5513
5575
|
if (chromeKludge && !this.trackWrites) forceSelUpdate = true;
|
|
5514
5576
|
}
|
|
5515
5577
|
|
|
5516
|
-
if (forceSelUpdate || !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.
|
|
5578
|
+
if (forceSelUpdate || !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) && anchorInRightPlace(this))) {
|
|
5517
5579
|
selectionToDOM(this, forceSelUpdate);
|
|
5518
5580
|
} else {
|
|
5519
5581
|
syncNodeSelection(this, state.selection);
|
|
@@ -5538,7 +5600,7 @@ var EditorView = function () {
|
|
|
5538
5600
|
value: function scrollToSelection() {
|
|
5539
5601
|
var _this16 = this;
|
|
5540
5602
|
|
|
5541
|
-
var startDOM = this.
|
|
5603
|
+
var startDOM = this.domSelectionRange().focusNode;
|
|
5542
5604
|
if (this.someProp("handleScrollToSelection", function (f) {
|
|
5543
5605
|
return f(_this16);
|
|
5544
5606
|
})) ;else if (this.state.selection instanceof prosemirrorState.NodeSelection) {
|
|
@@ -5721,6 +5783,11 @@ var EditorView = function () {
|
|
|
5721
5783
|
var dispatchTransaction = this._props.dispatchTransaction;
|
|
5722
5784
|
if (dispatchTransaction) dispatchTransaction.call(this, tr);else this.updateState(this.state.apply(tr));
|
|
5723
5785
|
}
|
|
5786
|
+
}, {
|
|
5787
|
+
key: "domSelectionRange",
|
|
5788
|
+
value: function domSelectionRange() {
|
|
5789
|
+
return safari && this.root.nodeType === 11 && deepActiveElement(this.dom.ownerDocument) == this.dom ? safariShadowSelectionRange(this) : this.domSelection();
|
|
5790
|
+
}
|
|
5724
5791
|
}, {
|
|
5725
5792
|
key: "domSelection",
|
|
5726
5793
|
value: function domSelection() {
|
package/dist/index.js
CHANGED
|
@@ -2,27 +2,6 @@ import { TextSelection, NodeSelection, Selection, AllSelection } from 'prosemirr
|
|
|
2
2
|
import { DOMSerializer, Fragment, Mark, Slice, DOMParser } from 'prosemirror-model';
|
|
3
3
|
import { dropPoint } from 'prosemirror-transform';
|
|
4
4
|
|
|
5
|
-
const nav = typeof navigator != "undefined" ? navigator : null;
|
|
6
|
-
const doc = typeof document != "undefined" ? document : null;
|
|
7
|
-
const agent = (nav && nav.userAgent) || "";
|
|
8
|
-
const ie_edge = /Edge\/(\d+)/.exec(agent);
|
|
9
|
-
const ie_upto10 = /MSIE \d/.exec(agent);
|
|
10
|
-
const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
|
|
11
|
-
const ie = !!(ie_upto10 || ie_11up || ie_edge);
|
|
12
|
-
const ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
|
|
13
|
-
const gecko = !ie && /gecko\/(\d+)/i.test(agent);
|
|
14
|
-
gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
|
|
15
|
-
const _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
|
|
16
|
-
const chrome = !!_chrome;
|
|
17
|
-
const chrome_version = _chrome ? +_chrome[1] : 0;
|
|
18
|
-
const safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
|
|
19
|
-
// Is true for both iOS and iPadOS for convenience
|
|
20
|
-
const ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
|
|
21
|
-
const mac = ios || (nav ? /Mac/.test(nav.platform) : false);
|
|
22
|
-
const android = /Android \d/.test(agent);
|
|
23
|
-
const webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
|
|
24
|
-
const webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;
|
|
25
|
-
|
|
26
5
|
const domIndex = function (node) {
|
|
27
6
|
for (var index = 0;; index++) {
|
|
28
7
|
node = node.previousSibling;
|
|
@@ -100,10 +79,7 @@ function hasBlockDesc(dom) {
|
|
|
100
79
|
// Work around Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=447523
|
|
101
80
|
// (isCollapsed inappropriately returns true in shadow dom)
|
|
102
81
|
const selectionCollapsed = function (domSel) {
|
|
103
|
-
|
|
104
|
-
if (collapsed && chrome && domSel.rangeCount && !domSel.getRangeAt(0).collapsed)
|
|
105
|
-
collapsed = false;
|
|
106
|
-
return collapsed;
|
|
82
|
+
return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);
|
|
107
83
|
};
|
|
108
84
|
function keyEvent(keyCode, key) {
|
|
109
85
|
let event = document.createEvent("Event");
|
|
@@ -112,6 +88,33 @@ function keyEvent(keyCode, key) {
|
|
|
112
88
|
event.key = event.code = key;
|
|
113
89
|
return event;
|
|
114
90
|
}
|
|
91
|
+
function deepActiveElement(doc) {
|
|
92
|
+
let elt = doc.activeElement;
|
|
93
|
+
while (elt && elt.shadowRoot)
|
|
94
|
+
elt = elt.shadowRoot.activeElement;
|
|
95
|
+
return elt;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const nav = typeof navigator != "undefined" ? navigator : null;
|
|
99
|
+
const doc = typeof document != "undefined" ? document : null;
|
|
100
|
+
const agent = (nav && nav.userAgent) || "";
|
|
101
|
+
const ie_edge = /Edge\/(\d+)/.exec(agent);
|
|
102
|
+
const ie_upto10 = /MSIE \d/.exec(agent);
|
|
103
|
+
const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
|
|
104
|
+
const ie = !!(ie_upto10 || ie_11up || ie_edge);
|
|
105
|
+
const ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
|
|
106
|
+
const gecko = !ie && /gecko\/(\d+)/i.test(agent);
|
|
107
|
+
gecko && +(/Firefox\/(\d+)/.exec(agent) || [0, 0])[1];
|
|
108
|
+
const _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
|
|
109
|
+
const chrome = !!_chrome;
|
|
110
|
+
const chrome_version = _chrome ? +_chrome[1] : 0;
|
|
111
|
+
const safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
|
|
112
|
+
// Is true for both iOS and iPadOS for convenience
|
|
113
|
+
const ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
|
|
114
|
+
const mac = ios || (nav ? /Mac/.test(nav.platform) : false);
|
|
115
|
+
const android = /Android \d/.test(agent);
|
|
116
|
+
const webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
|
|
117
|
+
const webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0;
|
|
115
118
|
|
|
116
119
|
function windowRect(doc) {
|
|
117
120
|
return { left: 0, right: doc.documentElement.clientWidth,
|
|
@@ -580,16 +583,21 @@ function endOfTextblockHorizontal(view, state, dir) {
|
|
|
580
583
|
// one character, and see if that moves the cursor out of the
|
|
581
584
|
// textblock (or doesn't move it at all, when at the start/end of
|
|
582
585
|
// the document).
|
|
583
|
-
let
|
|
586
|
+
let { focusNode: oldNode, focusOffset: oldOff, anchorNode, anchorOffset } = view.domSelectionRange();
|
|
584
587
|
let oldBidiLevel = sel.caretBidiLevel // Only for Firefox
|
|
585
588
|
;
|
|
586
589
|
sel.modify("move", dir, "character");
|
|
587
590
|
let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
|
|
588
|
-
let
|
|
589
|
-
|
|
591
|
+
let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();
|
|
592
|
+
let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
|
|
593
|
+
(oldNode == newNode && oldOff == newOff);
|
|
590
594
|
// Restore the previous selection
|
|
591
|
-
|
|
592
|
-
|
|
595
|
+
try {
|
|
596
|
+
sel.collapse(anchorNode, anchorOffset);
|
|
597
|
+
if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend)
|
|
598
|
+
sel.extend(oldNode, oldOff);
|
|
599
|
+
}
|
|
600
|
+
catch (_) { }
|
|
593
601
|
if (oldBidiLevel != null)
|
|
594
602
|
sel.caretBidiLevel = oldBidiLevel;
|
|
595
603
|
return result;
|
|
@@ -957,24 +965,17 @@ class ViewDesc {
|
|
|
957
965
|
if ((domSel.extend || anchor == head) && !brKludge) {
|
|
958
966
|
domSel.collapse(anchorDOM.node, anchorDOM.offset);
|
|
959
967
|
try {
|
|
960
|
-
if (anchor != head)
|
|
961
|
-
|
|
962
|
-
// there was no selection. (#1308)
|
|
963
|
-
try {
|
|
964
|
-
domSel.extend(headDOM.node, headDOM.offset);
|
|
965
|
-
}
|
|
966
|
-
catch (_) { }
|
|
967
|
-
}
|
|
968
|
+
if (anchor != head)
|
|
969
|
+
domSel.extend(headDOM.node, headDOM.offset);
|
|
968
970
|
domSelExtended = true;
|
|
969
971
|
}
|
|
970
|
-
catch (
|
|
972
|
+
catch (_) {
|
|
971
973
|
// In some cases with Chrome the selection is empty after calling
|
|
972
974
|
// collapse, even when it should be valid. This appears to be a bug, but
|
|
973
975
|
// it is difficult to isolate. If this happens fallback to the old path
|
|
974
976
|
// without using extend.
|
|
975
|
-
if
|
|
976
|
-
|
|
977
|
-
// declare global: DOMException
|
|
977
|
+
// Similarly, this could crash on Safari if the editor is hidden, and
|
|
978
|
+
// there was no selection.
|
|
978
979
|
}
|
|
979
980
|
}
|
|
980
981
|
if (!domSelExtended) {
|
|
@@ -1295,7 +1296,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1295
1296
|
let { from, to } = view.state.selection;
|
|
1296
1297
|
if (!(view.state.selection instanceof TextSelection) || from < pos || to > pos + this.node.content.size)
|
|
1297
1298
|
return null;
|
|
1298
|
-
let sel = view.
|
|
1299
|
+
let sel = view.domSelectionRange();
|
|
1299
1300
|
let textNode = nearbyTextNode(sel.focusNode, sel.focusOffset);
|
|
1300
1301
|
if (!textNode || !this.dom.contains(textNode.parentNode))
|
|
1301
1302
|
return null;
|
|
@@ -2031,7 +2032,7 @@ function replaceNodes(nodes, from, to, view, replacement) {
|
|
|
2031
2032
|
}
|
|
2032
2033
|
|
|
2033
2034
|
function selectionFromDOM(view, origin = null) {
|
|
2034
|
-
let domSel = view.
|
|
2035
|
+
let domSel = view.domSelectionRange(), doc = view.state.doc;
|
|
2035
2036
|
if (!domSel.focusNode)
|
|
2036
2037
|
return null;
|
|
2037
2038
|
let nearestDesc = view.docView.nearestDesc(domSel.focusNode), inWidget = nearestDesc && nearestDesc.size == 0;
|
|
@@ -2075,7 +2076,7 @@ function selectionToDOM(view, force = false) {
|
|
|
2075
2076
|
// in Safari. And the drag selection delay is to workarond issues
|
|
2076
2077
|
// which only present in Chrome.
|
|
2077
2078
|
if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
|
|
2078
|
-
let domSel = view.
|
|
2079
|
+
let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
|
|
2079
2080
|
if (domSel.anchorNode && curSel.anchorNode &&
|
|
2080
2081
|
isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
|
|
2081
2082
|
view.input.mouseDown.delayedSelectionSync = true;
|
|
@@ -2150,7 +2151,7 @@ function resetEditable(element) {
|
|
|
2150
2151
|
function removeClassOnSelectionChange(view) {
|
|
2151
2152
|
let doc = view.dom.ownerDocument;
|
|
2152
2153
|
doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
|
|
2153
|
-
let domSel = view.
|
|
2154
|
+
let domSel = view.domSelectionRange();
|
|
2154
2155
|
let node = domSel.anchorNode, offset = domSel.anchorOffset;
|
|
2155
2156
|
doc.addEventListener("selectionchange", view.input.hideSelectionGuard = () => {
|
|
2156
2157
|
if (domSel.anchorNode != node || domSel.anchorOffset != offset) {
|
|
@@ -2214,7 +2215,7 @@ function hasFocusAndSelection(view) {
|
|
|
2214
2215
|
return hasSelection(view);
|
|
2215
2216
|
}
|
|
2216
2217
|
function hasSelection(view) {
|
|
2217
|
-
let sel = view.
|
|
2218
|
+
let sel = view.domSelectionRange();
|
|
2218
2219
|
if (!sel.anchorNode)
|
|
2219
2220
|
return false;
|
|
2220
2221
|
try {
|
|
@@ -2230,7 +2231,7 @@ function hasSelection(view) {
|
|
|
2230
2231
|
}
|
|
2231
2232
|
function anchorInRightPlace(view) {
|
|
2232
2233
|
let anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);
|
|
2233
|
-
let domSel = view.
|
|
2234
|
+
let domSel = view.domSelectionRange();
|
|
2234
2235
|
return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);
|
|
2235
2236
|
}
|
|
2236
2237
|
|
|
@@ -2297,7 +2298,7 @@ function isIgnorable(dom) {
|
|
|
2297
2298
|
// Make sure the cursor isn't directly after one or more ignored
|
|
2298
2299
|
// nodes, which will confuse the browser's cursor motion logic.
|
|
2299
2300
|
function skipIgnoredNodesLeft(view) {
|
|
2300
|
-
let sel = view.
|
|
2301
|
+
let sel = view.domSelectionRange();
|
|
2301
2302
|
let node = sel.focusNode, offset = sel.focusOffset;
|
|
2302
2303
|
if (!node)
|
|
2303
2304
|
return;
|
|
@@ -2349,14 +2350,14 @@ function skipIgnoredNodesLeft(view) {
|
|
|
2349
2350
|
}
|
|
2350
2351
|
}
|
|
2351
2352
|
if (force)
|
|
2352
|
-
setSelFocus(view,
|
|
2353
|
+
setSelFocus(view, node, offset);
|
|
2353
2354
|
else if (moveNode)
|
|
2354
|
-
setSelFocus(view,
|
|
2355
|
+
setSelFocus(view, moveNode, moveOffset);
|
|
2355
2356
|
}
|
|
2356
2357
|
// Make sure the cursor isn't directly before one or more ignored
|
|
2357
2358
|
// nodes.
|
|
2358
2359
|
function skipIgnoredNodesRight(view) {
|
|
2359
|
-
let sel = view.
|
|
2360
|
+
let sel = view.domSelectionRange();
|
|
2360
2361
|
let node = sel.focusNode, offset = sel.focusOffset;
|
|
2361
2362
|
if (!node)
|
|
2362
2363
|
return;
|
|
@@ -2398,13 +2399,14 @@ function skipIgnoredNodesRight(view) {
|
|
|
2398
2399
|
}
|
|
2399
2400
|
}
|
|
2400
2401
|
if (moveNode)
|
|
2401
|
-
setSelFocus(view,
|
|
2402
|
+
setSelFocus(view, moveNode, moveOffset);
|
|
2402
2403
|
}
|
|
2403
2404
|
function isBlockNode(dom) {
|
|
2404
2405
|
let desc = dom.pmViewDesc;
|
|
2405
2406
|
return desc && desc.node && desc.node.isBlock;
|
|
2406
2407
|
}
|
|
2407
|
-
function setSelFocus(view,
|
|
2408
|
+
function setSelFocus(view, node, offset) {
|
|
2409
|
+
let sel = view.domSelection();
|
|
2408
2410
|
if (selectionCollapsed(sel)) {
|
|
2409
2411
|
let range = document.createRange();
|
|
2410
2412
|
range.setEnd(node, offset);
|
|
@@ -2480,7 +2482,7 @@ function switchEditable(view, node, state) {
|
|
|
2480
2482
|
function safariDownArrowBug(view) {
|
|
2481
2483
|
if (!safari || view.state.selection.$head.parentOffset > 0)
|
|
2482
2484
|
return false;
|
|
2483
|
-
let { focusNode, focusOffset } = view.
|
|
2485
|
+
let { focusNode, focusOffset } = view.domSelectionRange();
|
|
2484
2486
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
|
|
2485
2487
|
focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
2486
2488
|
let child = focusNode.firstChild;
|
|
@@ -3206,13 +3208,13 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3206
3208
|
// the inserted text won't inherit the marks. So this moves it
|
|
3207
3209
|
// inside if necessary.
|
|
3208
3210
|
if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
|
|
3209
|
-
let sel = view.
|
|
3211
|
+
let sel = view.domSelectionRange();
|
|
3210
3212
|
for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
3211
3213
|
let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
|
|
3212
3214
|
if (!before)
|
|
3213
3215
|
break;
|
|
3214
3216
|
if (before.nodeType == 3) {
|
|
3215
|
-
|
|
3217
|
+
view.domSelection().collapse(before, before.nodeValue.length);
|
|
3216
3218
|
break;
|
|
3217
3219
|
}
|
|
3218
3220
|
else {
|
|
@@ -3468,7 +3470,7 @@ handlers.focus = view => {
|
|
|
3468
3470
|
view.domObserver.start();
|
|
3469
3471
|
view.focused = true;
|
|
3470
3472
|
setTimeout(() => {
|
|
3471
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
3473
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange()))
|
|
3472
3474
|
selectionToDOM(view);
|
|
3473
3475
|
}, 20);
|
|
3474
3476
|
}
|
|
@@ -4300,7 +4302,7 @@ class DOMObserver {
|
|
|
4300
4302
|
// us a selection change event before the DOM changes are
|
|
4301
4303
|
// reported.
|
|
4302
4304
|
if (ie && ie_version <= 11 && !this.view.state.selection.empty) {
|
|
4303
|
-
let sel = this.view.
|
|
4305
|
+
let sel = this.view.domSelectionRange();
|
|
4304
4306
|
// Selection.isCollapsed isn't reliable on IE
|
|
4305
4307
|
if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
4306
4308
|
return this.flushSoon();
|
|
@@ -4308,13 +4310,20 @@ class DOMObserver {
|
|
|
4308
4310
|
this.flush();
|
|
4309
4311
|
}
|
|
4310
4312
|
setCurSelection() {
|
|
4311
|
-
this.currentSelection.set(this.view.
|
|
4313
|
+
this.currentSelection.set(this.view.domSelectionRange());
|
|
4312
4314
|
}
|
|
4313
4315
|
ignoreSelectionChange(sel) {
|
|
4314
|
-
if (sel.
|
|
4316
|
+
if (!sel.focusNode)
|
|
4315
4317
|
return true;
|
|
4316
|
-
let
|
|
4317
|
-
let
|
|
4318
|
+
let ancestors = new Set, container;
|
|
4319
|
+
for (let scan = sel.focusNode; scan; scan = parentNode(scan))
|
|
4320
|
+
ancestors.add(scan);
|
|
4321
|
+
for (let scan = sel.anchorNode; scan; scan = parentNode(scan))
|
|
4322
|
+
if (ancestors.has(scan)) {
|
|
4323
|
+
container = scan;
|
|
4324
|
+
break;
|
|
4325
|
+
}
|
|
4326
|
+
let desc = container && this.view.docView.nearestDesc(container);
|
|
4318
4327
|
if (desc && desc.ignoreMutation({
|
|
4319
4328
|
type: "selection",
|
|
4320
4329
|
target: container.nodeType == 3 ? container.parentNode : container
|
|
@@ -4332,7 +4341,7 @@ class DOMObserver {
|
|
|
4332
4341
|
mutations = this.queue.concat(mutations);
|
|
4333
4342
|
this.queue.length = 0;
|
|
4334
4343
|
}
|
|
4335
|
-
let sel = view.
|
|
4344
|
+
let sel = view.domSelectionRange();
|
|
4336
4345
|
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4337
4346
|
let from = -1, to = -1, typeOver = false, added = [];
|
|
4338
4347
|
if (view.editable) {
|
|
@@ -4449,6 +4458,33 @@ function checkCSS(view) {
|
|
|
4449
4458
|
cssCheckWarned = true;
|
|
4450
4459
|
}
|
|
4451
4460
|
}
|
|
4461
|
+
// Used to work around a Safari Selection/shadow DOM bug
|
|
4462
|
+
// Based on https://github.com/codemirror/dev/issues/414 fix
|
|
4463
|
+
function safariShadowSelectionRange(view) {
|
|
4464
|
+
let found;
|
|
4465
|
+
function read(event) {
|
|
4466
|
+
event.preventDefault();
|
|
4467
|
+
event.stopImmediatePropagation();
|
|
4468
|
+
found = event.getTargetRanges()[0];
|
|
4469
|
+
}
|
|
4470
|
+
// Because Safari (at least in 2018-2022) doesn't provide regular
|
|
4471
|
+
// access to the selection inside a shadowRoot, we have to perform a
|
|
4472
|
+
// ridiculous hack to get at it—using `execCommand` to trigger a
|
|
4473
|
+
// `beforeInput` event so that we can read the target range from the
|
|
4474
|
+
// event.
|
|
4475
|
+
view.dom.addEventListener("beforeinput", read, true);
|
|
4476
|
+
document.execCommand("indent");
|
|
4477
|
+
view.dom.removeEventListener("beforeinput", read, true);
|
|
4478
|
+
let anchorNode = found.startContainer, anchorOffset = found.startOffset;
|
|
4479
|
+
let focusNode = found.endContainer, focusOffset = found.endOffset;
|
|
4480
|
+
let currentAnchor = view.domAtPos(view.state.selection.anchor);
|
|
4481
|
+
// Since such a range doesn't distinguish between anchor and head,
|
|
4482
|
+
// use a heuristic that flips it around if its end matches the
|
|
4483
|
+
// current anchor.
|
|
4484
|
+
if (isEquivalentPosition(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset))
|
|
4485
|
+
[anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset];
|
|
4486
|
+
return { anchorNode, anchorOffset, focusNode, focusOffset };
|
|
4487
|
+
}
|
|
4452
4488
|
|
|
4453
4489
|
// Note that all referencing and parsing is done with the
|
|
4454
4490
|
// start-of-operation selection and document, since that's the one
|
|
@@ -4457,7 +4493,7 @@ function checkCSS(view) {
|
|
|
4457
4493
|
// readDOMChange.
|
|
4458
4494
|
function parseBetween(view, from_, to_) {
|
|
4459
4495
|
let { node: parent, fromOffset, toOffset, from, to } = view.docView.parseRange(from_, to_);
|
|
4460
|
-
let domSel = view.
|
|
4496
|
+
let domSel = view.domSelectionRange();
|
|
4461
4497
|
let find;
|
|
4462
4498
|
let anchor = domSel.anchorNode;
|
|
4463
4499
|
if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
|
|
@@ -4985,7 +5021,7 @@ class EditorView {
|
|
|
4985
5021
|
// Chrome sometimes starts misreporting the selection, so this
|
|
4986
5022
|
// tracks that and forces a selection reset when our update
|
|
4987
5023
|
// did write to the node.
|
|
4988
|
-
let chromeKludge = chrome ? (this.trackWrites = this.
|
|
5024
|
+
let chromeKludge = chrome ? (this.trackWrites = this.domSelectionRange().focusNode) : null;
|
|
4989
5025
|
if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
|
|
4990
5026
|
this.docView.updateOuterDeco([]);
|
|
4991
5027
|
this.docView.destroy();
|
|
@@ -4999,7 +5035,8 @@ class EditorView {
|
|
|
4999
5035
|
// can cause a spurious DOM selection update, disrupting mouse
|
|
5000
5036
|
// drag selection.
|
|
5001
5037
|
if (forceSelUpdate ||
|
|
5002
|
-
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.
|
|
5038
|
+
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
|
|
5039
|
+
anchorInRightPlace(this))) {
|
|
5003
5040
|
selectionToDOM(this, forceSelUpdate);
|
|
5004
5041
|
}
|
|
5005
5042
|
else {
|
|
@@ -5023,7 +5060,7 @@ class EditorView {
|
|
|
5023
5060
|
@internal
|
|
5024
5061
|
*/
|
|
5025
5062
|
scrollToSelection() {
|
|
5026
|
-
let startDOM = this.
|
|
5063
|
+
let startDOM = this.domSelectionRange().focusNode;
|
|
5027
5064
|
if (this.someProp("handleScrollToSelection", f => f(this))) ;
|
|
5028
5065
|
else if (this.state.selection instanceof NodeSelection) {
|
|
5029
5066
|
let target = this.docView.domAfterPos(this.state.selection.from);
|
|
@@ -5261,6 +5298,13 @@ class EditorView {
|
|
|
5261
5298
|
/**
|
|
5262
5299
|
@internal
|
|
5263
5300
|
*/
|
|
5301
|
+
domSelectionRange() {
|
|
5302
|
+
return safari && this.root.nodeType === 11 && deepActiveElement(this.dom.ownerDocument) == this.dom
|
|
5303
|
+
? safariShadowSelectionRange(this) : this.domSelection();
|
|
5304
|
+
}
|
|
5305
|
+
/**
|
|
5306
|
+
@internal
|
|
5307
|
+
*/
|
|
5264
5308
|
domSelection() {
|
|
5265
5309
|
return this.root.getSelection();
|
|
5266
5310
|
}
|
package/package.json
CHANGED
package/src/capturekeys.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Selection, NodeSelection, TextSelection, AllSelection, EditorState} from "prosemirror-state"
|
|
2
2
|
import {EditorView} from "./index"
|
|
3
3
|
import * as browser from "./browser"
|
|
4
|
-
import {domIndex, selectionCollapsed
|
|
4
|
+
import {domIndex, selectionCollapsed} from "./dom"
|
|
5
5
|
import {selectionToDOM} from "./selection"
|
|
6
6
|
|
|
7
7
|
function moveSelectionBlock(state: EditorState, dir: number) {
|
|
@@ -62,7 +62,7 @@ function isIgnorable(dom: Node) {
|
|
|
62
62
|
// Make sure the cursor isn't directly after one or more ignored
|
|
63
63
|
// nodes, which will confuse the browser's cursor motion logic.
|
|
64
64
|
function skipIgnoredNodesLeft(view: EditorView) {
|
|
65
|
-
let sel = view.
|
|
65
|
+
let sel = view.domSelectionRange()
|
|
66
66
|
let node = sel.focusNode!, offset = sel.focusOffset
|
|
67
67
|
if (!node) return
|
|
68
68
|
let moveNode, moveOffset: number | undefined, force = false
|
|
@@ -103,14 +103,14 @@ function skipIgnoredNodesLeft(view: EditorView) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
if (force) setSelFocus(view,
|
|
107
|
-
else if (moveNode) setSelFocus(view,
|
|
106
|
+
if (force) setSelFocus(view, node, offset)
|
|
107
|
+
else if (moveNode) setSelFocus(view, moveNode, moveOffset!)
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// Make sure the cursor isn't directly before one or more ignored
|
|
111
111
|
// nodes.
|
|
112
112
|
function skipIgnoredNodesRight(view: EditorView) {
|
|
113
|
-
let sel = view.
|
|
113
|
+
let sel = view.domSelectionRange()
|
|
114
114
|
let node = sel.focusNode!, offset = sel.focusOffset
|
|
115
115
|
if (!node) return
|
|
116
116
|
let len = nodeLen(node)
|
|
@@ -144,7 +144,7 @@ function skipIgnoredNodesRight(view: EditorView) {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
if (moveNode) setSelFocus(view,
|
|
147
|
+
if (moveNode) setSelFocus(view, moveNode, moveOffset!)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
function isBlockNode(dom: Node) {
|
|
@@ -152,7 +152,8 @@ function isBlockNode(dom: Node) {
|
|
|
152
152
|
return desc && desc.node && desc.node.isBlock
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
function setSelFocus(view: EditorView,
|
|
155
|
+
function setSelFocus(view: EditorView, node: Node, offset: number) {
|
|
156
|
+
let sel = view.domSelection()
|
|
156
157
|
if (selectionCollapsed(sel)) {
|
|
157
158
|
let range = document.createRange()
|
|
158
159
|
range.setEnd(node, offset)
|
|
@@ -222,7 +223,7 @@ function switchEditable(view: EditorView, node: HTMLElement, state: string) {
|
|
|
222
223
|
// after it
|
|
223
224
|
function safariDownArrowBug(view: EditorView) {
|
|
224
225
|
if (!browser.safari || view.state.selection.$head.parentOffset > 0) return false
|
|
225
|
-
let {focusNode, focusOffset} = view.
|
|
226
|
+
let {focusNode, focusOffset} = view.domSelectionRange()
|
|
226
227
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
|
|
227
228
|
focusNode.firstChild && (focusNode.firstChild as HTMLElement).contentEditable == "false") {
|
|
228
229
|
let child = focusNode.firstChild as HTMLElement
|
package/src/dom.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import * as browser from "./browser"
|
|
2
|
-
|
|
3
1
|
export type DOMNode = InstanceType<typeof window.Node>
|
|
4
2
|
export type DOMSelection = InstanceType<typeof window.Selection>
|
|
3
|
+
export type DOMSelectionRange = {
|
|
4
|
+
focusNode: DOMNode | null, focusOffset: number,
|
|
5
|
+
anchorNode: DOMNode | null, anchorOffset: number
|
|
6
|
+
}
|
|
5
7
|
|
|
6
8
|
export const domIndex = function(node: Node) {
|
|
7
9
|
for (var index = 0;; index++) {
|
|
@@ -10,7 +12,7 @@ export const domIndex = function(node: Node) {
|
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
export const parentNode = function(node: Node) {
|
|
15
|
+
export const parentNode = function(node: Node): Node | null {
|
|
14
16
|
let parent = (node as HTMLSlotElement).assignedSlot || node.parentNode
|
|
15
17
|
return parent && parent.nodeType == 11 ? (parent as ShadowRoot).host : parent
|
|
16
18
|
}
|
|
@@ -80,11 +82,9 @@ function hasBlockDesc(dom: Node) {
|
|
|
80
82
|
|
|
81
83
|
// Work around Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=447523
|
|
82
84
|
// (isCollapsed inappropriately returns true in shadow dom)
|
|
83
|
-
export const selectionCollapsed = function(domSel:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
collapsed = false
|
|
87
|
-
return collapsed
|
|
85
|
+
export const selectionCollapsed = function(domSel: DOMSelectionRange) {
|
|
86
|
+
return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset,
|
|
87
|
+
domSel.anchorNode!, domSel.anchorOffset)
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export function keyEvent(keyCode: number, key: string) {
|
|
@@ -94,3 +94,9 @@ export function keyEvent(keyCode: number, key: string) {
|
|
|
94
94
|
;(event as any).key = (event as any).code = key
|
|
95
95
|
return event
|
|
96
96
|
}
|
|
97
|
+
|
|
98
|
+
export function deepActiveElement(doc: Document) {
|
|
99
|
+
let elt = doc.activeElement
|
|
100
|
+
while (elt && elt.shadowRoot) elt = elt.shadowRoot.activeElement
|
|
101
|
+
return elt
|
|
102
|
+
}
|
package/src/domchange.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {EditorView} from "./index"
|
|
|
15
15
|
function parseBetween(view: EditorView, from_: number, to_: number) {
|
|
16
16
|
let {node: parent, fromOffset, toOffset, from, to} = view.docView.parseRange(from_, to_)
|
|
17
17
|
|
|
18
|
-
let domSel = view.
|
|
18
|
+
let domSel = view.domSelectionRange()
|
|
19
19
|
let find: {node: DOMNode, offset: number, pos?: number}[] | undefined
|
|
20
20
|
let anchor = domSel.anchorNode
|
|
21
21
|
if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
|
package/src/domcoords.ts
CHANGED
|
@@ -452,15 +452,18 @@ function endOfTextblockHorizontal(view: EditorView, state: EditorState, dir: "le
|
|
|
452
452
|
// one character, and see if that moves the cursor out of the
|
|
453
453
|
// textblock (or doesn't move it at all, when at the start/end of
|
|
454
454
|
// the document).
|
|
455
|
-
let
|
|
455
|
+
let {focusNode: oldNode, focusOffset: oldOff, anchorNode, anchorOffset} = view.domSelectionRange()
|
|
456
456
|
let oldBidiLevel = (sel as any).caretBidiLevel // Only for Firefox
|
|
457
457
|
;(sel as any).modify("move", dir, "character")
|
|
458
458
|
let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom
|
|
459
|
-
let
|
|
460
|
-
|
|
459
|
+
let {focusNode: newNode, focusOffset: newOff} = view.domSelectionRange()
|
|
460
|
+
let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
|
|
461
|
+
(oldNode == newNode && oldOff == newOff)
|
|
461
462
|
// Restore the previous selection
|
|
462
|
-
|
|
463
|
-
|
|
463
|
+
try {
|
|
464
|
+
sel.collapse(anchorNode, anchorOffset)
|
|
465
|
+
if (oldNode && (oldNode != anchorNode || oldOff != anchorOffset) && sel.extend) sel.extend(oldNode, oldOff)
|
|
466
|
+
} catch (_) {}
|
|
464
467
|
if (oldBidiLevel != null) (sel as any).caretBidiLevel = oldBidiLevel
|
|
465
468
|
return result
|
|
466
469
|
})
|
package/src/domobserver.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Selection} from "prosemirror-state"
|
|
2
2
|
import * as browser from "./browser"
|
|
3
|
-
import {domIndex, isEquivalentPosition, selectionCollapsed,
|
|
3
|
+
import {domIndex, isEquivalentPosition, selectionCollapsed, parentNode, DOMSelectionRange, DOMNode} from "./dom"
|
|
4
4
|
import {hasFocusAndSelection, selectionToDOM, selectionFromDOM} from "./selection"
|
|
5
5
|
import {EditorView} from "./index"
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ class SelectionState {
|
|
|
21
21
|
focusNode: Node | null = null
|
|
22
22
|
focusOffset: number = 0
|
|
23
23
|
|
|
24
|
-
set(sel:
|
|
24
|
+
set(sel: DOMSelectionRange) {
|
|
25
25
|
this.anchorNode = sel.anchorNode; this.anchorOffset = sel.anchorOffset
|
|
26
26
|
this.focusNode = sel.focusNode; this.focusOffset = sel.focusOffset
|
|
27
27
|
}
|
|
@@ -30,7 +30,7 @@ class SelectionState {
|
|
|
30
30
|
this.anchorNode = this.focusNode = null
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
eq(sel:
|
|
33
|
+
eq(sel: DOMSelectionRange) {
|
|
34
34
|
return sel.anchorNode == this.anchorNode && sel.anchorOffset == this.anchorOffset &&
|
|
35
35
|
sel.focusNode == this.focusNode && sel.focusOffset == this.focusOffset
|
|
36
36
|
}
|
|
@@ -127,7 +127,7 @@ export class DOMObserver {
|
|
|
127
127
|
// us a selection change event before the DOM changes are
|
|
128
128
|
// reported.
|
|
129
129
|
if (browser.ie && browser.ie_version <= 11 && !this.view.state.selection.empty) {
|
|
130
|
-
let sel = this.view.
|
|
130
|
+
let sel = this.view.domSelectionRange()
|
|
131
131
|
// Selection.isCollapsed isn't reliable on IE
|
|
132
132
|
if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode!, sel.anchorOffset))
|
|
133
133
|
return this.flushSoon()
|
|
@@ -136,16 +136,21 @@ export class DOMObserver {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
setCurSelection() {
|
|
139
|
-
this.currentSelection.set(this.view.
|
|
139
|
+
this.currentSelection.set(this.view.domSelectionRange())
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
ignoreSelectionChange(sel:
|
|
143
|
-
if (sel.
|
|
144
|
-
let
|
|
145
|
-
let
|
|
142
|
+
ignoreSelectionChange(sel: DOMSelectionRange) {
|
|
143
|
+
if (!sel.focusNode) return true
|
|
144
|
+
let ancestors: Set<Node> = new Set, container: DOMNode | undefined
|
|
145
|
+
for (let scan: DOMNode | null = sel.focusNode; scan; scan = parentNode(scan)) ancestors.add(scan)
|
|
146
|
+
for (let scan = sel.anchorNode; scan; scan = parentNode(scan)) if (ancestors.has(scan)) {
|
|
147
|
+
container = scan
|
|
148
|
+
break
|
|
149
|
+
}
|
|
150
|
+
let desc = container && this.view.docView.nearestDesc(container)
|
|
146
151
|
if (desc && desc.ignoreMutation({
|
|
147
152
|
type: "selection",
|
|
148
|
-
target: container
|
|
153
|
+
target: container!.nodeType == 3 ? container!.parentNode : container
|
|
149
154
|
} as any)) {
|
|
150
155
|
this.setCurSelection()
|
|
151
156
|
return true
|
|
@@ -161,7 +166,7 @@ export class DOMObserver {
|
|
|
161
166
|
this.queue.length = 0
|
|
162
167
|
}
|
|
163
168
|
|
|
164
|
-
let sel = view.
|
|
169
|
+
let sel = view.domSelectionRange()
|
|
165
170
|
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel)
|
|
166
171
|
|
|
167
172
|
let from = -1, to = -1, typeOver = false, added: Node[] = []
|
|
@@ -270,3 +275,34 @@ function checkCSS(view: EditorView) {
|
|
|
270
275
|
cssCheckWarned = true
|
|
271
276
|
}
|
|
272
277
|
}
|
|
278
|
+
|
|
279
|
+
// Used to work around a Safari Selection/shadow DOM bug
|
|
280
|
+
// Based on https://github.com/codemirror/dev/issues/414 fix
|
|
281
|
+
export function safariShadowSelectionRange(view: EditorView): DOMSelectionRange {
|
|
282
|
+
let found: StaticRange | undefined
|
|
283
|
+
function read(event: InputEvent) {
|
|
284
|
+
event.preventDefault()
|
|
285
|
+
event.stopImmediatePropagation()
|
|
286
|
+
found = event.getTargetRanges()[0]
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Because Safari (at least in 2018-2022) doesn't provide regular
|
|
290
|
+
// access to the selection inside a shadowRoot, we have to perform a
|
|
291
|
+
// ridiculous hack to get at it—using `execCommand` to trigger a
|
|
292
|
+
// `beforeInput` event so that we can read the target range from the
|
|
293
|
+
// event.
|
|
294
|
+
view.dom.addEventListener("beforeinput", read, true)
|
|
295
|
+
document.execCommand("indent")
|
|
296
|
+
view.dom.removeEventListener("beforeinput", read, true)
|
|
297
|
+
|
|
298
|
+
let anchorNode = found!.startContainer, anchorOffset = found!.startOffset
|
|
299
|
+
let focusNode = found!.endContainer, focusOffset = found!.endOffset
|
|
300
|
+
|
|
301
|
+
let currentAnchor = view.domAtPos(view.state.selection.anchor)
|
|
302
|
+
// Since such a range doesn't distinguish between anchor and head,
|
|
303
|
+
// use a heuristic that flips it around if its end matches the
|
|
304
|
+
// current anchor.
|
|
305
|
+
if (isEquivalentPosition(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset))
|
|
306
|
+
[anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset]
|
|
307
|
+
return {anchorNode, anchorOffset, focusNode, focusOffset}
|
|
308
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,9 +7,9 @@ import {docViewDesc, ViewDesc, NodeView, NodeViewDesc} from "./viewdesc"
|
|
|
7
7
|
import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition, InputState} from "./input"
|
|
8
8
|
import {selectionToDOM, anchorInRightPlace, syncNodeSelection} from "./selection"
|
|
9
9
|
import {Decoration, viewDecorations, DecorationSource} from "./decoration"
|
|
10
|
-
import {DOMObserver} from "./domobserver"
|
|
10
|
+
import {DOMObserver, safariShadowSelectionRange} from "./domobserver"
|
|
11
11
|
import {readDOMChange} from "./domchange"
|
|
12
|
-
import {DOMSelection, DOMNode} from "./dom"
|
|
12
|
+
import {DOMSelection, DOMNode, DOMSelectionRange, deepActiveElement} from "./dom"
|
|
13
13
|
import * as browser from "./browser"
|
|
14
14
|
|
|
15
15
|
export {Decoration, DecorationSet, DecorationAttrs, DecorationSource} from "./decoration"
|
|
@@ -195,7 +195,7 @@ export class EditorView {
|
|
|
195
195
|
// Chrome sometimes starts misreporting the selection, so this
|
|
196
196
|
// tracks that and forces a selection reset when our update
|
|
197
197
|
// did write to the node.
|
|
198
|
-
let chromeKludge = browser.chrome ? (this.trackWrites = this.
|
|
198
|
+
let chromeKludge = browser.chrome ? (this.trackWrites = this.domSelectionRange().focusNode) : null
|
|
199
199
|
if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
|
|
200
200
|
this.docView.updateOuterDeco([])
|
|
201
201
|
this.docView.destroy()
|
|
@@ -208,7 +208,8 @@ export class EditorView {
|
|
|
208
208
|
// can cause a spurious DOM selection update, disrupting mouse
|
|
209
209
|
// drag selection.
|
|
210
210
|
if (forceSelUpdate ||
|
|
211
|
-
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.
|
|
211
|
+
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
|
|
212
|
+
anchorInRightPlace(this))) {
|
|
212
213
|
selectionToDOM(this, forceSelUpdate)
|
|
213
214
|
} else {
|
|
214
215
|
syncNodeSelection(this, state.selection)
|
|
@@ -230,7 +231,7 @@ export class EditorView {
|
|
|
230
231
|
|
|
231
232
|
/// @internal
|
|
232
233
|
scrollToSelection() {
|
|
233
|
-
let startDOM = this.
|
|
234
|
+
let startDOM = this.domSelectionRange().focusNode!
|
|
234
235
|
if (this.someProp("handleScrollToSelection", f => f(this))) {
|
|
235
236
|
// Handled
|
|
236
237
|
} else if (this.state.selection instanceof NodeSelection) {
|
|
@@ -449,6 +450,12 @@ export class EditorView {
|
|
|
449
450
|
else this.updateState(this.state.apply(tr))
|
|
450
451
|
}
|
|
451
452
|
|
|
453
|
+
/// @internal
|
|
454
|
+
domSelectionRange(): DOMSelectionRange {
|
|
455
|
+
return browser.safari && this.root.nodeType === 11 && deepActiveElement(this.dom.ownerDocument) == this.dom
|
|
456
|
+
? safariShadowSelectionRange(this) : this.domSelection()
|
|
457
|
+
}
|
|
458
|
+
|
|
452
459
|
/// @internal
|
|
453
460
|
domSelection(): DOMSelection {
|
|
454
461
|
return (this.root as Document).getSelection()!
|
package/src/input.ts
CHANGED
|
@@ -463,12 +463,12 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
463
463
|
// the inserted text won't inherit the marks. So this moves it
|
|
464
464
|
// inside if necessary.
|
|
465
465
|
if (browser.gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore!.marks.length) {
|
|
466
|
-
let sel = view.
|
|
466
|
+
let sel = view.domSelectionRange()
|
|
467
467
|
for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
468
468
|
let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1]
|
|
469
469
|
if (!before) break
|
|
470
470
|
if (before.nodeType == 3) {
|
|
471
|
-
|
|
471
|
+
view.domSelection().collapse(before, before.nodeValue!.length)
|
|
472
472
|
break
|
|
473
473
|
} else {
|
|
474
474
|
node = before
|
|
@@ -715,7 +715,7 @@ handlers.focus = view => {
|
|
|
715
715
|
view.domObserver.start()
|
|
716
716
|
view.focused = true
|
|
717
717
|
setTimeout(() => {
|
|
718
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
718
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange()))
|
|
719
719
|
selectionToDOM(view)
|
|
720
720
|
}, 20)
|
|
721
721
|
}
|
package/src/selection.ts
CHANGED
|
@@ -2,12 +2,12 @@ import {TextSelection, NodeSelection, Selection} from "prosemirror-state"
|
|
|
2
2
|
import {ResolvedPos} from "prosemirror-model"
|
|
3
3
|
|
|
4
4
|
import * as browser from "./browser"
|
|
5
|
-
import {
|
|
5
|
+
import {isEquivalentPosition, domIndex, isOnEdge, selectionCollapsed} from "./dom"
|
|
6
6
|
import {EditorView} from "./index"
|
|
7
7
|
import {NodeViewDesc} from "./viewdesc"
|
|
8
8
|
|
|
9
9
|
export function selectionFromDOM(view: EditorView, origin: string | null = null) {
|
|
10
|
-
let domSel = view.
|
|
10
|
+
let domSel = view.domSelectionRange(), doc = view.state.doc
|
|
11
11
|
if (!domSel.focusNode) return null
|
|
12
12
|
let nearestDesc = view.docView.nearestDesc(domSel.focusNode), inWidget = nearestDesc && nearestDesc.size == 0
|
|
13
13
|
let head = view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset, 1)
|
|
@@ -50,7 +50,7 @@ export function selectionToDOM(view: EditorView, force = false) {
|
|
|
50
50
|
// in Safari. And the drag selection delay is to workarond issues
|
|
51
51
|
// which only present in Chrome.
|
|
52
52
|
if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && browser.chrome) {
|
|
53
|
-
let domSel = view.
|
|
53
|
+
let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection
|
|
54
54
|
if (domSel.anchorNode && curSel.anchorNode &&
|
|
55
55
|
isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset,
|
|
56
56
|
curSel.anchorNode, curSel.anchorOffset)) {
|
|
@@ -121,7 +121,7 @@ function resetEditable(element: HTMLElement) {
|
|
|
121
121
|
function removeClassOnSelectionChange(view: EditorView) {
|
|
122
122
|
let doc = view.dom.ownerDocument
|
|
123
123
|
doc.removeEventListener("selectionchange", view.input.hideSelectionGuard!)
|
|
124
|
-
let domSel = view.
|
|
124
|
+
let domSel = view.domSelectionRange()
|
|
125
125
|
let node = domSel.anchorNode, offset = domSel.anchorOffset
|
|
126
126
|
doc.addEventListener("selectionchange", view.input.hideSelectionGuard = () => {
|
|
127
127
|
if (domSel.anchorNode != node || domSel.anchorOffset != offset) {
|
|
@@ -186,7 +186,7 @@ export function hasFocusAndSelection(view: EditorView) {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
export function hasSelection(view: EditorView) {
|
|
189
|
-
let sel = view.
|
|
189
|
+
let sel = view.domSelectionRange()
|
|
190
190
|
if (!sel.anchorNode) return false
|
|
191
191
|
try {
|
|
192
192
|
// Firefox will raise 'permission denied' errors when accessing
|
|
@@ -201,6 +201,6 @@ export function hasSelection(view: EditorView) {
|
|
|
201
201
|
|
|
202
202
|
export function anchorInRightPlace(view: EditorView) {
|
|
203
203
|
let anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0)
|
|
204
|
-
let domSel = view.
|
|
204
|
+
let domSel = view.domSelectionRange()
|
|
205
205
|
return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode!, domSel.anchorOffset)
|
|
206
206
|
}
|
package/src/viewdesc.ts
CHANGED
|
@@ -419,20 +419,16 @@ export class ViewDesc {
|
|
|
419
419
|
if ((domSel.extend || anchor == head) && !brKludge) {
|
|
420
420
|
domSel.collapse(anchorDOM.node, anchorDOM.offset)
|
|
421
421
|
try {
|
|
422
|
-
if (anchor != head)
|
|
423
|
-
|
|
424
|
-
// there was no selection. (#1308)
|
|
425
|
-
try { domSel.extend(headDOM.node, headDOM.offset) }
|
|
426
|
-
catch (_) {}
|
|
427
|
-
}
|
|
422
|
+
if (anchor != head)
|
|
423
|
+
domSel.extend(headDOM.node, headDOM.offset)
|
|
428
424
|
domSelExtended = true
|
|
429
|
-
} catch (
|
|
425
|
+
} catch (_) {
|
|
430
426
|
// In some cases with Chrome the selection is empty after calling
|
|
431
427
|
// collapse, even when it should be valid. This appears to be a bug, but
|
|
432
428
|
// it is difficult to isolate. If this happens fallback to the old path
|
|
433
429
|
// without using extend.
|
|
434
|
-
if
|
|
435
|
-
//
|
|
430
|
+
// Similarly, this could crash on Safari if the editor is hidden, and
|
|
431
|
+
// there was no selection.
|
|
436
432
|
}
|
|
437
433
|
}
|
|
438
434
|
if (!domSelExtended) {
|
|
@@ -762,7 +758,7 @@ export class NodeViewDesc extends ViewDesc {
|
|
|
762
758
|
// are inside of this node
|
|
763
759
|
let {from, to} = view.state.selection
|
|
764
760
|
if (!(view.state.selection instanceof TextSelection) || from < pos || to > pos + this.node.content.size) return null
|
|
765
|
-
let sel = view.
|
|
761
|
+
let sel = view.domSelectionRange()
|
|
766
762
|
let textNode = nearbyTextNode(sel.focusNode!, sel.focusOffset)
|
|
767
763
|
if (!textNode || !this.dom.contains(textNode.parentNode)) return null
|
|
768
764
|
|