prosemirror-view 1.18.10 → 1.18.11

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,13 @@
1
+ ## 1.18.11 (2021-07-22)
2
+
3
+ ### Bug fixes
4
+
5
+ Work around an issue where Chrome and Safari will replace some spaces with non-breaking spaces when putting HTML on the clipboard.
6
+
7
+ When pasting as plain text (shift-mod-v) apply the marks at the selection to the inserted content.
8
+
9
+ Fix flaky behavior when starting a composition with a selection that spans multiple blocks.
10
+
1
11
  ## 1.18.10 (2021-07-15)
2
12
 
3
13
  ### Bug fixes
package/dist/index.es.js CHANGED
@@ -1039,7 +1039,7 @@ ViewDesc.prototype.markDirty = function markDirty (from, to) {
1039
1039
  else { child.markDirty(from - startInside, to - startInside); }
1040
1040
  return
1041
1041
  } else {
1042
- child.dirty = NODE_DIRTY;
1042
+ child.dirty = child.dom == child.contentDOM && child.dom.parentNode == this.contentDOM ? CONTENT_DIRTY : NODE_DIRTY;
1043
1043
  }
1044
1044
  }
1045
1045
  offset = end;
@@ -1298,8 +1298,10 @@ var NodeViewDesc = /*@__PURE__*/(function (ViewDesc) {
1298
1298
  var this$1 = this;
1299
1299
 
1300
1300
  var inline = this.node.inlineContent, off = pos;
1301
- var composition = inline && view.composing && this.localCompositionNode(view, pos);
1302
- var updater = new ViewTreeUpdater(this, composition && composition.node);
1301
+ var composition = view.composing && this.localCompositionInfo(view, pos);
1302
+ var localComposition = composition && composition.pos > -1 ? composition : null;
1303
+ var compositionInChild = composition && composition.pos < 0;
1304
+ var updater = new ViewTreeUpdater(this, localComposition && localComposition.node);
1303
1305
  iterDeco(this.node, this.innerDeco, function (widget, i, insideNode) {
1304
1306
  if (widget.spec.marks)
1305
1307
  { updater.syncToMarks(widget.spec.marks, inline, view); }
@@ -1311,13 +1313,15 @@ var NodeViewDesc = /*@__PURE__*/(function (ViewDesc) {
1311
1313
  }, function (child, outerDeco, innerDeco, i) {
1312
1314
  // Make sure the wrapping mark descs match the node's marks.
1313
1315
  updater.syncToMarks(child.marks, inline, view);
1314
- // Either find an existing desc that exactly matches this node,
1315
- // and drop the descs before it.
1316
- updater.findNodeMatch(child, outerDeco, innerDeco, i) ||
1317
- // Or try updating the next desc to reflect this node.
1318
- updater.updateNextNode(child, outerDeco, innerDeco, view, i) ||
1319
- // Or just add it as a new desc.
1316
+ // Try several strategies for drawing this node
1317
+ var compIndex;
1318
+ if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ; else if (compositionInChild && view.state.selection.from > off &&
1319
+ view.state.selection.to < off + child.nodeSize &&
1320
+ (compIndex = updater.findIndexWithChild(composition.node)) > -1 &&
1321
+ updater.updateNodeAt(child, outerDeco, innerDeco, compIndex, view)) ; else if (updater.updateNextNode(child, outerDeco, innerDeco, view, i)) ; else {
1322
+ // Add it as a new view
1320
1323
  updater.addNode(child, outerDeco, innerDeco, view, off);
1324
+ }
1321
1325
  off += child.nodeSize;
1322
1326
  });
1323
1327
  // Drop all remaining descs after the current position.
@@ -1328,16 +1332,15 @@ var NodeViewDesc = /*@__PURE__*/(function (ViewDesc) {
1328
1332
  // Sync the DOM if anything changed
1329
1333
  if (updater.changed || this.dirty == CONTENT_DIRTY) {
1330
1334
  // May have to protect focused DOM from being changed if a composition is active
1331
- if (composition) { this.protectLocalComposition(view, composition); }
1335
+ if (localComposition) { this.protectLocalComposition(view, localComposition); }
1332
1336
  renderDescs(this.contentDOM, this.children, view);
1333
1337
  if (result.ios) { iosHacks(this.dom); }
1334
1338
  }
1335
1339
  };
1336
1340
 
1337
- NodeViewDesc.prototype.localCompositionNode = function localCompositionNode (view, pos) {
1341
+ NodeViewDesc.prototype.localCompositionInfo = function localCompositionInfo (view, pos) {
1338
1342
  // Only do something if both the selection and a focused text node
1339
- // are inside of this node, and the node isn't already part of a
1340
- // view that's a child of this view
1343
+ // are inside of this node
1341
1344
  var ref = view.state.selection;
1342
1345
  var from = ref.from;
1343
1346
  var to = ref.to;
@@ -1346,13 +1349,16 @@ var NodeViewDesc = /*@__PURE__*/(function (ViewDesc) {
1346
1349
  var textNode = nearbyTextNode(sel.focusNode, sel.focusOffset);
1347
1350
  if (!textNode || !this.dom.contains(textNode.parentNode)) { return }
1348
1351
 
1349
- // Find the text in the focused node in the node, stop if it's not
1350
- // there (may have been modified through other means, in which
1351
- // case it should overwritten)
1352
- var text = textNode.nodeValue;
1353
- var textPos = findTextInFragment(this.node.content, text, from - pos, to - pos);
1354
-
1355
- return textPos < 0 ? null : {node: textNode, pos: textPos, text: text}
1352
+ if (this.node.inlineContent) {
1353
+ // Find the text in the focused node in the node, stop if it's not
1354
+ // there (may have been modified through other means, in which
1355
+ // case it should overwritten)
1356
+ var text = textNode.nodeValue;
1357
+ var textPos = findTextInFragment(this.node.content, text, from - pos, to - pos);
1358
+ return textPos < 0 ? null : {node: textNode, pos: textPos, text: text}
1359
+ } else {
1360
+ return {node: textNode, pos: -1}
1361
+ }
1356
1362
  };
1357
1363
 
1358
1364
  NodeViewDesc.prototype.protectLocalComposition = function protectLocalComposition (view, ref) {
@@ -1805,6 +1811,29 @@ ViewTreeUpdater.prototype.findNodeMatch = function findNodeMatch (node, outerDec
1805
1811
  return true
1806
1812
  };
1807
1813
 
1814
+ ViewTreeUpdater.prototype.updateNodeAt = function updateNodeAt (node, outerDeco, innerDeco, index, view) {
1815
+ var child = this.top.children[index];
1816
+ if (!child.update(node, outerDeco, innerDeco, view)) { return false }
1817
+ this.destroyBetween(this.index, index);
1818
+ this.index = index + 1;
1819
+ return true
1820
+ };
1821
+
1822
+ ViewTreeUpdater.prototype.findIndexWithChild = function findIndexWithChild (domNode) {
1823
+ for (;;) {
1824
+ var parent = domNode.parentNode;
1825
+ if (!parent) { return -1 }
1826
+ if (parent == this.top.contentDOM) {
1827
+ var desc = domNode.pmViewDesc;
1828
+ if (desc) { for (var i = this.index; i < this.top.children.length; i++) {
1829
+ if (this.top.children[i] == desc) { return i }
1830
+ } }
1831
+ return -1
1832
+ }
1833
+ domNode = parent;
1834
+ }
1835
+ };
1836
+
1808
1837
  // : (Node, [Decoration], DecorationSource, EditorView, Fragment, number) → bool
1809
1838
  // Try to update the next node, if any, to the given data. Checks
1810
1839
  // pre-matches to avoid overwriting nodes that could still be used.
@@ -2894,14 +2923,19 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2894
2923
  if (parsed) {
2895
2924
  slice = parsed;
2896
2925
  } else {
2926
+ var marks = $context.marks();
2927
+ var ref = view.state;
2928
+ var schema = ref.schema;
2929
+ var serializer = DOMSerializer.fromSchema(schema);
2897
2930
  dom = document.createElement("div");
2898
2931
  text.trim().split(/(?:\r\n?|\n)+/).forEach(function (block) {
2899
- dom.appendChild(document.createElement("p")).textContent = block;
2932
+ dom.appendChild(document.createElement("p")).appendChild(serializer.serializeNode(schema.text(block, marks)));
2900
2933
  });
2901
2934
  }
2902
2935
  } else {
2903
2936
  view.someProp("transformPastedHTML", function (f) { html = f(html); });
2904
2937
  dom = readHTML(html);
2938
+ if (result.webkit) { restoreReplacedSpaces(dom); }
2905
2939
  }
2906
2940
 
2907
2941
  var contextNode = dom && dom.querySelector("[data-pm-slice]");
@@ -3034,6 +3068,20 @@ function readHTML(html) {
3034
3068
  return elt
3035
3069
  }
3036
3070
 
3071
+ // Webkit browsers do some hard-to-predict replacement of regular
3072
+ // spaces with non-breaking spaces when putting content on the
3073
+ // clipboard. This tries to convert such non-breaking spaces (which
3074
+ // will be wrapped in a plain span on Chrome, a span with class
3075
+ // Apple-converted-space on Safari) back to regular spaces.
3076
+ function restoreReplacedSpaces(dom) {
3077
+ var nodes = dom.querySelectorAll(result.chrome ? "span:not([class]):not([style])" : "span.Apple-converted-space");
3078
+ for (var i = 0; i < nodes.length; i++) {
3079
+ var node = nodes[i];
3080
+ if (node.childNodes.length == 1 && node.textContent == "\u00a0" && node.parentNode)
3081
+ { node.parentNode.replaceChild(dom.ownerDocument.createTextNode(" "), node); }
3082
+ }
3083
+ }
3084
+
3037
3085
  function addContext(slice, context) {
3038
3086
  if (!slice.size) { return slice }
3039
3087
  var schema = slice.content.firstChild.type.schema, array;