prosemirror-view 1.28.1 → 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 +12 -0
- package/dist/index.cjs +133 -61
- package/dist/index.js +110 -60
- 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 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 1.28.3 (2022-10-05)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Work around the five-year-old Safari bug where it won't accurately report the selection inside shadow roots, which would break ProseMirror when put in shadow DOM.
|
|
6
|
+
|
|
7
|
+
## 1.28.2 (2022-09-24)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Avoid a crash in selection updates in a hidden editor on Safari.
|
|
12
|
+
|
|
1
13
|
## 1.28.1 (2022-09-21)
|
|
2
14
|
|
|
3
15
|
### Bug fixes
|
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
|
});
|
|
@@ -1104,9 +1124,7 @@ var ViewDesc = function () {
|
|
|
1104
1124
|
try {
|
|
1105
1125
|
if (anchor != head) domSel.extend(headDOM.node, headDOM.offset);
|
|
1106
1126
|
domSelExtended = true;
|
|
1107
|
-
} catch (
|
|
1108
|
-
if (!(err instanceof DOMException)) throw err;
|
|
1109
|
-
}
|
|
1127
|
+
} catch (_) {}
|
|
1110
1128
|
}
|
|
1111
1129
|
|
|
1112
1130
|
if (!domSelExtended) {
|
|
@@ -1491,7 +1509,7 @@ var NodeViewDesc = function (_ViewDesc4) {
|
|
|
1491
1509
|
from = _view$state$selection.from,
|
|
1492
1510
|
to = _view$state$selection.to;
|
|
1493
1511
|
if (!(view.state.selection instanceof prosemirrorState.TextSelection) || from < pos || to > pos + this.node.content.size) return null;
|
|
1494
|
-
var sel = view.
|
|
1512
|
+
var sel = view.domSelectionRange();
|
|
1495
1513
|
var textNode = nearbyTextNode(sel.focusNode, sel.focusOffset);
|
|
1496
1514
|
if (!textNode || !this.dom.contains(textNode.parentNode)) return null;
|
|
1497
1515
|
|
|
@@ -2401,7 +2419,7 @@ function replaceNodes(nodes, from, to, view, replacement) {
|
|
|
2401
2419
|
|
|
2402
2420
|
function selectionFromDOM(view) {
|
|
2403
2421
|
var origin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
2404
|
-
var domSel = view.
|
|
2422
|
+
var domSel = view.domSelectionRange(),
|
|
2405
2423
|
doc = view.state.doc;
|
|
2406
2424
|
if (!domSel.focusNode) return null;
|
|
2407
2425
|
var nearestDesc = view.docView.nearestDesc(domSel.focusNode),
|
|
@@ -2450,7 +2468,7 @@ function selectionToDOM(view) {
|
|
|
2450
2468
|
if (!editorOwnsSelection(view)) return;
|
|
2451
2469
|
|
|
2452
2470
|
if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
|
|
2453
|
-
var domSel = view.
|
|
2471
|
+
var domSel = view.domSelectionRange(),
|
|
2454
2472
|
curSel = view.domObserver.currentSelection;
|
|
2455
2473
|
|
|
2456
2474
|
if (domSel.anchorNode && curSel.anchorNode && isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
|
|
@@ -2533,7 +2551,7 @@ function resetEditable(element) {
|
|
|
2533
2551
|
function removeClassOnSelectionChange(view) {
|
|
2534
2552
|
var doc = view.dom.ownerDocument;
|
|
2535
2553
|
doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
|
|
2536
|
-
var domSel = view.
|
|
2554
|
+
var domSel = view.domSelectionRange();
|
|
2537
2555
|
var node = domSel.anchorNode,
|
|
2538
2556
|
offset = domSel.anchorOffset;
|
|
2539
2557
|
doc.addEventListener("selectionchange", view.input.hideSelectionGuard = function () {
|
|
@@ -2595,7 +2613,7 @@ function hasFocusAndSelection(view) {
|
|
|
2595
2613
|
}
|
|
2596
2614
|
|
|
2597
2615
|
function hasSelection(view) {
|
|
2598
|
-
var sel = view.
|
|
2616
|
+
var sel = view.domSelectionRange();
|
|
2599
2617
|
if (!sel.anchorNode) return false;
|
|
2600
2618
|
|
|
2601
2619
|
try {
|
|
@@ -2607,7 +2625,7 @@ function hasSelection(view) {
|
|
|
2607
2625
|
|
|
2608
2626
|
function anchorInRightPlace(view) {
|
|
2609
2627
|
var anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);
|
|
2610
|
-
var domSel = view.
|
|
2628
|
+
var domSel = view.domSelectionRange();
|
|
2611
2629
|
return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);
|
|
2612
2630
|
}
|
|
2613
2631
|
|
|
@@ -2671,7 +2689,7 @@ function isIgnorable(dom) {
|
|
|
2671
2689
|
}
|
|
2672
2690
|
|
|
2673
2691
|
function skipIgnoredNodesLeft(view) {
|
|
2674
|
-
var sel = view.
|
|
2692
|
+
var sel = view.domSelectionRange();
|
|
2675
2693
|
var node = sel.focusNode,
|
|
2676
2694
|
offset = sel.focusOffset;
|
|
2677
2695
|
if (!node) return;
|
|
@@ -2717,11 +2735,11 @@ function skipIgnoredNodesLeft(view) {
|
|
|
2717
2735
|
}
|
|
2718
2736
|
}
|
|
2719
2737
|
|
|
2720
|
-
if (force) setSelFocus(view,
|
|
2738
|
+
if (force) setSelFocus(view, node, offset);else if (moveNode) setSelFocus(view, moveNode, moveOffset);
|
|
2721
2739
|
}
|
|
2722
2740
|
|
|
2723
2741
|
function skipIgnoredNodesRight(view) {
|
|
2724
|
-
var sel = view.
|
|
2742
|
+
var sel = view.domSelectionRange();
|
|
2725
2743
|
var node = sel.focusNode,
|
|
2726
2744
|
offset = sel.focusOffset;
|
|
2727
2745
|
if (!node) return;
|
|
@@ -2760,7 +2778,7 @@ function skipIgnoredNodesRight(view) {
|
|
|
2760
2778
|
}
|
|
2761
2779
|
}
|
|
2762
2780
|
|
|
2763
|
-
if (moveNode) setSelFocus(view,
|
|
2781
|
+
if (moveNode) setSelFocus(view, moveNode, moveOffset);
|
|
2764
2782
|
}
|
|
2765
2783
|
|
|
2766
2784
|
function isBlockNode(dom) {
|
|
@@ -2768,7 +2786,9 @@ function isBlockNode(dom) {
|
|
|
2768
2786
|
return desc && desc.node && desc.node.isBlock;
|
|
2769
2787
|
}
|
|
2770
2788
|
|
|
2771
|
-
function setSelFocus(view,
|
|
2789
|
+
function setSelFocus(view, node, offset) {
|
|
2790
|
+
var sel = view.domSelection();
|
|
2791
|
+
|
|
2772
2792
|
if (selectionCollapsed(sel)) {
|
|
2773
2793
|
var range = document.createRange();
|
|
2774
2794
|
range.setEnd(node, offset);
|
|
@@ -2837,9 +2857,9 @@ function switchEditable(view, node, state) {
|
|
|
2837
2857
|
function safariDownArrowBug(view) {
|
|
2838
2858
|
if (!safari || view.state.selection.$head.parentOffset > 0) return false;
|
|
2839
2859
|
|
|
2840
|
-
var _view$
|
|
2841
|
-
focusNode = _view$
|
|
2842
|
-
focusOffset = _view$
|
|
2860
|
+
var _view$domSelectionRan3 = view.domSelectionRange(),
|
|
2861
|
+
focusNode = _view$domSelectionRan3.focusNode,
|
|
2862
|
+
focusOffset = _view$domSelectionRan3.focusOffset;
|
|
2843
2863
|
|
|
2844
2864
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 && focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
2845
2865
|
var child = focusNode.firstChild;
|
|
@@ -3634,14 +3654,14 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
|
|
|
3634
3654
|
endComposition(view);
|
|
3635
3655
|
|
|
3636
3656
|
if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
|
|
3637
|
-
var sel = view.
|
|
3657
|
+
var sel = view.domSelectionRange();
|
|
3638
3658
|
|
|
3639
3659
|
for (var node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
3640
3660
|
var before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
|
|
3641
3661
|
if (!before) break;
|
|
3642
3662
|
|
|
3643
3663
|
if (before.nodeType == 3) {
|
|
3644
|
-
|
|
3664
|
+
view.domSelection().collapse(before, before.nodeValue.length);
|
|
3645
3665
|
break;
|
|
3646
3666
|
} else {
|
|
3647
3667
|
node = before;
|
|
@@ -3893,7 +3913,7 @@ handlers.focus = function (view) {
|
|
|
3893
3913
|
view.domObserver.start();
|
|
3894
3914
|
view.focused = true;
|
|
3895
3915
|
setTimeout(function () {
|
|
3896
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
3916
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange())) selectionToDOM(view);
|
|
3897
3917
|
}, 20);
|
|
3898
3918
|
}
|
|
3899
3919
|
};
|
|
@@ -4821,7 +4841,7 @@ var DOMObserver = function () {
|
|
|
4821
4841
|
if (this.suppressingSelectionUpdates) return selectionToDOM(this.view);
|
|
4822
4842
|
|
|
4823
4843
|
if (ie && ie_version <= 11 && !this.view.state.selection.empty) {
|
|
4824
|
-
var sel = this.view.
|
|
4844
|
+
var sel = this.view.domSelectionRange();
|
|
4825
4845
|
if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset)) return this.flushSoon();
|
|
4826
4846
|
}
|
|
4827
4847
|
|
|
@@ -4830,14 +4850,27 @@ var DOMObserver = function () {
|
|
|
4830
4850
|
}, {
|
|
4831
4851
|
key: "setCurSelection",
|
|
4832
4852
|
value: function setCurSelection() {
|
|
4833
|
-
this.currentSelection.set(this.view.
|
|
4853
|
+
this.currentSelection.set(this.view.domSelectionRange());
|
|
4834
4854
|
}
|
|
4835
4855
|
}, {
|
|
4836
4856
|
key: "ignoreSelectionChange",
|
|
4837
4857
|
value: function ignoreSelectionChange(sel) {
|
|
4838
|
-
if (sel.
|
|
4839
|
-
var
|
|
4840
|
-
|
|
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);
|
|
4841
4874
|
|
|
4842
4875
|
if (desc && desc.ignoreMutation({
|
|
4843
4876
|
type: "selection",
|
|
@@ -4859,7 +4892,7 @@ var DOMObserver = function () {
|
|
|
4859
4892
|
this.queue.length = 0;
|
|
4860
4893
|
}
|
|
4861
4894
|
|
|
4862
|
-
var sel = view.
|
|
4895
|
+
var sel = view.domSelectionRange();
|
|
4863
4896
|
var newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4864
4897
|
var from = -1,
|
|
4865
4898
|
to = -1,
|
|
@@ -4979,6 +5012,40 @@ function checkCSS(view) {
|
|
|
4979
5012
|
}
|
|
4980
5013
|
}
|
|
4981
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
|
+
|
|
4982
5049
|
function parseBetween(view, from_, to_) {
|
|
4983
5050
|
var _view$docView$parseRa = view.docView.parseRange(from_, to_),
|
|
4984
5051
|
parent = _view$docView$parseRa.node,
|
|
@@ -4987,7 +5054,7 @@ function parseBetween(view, from_, to_) {
|
|
|
4987
5054
|
from = _view$docView$parseRa.from,
|
|
4988
5055
|
to = _view$docView$parseRa.to;
|
|
4989
5056
|
|
|
4990
|
-
var domSel = view.
|
|
5057
|
+
var domSel = view.domSelectionRange();
|
|
4991
5058
|
var find;
|
|
4992
5059
|
var anchor = domSel.anchorNode;
|
|
4993
5060
|
|
|
@@ -5497,7 +5564,7 @@ var EditorView = function () {
|
|
|
5497
5564
|
var forceSelUpdate = updateDoc && (ie || chrome) && !this.composing && !prev.selection.empty && !state.selection.empty && selectionContextChanged(prev.selection, state.selection);
|
|
5498
5565
|
|
|
5499
5566
|
if (updateDoc) {
|
|
5500
|
-
var chromeKludge = chrome ? this.trackWrites = this.
|
|
5567
|
+
var chromeKludge = chrome ? this.trackWrites = this.domSelectionRange().focusNode : null;
|
|
5501
5568
|
|
|
5502
5569
|
if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
|
|
5503
5570
|
this.docView.updateOuterDeco([]);
|
|
@@ -5508,7 +5575,7 @@ var EditorView = function () {
|
|
|
5508
5575
|
if (chromeKludge && !this.trackWrites) forceSelUpdate = true;
|
|
5509
5576
|
}
|
|
5510
5577
|
|
|
5511
|
-
if (forceSelUpdate || !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.
|
|
5578
|
+
if (forceSelUpdate || !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) && anchorInRightPlace(this))) {
|
|
5512
5579
|
selectionToDOM(this, forceSelUpdate);
|
|
5513
5580
|
} else {
|
|
5514
5581
|
syncNodeSelection(this, state.selection);
|
|
@@ -5533,7 +5600,7 @@ var EditorView = function () {
|
|
|
5533
5600
|
value: function scrollToSelection() {
|
|
5534
5601
|
var _this16 = this;
|
|
5535
5602
|
|
|
5536
|
-
var startDOM = this.
|
|
5603
|
+
var startDOM = this.domSelectionRange().focusNode;
|
|
5537
5604
|
if (this.someProp("handleScrollToSelection", function (f) {
|
|
5538
5605
|
return f(_this16);
|
|
5539
5606
|
})) ;else if (this.state.selection instanceof prosemirrorState.NodeSelection) {
|
|
@@ -5716,6 +5783,11 @@ var EditorView = function () {
|
|
|
5716
5783
|
var dispatchTransaction = this._props.dispatchTransaction;
|
|
5717
5784
|
if (dispatchTransaction) dispatchTransaction.call(this, tr);else this.updateState(this.state.apply(tr));
|
|
5718
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
|
+
}
|
|
5719
5791
|
}, {
|
|
5720
5792
|
key: "domSelection",
|
|
5721
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;
|
|
@@ -961,14 +969,13 @@ class ViewDesc {
|
|
|
961
969
|
domSel.extend(headDOM.node, headDOM.offset);
|
|
962
970
|
domSelExtended = true;
|
|
963
971
|
}
|
|
964
|
-
catch (
|
|
972
|
+
catch (_) {
|
|
965
973
|
// In some cases with Chrome the selection is empty after calling
|
|
966
974
|
// collapse, even when it should be valid. This appears to be a bug, but
|
|
967
975
|
// it is difficult to isolate. If this happens fallback to the old path
|
|
968
976
|
// without using extend.
|
|
969
|
-
if
|
|
970
|
-
|
|
971
|
-
// declare global: DOMException
|
|
977
|
+
// Similarly, this could crash on Safari if the editor is hidden, and
|
|
978
|
+
// there was no selection.
|
|
972
979
|
}
|
|
973
980
|
}
|
|
974
981
|
if (!domSelExtended) {
|
|
@@ -1289,7 +1296,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1289
1296
|
let { from, to } = view.state.selection;
|
|
1290
1297
|
if (!(view.state.selection instanceof TextSelection) || from < pos || to > pos + this.node.content.size)
|
|
1291
1298
|
return null;
|
|
1292
|
-
let sel = view.
|
|
1299
|
+
let sel = view.domSelectionRange();
|
|
1293
1300
|
let textNode = nearbyTextNode(sel.focusNode, sel.focusOffset);
|
|
1294
1301
|
if (!textNode || !this.dom.contains(textNode.parentNode))
|
|
1295
1302
|
return null;
|
|
@@ -2025,7 +2032,7 @@ function replaceNodes(nodes, from, to, view, replacement) {
|
|
|
2025
2032
|
}
|
|
2026
2033
|
|
|
2027
2034
|
function selectionFromDOM(view, origin = null) {
|
|
2028
|
-
let domSel = view.
|
|
2035
|
+
let domSel = view.domSelectionRange(), doc = view.state.doc;
|
|
2029
2036
|
if (!domSel.focusNode)
|
|
2030
2037
|
return null;
|
|
2031
2038
|
let nearestDesc = view.docView.nearestDesc(domSel.focusNode), inWidget = nearestDesc && nearestDesc.size == 0;
|
|
@@ -2069,7 +2076,7 @@ function selectionToDOM(view, force = false) {
|
|
|
2069
2076
|
// in Safari. And the drag selection delay is to workarond issues
|
|
2070
2077
|
// which only present in Chrome.
|
|
2071
2078
|
if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
|
|
2072
|
-
let domSel = view.
|
|
2079
|
+
let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
|
|
2073
2080
|
if (domSel.anchorNode && curSel.anchorNode &&
|
|
2074
2081
|
isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
|
|
2075
2082
|
view.input.mouseDown.delayedSelectionSync = true;
|
|
@@ -2144,7 +2151,7 @@ function resetEditable(element) {
|
|
|
2144
2151
|
function removeClassOnSelectionChange(view) {
|
|
2145
2152
|
let doc = view.dom.ownerDocument;
|
|
2146
2153
|
doc.removeEventListener("selectionchange", view.input.hideSelectionGuard);
|
|
2147
|
-
let domSel = view.
|
|
2154
|
+
let domSel = view.domSelectionRange();
|
|
2148
2155
|
let node = domSel.anchorNode, offset = domSel.anchorOffset;
|
|
2149
2156
|
doc.addEventListener("selectionchange", view.input.hideSelectionGuard = () => {
|
|
2150
2157
|
if (domSel.anchorNode != node || domSel.anchorOffset != offset) {
|
|
@@ -2208,7 +2215,7 @@ function hasFocusAndSelection(view) {
|
|
|
2208
2215
|
return hasSelection(view);
|
|
2209
2216
|
}
|
|
2210
2217
|
function hasSelection(view) {
|
|
2211
|
-
let sel = view.
|
|
2218
|
+
let sel = view.domSelectionRange();
|
|
2212
2219
|
if (!sel.anchorNode)
|
|
2213
2220
|
return false;
|
|
2214
2221
|
try {
|
|
@@ -2224,7 +2231,7 @@ function hasSelection(view) {
|
|
|
2224
2231
|
}
|
|
2225
2232
|
function anchorInRightPlace(view) {
|
|
2226
2233
|
let anchorDOM = view.docView.domFromPos(view.state.selection.anchor, 0);
|
|
2227
|
-
let domSel = view.
|
|
2234
|
+
let domSel = view.domSelectionRange();
|
|
2228
2235
|
return isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset);
|
|
2229
2236
|
}
|
|
2230
2237
|
|
|
@@ -2291,7 +2298,7 @@ function isIgnorable(dom) {
|
|
|
2291
2298
|
// Make sure the cursor isn't directly after one or more ignored
|
|
2292
2299
|
// nodes, which will confuse the browser's cursor motion logic.
|
|
2293
2300
|
function skipIgnoredNodesLeft(view) {
|
|
2294
|
-
let sel = view.
|
|
2301
|
+
let sel = view.domSelectionRange();
|
|
2295
2302
|
let node = sel.focusNode, offset = sel.focusOffset;
|
|
2296
2303
|
if (!node)
|
|
2297
2304
|
return;
|
|
@@ -2343,14 +2350,14 @@ function skipIgnoredNodesLeft(view) {
|
|
|
2343
2350
|
}
|
|
2344
2351
|
}
|
|
2345
2352
|
if (force)
|
|
2346
|
-
setSelFocus(view,
|
|
2353
|
+
setSelFocus(view, node, offset);
|
|
2347
2354
|
else if (moveNode)
|
|
2348
|
-
setSelFocus(view,
|
|
2355
|
+
setSelFocus(view, moveNode, moveOffset);
|
|
2349
2356
|
}
|
|
2350
2357
|
// Make sure the cursor isn't directly before one or more ignored
|
|
2351
2358
|
// nodes.
|
|
2352
2359
|
function skipIgnoredNodesRight(view) {
|
|
2353
|
-
let sel = view.
|
|
2360
|
+
let sel = view.domSelectionRange();
|
|
2354
2361
|
let node = sel.focusNode, offset = sel.focusOffset;
|
|
2355
2362
|
if (!node)
|
|
2356
2363
|
return;
|
|
@@ -2392,13 +2399,14 @@ function skipIgnoredNodesRight(view) {
|
|
|
2392
2399
|
}
|
|
2393
2400
|
}
|
|
2394
2401
|
if (moveNode)
|
|
2395
|
-
setSelFocus(view,
|
|
2402
|
+
setSelFocus(view, moveNode, moveOffset);
|
|
2396
2403
|
}
|
|
2397
2404
|
function isBlockNode(dom) {
|
|
2398
2405
|
let desc = dom.pmViewDesc;
|
|
2399
2406
|
return desc && desc.node && desc.node.isBlock;
|
|
2400
2407
|
}
|
|
2401
|
-
function setSelFocus(view,
|
|
2408
|
+
function setSelFocus(view, node, offset) {
|
|
2409
|
+
let sel = view.domSelection();
|
|
2402
2410
|
if (selectionCollapsed(sel)) {
|
|
2403
2411
|
let range = document.createRange();
|
|
2404
2412
|
range.setEnd(node, offset);
|
|
@@ -2474,7 +2482,7 @@ function switchEditable(view, node, state) {
|
|
|
2474
2482
|
function safariDownArrowBug(view) {
|
|
2475
2483
|
if (!safari || view.state.selection.$head.parentOffset > 0)
|
|
2476
2484
|
return false;
|
|
2477
|
-
let { focusNode, focusOffset } = view.
|
|
2485
|
+
let { focusNode, focusOffset } = view.domSelectionRange();
|
|
2478
2486
|
if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
|
|
2479
2487
|
focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
2480
2488
|
let child = focusNode.firstChild;
|
|
@@ -3200,13 +3208,13 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3200
3208
|
// the inserted text won't inherit the marks. So this moves it
|
|
3201
3209
|
// inside if necessary.
|
|
3202
3210
|
if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
|
|
3203
|
-
let sel = view.
|
|
3211
|
+
let sel = view.domSelectionRange();
|
|
3204
3212
|
for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
3205
3213
|
let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
|
|
3206
3214
|
if (!before)
|
|
3207
3215
|
break;
|
|
3208
3216
|
if (before.nodeType == 3) {
|
|
3209
|
-
|
|
3217
|
+
view.domSelection().collapse(before, before.nodeValue.length);
|
|
3210
3218
|
break;
|
|
3211
3219
|
}
|
|
3212
3220
|
else {
|
|
@@ -3462,7 +3470,7 @@ handlers.focus = view => {
|
|
|
3462
3470
|
view.domObserver.start();
|
|
3463
3471
|
view.focused = true;
|
|
3464
3472
|
setTimeout(() => {
|
|
3465
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
3473
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelectionRange()))
|
|
3466
3474
|
selectionToDOM(view);
|
|
3467
3475
|
}, 20);
|
|
3468
3476
|
}
|
|
@@ -4294,7 +4302,7 @@ class DOMObserver {
|
|
|
4294
4302
|
// us a selection change event before the DOM changes are
|
|
4295
4303
|
// reported.
|
|
4296
4304
|
if (ie && ie_version <= 11 && !this.view.state.selection.empty) {
|
|
4297
|
-
let sel = this.view.
|
|
4305
|
+
let sel = this.view.domSelectionRange();
|
|
4298
4306
|
// Selection.isCollapsed isn't reliable on IE
|
|
4299
4307
|
if (sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
4300
4308
|
return this.flushSoon();
|
|
@@ -4302,13 +4310,20 @@ class DOMObserver {
|
|
|
4302
4310
|
this.flush();
|
|
4303
4311
|
}
|
|
4304
4312
|
setCurSelection() {
|
|
4305
|
-
this.currentSelection.set(this.view.
|
|
4313
|
+
this.currentSelection.set(this.view.domSelectionRange());
|
|
4306
4314
|
}
|
|
4307
4315
|
ignoreSelectionChange(sel) {
|
|
4308
|
-
if (sel.
|
|
4316
|
+
if (!sel.focusNode)
|
|
4309
4317
|
return true;
|
|
4310
|
-
let
|
|
4311
|
-
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);
|
|
4312
4327
|
if (desc && desc.ignoreMutation({
|
|
4313
4328
|
type: "selection",
|
|
4314
4329
|
target: container.nodeType == 3 ? container.parentNode : container
|
|
@@ -4326,7 +4341,7 @@ class DOMObserver {
|
|
|
4326
4341
|
mutations = this.queue.concat(mutations);
|
|
4327
4342
|
this.queue.length = 0;
|
|
4328
4343
|
}
|
|
4329
|
-
let sel = view.
|
|
4344
|
+
let sel = view.domSelectionRange();
|
|
4330
4345
|
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4331
4346
|
let from = -1, to = -1, typeOver = false, added = [];
|
|
4332
4347
|
if (view.editable) {
|
|
@@ -4443,6 +4458,33 @@ function checkCSS(view) {
|
|
|
4443
4458
|
cssCheckWarned = true;
|
|
4444
4459
|
}
|
|
4445
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
|
+
}
|
|
4446
4488
|
|
|
4447
4489
|
// Note that all referencing and parsing is done with the
|
|
4448
4490
|
// start-of-operation selection and document, since that's the one
|
|
@@ -4451,7 +4493,7 @@ function checkCSS(view) {
|
|
|
4451
4493
|
// readDOMChange.
|
|
4452
4494
|
function parseBetween(view, from_, to_) {
|
|
4453
4495
|
let { node: parent, fromOffset, toOffset, from, to } = view.docView.parseRange(from_, to_);
|
|
4454
|
-
let domSel = view.
|
|
4496
|
+
let domSel = view.domSelectionRange();
|
|
4455
4497
|
let find;
|
|
4456
4498
|
let anchor = domSel.anchorNode;
|
|
4457
4499
|
if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
|
|
@@ -4979,7 +5021,7 @@ class EditorView {
|
|
|
4979
5021
|
// Chrome sometimes starts misreporting the selection, so this
|
|
4980
5022
|
// tracks that and forces a selection reset when our update
|
|
4981
5023
|
// did write to the node.
|
|
4982
|
-
let chromeKludge = chrome ? (this.trackWrites = this.
|
|
5024
|
+
let chromeKludge = chrome ? (this.trackWrites = this.domSelectionRange().focusNode) : null;
|
|
4983
5025
|
if (redraw || !this.docView.update(state.doc, outerDeco, innerDeco, this)) {
|
|
4984
5026
|
this.docView.updateOuterDeco([]);
|
|
4985
5027
|
this.docView.destroy();
|
|
@@ -4993,7 +5035,8 @@ class EditorView {
|
|
|
4993
5035
|
// can cause a spurious DOM selection update, disrupting mouse
|
|
4994
5036
|
// drag selection.
|
|
4995
5037
|
if (forceSelUpdate ||
|
|
4996
|
-
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.
|
|
5038
|
+
!(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
|
|
5039
|
+
anchorInRightPlace(this))) {
|
|
4997
5040
|
selectionToDOM(this, forceSelUpdate);
|
|
4998
5041
|
}
|
|
4999
5042
|
else {
|
|
@@ -5017,7 +5060,7 @@ class EditorView {
|
|
|
5017
5060
|
@internal
|
|
5018
5061
|
*/
|
|
5019
5062
|
scrollToSelection() {
|
|
5020
|
-
let startDOM = this.
|
|
5063
|
+
let startDOM = this.domSelectionRange().focusNode;
|
|
5021
5064
|
if (this.someProp("handleScrollToSelection", f => f(this))) ;
|
|
5022
5065
|
else if (this.state.selection instanceof NodeSelection) {
|
|
5023
5066
|
let target = this.docView.domAfterPos(this.state.selection.from);
|
|
@@ -5255,6 +5298,13 @@ class EditorView {
|
|
|
5255
5298
|
/**
|
|
5256
5299
|
@internal
|
|
5257
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
|
+
*/
|
|
5258
5308
|
domSelection() {
|
|
5259
5309
|
return this.root.getSelection();
|
|
5260
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,15 +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)
|
|
422
|
+
if (anchor != head)
|
|
423
|
+
domSel.extend(headDOM.node, headDOM.offset)
|
|
423
424
|
domSelExtended = true
|
|
424
|
-
} catch (
|
|
425
|
+
} catch (_) {
|
|
425
426
|
// In some cases with Chrome the selection is empty after calling
|
|
426
427
|
// collapse, even when it should be valid. This appears to be a bug, but
|
|
427
428
|
// it is difficult to isolate. If this happens fallback to the old path
|
|
428
429
|
// without using extend.
|
|
429
|
-
if
|
|
430
|
-
//
|
|
430
|
+
// Similarly, this could crash on Safari if the editor is hidden, and
|
|
431
|
+
// there was no selection.
|
|
431
432
|
}
|
|
432
433
|
}
|
|
433
434
|
if (!domSelExtended) {
|
|
@@ -757,7 +758,7 @@ export class NodeViewDesc extends ViewDesc {
|
|
|
757
758
|
// are inside of this node
|
|
758
759
|
let {from, to} = view.state.selection
|
|
759
760
|
if (!(view.state.selection instanceof TextSelection) || from < pos || to > pos + this.node.content.size) return null
|
|
760
|
-
let sel = view.
|
|
761
|
+
let sel = view.domSelectionRange()
|
|
761
762
|
let textNode = nearbyTextNode(sel.focusNode!, sel.focusOffset)
|
|
762
763
|
if (!textNode || !this.dom.contains(textNode.parentNode)) return null
|
|
763
764
|
|