prosemirror-view 1.20.0 → 1.21.0

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 CHANGED
@@ -1,3 +1,37 @@
1
+ ## 1.21.0 (2021-10-29)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix issue where recent Mobile Safari versions weren't treated as Mac platforms.
6
+
7
+ ### New features
8
+
9
+ Multiple `style` properties provided through the `attributes` prop are now merged. Adjust mac detection for recent changes to navigator.platform on iOS
10
+
11
+ ## 1.20.3 (2021-10-13)
12
+
13
+ ### Bug fixes
14
+
15
+ Stop removing leading/trailing whitespace from pasted plain text.
16
+
17
+ Fix an issue that could cause invalid content to be produced when pasting HTML with isolating nodes in it.
18
+
19
+ ## 1.20.2 (2021-10-07)
20
+
21
+ ### Bug fixes
22
+
23
+ Fix a crash when pasting whitespace-only content as text.
24
+
25
+ ## 1.20.1 (2021-09-09)
26
+
27
+ ### Bug fixes
28
+
29
+ The library accidentally allowed node decorations on text nodes. It no longer does.
30
+
31
+ Fix an issue on Chrome and Safari where coordinates for positions between uneditable nodes and the end of a textblock would return zero-height rectangles.
32
+
33
+ Fix a bug where vertical `endOfTextblock` queries could inappropriately return true when a small line height is used.
34
+
1
35
  ## 1.20.0 (2021-09-03)
2
36
 
3
37
  ### New features
package/dist/index.es.js CHANGED
@@ -9,7 +9,6 @@ if (typeof navigator != "undefined" && typeof document != "undefined") {
9
9
  var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
10
10
  var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
11
11
 
12
- result.mac = /Mac/.test(navigator.platform);
13
12
  var ie = result.ie = !!(ie_upto10 || ie_11up || ie_edge);
14
13
  result.ie_version = ie_upto10 ? document.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : null;
15
14
  result.gecko = !ie && /gecko\/(\d+)/i.test(navigator.userAgent);
@@ -20,6 +19,7 @@ if (typeof navigator != "undefined" && typeof document != "undefined") {
20
19
  // Is true for both iOS and iPadOS for convenience
21
20
  result.safari = !ie && /Apple Computer/.test(navigator.vendor);
22
21
  result.ios = result.safari && (/Mobile\/\w+/.test(navigator.userAgent) || navigator.maxTouchPoints > 2);
22
+ result.mac = result.ios || /Mac/.test(navigator.platform);
23
23
  result.android = /Android \d/.test(navigator.userAgent);
24
24
  result.webkit = "webkitFontSmoothing" in document.documentElement.style;
25
25
  result.webkit_version = result.webkit && +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1];
@@ -357,19 +357,19 @@ function elementFromPoint(element, coords, box) {
357
357
  function posAtCoords(view, coords) {
358
358
  var assign, assign$1;
359
359
 
360
- var root = view.root, node, offset;
361
- if (root.caretPositionFromPoint) {
360
+ var doc = view.dom.ownerDocument, node, offset;
361
+ if (doc.caretPositionFromPoint) {
362
362
  try { // Firefox throws for this call in hard-to-predict circumstances (#994)
363
- var pos$1 = root.caretPositionFromPoint(coords.left, coords.top);
363
+ var pos$1 = doc.caretPositionFromPoint(coords.left, coords.top);
364
364
  if (pos$1) { ((assign = pos$1, node = assign.offsetNode, offset = assign.offset)); }
365
365
  } catch (_) {}
366
366
  }
367
- if (!node && root.caretRangeFromPoint) {
368
- var range = root.caretRangeFromPoint(coords.left, coords.top);
367
+ if (!node && doc.caretRangeFromPoint) {
368
+ var range = doc.caretRangeFromPoint(coords.left, coords.top);
369
369
  if (range) { ((assign$1 = range, node = assign$1.startContainer, offset = assign$1.startOffset)); }
370
370
  }
371
371
 
372
- var elt = root.elementFromPoint(coords.left, coords.top + 1), pos;
372
+ var elt = (view.root.elementFromPoint ? view.root : doc).elementFromPoint(coords.left, coords.top + 1), pos;
373
373
  if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {
374
374
  var box = view.dom.getBoundingClientRect();
375
375
  if (!inRect(coords, box)) { return null }
@@ -480,7 +480,8 @@ function coordsAtPos(view, pos, side) {
480
480
  }
481
481
  if (offset < nodeSize(node)) {
482
482
  var after$1 = node.childNodes[offset];
483
- var target$1 = after$1.nodeType == 3 ? textRange(after$1, 0, (supportEmptyRange ? 0 : 1))
483
+ while (after$1.pmViewDesc && after$1.pmViewDesc.ignoreForCoords) { after$1 = after$1.nextSibling; }
484
+ var target$1 = !after$1 ? null : after$1.nodeType == 3 ? textRange(after$1, 0, (supportEmptyRange ? 0 : 1))
484
485
  : after$1.nodeType == 1 ? after$1 : null;
485
486
  if (target$1) { return flattenV(singleRect(target$1, -1), true) }
486
487
  }
@@ -535,7 +536,9 @@ function endOfTextblockVertical(view, state, dir) {
535
536
  else { continue }
536
537
  for (var i = 0; i < boxes.length; i++) {
537
538
  var box = boxes[i];
538
- if (box.bottom > box.top && (dir == "up" ? box.bottom < coords.top + 1 : box.top > coords.bottom - 1))
539
+ if (box.bottom > box.top + 1 &&
540
+ (dir == "up" ? coords.top - box.top > (box.bottom - coords.top) * 2
541
+ : box.bottom - coords.bottom > (coords.bottom - box.top) * 2))
539
542
  { return false }
540
543
  }
541
544
  }
@@ -687,7 +690,7 @@ var ViewDesc = function ViewDesc(parent, children, dom, contentDOM) {
687
690
  this.dirty = NOT_DIRTY;
688
691
  };
689
692
 
690
- var prototypeAccessors = { beforePosition: { configurable: true },size: { configurable: true },border: { configurable: true },posBefore: { configurable: true },posAtStart: { configurable: true },posAfter: { configurable: true },posAtEnd: { configurable: true },contentLost: { configurable: true },domAtom: { configurable: true } };
693
+ var prototypeAccessors = { size: { configurable: true },border: { configurable: true },posBefore: { configurable: true },posAtStart: { configurable: true },posAfter: { configurable: true },posAtEnd: { configurable: true },contentLost: { configurable: true },domAtom: { configurable: true },ignoreForCoords: { configurable: true } };
691
694
 
692
695
  // Used to check whether a given description corresponds to a
693
696
  // widget/mark/node.
@@ -696,8 +699,6 @@ ViewDesc.prototype.matchesMark = function matchesMark () { return false };
696
699
  ViewDesc.prototype.matchesNode = function matchesNode () { return false };
697
700
  ViewDesc.prototype.matchesHack = function matchesHack (_nodeName) { return false };
698
701
 
699
- prototypeAccessors.beforePosition.get = function () { return false };
700
-
701
702
  // : () → ?ParseRule
702
703
  // When parsing in-editor content (in domchange.js), we allow
703
704
  // descriptions to determine the parse rules that should be used to
@@ -846,23 +847,34 @@ ViewDesc.prototype.descAt = function descAt (pos) {
846
847
  // : (number, number) → {node: dom.Node, offset: number}
847
848
  ViewDesc.prototype.domFromPos = function domFromPos (pos, side) {
848
849
  if (!this.contentDOM) { return {node: this.dom, offset: 0} }
849
- for (var offset = 0, i = 0, first = true;; i++, first = false) {
850
- // Skip removed or always-before children
851
- while (i < this.children.length && (this.children[i].beforePosition ||
852
- this.children[i].dom.parentNode != this.contentDOM))
853
- { offset += this.children[i++].size; }
854
- var child = i == this.children.length ? null : this.children[i];
855
- if (offset == pos && (side == 0 || !child || !child.size || child.border || (side < 0 && first)) ||
856
- child && child.domAtom && pos < offset + child.size) { return {
857
- node: this.contentDOM,
858
- offset: child ? domIndex(child.dom) : this.contentDOM.childNodes.length
859
- } }
860
- if (!child) { throw new Error("Invalid position " + pos) }
861
- var end = offset + child.size;
862
- if (!child.domAtom && (side < 0 && !child.border ? end >= pos : end > pos) &&
863
- (end > pos || i + 1 >= this.children.length || !this.children[i + 1].beforePosition))
864
- { return child.domFromPos(pos - offset - child.border, side) }
865
- offset = end;
850
+ // First find the position in the child array
851
+ var i = 0, offset = 0;
852
+ for (var curPos = 0; i < this.children.length; i++) {
853
+ var child = this.children[i], end = curPos + child.size;
854
+ if (end > pos || child instanceof TrailingHackViewDesc) { offset = pos - curPos; break }
855
+ curPos = end;
856
+ }
857
+ // If this points into the middle of a child, call through
858
+ if (offset) { return this.children[i].domFromPos(offset - this.children[i].border, side) }
859
+ // Go back if there were any zero-length widgets with side >= 0 before this point
860
+ for (var prev = (void 0); i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.widget.type.side >= 0; i--) {}
861
+ // Scan towards the first useable node
862
+ if (side <= 0) {
863
+ var prev$1, enter = true;
864
+ for (;; i--, enter = false) {
865
+ prev$1 = i ? this.children[i - 1] : null;
866
+ if (!prev$1 || prev$1.dom.parentNode == this.contentDOM) { break }
867
+ }
868
+ if (prev$1 && side && enter && !prev$1.border && !prev$1.domAtom) { return prev$1.domFromPos(prev$1.size, side) }
869
+ return {node: this.contentDOM, offset: prev$1 ? domIndex(prev$1.dom) + 1 : 0}
870
+ } else {
871
+ var next, enter$1 = true;
872
+ for (;; i++, enter$1 = false) {
873
+ next = i < this.children.length ? this.children[i] : null;
874
+ if (!next || next.dom.parentNode == this.contentDOM) { break }
875
+ }
876
+ if (next && enter$1 && !next.border && !next.domAtom) { return next.domFromPos(0, side) }
877
+ return {node: this.contentDOM, offset: next ? domIndex(next.dom) : this.contentDOM.childNodes.length}
866
878
  }
867
879
  };
868
880
 
@@ -1057,6 +1069,8 @@ ViewDesc.prototype.markParentsDirty = function markParentsDirty () {
1057
1069
 
1058
1070
  prototypeAccessors.domAtom.get = function () { return false };
1059
1071
 
1072
+ prototypeAccessors.ignoreForCoords.get = function () { return false };
1073
+
1060
1074
  Object.defineProperties( ViewDesc.prototype, prototypeAccessors );
1061
1075
 
1062
1076
  // Reused array to avoid allocating fresh arrays for things that will
@@ -1090,11 +1104,7 @@ var WidgetViewDesc = /*@__PURE__*/(function (ViewDesc) {
1090
1104
  WidgetViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
1091
1105
  WidgetViewDesc.prototype.constructor = WidgetViewDesc;
1092
1106
 
1093
- var prototypeAccessors$1 = { beforePosition: { configurable: true },domAtom: { configurable: true } };
1094
-
1095
- prototypeAccessors$1.beforePosition.get = function () {
1096
- return this.widget.type.side < 0
1097
- };
1107
+ var prototypeAccessors$1 = { domAtom: { configurable: true } };
1098
1108
 
1099
1109
  WidgetViewDesc.prototype.matchesWidget = function matchesWidget (widget) {
1100
1110
  return this.dirty == NOT_DIRTY && widget.type.eq(this.widget.type)
@@ -1520,11 +1530,12 @@ var TrailingHackViewDesc = /*@__PURE__*/(function (ViewDesc) {
1520
1530
  TrailingHackViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
1521
1531
  TrailingHackViewDesc.prototype.constructor = TrailingHackViewDesc;
1522
1532
 
1523
- var prototypeAccessors$5 = { domAtom: { configurable: true } };
1533
+ var prototypeAccessors$5 = { domAtom: { configurable: true },ignoreForCoords: { configurable: true } };
1524
1534
 
1525
1535
  TrailingHackViewDesc.prototype.parseRule = function parseRule () { return {ignore: true} };
1526
1536
  TrailingHackViewDesc.prototype.matchesHack = function matchesHack (nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName };
1527
1537
  prototypeAccessors$5.domAtom.get = function () { return true };
1538
+ prototypeAccessors$5.ignoreForCoords.get = function () { return this.dom.nodeName == "IMG" };
1528
1539
 
1529
1540
  Object.defineProperties( TrailingHackViewDesc.prototype, prototypeAccessors$5 );
1530
1541
 
@@ -1903,6 +1914,7 @@ ViewTreeUpdater.prototype.addHackNode = function addHackNode (nodeName) {
1903
1914
  } else {
1904
1915
  var dom = document.createElement(nodeName);
1905
1916
  if (nodeName == "IMG") { dom.className = "ProseMirror-separator"; }
1917
+ if (nodeName == "BR") { dom.className = "ProseMirror-trailingBreak"; }
1906
1918
  this.top.children.splice(this.index++, 0, new TrailingHackViewDesc(this.top, nothing, dom, null));
1907
1919
  this.changed = true;
1908
1920
  }
@@ -2929,7 +2941,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2929
2941
  var asText = text && (plainText || inCode || !html);
2930
2942
  if (asText) {
2931
2943
  view.someProp("transformPastedText", function (f) { text = f(text, inCode || plainText); });
2932
- if (inCode) { return new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) }
2944
+ if (inCode) { return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty }
2933
2945
  var parsed = view.someProp("clipboardTextParser", function (f) { return f(text, $context, plainText); });
2934
2946
  if (parsed) {
2935
2947
  slice = parsed;
@@ -2939,8 +2951,9 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2939
2951
  var schema = ref.schema;
2940
2952
  var serializer = DOMSerializer.fromSchema(schema);
2941
2953
  dom = document.createElement("div");
2942
- text.trim().split(/(?:\r\n?|\n)+/).forEach(function (block) {
2943
- dom.appendChild(document.createElement("p")).appendChild(serializer.serializeNode(schema.text(block, marks)));
2954
+ text.split(/(?:\r\n?|\n)+/).forEach(function (block) {
2955
+ var p = dom.appendChild(document.createElement("p"));
2956
+ if (block) { p.appendChild(serializer.serializeNode(schema.text(block, marks))); }
2944
2957
  });
2945
2958
  }
2946
2959
  } else {
@@ -2955,10 +2968,19 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2955
2968
  var parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
2956
2969
  slice = parser.parseSlice(dom, {preserveWhitespace: !!(asText || sliceData), context: $context});
2957
2970
  }
2958
- if (sliceData)
2959
- { slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[3]); }
2960
- else // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent
2961
- { slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), false); }
2971
+ if (sliceData) {
2972
+ slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[3]);
2973
+ } else { // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent
2974
+ slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), true);
2975
+ if (slice.openStart || slice.openEnd) {
2976
+ var openStart = 0, openEnd = 0;
2977
+ for (var node = slice.content.firstChild; openStart < slice.openStart && !node.type.spec.isolating;
2978
+ openStart++, node = node.firstChild) {}
2979
+ for (var node$1 = slice.content.lastChild; openEnd < slice.openEnd && !node$1.type.spec.isolating;
2980
+ openEnd++, node$1 = node$1.lastChild) {}
2981
+ slice = closeSlice(slice, openStart, openEnd);
2982
+ }
2983
+ }
2962
2984
 
2963
2985
  view.someProp("transformPasted", function (f) { slice = f(slice); });
2964
2986
  return slice
@@ -4137,7 +4159,8 @@ NodeType.prototype.valid = function valid (node, span) {
4137
4159
  var ref = node.content.findIndex(span.from);
4138
4160
  var index = ref.index;
4139
4161
  var offset = ref.offset;
4140
- return offset == span.from && offset + node.child(index).nodeSize == span.to
4162
+ var child;
4163
+ return offset == span.from && !(child = node.child(index)).isText && offset + child.nodeSize == span.to
4141
4164
  };
4142
4165
 
4143
4166
  NodeType.prototype.eq = function eq (other) {
@@ -5162,6 +5185,9 @@ function computeDocDeco(view) {
5162
5185
  if (value) { for (var attr in value) {
5163
5186
  if (attr == "class")
5164
5187
  { attrs.class += " " + value[attr]; }
5188
+ if (attr == "style") {
5189
+ attrs.style = (attrs.style ? attrs.style + ";" : "") + value[attr];
5190
+ }
5165
5191
  else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
5166
5192
  { attrs[attr] = String(value[attr]); }
5167
5193
  } }