prosemirror-view 1.32.2 → 1.32.4

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,17 @@
1
+ ## 1.32.4 (2023-11-08)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a case where a DOM change involving astal characters could create odd steps that started and ended in the middle of UTF16 surrogate pairs.
6
+
7
+ Dragging a draggable node will no longer implicitly select it.
8
+
9
+ ## 1.32.3 (2023-11-01)
10
+
11
+ ### Bug fixes
12
+
13
+ Fix a bug where, in some situations, pasting plain text pasted HTML markup.
14
+
1
15
  ## 1.32.2 (2023-10-27)
2
16
 
3
17
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -3994,7 +3994,7 @@ function doPaste(view, text, html, preferPlain, event) {
3994
3994
  }
3995
3995
 
3996
3996
  function getText(clipboardData) {
3997
- var text = clipboardData.getData("text/html") || clipboardData.getData("Text");
3997
+ var text = clipboardData.getData("text/plain") || clipboardData.getData("Text");
3998
3998
  if (text) return text;
3999
3999
  var uris = clipboardData.getData("text/uri-list");
4000
4000
  return uris ? uris.replace(/\r?\n/g, " ") : "";
@@ -4008,11 +4008,12 @@ editHandlers.paste = function (view, _event) {
4008
4008
  if (data && doPaste(view, getText(data), data.getData("text/html"), plain, event)) event.preventDefault();else capturePaste(view, event);
4009
4009
  };
4010
4010
 
4011
- var Dragging = _createClass(function Dragging(slice, move) {
4011
+ var Dragging = _createClass(function Dragging(slice, move, node) {
4012
4012
  _classCallCheck(this, Dragging);
4013
4013
 
4014
4014
  this.slice = slice;
4015
4015
  this.move = move;
4016
+ this.node = node;
4016
4017
  });
4017
4018
 
4018
4019
  var dragCopyModifier = mac ? "altKey" : "ctrlKey";
@@ -4024,14 +4025,15 @@ handlers.dragstart = function (view, _event) {
4024
4025
  if (!event.dataTransfer) return;
4025
4026
  var sel = view.state.selection;
4026
4027
  var pos = sel.empty ? null : view.posAtCoords(eventCoords(event));
4028
+ var node;
4027
4029
  if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof prosemirrorState.NodeSelection ? sel.to - 1 : sel.to)) ;else if (mouseDown && mouseDown.mightDrag) {
4028
- view.dispatch(view.state.tr.setSelection(prosemirrorState.NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)));
4030
+ node = prosemirrorState.NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
4029
4031
  } else if (event.target && event.target.nodeType == 1) {
4030
4032
  var desc = view.docView.nearestDesc(event.target, true);
4031
- if (desc && desc.node.type.spec.draggable && desc != view.docView) view.dispatch(view.state.tr.setSelection(prosemirrorState.NodeSelection.create(view.state.doc, desc.posBefore)));
4033
+ if (desc && desc.node.type.spec.draggable && desc != view.docView) node = prosemirrorState.NodeSelection.create(view.state.doc, desc.posBefore);
4032
4034
  }
4033
4035
 
4034
- var slice = view.state.selection.content(),
4036
+ var slice = (node || view.state.selection).content(),
4035
4037
  _serializeForClipboar2 = serializeForClipboard(view, slice),
4036
4038
  dom = _serializeForClipboar2.dom,
4037
4039
  text = _serializeForClipboar2.text;
@@ -4040,7 +4042,7 @@ handlers.dragstart = function (view, _event) {
4040
4042
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
4041
4043
  event.dataTransfer.effectAllowed = "copyMove";
4042
4044
  if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text);
4043
- view.dragging = new Dragging(slice, !event[dragCopyModifier]);
4045
+ view.dragging = new Dragging(slice, !event[dragCopyModifier], node);
4044
4046
  };
4045
4047
 
4046
4048
  handlers.dragend = function (view) {
@@ -4086,7 +4088,12 @@ editHandlers.drop = function (view, _event) {
4086
4088
  var insertPos = slice ? prosemirrorTransform.dropPoint(view.state.doc, $mouse.pos, slice) : $mouse.pos;
4087
4089
  if (insertPos == null) insertPos = $mouse.pos;
4088
4090
  var tr = view.state.tr;
4089
- if (move) tr.deleteSelection();
4091
+
4092
+ if (move) {
4093
+ var node = dragging.node;
4094
+ if (node) node.replace(tr);else tr.deleteSelection();
4095
+ }
4096
+
4090
4097
  var pos = tr.mapping.map(insertPos);
4091
4098
  var isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
4092
4099
  var beforeInsert = tr.doc;
@@ -5648,12 +5655,14 @@ function findDiff(a, b, pos, preferredPos, preferredSide) {
5648
5655
  if (endA < start && a.size < b.size) {
5649
5656
  var move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
5650
5657
  start -= move;
5658
+ if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1))) start += move ? 1 : -1;
5651
5659
  endB = start + (endB - endA);
5652
5660
  endA = start;
5653
5661
  } else if (endB < start) {
5654
5662
  var _move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
5655
5663
 
5656
5664
  start -= _move;
5665
+ if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1))) start += _move ? 1 : -1;
5657
5666
  endA = start + (endA - endB);
5658
5667
  endB = start;
5659
5668
  }
@@ -5665,6 +5674,13 @@ function findDiff(a, b, pos, preferredPos, preferredSide) {
5665
5674
  };
5666
5675
  }
5667
5676
 
5677
+ function isSurrogatePair(str) {
5678
+ if (str.length != 2) return false;
5679
+ var a = str.charCodeAt(0),
5680
+ b = str.charCodeAt(1);
5681
+ return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
5682
+ }
5683
+
5668
5684
  var __serializeForClipboard = serializeForClipboard;
5669
5685
  var __parseFromClipboard = parseFromClipboard;
5670
5686
  var __endComposition = endComposition;
@@ -5770,6 +5786,8 @@ var EditorView = function () {
5770
5786
  }, {
5771
5787
  key: "updateStateInner",
5772
5788
  value: function updateStateInner(state, prevProps) {
5789
+ var _a;
5790
+
5773
5791
  var prev = this.state,
5774
5792
  redraw = false,
5775
5793
  updateSel = false;
@@ -5831,6 +5849,7 @@ var EditorView = function () {
5831
5849
  }
5832
5850
 
5833
5851
  this.updatePluginViews(prev);
5852
+ if (((_a = this.dragging) === null || _a === void 0 ? void 0 : _a.node) && !prev.doc.eq(state.doc)) this.updateDraggedNode(this.dragging, prev);
5834
5853
 
5835
5854
  if (scroll == "reset") {
5836
5855
  this.dom.scrollTop = 0;
@@ -5887,6 +5906,22 @@ var EditorView = function () {
5887
5906
  }
5888
5907
  }
5889
5908
  }
5909
+ }, {
5910
+ key: "updateDraggedNode",
5911
+ value: function updateDraggedNode(dragging, prev) {
5912
+ var sel = dragging.node,
5913
+ found = -1;
5914
+
5915
+ if (this.state.doc.nodeAt(sel.from) == sel.node) {
5916
+ found = sel.from;
5917
+ } else {
5918
+ var movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size);
5919
+ var moved = movedPos > 0 && this.state.doc.nodeAt(movedPos);
5920
+ if (moved == sel.node) found = movedPos;
5921
+ }
5922
+
5923
+ this.dragging = new Dragging(dragging.slice, dragging.move, found < 0 ? undefined : prosemirrorState.NodeSelection.create(this.state.doc, found));
5924
+ }
5890
5925
  }, {
5891
5926
  key: "someProp",
5892
5927
  value: function someProp(propName, f) {
package/dist/index.d.cts CHANGED
@@ -466,6 +466,7 @@ declare class EditorView {
466
466
  private updateStateInner;
467
467
  private destroyPluginViews;
468
468
  private updatePluginViews;
469
+ private updateDraggedNode;
469
470
  /**
470
471
  Goes over the values of a prop, first those provided directly,
471
472
  then those from plugins given to the view, then from plugins in
package/dist/index.d.ts CHANGED
@@ -466,6 +466,7 @@ declare class EditorView {
466
466
  private updateStateInner;
467
467
  private destroyPluginViews;
468
468
  private updatePluginViews;
469
+ private updateDraggedNode;
469
470
  /**
470
471
  Goes over the values of a prop, first those provided directly,
471
472
  then those from plugins given to the view, then from plugins in
package/dist/index.js CHANGED
@@ -3523,7 +3523,7 @@ function doPaste(view, text, html, preferPlain, event) {
3523
3523
  return true;
3524
3524
  }
3525
3525
  function getText(clipboardData) {
3526
- let text = clipboardData.getData("text/html") || clipboardData.getData("Text");
3526
+ let text = clipboardData.getData("text/plain") || clipboardData.getData("Text");
3527
3527
  if (text)
3528
3528
  return text;
3529
3529
  let uris = clipboardData.getData("text/uri-list");
@@ -3545,9 +3545,10 @@ editHandlers.paste = (view, _event) => {
3545
3545
  capturePaste(view, event);
3546
3546
  };
3547
3547
  class Dragging {
3548
- constructor(slice, move) {
3548
+ constructor(slice, move, node) {
3549
3549
  this.slice = slice;
3550
3550
  this.move = move;
3551
+ this.node = node;
3551
3552
  }
3552
3553
  }
3553
3554
  const dragCopyModifier = mac ? "altKey" : "ctrlKey";
@@ -3560,23 +3561,24 @@ handlers.dragstart = (view, _event) => {
3560
3561
  return;
3561
3562
  let sel = view.state.selection;
3562
3563
  let pos = sel.empty ? null : view.posAtCoords(eventCoords(event));
3564
+ let node;
3563
3565
  if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof NodeSelection ? sel.to - 1 : sel.to)) ;
3564
3566
  else if (mouseDown && mouseDown.mightDrag) {
3565
- view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)));
3567
+ node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
3566
3568
  }
3567
3569
  else if (event.target && event.target.nodeType == 1) {
3568
3570
  let desc = view.docView.nearestDesc(event.target, true);
3569
3571
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
3570
- view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, desc.posBefore)));
3572
+ node = NodeSelection.create(view.state.doc, desc.posBefore);
3571
3573
  }
3572
- let slice = view.state.selection.content(), { dom, text } = serializeForClipboard(view, slice);
3574
+ let slice = (node || view.state.selection).content(), { dom, text } = serializeForClipboard(view, slice);
3573
3575
  event.dataTransfer.clearData();
3574
3576
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3575
3577
  // See https://github.com/ProseMirror/prosemirror/issues/1156
3576
3578
  event.dataTransfer.effectAllowed = "copyMove";
3577
3579
  if (!brokenClipboardAPI)
3578
3580
  event.dataTransfer.setData("text/plain", text);
3579
- view.dragging = new Dragging(slice, !event[dragCopyModifier]);
3581
+ view.dragging = new Dragging(slice, !event[dragCopyModifier], node);
3580
3582
  };
3581
3583
  handlers.dragend = view => {
3582
3584
  let dragging = view.dragging;
@@ -3615,8 +3617,13 @@ editHandlers.drop = (view, _event) => {
3615
3617
  if (insertPos == null)
3616
3618
  insertPos = $mouse.pos;
3617
3619
  let tr = view.state.tr;
3618
- if (move)
3619
- tr.deleteSelection();
3620
+ if (move) {
3621
+ let { node } = dragging;
3622
+ if (node)
3623
+ node.replace(tr);
3624
+ else
3625
+ tr.deleteSelection();
3626
+ }
3620
3627
  let pos = tr.mapping.map(insertPos);
3621
3628
  let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
3622
3629
  let beforeInsert = tr.doc;
@@ -5025,17 +5032,27 @@ function findDiff(a, b, pos, preferredPos, preferredSide) {
5025
5032
  if (endA < start && a.size < b.size) {
5026
5033
  let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
5027
5034
  start -= move;
5035
+ if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
5036
+ start += move ? 1 : -1;
5028
5037
  endB = start + (endB - endA);
5029
5038
  endA = start;
5030
5039
  }
5031
5040
  else if (endB < start) {
5032
5041
  let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
5033
5042
  start -= move;
5043
+ if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
5044
+ start += move ? 1 : -1;
5034
5045
  endA = start + (endA - endB);
5035
5046
  endB = start;
5036
5047
  }
5037
5048
  return { start, endA, endB };
5038
5049
  }
5050
+ function isSurrogatePair(str) {
5051
+ if (str.length != 2)
5052
+ return false;
5053
+ let a = str.charCodeAt(0), b = str.charCodeAt(1);
5054
+ return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
5055
+ }
5039
5056
 
5040
5057
  /**
5041
5058
  @internal
@@ -5182,6 +5199,7 @@ class EditorView {
5182
5199
  this.updateStateInner(state, this._props);
5183
5200
  }
5184
5201
  updateStateInner(state, prevProps) {
5202
+ var _a;
5185
5203
  let prev = this.state, redraw = false, updateSel = false;
5186
5204
  // When stored marks are added, stop composition, so that they can
5187
5205
  // be displayed.
@@ -5249,6 +5267,8 @@ class EditorView {
5249
5267
  this.domObserver.start();
5250
5268
  }
5251
5269
  this.updatePluginViews(prev);
5270
+ if (((_a = this.dragging) === null || _a === void 0 ? void 0 : _a.node) && !prev.doc.eq(state.doc))
5271
+ this.updateDraggedNode(this.dragging, prev);
5252
5272
  if (scroll == "reset") {
5253
5273
  this.dom.scrollTop = 0;
5254
5274
  }
@@ -5303,6 +5323,19 @@ class EditorView {
5303
5323
  }
5304
5324
  }
5305
5325
  }
5326
+ updateDraggedNode(dragging, prev) {
5327
+ let sel = dragging.node, found = -1;
5328
+ if (this.state.doc.nodeAt(sel.from) == sel.node) {
5329
+ found = sel.from;
5330
+ }
5331
+ else {
5332
+ let movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size);
5333
+ let moved = movedPos > 0 && this.state.doc.nodeAt(movedPos);
5334
+ if (moved == sel.node)
5335
+ found = movedPos;
5336
+ }
5337
+ this.dragging = new Dragging(dragging.slice, dragging.move, found < 0 ? undefined : NodeSelection.create(this.state.doc, found));
5338
+ }
5306
5339
  someProp(propName, f) {
5307
5340
  let prop = this._props && this._props[propName], value;
5308
5341
  if (prop != null && (value = f ? f(prop) : prop))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.32.2",
3
+ "version": "1.32.4",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/domchange.ts CHANGED
@@ -354,13 +354,23 @@ function findDiff(a: Fragment, b: Fragment, pos: number, preferredPos: number, p
354
354
  if (endA < start && a.size < b.size) {
355
355
  let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0
356
356
  start -= move
357
+ if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
358
+ start += move ? 1 : -1
357
359
  endB = start + (endB - endA)
358
360
  endA = start
359
361
  } else if (endB < start) {
360
362
  let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0
361
363
  start -= move
364
+ if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
365
+ start += move ? 1 : -1
362
366
  endA = start + (endA - endB)
363
367
  endB = start
364
368
  }
365
369
  return {start, endA, endB}
366
370
  }
371
+
372
+ function isSurrogatePair(str: string) {
373
+ if (str.length != 2) return false
374
+ let a = str.charCodeAt(0), b = str.charCodeAt(1)
375
+ return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF
376
+ }
package/src/index.ts CHANGED
@@ -4,7 +4,8 @@ import {Slice, ResolvedPos, DOMParser, DOMSerializer, Node, Mark} from "prosemir
4
4
  import {scrollRectIntoView, posAtCoords, coordsAtPos, endOfTextblock, storeScrollPos,
5
5
  resetScrollPos, focusPreventScroll} from "./domcoords"
6
6
  import {docViewDesc, ViewDesc, NodeView, NodeViewDesc} from "./viewdesc"
7
- import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition, InputState, doPaste} from "./input"
7
+ import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition,
8
+ InputState, doPaste, Dragging} from "./input"
8
9
  import {selectionToDOM, anchorInRightPlace, syncNodeSelection} from "./selection"
9
10
  import {Decoration, viewDecorations, DecorationSource} from "./decoration"
10
11
  import {DOMObserver, safariShadowSelectionRange} from "./domobserver"
@@ -219,6 +220,8 @@ export class EditorView {
219
220
  }
220
221
 
221
222
  this.updatePluginViews(prev)
223
+ if ((this.dragging as Dragging)?.node && !prev.doc.eq(state.doc))
224
+ this.updateDraggedNode(this.dragging as Dragging, prev)
222
225
 
223
226
  if (scroll == "reset") {
224
227
  this.dom.scrollTop = 0
@@ -267,6 +270,19 @@ export class EditorView {
267
270
  }
268
271
  }
269
272
 
273
+ private updateDraggedNode(dragging: Dragging, prev: EditorState) {
274
+ let sel = dragging.node!, found = -1
275
+ if (this.state.doc.nodeAt(sel.from) == sel.node) {
276
+ found = sel.from
277
+ } else {
278
+ let movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size)
279
+ let moved = movedPos > 0 && this.state.doc.nodeAt(movedPos)
280
+ if (moved == sel.node) found = movedPos
281
+ }
282
+ this.dragging = new Dragging(dragging.slice, dragging.move,
283
+ found < 0 ? undefined : NodeSelection.create(this.state.doc, found))
284
+ }
285
+
270
286
  /// Goes over the values of a prop, first those provided directly,
271
287
  /// then those from plugins given to the view, then from plugins in
272
288
  /// the state (in order), and calls `f` every time a non-undefined
package/src/input.ts CHANGED
@@ -609,7 +609,7 @@ export function doPaste(view: EditorView, text: string, html: string | null, pre
609
609
  }
610
610
 
611
611
  function getText(clipboardData: DataTransfer) {
612
- let text = clipboardData.getData("text/html") || clipboardData.getData("Text")
612
+ let text = clipboardData.getData("text/plain") || clipboardData.getData("Text")
613
613
  if (text) return text
614
614
  let uris = clipboardData.getData("text/uri-list")
615
615
  return uris ? uris.replace(/\r?\n/g, " ") : ""
@@ -630,8 +630,8 @@ editHandlers.paste = (view, _event) => {
630
630
  capturePaste(view, event)
631
631
  }
632
632
 
633
- class Dragging {
634
- constructor(readonly slice: Slice, readonly move: boolean) {}
633
+ export class Dragging {
634
+ constructor(readonly slice: Slice, readonly move: boolean, readonly node?: NodeSelection) {}
635
635
  }
636
636
 
637
637
  const dragCopyModifier: keyof DragEvent = browser.mac ? "altKey" : "ctrlKey"
@@ -644,22 +644,23 @@ handlers.dragstart = (view, _event) => {
644
644
 
645
645
  let sel = view.state.selection
646
646
  let pos = sel.empty ? null : view.posAtCoords(eventCoords(event))
647
+ let node: undefined | NodeSelection
647
648
  if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof NodeSelection ? sel.to - 1: sel.to)) {
648
649
  // In selection
649
650
  } else if (mouseDown && mouseDown.mightDrag) {
650
- view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)))
651
+ node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)
651
652
  } else if (event.target && (event.target as HTMLElement).nodeType == 1) {
652
653
  let desc = view.docView.nearestDesc(event.target as HTMLElement, true)
653
654
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
654
- view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, desc.posBefore)))
655
+ node = NodeSelection.create(view.state.doc, desc.posBefore)
655
656
  }
656
- let slice = view.state.selection.content(), {dom, text} = serializeForClipboard(view, slice)
657
+ let slice = (node || view.state.selection).content(), {dom, text} = serializeForClipboard(view, slice)
657
658
  event.dataTransfer.clearData()
658
659
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML)
659
660
  // See https://github.com/ProseMirror/prosemirror/issues/1156
660
661
  event.dataTransfer.effectAllowed = "copyMove"
661
662
  if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text)
662
- view.dragging = new Dragging(slice, !event[dragCopyModifier])
663
+ view.dragging = new Dragging(slice, !event[dragCopyModifier], node)
663
664
  }
664
665
 
665
666
  handlers.dragend = view => {
@@ -700,7 +701,11 @@ editHandlers.drop = (view, _event) => {
700
701
  if (insertPos == null) insertPos = $mouse.pos
701
702
 
702
703
  let tr = view.state.tr
703
- if (move) tr.deleteSelection()
704
+ if (move) {
705
+ let {node} = dragging as Dragging
706
+ if (node) node.replace(tr)
707
+ else tr.deleteSelection()
708
+ }
704
709
 
705
710
  let pos = tr.mapping.map(insertPos)
706
711
  let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1