prosemirror-view 1.42.4 → 1.42.6
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 +22 -0
- package/dist/index.cjs +150 -128
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +165 -140
- package/package.json +2 -2
- package/src/capturekeys.ts +31 -35
- package/src/clipboard.ts +10 -7
- package/src/dom.ts +15 -8
- package/src/domchange.ts +15 -6
- package/src/domcoords.ts +52 -53
- package/src/domobserver.ts +6 -7
- package/src/index.ts +4 -4
- package/src/input.ts +7 -7
- package/src/selection.ts +19 -6
- package/src/viewdesc.ts +37 -33
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TextSelection, NodeSelection,
|
|
1
|
+
import { TextSelection, NodeSelection, Selection, AllSelection } from 'prosemirror-state';
|
|
2
2
|
import { DOMSerializer, Fragment, Mark, Slice, DOMParser } from 'prosemirror-model';
|
|
3
3
|
import { dropPoint } from 'prosemirror-transform';
|
|
4
4
|
|
|
@@ -41,15 +41,15 @@ function scanFor(node, off, targetNode, targetOff, dir) {
|
|
|
41
41
|
return true;
|
|
42
42
|
if (off == (dir < 0 ? 0 : nodeSize(node))) {
|
|
43
43
|
let parent = node.parentNode;
|
|
44
|
-
if (!parent || parent
|
|
44
|
+
if (!parent || !isElt(parent) || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
|
|
45
45
|
node.contentEditable == "false")
|
|
46
46
|
return false;
|
|
47
47
|
off = domIndex(node) + (dir < 0 ? 0 : 1);
|
|
48
48
|
node = parent;
|
|
49
49
|
}
|
|
50
|
-
else if (node
|
|
50
|
+
else if (isElt(node)) {
|
|
51
51
|
let child = node.childNodes[off + (dir < 0 ? -1 : 0)];
|
|
52
|
-
if (child
|
|
52
|
+
if (isElt(child) && child.contentEditable == "false") {
|
|
53
53
|
if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection)
|
|
54
54
|
off += dir;
|
|
55
55
|
else
|
|
@@ -68,11 +68,16 @@ function scanFor(node, off, targetNode, targetOff, dir) {
|
|
|
68
68
|
function nodeSize(node) {
|
|
69
69
|
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
70
70
|
}
|
|
71
|
+
function isElt(node) { return node.nodeType == 1; }
|
|
72
|
+
function isText(node) { return node.nodeType == 3; }
|
|
73
|
+
function contains(parent, child) {
|
|
74
|
+
return child ? parent.contains(isElt(child) ? child : child.parentNode) : false;
|
|
75
|
+
}
|
|
71
76
|
function textNodeBefore$1(node, offset) {
|
|
72
77
|
for (;;) {
|
|
73
|
-
if (node
|
|
78
|
+
if (isText(node) && offset)
|
|
74
79
|
return node;
|
|
75
|
-
if (node
|
|
80
|
+
if (isElt(node) && offset > 0) {
|
|
76
81
|
if (node.contentEditable == "false")
|
|
77
82
|
return null;
|
|
78
83
|
node = node.childNodes[offset - 1];
|
|
@@ -89,9 +94,9 @@ function textNodeBefore$1(node, offset) {
|
|
|
89
94
|
}
|
|
90
95
|
function textNodeAfter$1(node, offset) {
|
|
91
96
|
for (;;) {
|
|
92
|
-
if (node
|
|
97
|
+
if (isText(node) && offset < node.nodeValue.length)
|
|
93
98
|
return node;
|
|
94
|
-
if (node
|
|
99
|
+
if (isElt(node) && offset < node.childNodes.length) {
|
|
95
100
|
if (node.contentEditable == "false")
|
|
96
101
|
return null;
|
|
97
102
|
node = node.childNodes[offset];
|
|
@@ -215,13 +220,12 @@ function scrollRectIntoView(view, rect, startDOM) {
|
|
|
215
220
|
for (let parent = startDOM || view.dom;;) {
|
|
216
221
|
if (!parent)
|
|
217
222
|
break;
|
|
218
|
-
if (parent
|
|
223
|
+
if (!isElt(parent)) {
|
|
219
224
|
parent = parentNode(parent);
|
|
220
225
|
continue;
|
|
221
226
|
}
|
|
222
|
-
let
|
|
223
|
-
let
|
|
224
|
-
let bounding = atTop ? windowRect(doc) : clientRect(elt);
|
|
227
|
+
let atTop = parent == doc.body;
|
|
228
|
+
let bounding = atTop ? windowRect(doc) : clientRect(parent);
|
|
225
229
|
let moveX = 0, moveY = 0;
|
|
226
230
|
if (rect.top < bounding.top + getSide(scrollThreshold, "top"))
|
|
227
231
|
moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top"));
|
|
@@ -238,12 +242,12 @@ function scrollRectIntoView(view, rect, startDOM) {
|
|
|
238
242
|
doc.defaultView.scrollBy(moveX, moveY);
|
|
239
243
|
}
|
|
240
244
|
else {
|
|
241
|
-
let startX =
|
|
245
|
+
let startX = parent.scrollLeft, startY = parent.scrollTop;
|
|
242
246
|
if (moveY)
|
|
243
|
-
|
|
247
|
+
parent.scrollTop += moveY;
|
|
244
248
|
if (moveX)
|
|
245
|
-
|
|
246
|
-
let dX =
|
|
249
|
+
parent.scrollLeft += moveX;
|
|
250
|
+
let dX = parent.scrollLeft - startX, dY = parent.scrollTop - startY;
|
|
247
251
|
rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
|
|
248
252
|
}
|
|
249
253
|
}
|
|
@@ -318,14 +322,15 @@ function focusPreventScroll(dom) {
|
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
324
|
function findOffsetInNode(node, coords) {
|
|
321
|
-
let closest
|
|
325
|
+
let closest;
|
|
326
|
+
let dxClosest = 2e8, coordsClosest, offset = 0;
|
|
322
327
|
let rowBot = coords.top, rowTop = coords.top;
|
|
323
328
|
let firstBelow, coordsBelow;
|
|
324
329
|
for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
|
|
325
330
|
let rects;
|
|
326
|
-
if (child
|
|
331
|
+
if (isElt(child))
|
|
327
332
|
rects = child.getClientRects();
|
|
328
|
-
else if (child
|
|
333
|
+
else if (isText(child))
|
|
329
334
|
rects = textRange(child).getClientRects();
|
|
330
335
|
else
|
|
331
336
|
continue;
|
|
@@ -339,11 +344,11 @@ function findOffsetInNode(node, coords) {
|
|
|
339
344
|
if (dx < dxClosest) {
|
|
340
345
|
closest = child;
|
|
341
346
|
dxClosest = dx;
|
|
342
|
-
coordsClosest = dx && closest
|
|
347
|
+
coordsClosest = dx && isText(closest) ? {
|
|
343
348
|
left: rect.right < coords.left ? rect.right : rect.left,
|
|
344
349
|
top: coords.top
|
|
345
350
|
} : coords;
|
|
346
|
-
if (child
|
|
351
|
+
if (isElt(child) && dx)
|
|
347
352
|
offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0);
|
|
348
353
|
continue;
|
|
349
354
|
}
|
|
@@ -362,9 +367,9 @@ function findOffsetInNode(node, coords) {
|
|
|
362
367
|
coordsClosest = coordsBelow;
|
|
363
368
|
dxClosest = 0;
|
|
364
369
|
}
|
|
365
|
-
if (closest && closest
|
|
370
|
+
if (closest && isText(closest))
|
|
366
371
|
return findOffsetInText(closest, coordsClosest);
|
|
367
|
-
if (!closest ||
|
|
372
|
+
if (!closest || dxClosest)
|
|
368
373
|
return { node, offset };
|
|
369
374
|
return findOffsetInNode(closest, coordsClosest);
|
|
370
375
|
}
|
|
@@ -397,7 +402,7 @@ function targetKludge(dom, coords) {
|
|
|
397
402
|
}
|
|
398
403
|
function posFromElement(view, elt, coords) {
|
|
399
404
|
let { node, offset } = findOffsetInNode(elt, coords), bias = -1;
|
|
400
|
-
if (node
|
|
405
|
+
if (isElt(node) && !node.firstChild) {
|
|
401
406
|
let rect = node.getBoundingClientRect();
|
|
402
407
|
bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
|
|
403
408
|
}
|
|
@@ -417,7 +422,7 @@ function posFromCaret(view, node, offset, coords) {
|
|
|
417
422
|
let desc = view.docView.nearestDesc(cur, true), rect;
|
|
418
423
|
if (!desc)
|
|
419
424
|
return null;
|
|
420
|
-
if (desc.dom
|
|
425
|
+
if (isElt(desc.dom) && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
|
|
421
426
|
// Ignore elements with zero-size bounding rectangles
|
|
422
427
|
((rect = desc.dom.getBoundingClientRect()).width || rect.height)) {
|
|
423
428
|
if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) {
|
|
@@ -444,7 +449,7 @@ function elementFromPoint(element, coords, box) {
|
|
|
444
449
|
if (len && box.top < box.bottom) {
|
|
445
450
|
for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {
|
|
446
451
|
let child = element.childNodes[i];
|
|
447
|
-
if (child
|
|
452
|
+
if (isElt(child)) {
|
|
448
453
|
let rects = child.getClientRects();
|
|
449
454
|
for (let j = 0; j < rects.length; j++) {
|
|
450
455
|
let rect = rects[j];
|
|
@@ -467,7 +472,7 @@ function posAtCoords(view, coords) {
|
|
|
467
472
|
let elt = (view.root.elementFromPoint ? view.root : doc)
|
|
468
473
|
.elementFromPoint(coords.left, coords.top);
|
|
469
474
|
let pos;
|
|
470
|
-
if (!elt || !view.dom.contains(elt
|
|
475
|
+
if (!elt || !view.dom.contains(elt)) {
|
|
471
476
|
let box = view.dom.getBoundingClientRect();
|
|
472
477
|
if (!inRect(coords, box))
|
|
473
478
|
return null;
|
|
@@ -483,7 +488,7 @@ function posAtCoords(view, coords) {
|
|
|
483
488
|
}
|
|
484
489
|
elt = targetKludge(elt, coords);
|
|
485
490
|
if (node) {
|
|
486
|
-
if (gecko && node
|
|
491
|
+
if (gecko && isElt(node)) {
|
|
487
492
|
// Firefox will sometimes return offsets into <input> nodes, which
|
|
488
493
|
// have no actual children, from caretPositionFromPoint (#953)
|
|
489
494
|
offset = Math.min(offset, node.childNodes.length);
|
|
@@ -498,18 +503,18 @@ function posAtCoords(view, coords) {
|
|
|
498
503
|
}
|
|
499
504
|
let prev;
|
|
500
505
|
// When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.
|
|
501
|
-
if (webkit && offset && node
|
|
506
|
+
if (webkit && offset && isElt(node) && isElt(prev = node.childNodes[offset - 1]) &&
|
|
502
507
|
prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top)
|
|
503
508
|
offset--;
|
|
504
509
|
// Suspiciously specific kludge to work around caret*FromPoint
|
|
505
510
|
// never returning a position at the end of the document
|
|
506
|
-
if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild
|
|
511
|
+
if (node == view.dom && offset == node.childNodes.length - 1 && isElt(node.lastChild) &&
|
|
507
512
|
coords.top > node.lastChild.getBoundingClientRect().bottom)
|
|
508
513
|
pos = view.state.doc.content.size;
|
|
509
514
|
// Ignore positions directly after a BR, since caret*FromPoint
|
|
510
515
|
// 'round up' positions that would be more accurately placed
|
|
511
516
|
// before the BR node.
|
|
512
|
-
else if (offset == 0 || node
|
|
517
|
+
else if (offset == 0 || !isElt(node) || node.childNodes[offset - 1].nodeName != "BR")
|
|
513
518
|
pos = posFromCaret(view, node, offset, coords);
|
|
514
519
|
}
|
|
515
520
|
if (pos == null)
|
|
@@ -535,7 +540,7 @@ const BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
|
|
|
535
540
|
function coordsAtPos(view, pos, side) {
|
|
536
541
|
let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
|
|
537
542
|
let supportEmptyRange = webkit || gecko;
|
|
538
|
-
if (node
|
|
543
|
+
if (isText(node)) {
|
|
539
544
|
// These browsers support querying empty text ranges. Prefer that in
|
|
540
545
|
// bidi context or when at the end of a node.
|
|
541
546
|
if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
|
|
@@ -577,12 +582,12 @@ function coordsAtPos(view, pos, side) {
|
|
|
577
582
|
if (!$dom.parent.inlineContent) {
|
|
578
583
|
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
579
584
|
let before = node.childNodes[offset - 1];
|
|
580
|
-
if (before
|
|
585
|
+
if (isElt(before))
|
|
581
586
|
return flattenH(before.getBoundingClientRect(), false);
|
|
582
587
|
}
|
|
583
588
|
if (atom == null && offset < nodeSize(node)) {
|
|
584
589
|
let after = node.childNodes[offset];
|
|
585
|
-
if (after
|
|
590
|
+
if (isElt(after))
|
|
586
591
|
return flattenH(after.getBoundingClientRect(), true);
|
|
587
592
|
}
|
|
588
593
|
return flattenH(node.getBoundingClientRect(), side >= 0);
|
|
@@ -590,10 +595,10 @@ function coordsAtPos(view, pos, side) {
|
|
|
590
595
|
// Inline, not in text node (this is not Bidi-safe)
|
|
591
596
|
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
592
597
|
let before = node.childNodes[offset - 1];
|
|
593
|
-
let target = before
|
|
598
|
+
let target = isText(before) ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
|
|
594
599
|
// BR nodes tend to only return the rectangle before them.
|
|
595
600
|
// Only use them if they are the last element in their parent
|
|
596
|
-
: before
|
|
601
|
+
: isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
|
|
597
602
|
if (target)
|
|
598
603
|
return flattenV(singleRect(target, 1), false);
|
|
599
604
|
}
|
|
@@ -601,13 +606,13 @@ function coordsAtPos(view, pos, side) {
|
|
|
601
606
|
let after = node.childNodes[offset];
|
|
602
607
|
while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)
|
|
603
608
|
after = after.nextSibling;
|
|
604
|
-
let target = !after ? null : after
|
|
605
|
-
: after
|
|
609
|
+
let target = !after ? null : isText(after) ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
|
|
610
|
+
: isElt(after) ? after : null;
|
|
606
611
|
if (target)
|
|
607
612
|
return flattenV(singleRect(target, -1), true);
|
|
608
613
|
}
|
|
609
614
|
// All else failed, just try to get a rectangle for the target node
|
|
610
|
-
return flattenV(singleRect(node
|
|
615
|
+
return flattenV(singleRect(isText(node) ? textRange(node) : node, -side), side >= 0);
|
|
611
616
|
}
|
|
612
617
|
function flattenV(rect, left) {
|
|
613
618
|
if (rect.width == 0)
|
|
@@ -657,9 +662,9 @@ function endOfTextblockVertical(view, state, dir) {
|
|
|
657
662
|
let coords = coordsAtPos(view, $pos.pos, 1);
|
|
658
663
|
for (let child = dom.firstChild; child; child = child.nextSibling) {
|
|
659
664
|
let boxes;
|
|
660
|
-
if (child
|
|
665
|
+
if (isElt(child))
|
|
661
666
|
boxes = child.getClientRects();
|
|
662
|
-
else if (child
|
|
667
|
+
else if (isText(child))
|
|
663
668
|
boxes = textRange(child, 0, child.nodeValue.length).getClientRects();
|
|
664
669
|
else
|
|
665
670
|
continue;
|
|
@@ -699,8 +704,7 @@ function endOfTextblockHorizontal(view, state, dir) {
|
|
|
699
704
|
sel.modify("move", dir, "character");
|
|
700
705
|
let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
|
|
701
706
|
let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();
|
|
702
|
-
let result = newNode && !
|
|
703
|
-
(oldNode == newNode && oldOff == newOff);
|
|
707
|
+
let result = newNode && !contains(parentDOM, newNode) || (oldNode == newNode && oldOff == newOff);
|
|
704
708
|
// Restore the previous selection
|
|
705
709
|
try {
|
|
706
710
|
sel.collapse(anchorNode, anchorOffset);
|
|
@@ -808,7 +812,7 @@ class ViewDesc {
|
|
|
808
812
|
localPosFromDOM(dom, offset, bias) {
|
|
809
813
|
// If the DOM position is in the content, use the child desc after
|
|
810
814
|
// it to figure out a position.
|
|
811
|
-
if (this.contentDOM && this.contentDOM
|
|
815
|
+
if (this.contentDOM && contains(this.contentDOM, dom)) {
|
|
812
816
|
if (bias < 0) {
|
|
813
817
|
let domBefore, desc;
|
|
814
818
|
if (dom == this.contentDOM) {
|
|
@@ -846,7 +850,7 @@ class ViewDesc {
|
|
|
846
850
|
atEnd = offset > domIndex(this.contentDOM);
|
|
847
851
|
}
|
|
848
852
|
else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {
|
|
849
|
-
atEnd = dom.compareDocumentPosition(this.contentDOM) &
|
|
853
|
+
atEnd = !!(dom.compareDocumentPosition(this.contentDOM) & 4);
|
|
850
854
|
}
|
|
851
855
|
else if (this.dom.firstChild) {
|
|
852
856
|
if (offset == 0)
|
|
@@ -876,7 +880,7 @@ class ViewDesc {
|
|
|
876
880
|
if (desc && (!onlyNodes || desc.node)) {
|
|
877
881
|
// If dom is outside of this desc's nodeDOM, don't count it.
|
|
878
882
|
if (first && (nodeDOM = desc.nodeDOM) &&
|
|
879
|
-
!(nodeDOM
|
|
883
|
+
!(isElt(nodeDOM) ? contains(nodeDOM, dom) : nodeDOM == dom))
|
|
880
884
|
first = false;
|
|
881
885
|
else
|
|
882
886
|
return desc;
|
|
@@ -926,7 +930,7 @@ class ViewDesc {
|
|
|
926
930
|
let i = 0, offset = 0;
|
|
927
931
|
for (let curPos = 0; i < this.children.length; i++) {
|
|
928
932
|
let child = this.children[i], end = curPos + child.size;
|
|
929
|
-
if (end > pos
|
|
933
|
+
if (end > pos) {
|
|
930
934
|
offset = pos - curPos;
|
|
931
935
|
break;
|
|
932
936
|
}
|
|
@@ -936,7 +940,11 @@ class ViewDesc {
|
|
|
936
940
|
if (offset)
|
|
937
941
|
return this.children[i].domFromPos(offset - this.children[i].border, side);
|
|
938
942
|
// Go back if there were any zero-length widgets with side >= 0 before this point
|
|
939
|
-
for (
|
|
943
|
+
for (; i > 0; i--) {
|
|
944
|
+
let prev = this.children[i - 1];
|
|
945
|
+
if (prev.size || !(prev instanceof BufferHackViewDesc || prev instanceof WidgetViewDesc && prev.side >= 0))
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
940
948
|
// Scan towards the first useable node
|
|
941
949
|
if (side <= 0) {
|
|
942
950
|
let prev, enter = true;
|
|
@@ -1013,7 +1021,7 @@ class ViewDesc {
|
|
|
1013
1021
|
}
|
|
1014
1022
|
domAfterPos(pos) {
|
|
1015
1023
|
let { node, offset } = this.domFromPos(pos, 0);
|
|
1016
|
-
if (node
|
|
1024
|
+
if (!isElt(node) || offset == node.childNodes.length)
|
|
1017
1025
|
throw new RangeError("No node after pos " + pos);
|
|
1018
1026
|
return node.childNodes[offset];
|
|
1019
1027
|
}
|
|
@@ -1042,7 +1050,7 @@ class ViewDesc {
|
|
|
1042
1050
|
// reported position in such situations (#1092).
|
|
1043
1051
|
if ((gecko || safari) && anchor == head) {
|
|
1044
1052
|
let { node, offset } = anchorDOM;
|
|
1045
|
-
if (node
|
|
1053
|
+
if (isText(node)) {
|
|
1046
1054
|
brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
|
|
1047
1055
|
// Issue #1128
|
|
1048
1056
|
if (brKludge && offset == node.nodeValue.length) {
|
|
@@ -1065,7 +1073,7 @@ class ViewDesc {
|
|
|
1065
1073
|
}
|
|
1066
1074
|
// Firefox can act strangely when the selection is in front of an
|
|
1067
1075
|
// uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536
|
|
1068
|
-
if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode
|
|
1076
|
+
if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && isElt(selRange.focusNode)) {
|
|
1069
1077
|
let after = selRange.focusNode.childNodes[selRange.focusOffset];
|
|
1070
1078
|
if (after && after.contentEditable == "false")
|
|
1071
1079
|
force = true;
|
|
@@ -1164,14 +1172,12 @@ class WidgetViewDesc extends ViewDesc {
|
|
|
1164
1172
|
return self.parent.posBeforeChild(self);
|
|
1165
1173
|
});
|
|
1166
1174
|
if (!widget.type.spec.raw) {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
dom.contentEditable = "false";
|
|
1174
|
-
dom.classList.add("ProseMirror-widget");
|
|
1175
|
+
let elt = isElt(dom) ? dom : document.createElement("span");
|
|
1176
|
+
if (elt != dom)
|
|
1177
|
+
elt.appendChild(dom);
|
|
1178
|
+
if (!elt.hasAttribute("contenteditable"))
|
|
1179
|
+
elt.contentEditable = "false";
|
|
1180
|
+
elt.classList.add("ProseMirror-widget");
|
|
1175
1181
|
}
|
|
1176
1182
|
super(parent, [], dom, null);
|
|
1177
1183
|
this.widget = widget;
|
|
@@ -1307,7 +1313,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1307
1313
|
if (node.isText) {
|
|
1308
1314
|
if (!dom)
|
|
1309
1315
|
dom = document.createTextNode(node.text);
|
|
1310
|
-
else if (dom
|
|
1316
|
+
else if (!isText(dom))
|
|
1311
1317
|
throw new RangeError("Text must be rendered as a DOM text node");
|
|
1312
1318
|
}
|
|
1313
1319
|
else if (!dom) {
|
|
@@ -1359,7 +1365,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1359
1365
|
}
|
|
1360
1366
|
if (!rule.contentElement) {
|
|
1361
1367
|
let found = addedNodes &&
|
|
1362
|
-
addedNodes.find(n => n
|
|
1368
|
+
addedNodes.find(n => isElt(n) && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
|
|
1363
1369
|
if (found)
|
|
1364
1370
|
rule.contentElement = found;
|
|
1365
1371
|
else
|
|
@@ -1384,6 +1390,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1384
1390
|
let localComposition = composition && composition.pos > -1 ? composition : null;
|
|
1385
1391
|
let compositionInChild = composition && composition.pos < 0;
|
|
1386
1392
|
let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);
|
|
1393
|
+
let addBuffers = this.node.inlineContent, atBufferPos = addBuffers && this.node.isBlock;
|
|
1387
1394
|
iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => {
|
|
1388
1395
|
if (widget.spec.marks)
|
|
1389
1396
|
updater.syncToMarks(widget.spec.marks, inline, view, i);
|
|
@@ -1395,6 +1402,8 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1395
1402
|
}, (child, outerDeco, innerDeco, i) => {
|
|
1396
1403
|
// Make sure the wrapping mark descs match the node's marks.
|
|
1397
1404
|
updater.syncToMarks(child.marks, inline, view, i);
|
|
1405
|
+
if (atBufferPos && child.isAtom && !child.isText)
|
|
1406
|
+
updater.addHackNode("IMG", updater.top);
|
|
1398
1407
|
// Try several strategies for drawing this node
|
|
1399
1408
|
let compIndex;
|
|
1400
1409
|
if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;
|
|
@@ -1408,6 +1417,8 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1408
1417
|
updater.addNode(child, outerDeco, innerDeco, view, off);
|
|
1409
1418
|
}
|
|
1410
1419
|
off += child.nodeSize;
|
|
1420
|
+
if (addBuffers)
|
|
1421
|
+
atBufferPos = child.isAtom && !child.isText;
|
|
1411
1422
|
});
|
|
1412
1423
|
// Drop all remaining descs after the current position.
|
|
1413
1424
|
updater.syncToMarks([], inline, view, 0);
|
|
@@ -1486,7 +1497,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1486
1497
|
updateOuterDeco(outerDeco) {
|
|
1487
1498
|
if (sameOuterDeco(outerDeco, this.outerDeco))
|
|
1488
1499
|
return;
|
|
1489
|
-
let needsWrap = this.nodeDOM
|
|
1500
|
+
let needsWrap = !isElt(this.nodeDOM);
|
|
1490
1501
|
let oldDOM = this.dom;
|
|
1491
1502
|
this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));
|
|
1492
1503
|
if (this.dom != oldDOM) {
|
|
@@ -1497,7 +1508,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1497
1508
|
}
|
|
1498
1509
|
// Mark this node as being the selected node.
|
|
1499
1510
|
selectNode() {
|
|
1500
|
-
if (this.nodeDOM
|
|
1511
|
+
if (isElt(this.nodeDOM)) {
|
|
1501
1512
|
this.nodeDOM.classList.add("ProseMirror-selectednode");
|
|
1502
1513
|
if (this.contentDOM || !this.node.type.spec.draggable)
|
|
1503
1514
|
this.nodeDOM.draggable = true;
|
|
@@ -1505,7 +1516,7 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1505
1516
|
}
|
|
1506
1517
|
// Remove selected node marking from this node.
|
|
1507
1518
|
deselectNode() {
|
|
1508
|
-
if (this.nodeDOM
|
|
1519
|
+
if (isElt(this.nodeDOM)) {
|
|
1509
1520
|
this.nodeDOM.classList.remove("ProseMirror-selectednode");
|
|
1510
1521
|
if (this.contentDOM || !this.node.type.spec.draggable)
|
|
1511
1522
|
this.nodeDOM.removeAttribute("draggable");
|
|
@@ -1576,9 +1587,9 @@ class TextViewDesc extends NodeViewDesc {
|
|
|
1576
1587
|
get domAtom() { return false; }
|
|
1577
1588
|
isText(text) { return this.node.text == text; }
|
|
1578
1589
|
}
|
|
1579
|
-
// A dummy desc used to tag
|
|
1590
|
+
// A dummy desc used to tag extra BR or IMG nodes created to work
|
|
1580
1591
|
// around contentEditable terribleness.
|
|
1581
|
-
class
|
|
1592
|
+
class BufferHackViewDesc extends ViewDesc {
|
|
1582
1593
|
parseRule() { return { ignore: true }; }
|
|
1583
1594
|
matchesHack(nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; }
|
|
1584
1595
|
get domAtom() { return true; }
|
|
@@ -1751,7 +1762,7 @@ function patchAttributes(dom, prev, cur) {
|
|
|
1751
1762
|
}
|
|
1752
1763
|
}
|
|
1753
1764
|
function applyOuterDeco(dom, deco, node) {
|
|
1754
|
-
return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom
|
|
1765
|
+
return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, !isElt(dom)));
|
|
1755
1766
|
}
|
|
1756
1767
|
function sameOuterDeco(a, b) {
|
|
1757
1768
|
if (a.length != b.length)
|
|
@@ -2014,7 +2025,7 @@ class ViewTreeUpdater {
|
|
|
2014
2025
|
}
|
|
2015
2026
|
if (nodeName == "BR")
|
|
2016
2027
|
dom.className = "ProseMirror-trailingBreak";
|
|
2017
|
-
let hack = new
|
|
2028
|
+
let hack = new BufferHackViewDesc(this.top, [], dom, null);
|
|
2018
2029
|
if (parent != this.top)
|
|
2019
2030
|
parent.children.push(hack);
|
|
2020
2031
|
else
|
|
@@ -2023,7 +2034,7 @@ class ViewTreeUpdater {
|
|
|
2023
2034
|
}
|
|
2024
2035
|
}
|
|
2025
2036
|
isLocked(node) {
|
|
2026
|
-
return this.lock && (node == this.lock || node
|
|
2037
|
+
return this.lock && (node == this.lock || isElt(node) && node.contains(this.lock.parentNode));
|
|
2027
2038
|
}
|
|
2028
2039
|
}
|
|
2029
2040
|
// Iterate from the end of the fragment and array of descs to find
|
|
@@ -2225,12 +2236,27 @@ function selectionFromDOM(view, origin = null) {
|
|
|
2225
2236
|
anchor = head;
|
|
2226
2237
|
while (nearestDesc && !nearestDesc.node)
|
|
2227
2238
|
nearestDesc = nearestDesc.parent;
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2239
|
+
if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) &&
|
|
2240
|
+
nearestDesc.parent &&
|
|
2241
|
+
!(nearestDesc.node.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
|
|
2231
2242
|
let pos = nearestDesc.posBefore;
|
|
2232
2243
|
selection = new NodeSelection(head == pos ? $head : doc.resolve(pos));
|
|
2233
2244
|
}
|
|
2245
|
+
else if (gecko && origin == "key" && head > view.state.selection.to &&
|
|
2246
|
+
isElt(domSel.focusNode) && domSel.focusOffset == domSel.focusNode.childNodes.length &&
|
|
2247
|
+
nearestDesc && nearestDesc.posAtStart > view.state.selection.to) {
|
|
2248
|
+
// Firefox will jump across scrollable wrapper nodes on keyboard
|
|
2249
|
+
// cursor motion (#1594). This tries to detect this situation
|
|
2250
|
+
// and work around it.
|
|
2251
|
+
for (let scan = domSel.focusNode;; scan = scan.parentNode) {
|
|
2252
|
+
if (getComputedStyle(scan).overflow != "visible") {
|
|
2253
|
+
selection = Selection.findFrom(doc.resolve(nearestDesc.posAtStart), 1);
|
|
2254
|
+
break;
|
|
2255
|
+
}
|
|
2256
|
+
if (scan == nearestDesc.dom || scan.nextSibling || !scan.parentNode || !isElt(scan.parentNode))
|
|
2257
|
+
break;
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2234
2260
|
}
|
|
2235
2261
|
else {
|
|
2236
2262
|
if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {
|
|
@@ -2416,8 +2442,7 @@ function hasSelection(view) {
|
|
|
2416
2442
|
// Firefox will raise 'permission denied' errors when accessing
|
|
2417
2443
|
// properties of `sel.anchorNode` when it's in a generated CSS
|
|
2418
2444
|
// element.
|
|
2419
|
-
return view.dom
|
|
2420
|
-
(view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
|
|
2445
|
+
return contains(view.dom, sel.anchorNode) && (view.editable || contains(view.dom, sel.focusNode));
|
|
2421
2446
|
}
|
|
2422
2447
|
catch (_) {
|
|
2423
2448
|
return false;
|
|
@@ -2468,15 +2493,14 @@ function selectHorizontally(view, dir, mods) {
|
|
|
2468
2493
|
if (NodeSelection.isSelectable(node)) {
|
|
2469
2494
|
return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
|
|
2470
2495
|
}
|
|
2471
|
-
else
|
|
2496
|
+
else {
|
|
2472
2497
|
// Chrome and Safari will introduce extra pointless cursor
|
|
2473
|
-
// positions around inline uneditable nodes,
|
|
2474
|
-
//
|
|
2498
|
+
// positions around inline uneditable nodes (#937), and
|
|
2499
|
+
// Firefox will sometimes just plain refuse to move across
|
|
2500
|
+
// them (#1592), so in this situation we move the cursor
|
|
2501
|
+
// ourselves.
|
|
2475
2502
|
return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
|
|
2476
2503
|
}
|
|
2477
|
-
else {
|
|
2478
|
-
return false;
|
|
2479
|
-
}
|
|
2480
2504
|
}
|
|
2481
2505
|
}
|
|
2482
2506
|
else if (sel instanceof NodeSelection && sel.node.isInline) {
|
|
@@ -2489,13 +2513,10 @@ function selectHorizontally(view, dir, mods) {
|
|
|
2489
2513
|
return false;
|
|
2490
2514
|
}
|
|
2491
2515
|
}
|
|
2492
|
-
function nodeLen(node) {
|
|
2493
|
-
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
2494
|
-
}
|
|
2495
2516
|
function isIgnorable(dom, dir) {
|
|
2496
2517
|
let desc = dom.pmViewDesc;
|
|
2497
2518
|
return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
|
|
2498
|
-
: dom
|
|
2519
|
+
: isElt(dom) && dom.contentEditable == "false";
|
|
2499
2520
|
}
|
|
2500
2521
|
function skipIgnoredNodes(view, dir) {
|
|
2501
2522
|
return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
|
|
@@ -2511,25 +2532,23 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2511
2532
|
// Gecko will do odd things when the selection is directly in front
|
|
2512
2533
|
// of a non-editable node, so in that case, move it into the next
|
|
2513
2534
|
// node if possible. Issue prosemirror/prosemirror#832.
|
|
2514
|
-
if (gecko && node
|
|
2535
|
+
if (gecko && isElt(node) && offset < nodeSize(node) && isIgnorable(node.childNodes[offset], -1))
|
|
2515
2536
|
force = true;
|
|
2516
2537
|
for (;;) {
|
|
2517
2538
|
if (offset > 0) {
|
|
2518
|
-
if (node
|
|
2539
|
+
if (!isElt(node))
|
|
2519
2540
|
break;
|
|
2541
|
+
let before = node.childNodes[offset - 1];
|
|
2542
|
+
if (isIgnorable(before, -1)) {
|
|
2543
|
+
moveNode = node;
|
|
2544
|
+
moveOffset = --offset;
|
|
2545
|
+
}
|
|
2546
|
+
else if (isText(before)) {
|
|
2547
|
+
node = before;
|
|
2548
|
+
offset = node.nodeValue.length;
|
|
2520
2549
|
}
|
|
2521
2550
|
else {
|
|
2522
|
-
|
|
2523
|
-
if (isIgnorable(before, -1)) {
|
|
2524
|
-
moveNode = node;
|
|
2525
|
-
moveOffset = --offset;
|
|
2526
|
-
}
|
|
2527
|
-
else if (before.nodeType == 3) {
|
|
2528
|
-
node = before;
|
|
2529
|
-
offset = node.nodeValue.length;
|
|
2530
|
-
}
|
|
2531
|
-
else
|
|
2532
|
-
break;
|
|
2551
|
+
break;
|
|
2533
2552
|
}
|
|
2534
2553
|
}
|
|
2535
2554
|
else if (isBlockNode(node)) {
|
|
@@ -2550,7 +2569,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2550
2569
|
}
|
|
2551
2570
|
else {
|
|
2552
2571
|
node = prev;
|
|
2553
|
-
offset =
|
|
2572
|
+
offset = nodeSize(node);
|
|
2554
2573
|
}
|
|
2555
2574
|
}
|
|
2556
2575
|
}
|
|
@@ -2566,19 +2585,20 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2566
2585
|
let node = sel.focusNode, offset = sel.focusOffset;
|
|
2567
2586
|
if (!node)
|
|
2568
2587
|
return;
|
|
2569
|
-
let len =
|
|
2588
|
+
let len = nodeSize(node);
|
|
2570
2589
|
let moveNode, moveOffset;
|
|
2571
2590
|
for (;;) {
|
|
2572
2591
|
if (offset < len) {
|
|
2573
|
-
if (node
|
|
2592
|
+
if (!isElt(node))
|
|
2574
2593
|
break;
|
|
2575
2594
|
let after = node.childNodes[offset];
|
|
2576
2595
|
if (isIgnorable(after, 1)) {
|
|
2577
2596
|
moveNode = node;
|
|
2578
2597
|
moveOffset = ++offset;
|
|
2579
2598
|
}
|
|
2580
|
-
else
|
|
2599
|
+
else {
|
|
2581
2600
|
break;
|
|
2601
|
+
}
|
|
2582
2602
|
}
|
|
2583
2603
|
else if (isBlockNode(node)) {
|
|
2584
2604
|
break;
|
|
@@ -2599,7 +2619,7 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2599
2619
|
else {
|
|
2600
2620
|
node = next;
|
|
2601
2621
|
offset = 0;
|
|
2602
|
-
len =
|
|
2622
|
+
len = nodeSize(node);
|
|
2603
2623
|
}
|
|
2604
2624
|
}
|
|
2605
2625
|
}
|
|
@@ -2617,9 +2637,9 @@ function textNodeAfter(node, offset) {
|
|
|
2617
2637
|
}
|
|
2618
2638
|
while (node && offset < node.childNodes.length) {
|
|
2619
2639
|
let next = node.childNodes[offset];
|
|
2620
|
-
if (next
|
|
2640
|
+
if (isText(next))
|
|
2621
2641
|
return next;
|
|
2622
|
-
if (next
|
|
2642
|
+
if (isElt(next) && next.contentEditable == "false")
|
|
2623
2643
|
break;
|
|
2624
2644
|
node = next;
|
|
2625
2645
|
offset = 0;
|
|
@@ -2632,16 +2652,16 @@ function textNodeBefore(node, offset) {
|
|
|
2632
2652
|
}
|
|
2633
2653
|
while (node && offset) {
|
|
2634
2654
|
let next = node.childNodes[offset - 1];
|
|
2635
|
-
if (next
|
|
2655
|
+
if (isText(next))
|
|
2636
2656
|
return next;
|
|
2637
|
-
if (next
|
|
2657
|
+
if (isElt(next) && next.contentEditable == "false")
|
|
2638
2658
|
break;
|
|
2639
2659
|
node = next;
|
|
2640
2660
|
offset = node.childNodes.length;
|
|
2641
2661
|
}
|
|
2642
2662
|
}
|
|
2643
2663
|
function setSelFocus(view, node, offset) {
|
|
2644
|
-
if (node
|
|
2664
|
+
if (!isText(node)) {
|
|
2645
2665
|
let before, after;
|
|
2646
2666
|
if (after = textNodeAfter(node, offset)) {
|
|
2647
2667
|
node = after;
|
|
@@ -2751,8 +2771,8 @@ function safariDownArrowBug(view) {
|
|
|
2751
2771
|
if (!safari || view.state.selection.$head.parentOffset > 0)
|
|
2752
2772
|
return false;
|
|
2753
2773
|
let { focusNode, focusOffset } = view.domSelectionRange();
|
|
2754
|
-
if (focusNode && focusNode
|
|
2755
|
-
focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
|
|
2774
|
+
if (focusNode && isElt(focusNode) && focusOffset == 0 &&
|
|
2775
|
+
focusNode.firstChild && isElt(focusNode.firstChild) && focusNode.firstChild.contentEditable == "false") {
|
|
2756
2776
|
let child = focusNode.firstChild;
|
|
2757
2777
|
switchEditable(view, child, "true");
|
|
2758
2778
|
setTimeout(() => switchEditable(view, child, "false"), 20);
|
|
@@ -2823,7 +2843,7 @@ function serializeForClipboard(view, slice) {
|
|
|
2823
2843
|
let doc = detachedDoc(), wrap = doc.createElement("div");
|
|
2824
2844
|
wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
|
|
2825
2845
|
let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
|
|
2826
|
-
while (firstChild && firstChild
|
|
2846
|
+
while (firstChild && isElt(firstChild) && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
|
|
2827
2847
|
for (let i = needsWrap.length - 1; i >= 0; i--) {
|
|
2828
2848
|
let wrapper = doc.createElement(needsWrap[i]);
|
|
2829
2849
|
while (wrap.firstChild)
|
|
@@ -2833,7 +2853,7 @@ function serializeForClipboard(view, slice) {
|
|
|
2833
2853
|
}
|
|
2834
2854
|
firstChild = wrap.firstChild;
|
|
2835
2855
|
}
|
|
2836
|
-
if (firstChild && firstChild
|
|
2856
|
+
if (firstChild && isElt(firstChild))
|
|
2837
2857
|
firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
|
|
2838
2858
|
let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
|
|
2839
2859
|
slice.content.textBetween(0, slice.content.size, "\n\n");
|
|
@@ -2879,7 +2899,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2879
2899
|
if (sliceData && sliceData[3])
|
|
2880
2900
|
for (let i = +sliceData[3]; i > 0; i--) {
|
|
2881
2901
|
let child = dom.firstChild;
|
|
2882
|
-
while (child && child
|
|
2902
|
+
while (child && !isElt(child))
|
|
2883
2903
|
child = child.nextSibling;
|
|
2884
2904
|
if (!child)
|
|
2885
2905
|
break;
|
|
@@ -3084,12 +3104,11 @@ function addContext(slice, context) {
|
|
|
3084
3104
|
if (!type || type.hasRequiredAttrs())
|
|
3085
3105
|
break;
|
|
3086
3106
|
try {
|
|
3087
|
-
type.
|
|
3107
|
+
content = Fragment.from(type.create(array[i + 1], content));
|
|
3088
3108
|
}
|
|
3089
3109
|
catch (e) {
|
|
3090
3110
|
break;
|
|
3091
3111
|
}
|
|
3092
|
-
content = Fragment.from(type.create(array[i + 1], content));
|
|
3093
3112
|
openStart++;
|
|
3094
3113
|
openEnd++;
|
|
3095
3114
|
}
|
|
@@ -3266,8 +3285,7 @@ function updateSelection(view, selection, origin) {
|
|
|
3266
3285
|
if (view.state.selection.eq(selection))
|
|
3267
3286
|
return;
|
|
3268
3287
|
let tr = view.state.tr.setSelection(selection);
|
|
3269
|
-
|
|
3270
|
-
tr.setMeta("pointer", true);
|
|
3288
|
+
tr.setMeta("pointer", true);
|
|
3271
3289
|
view.dispatch(tr);
|
|
3272
3290
|
}
|
|
3273
3291
|
function selectClickedLeaf(view, inside) {
|
|
@@ -3275,7 +3293,7 @@ function selectClickedLeaf(view, inside) {
|
|
|
3275
3293
|
return false;
|
|
3276
3294
|
let $pos = view.state.doc.resolve(inside), node = $pos.nodeAfter;
|
|
3277
3295
|
if (node && node.isAtom && NodeSelection.isSelectable(node)) {
|
|
3278
|
-
updateSelection(view, new NodeSelection($pos)
|
|
3296
|
+
updateSelection(view, new NodeSelection($pos));
|
|
3279
3297
|
return true;
|
|
3280
3298
|
}
|
|
3281
3299
|
return false;
|
|
@@ -3299,7 +3317,7 @@ function selectClickedNode(view, inside) {
|
|
|
3299
3317
|
}
|
|
3300
3318
|
}
|
|
3301
3319
|
if (selectAt != null) {
|
|
3302
|
-
updateSelection(view, NodeSelection.create(view.state.doc, selectAt)
|
|
3320
|
+
updateSelection(view, NodeSelection.create(view.state.doc, selectAt));
|
|
3303
3321
|
return true;
|
|
3304
3322
|
}
|
|
3305
3323
|
else {
|
|
@@ -3326,7 +3344,7 @@ function defaultTripleClick(view, inside, event) {
|
|
|
3326
3344
|
let selection = selectionForTripleClick(view, inside, true), doc = view.state.doc;
|
|
3327
3345
|
if (!selection)
|
|
3328
3346
|
return false;
|
|
3329
|
-
updateSelection(view, selection
|
|
3347
|
+
updateSelection(view, selection);
|
|
3330
3348
|
if (selection instanceof TextSelection && doc.eq(view.state.doc))
|
|
3331
3349
|
view.input.mouseDown = new TripleClickDrag(view, selection);
|
|
3332
3350
|
return true;
|
|
@@ -3422,7 +3440,7 @@ class LeftMouseDown extends MouseDown {
|
|
|
3422
3440
|
}
|
|
3423
3441
|
const target = flushed ? null : event.target;
|
|
3424
3442
|
const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
|
|
3425
|
-
this.target = targetDesc && targetDesc.nodeDOM
|
|
3443
|
+
this.target = targetDesc && isElt(targetDesc.nodeDOM) ? targetDesc.nodeDOM : null;
|
|
3426
3444
|
let { selection } = view.state;
|
|
3427
3445
|
if (event.button == 0 &&
|
|
3428
3446
|
(targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
|
|
@@ -3489,7 +3507,7 @@ class LeftMouseDown extends MouseDown {
|
|
|
3489
3507
|
// works around that.
|
|
3490
3508
|
(chrome && !this.view.state.selection.visible &&
|
|
3491
3509
|
Math.min(Math.abs(pos.pos - this.view.state.selection.from), Math.abs(pos.pos - this.view.state.selection.to)) <= 2))) {
|
|
3492
|
-
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(pos.pos))
|
|
3510
|
+
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(pos.pos)));
|
|
3493
3511
|
event.preventDefault();
|
|
3494
3512
|
}
|
|
3495
3513
|
else {
|
|
@@ -3532,7 +3550,7 @@ class TripleClickDrag extends MouseDown {
|
|
|
3532
3550
|
return;
|
|
3533
3551
|
let { doc } = this.view.state, start = this.startSelection;
|
|
3534
3552
|
let [anchor, head] = target.from < start.from ? [start.to, target.from] : [start.from, target.to];
|
|
3535
|
-
updateSelection(this.view, TextSelection.create(doc, anchor, head)
|
|
3553
|
+
updateSelection(this.view, TextSelection.create(doc, anchor, head));
|
|
3536
3554
|
}
|
|
3537
3555
|
}
|
|
3538
3556
|
handlers.touchstart = view => {
|
|
@@ -3586,11 +3604,11 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3586
3604
|
// inside if necessary.
|
|
3587
3605
|
if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
|
|
3588
3606
|
let sel = view.domSelectionRange();
|
|
3589
|
-
for (let node = sel.focusNode, offset = sel.focusOffset; node && node
|
|
3607
|
+
for (let node = sel.focusNode, offset = sel.focusOffset; node && isElt(node) && offset != 0;) {
|
|
3590
3608
|
let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
|
|
3591
3609
|
if (!before)
|
|
3592
3610
|
break;
|
|
3593
|
-
if (before
|
|
3611
|
+
if (isText(before)) {
|
|
3594
3612
|
let sel = view.domSelection();
|
|
3595
3613
|
if (sel)
|
|
3596
3614
|
sel.collapse(before, before.nodeValue.length);
|
|
@@ -3609,10 +3627,10 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3609
3627
|
};
|
|
3610
3628
|
function selectionBeforeUneditable(view) {
|
|
3611
3629
|
let { focusNode, focusOffset } = view.domSelectionRange();
|
|
3612
|
-
if (!focusNode || focusNode
|
|
3630
|
+
if (!focusNode || !isElt(focusNode) || focusOffset >= focusNode.childNodes.length)
|
|
3613
3631
|
return false;
|
|
3614
3632
|
let next = focusNode.childNodes[focusOffset];
|
|
3615
|
-
return next
|
|
3633
|
+
return isElt(next) && next.contentEditable == "false";
|
|
3616
3634
|
}
|
|
3617
3635
|
editHandlers.compositionend = (view, event) => {
|
|
3618
3636
|
if (view.composing) {
|
|
@@ -3814,7 +3832,7 @@ handlers.dragstart = (view, _event) => {
|
|
|
3814
3832
|
else if (mouseDown && mouseDown.mightDrag) {
|
|
3815
3833
|
node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
|
|
3816
3834
|
}
|
|
3817
|
-
else if (event.target && event.target
|
|
3835
|
+
else if (event.target && isElt(event.target)) {
|
|
3818
3836
|
let desc = view.docView.nearestDesc(event.target, true);
|
|
3819
3837
|
if (desc && desc.node.type.spec.draggable && desc != view.docView)
|
|
3820
3838
|
node = NodeSelection.create(view.state.doc, desc.posBefore);
|
|
@@ -4785,7 +4803,7 @@ class DOMObserver {
|
|
|
4785
4803
|
let desc = container && this.view.docView.nearestDesc(container);
|
|
4786
4804
|
if (desc && desc.ignoreMutation({
|
|
4787
4805
|
type: "selection",
|
|
4788
|
-
target: container
|
|
4806
|
+
target: isText(container) ? container.parentNode : container
|
|
4789
4807
|
})) {
|
|
4790
4808
|
this.setCurSelection();
|
|
4791
4809
|
return true;
|
|
@@ -4827,7 +4845,7 @@ class DOMObserver {
|
|
|
4827
4845
|
for (let node of added)
|
|
4828
4846
|
if (node.nodeName == "BR" && node.parentNode) {
|
|
4829
4847
|
let after = node.nextSibling;
|
|
4830
|
-
while (after && after
|
|
4848
|
+
while (after && isElt(after)) {
|
|
4831
4849
|
if (after.contentEditable == "false") {
|
|
4832
4850
|
node.parentNode.removeChild(node);
|
|
4833
4851
|
break;
|
|
@@ -4900,7 +4918,7 @@ class DOMObserver {
|
|
|
4900
4918
|
for (let i = 0; i < mut.addedNodes.length; i++) {
|
|
4901
4919
|
let node = mut.addedNodes[i];
|
|
4902
4920
|
added.push(node);
|
|
4903
|
-
if (node
|
|
4921
|
+
if (isText(node))
|
|
4904
4922
|
this.lastChangedTextNode = node;
|
|
4905
4923
|
}
|
|
4906
4924
|
if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
|
|
@@ -5015,8 +5033,7 @@ function fixUpBadSafariComposition(view, addedNodes) {
|
|
|
5015
5033
|
let parent = nextCell;
|
|
5016
5034
|
for (;;) {
|
|
5017
5035
|
let first = parent.firstChild;
|
|
5018
|
-
if (!first || first
|
|
5019
|
-
/^(BR|IMG)$/.test(first.nodeName))
|
|
5036
|
+
if (!first || !isElt(first) || first.contentEditable == "false" || /^(BR|IMG)$/.test(first.nodeName))
|
|
5020
5037
|
break;
|
|
5021
5038
|
parent = first;
|
|
5022
5039
|
}
|
|
@@ -5041,7 +5058,7 @@ function parseBetween(view, from_, to_, addedNodes) {
|
|
|
5041
5058
|
let domSel = view.domSelectionRange();
|
|
5042
5059
|
let find;
|
|
5043
5060
|
let anchor = domSel.anchorNode;
|
|
5044
|
-
if (anchor && view.dom
|
|
5061
|
+
if (anchor && contains(view.dom, anchor)) {
|
|
5045
5062
|
find = [{ node: anchor, offset: domSel.anchorOffset }];
|
|
5046
5063
|
if (!selectionCollapsed(domSel))
|
|
5047
5064
|
find.push({ node: domSel.focusNode, offset: domSel.focusOffset });
|
|
@@ -5149,7 +5166,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5149
5166
|
if (change)
|
|
5150
5167
|
view.input.domChangeCount++;
|
|
5151
5168
|
if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&
|
|
5152
|
-
addedNodes.some(n => n
|
|
5169
|
+
addedNodes.some(n => isElt(n) && !isInline.test(n.nodeName)) &&
|
|
5153
5170
|
(!change || change.endA >= change.endB) &&
|
|
5154
5171
|
view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
|
|
5155
5172
|
view.input.lastIOSEnter = 0;
|
|
@@ -5207,9 +5224,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5207
5224
|
// as being an iOS enter press), just dispatch an Enter key instead.
|
|
5208
5225
|
if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
|
|
5209
5226
|
(!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
|
|
5210
|
-
(!inlineChange && $from.pos
|
|
5211
|
-
(!$from.sameParent($to) || !$from.parent.inlineContent) &&
|
|
5212
|
-
$from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
|
|
5227
|
+
(!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
|
|
5213
5228
|
view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
|
|
5214
5229
|
view.input.lastIOSEnter = 0;
|
|
5215
5230
|
return;
|
|
@@ -5360,6 +5375,16 @@ function looksLikeBackspace(old, start, end, $newStart, $newEnd) {
|
|
|
5360
5375
|
// The fragments after the join point must match
|
|
5361
5376
|
return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
|
|
5362
5377
|
}
|
|
5378
|
+
function looksLikeEnter(content, from, to) {
|
|
5379
|
+
let newTextlines = 0, newLeaves = 0;
|
|
5380
|
+
content.nodesBetween(from, to, (node, pos) => {
|
|
5381
|
+
if (node.isTextblock && pos >= from && pos < to)
|
|
5382
|
+
newTextlines++;
|
|
5383
|
+
else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
|
|
5384
|
+
newLeaves++;
|
|
5385
|
+
});
|
|
5386
|
+
return newLeaves == 0 && newTextlines == 1;
|
|
5387
|
+
}
|
|
5363
5388
|
function skipClosingAndOpening($pos, fromEnd, mayOpen) {
|
|
5364
5389
|
let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
|
|
5365
5390
|
while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
|
|
@@ -5629,11 +5654,11 @@ class EditorView {
|
|
|
5629
5654
|
*/
|
|
5630
5655
|
scrollToSelection() {
|
|
5631
5656
|
let startDOM = this.domSelectionRange().focusNode;
|
|
5632
|
-
if (!startDOM || !this.dom
|
|
5657
|
+
if (!startDOM || !contains(this.dom, startDOM)) ;
|
|
5633
5658
|
else if (this.someProp("handleScrollToSelection", f => f(this))) ;
|
|
5634
5659
|
else if (this.state.selection instanceof NodeSelection) {
|
|
5635
5660
|
let target = this.docView.domAfterPos(this.state.selection.from);
|
|
5636
|
-
if (target
|
|
5661
|
+
if (isElt(target))
|
|
5637
5662
|
scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);
|
|
5638
5663
|
}
|
|
5639
5664
|
else {
|
|
@@ -5898,7 +5923,7 @@ class EditorView {
|
|
|
5898
5923
|
@internal
|
|
5899
5924
|
*/
|
|
5900
5925
|
domSelectionRange() {
|
|
5901
|
-
let sel = this.domSelection();
|
|
5926
|
+
let sel = this.dom.isConnected !== false && this.domSelection();
|
|
5902
5927
|
if (!sel)
|
|
5903
5928
|
return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 };
|
|
5904
5929
|
return safari && this.root.nodeType === 11 &&
|