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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TextSelection, NodeSelection, AllSelection, Selection } from 'prosemirror-state';
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.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
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.nodeType == 1) {
50
+ else if (isElt(node)) {
51
51
  let child = node.childNodes[off + (dir < 0 ? -1 : 0)];
52
- if (child.nodeType == 1 && child.contentEditable == "false") {
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.nodeType == 3 && offset)
78
+ if (isText(node) && offset)
74
79
  return node;
75
- if (node.nodeType == 1 && offset > 0) {
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.nodeType == 3 && offset < node.nodeValue.length)
97
+ if (isText(node) && offset < node.nodeValue.length)
93
98
  return node;
94
- if (node.nodeType == 1 && offset < node.childNodes.length) {
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.nodeType != 1) {
223
+ if (!isElt(parent)) {
219
224
  parent = parentNode(parent);
220
225
  continue;
221
226
  }
222
- let elt = parent;
223
- let atTop = elt == doc.body;
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 = elt.scrollLeft, startY = elt.scrollTop;
245
+ let startX = parent.scrollLeft, startY = parent.scrollTop;
242
246
  if (moveY)
243
- elt.scrollTop += moveY;
247
+ parent.scrollTop += moveY;
244
248
  if (moveX)
245
- elt.scrollLeft += moveX;
246
- let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;
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, dxClosest = 2e8, coordsClosest, offset = 0;
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.nodeType == 1)
331
+ if (isElt(child))
327
332
  rects = child.getClientRects();
328
- else if (child.nodeType == 3)
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.nodeType == 3 ? {
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.nodeType == 1 && dx)
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.nodeType == 3)
370
+ if (closest && isText(closest))
366
371
  return findOffsetInText(closest, coordsClosest);
367
- if (!closest || (dxClosest && closest.nodeType == 1))
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.nodeType == 1 && !node.firstChild) {
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.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
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.nodeType == 1) {
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.nodeType != 1 ? elt.parentNode : 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.nodeType == 1) {
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.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&
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.nodeType == 1 &&
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.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR")
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.nodeType == 3) {
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.nodeType == 1)
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.nodeType == 1)
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.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
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.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
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.nodeType == 3 ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
605
- : after.nodeType == 1 ? after : null;
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.nodeType == 3 ? textRange(node) : node, -side), side >= 0);
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.nodeType == 1)
665
+ if (isElt(child))
661
666
  boxes = child.getClientRects();
662
- else if (child.nodeType == 3)
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 && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
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.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {
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) & 2;
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.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))
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 || child instanceof TrailingHackViewDesc) {
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 (let prev; i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }
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.nodeType != 1 || offset == node.childNodes.length)
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.nodeType == 3) {
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.nodeType == 1) {
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
- if (dom.nodeType != 1) {
1168
- let wrap = document.createElement("span");
1169
- wrap.appendChild(dom);
1170
- dom = wrap;
1171
- }
1172
- if (!dom.hasAttribute("contenteditable"))
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.nodeType != 3)
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.nodeType == 1 && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(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.nodeType != 1;
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.nodeType == 1) {
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.nodeType == 1) {
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 trailing BR or IMG nodes created to work
1590
+ // A dummy desc used to tag extra BR or IMG nodes created to work
1580
1591
  // around contentEditable terribleness.
1581
- class TrailingHackViewDesc extends ViewDesc {
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.nodeType != 1));
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 TrailingHackViewDesc(this.top, [], dom, null);
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.nodeType == 1 && node.contains(this.lock.parentNode));
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
- let nearestDescNode = nearestDesc.node;
2229
- if (nearestDesc && nearestDescNode.isAtom && NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent
2230
- && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
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.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&
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 if (webkit) {
2496
+ else {
2472
2497
  // Chrome and Safari will introduce extra pointless cursor
2473
- // positions around inline uneditable nodes, so we have to
2474
- // take over and move the cursor past them (#937)
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.nodeType == 1 && dom.contentEditable == "false";
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.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
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.nodeType != 1) {
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
- let before = node.childNodes[offset - 1];
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 = nodeLen(node);
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 = nodeLen(node);
2588
+ let len = nodeSize(node);
2570
2589
  let moveNode, moveOffset;
2571
2590
  for (;;) {
2572
2591
  if (offset < len) {
2573
- if (node.nodeType != 1)
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 = nodeLen(node);
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.nodeType == 3)
2640
+ if (isText(next))
2621
2641
  return next;
2622
- if (next.nodeType == 1 && next.contentEditable == "false")
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.nodeType == 3)
2655
+ if (isText(next))
2636
2656
  return next;
2637
- if (next.nodeType == 1 && next.contentEditable == "false")
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.nodeType != 3) {
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.nodeType == 1 && focusOffset == 0 &&
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.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
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.nodeType == 1)
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.nodeType != 1)
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.checkAttrs(array[i + 1]);
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
- if (origin == "pointer")
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), "pointer");
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), "pointer");
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, "pointer");
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.nodeType == 1 ? targetDesc.nodeDOM : null;
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)), "pointer");
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), "pointer");
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.nodeType == 1 && offset != 0;) {
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.nodeType == 3) {
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.nodeType != 1 || focusOffset >= focusNode.childNodes.length)
3630
+ if (!focusNode || !isElt(focusNode) || focusOffset >= focusNode.childNodes.length)
3613
3631
  return false;
3614
3632
  let next = focusNode.childNodes[focusOffset];
3615
- return next.nodeType == 1 && next.contentEditable == "false";
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.nodeType == 1) {
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.nodeType == 3 ? container.parentNode : 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.nodeType == 1) {
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.nodeType == 3)
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.nodeType != 1 || first.contentEditable == "false" ||
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.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
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.nodeType == 1 && !isInline.test(n.nodeName)) &&
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 < parse.doc.content.size &&
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.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;
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.nodeType == 1)
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 &&