prosemirror-view 1.33.7 → 1.33.9

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.33.9 (2024-07-18)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where dragging an image on Chrome versions before 121 failed to put the image file in the clipboard data.
6
+
7
+ Enable cross-site scripting protection hack when rendering nodes and marks inside the editor.
8
+
9
+ ## 1.33.8 (2024-06-11)
10
+
11
+ ### Bug fixes
12
+
13
+ When composition happens with the cursor between two text nodes, use the last mutated one to guess which one is being changed.
14
+
1
15
  ## 1.33.7 (2024-05-31)
2
16
 
3
17
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1216,7 +1216,7 @@ var MarkViewDesc = function (_ViewDesc3) {
1216
1216
  value: function create(parent, mark, inline, view) {
1217
1217
  var custom = view.nodeViews[mark.type.name];
1218
1218
  var spec = custom && custom(mark, view, inline);
1219
- if (!spec || !spec.dom) spec = prosemirrorModel.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline));
1219
+ if (!spec || !spec.dom) spec = prosemirrorModel.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
1220
1220
  return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
1221
1221
  }
1222
1222
  }]);
@@ -1415,9 +1415,9 @@ var NodeViewDesc = function (_ViewDesc4) {
1415
1415
  if (node.isText) {
1416
1416
  if (!dom) dom = document.createTextNode(node.text);else if (dom.nodeType != 3) throw new RangeError("Text must be rendered as a DOM text node");
1417
1417
  } else if (!dom) {
1418
- var _prosemirrorModel$DOM = prosemirrorModel.DOMSerializer.renderSpec(document, node.type.spec.toDOM(node));
1419
- dom = _prosemirrorModel$DOM.dom;
1420
- contentDOM = _prosemirrorModel$DOM.contentDOM;
1418
+ var _spec = prosemirrorModel.DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs);
1419
+ dom = _spec.dom;
1420
+ contentDOM = _spec.contentDOM;
1421
1421
  }
1422
1422
  if (!contentDOM && !node.isText && dom.nodeName != "BR") {
1423
1423
  if (!dom.hasAttribute("contenteditable")) dom.contentEditable = "false";
@@ -3247,7 +3247,9 @@ function findCompositionNode(view) {
3247
3247
  var textBefore = textNodeBefore$1(sel.focusNode, sel.focusOffset);
3248
3248
  var textAfter = textNodeAfter$1(sel.focusNode, sel.focusOffset);
3249
3249
  if (textBefore && textAfter && textBefore != textAfter) {
3250
- var descAfter = textAfter.pmViewDesc;
3250
+ var descAfter = textAfter.pmViewDesc,
3251
+ lastChanged = view.domObserver.lastChangedTextNode;
3252
+ if (textBefore == lastChanged || textAfter == lastChanged) return lastChanged;
3251
3253
  if (!descAfter || !descAfter.isText(textAfter.nodeValue)) {
3252
3254
  return textAfter;
3253
3255
  } else if (view.input.compositionNode == textAfter) {
@@ -3378,7 +3380,7 @@ handlers.dragstart = function (view, _event) {
3378
3380
  dom = _serializeForClipboar2.dom,
3379
3381
  text = _serializeForClipboar2.text,
3380
3382
  slice = _serializeForClipboar2.slice;
3381
- event.dataTransfer.clearData();
3383
+ if (!event.dataTransfer.files.length || !chrome || chrome_version > 120) event.dataTransfer.clearData();
3382
3384
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3383
3385
  event.dataTransfer.effectAllowed = "copyMove";
3384
3386
  if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text);
@@ -4111,6 +4113,7 @@ var DOMObserver = function () {
4111
4113
  this.currentSelection = new SelectionState();
4112
4114
  this.onCharData = null;
4113
4115
  this.suppressingSelectionUpdates = false;
4116
+ this.lastChangedTextNode = null;
4114
4117
  this.observer = window.MutationObserver && new window.MutationObserver(function (mutations) {
4115
4118
  for (var i = 0; i < mutations.length; i++) _this11.queue.push(mutations[i]);
4116
4119
  if (ie && ie_version <= 11 && mutations.some(function (m) {
@@ -4321,7 +4324,11 @@ var DOMObserver = function () {
4321
4324
  if (mut.type == "attributes" && (desc == this.view.docView || mut.attributeName == "contenteditable" || mut.attributeName == "style" && !mut.oldValue && !mut.target.getAttribute("style"))) return null;
4322
4325
  if (!desc || desc.ignoreMutation(mut)) return null;
4323
4326
  if (mut.type == "childList") {
4324
- for (var i = 0; i < mut.addedNodes.length; i++) added.push(mut.addedNodes[i]);
4327
+ for (var i = 0; i < mut.addedNodes.length; i++) {
4328
+ var node = mut.addedNodes[i];
4329
+ added.push(node);
4330
+ if (node.nodeType == 3) this.lastChangedTextNode = node;
4331
+ }
4325
4332
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target)) return {
4326
4333
  from: desc.posBefore,
4327
4334
  to: desc.posAfter
@@ -4351,6 +4358,7 @@ var DOMObserver = function () {
4351
4358
  to: desc.posAtEnd + desc.border
4352
4359
  };
4353
4360
  } else {
4361
+ this.lastChangedTextNode = mut.target;
4354
4362
  return {
4355
4363
  from: desc.posAtStart,
4356
4364
  to: desc.posAtEnd,
package/dist/index.js CHANGED
@@ -1195,7 +1195,7 @@ class MarkViewDesc extends ViewDesc {
1195
1195
  let custom = view.nodeViews[mark.type.name];
1196
1196
  let spec = custom && custom(mark, view, inline);
1197
1197
  if (!spec || !spec.dom)
1198
- spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline));
1198
+ spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
1199
1199
  return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
1200
1200
  }
1201
1201
  parseRule() {
@@ -1267,7 +1267,8 @@ class NodeViewDesc extends ViewDesc {
1267
1267
  throw new RangeError("Text must be rendered as a DOM text node");
1268
1268
  }
1269
1269
  else if (!dom) {
1270
- ({ dom, contentDOM } = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node)));
1270
+ let spec = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs);
1271
+ ({ dom, contentDOM } = spec);
1271
1272
  }
1272
1273
  if (!contentDOM && !node.isText && dom.nodeName != "BR") { // Chrome gets confused by <br contenteditable=false>
1273
1274
  if (!dom.hasAttribute("contenteditable"))
@@ -3460,7 +3461,9 @@ function findCompositionNode(view) {
3460
3461
  let textBefore = textNodeBefore$1(sel.focusNode, sel.focusOffset);
3461
3462
  let textAfter = textNodeAfter$1(sel.focusNode, sel.focusOffset);
3462
3463
  if (textBefore && textAfter && textBefore != textAfter) {
3463
- let descAfter = textAfter.pmViewDesc;
3464
+ let descAfter = textAfter.pmViewDesc, lastChanged = view.domObserver.lastChangedTextNode;
3465
+ if (textBefore == lastChanged || textAfter == lastChanged)
3466
+ return lastChanged;
3464
3467
  if (!descAfter || !descAfter.isText(textAfter.nodeValue)) {
3465
3468
  return textAfter;
3466
3469
  }
@@ -3629,7 +3632,9 @@ handlers.dragstart = (view, _event) => {
3629
3632
  }
3630
3633
  let draggedSlice = (node || view.state.selection).content();
3631
3634
  let { dom, text, slice } = serializeForClipboard(view, draggedSlice);
3632
- event.dataTransfer.clearData();
3635
+ // Pre-120 Chrome versions clear files when calling `clearData` (#1472)
3636
+ if (!event.dataTransfer.files.length || !chrome || chrome_version > 120)
3637
+ event.dataTransfer.clearData();
3633
3638
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3634
3639
  // See https://github.com/ProseMirror/prosemirror/issues/1156
3635
3640
  event.dataTransfer.effectAllowed = "copyMove";
@@ -4472,6 +4477,7 @@ class DOMObserver {
4472
4477
  this.currentSelection = new SelectionState;
4473
4478
  this.onCharData = null;
4474
4479
  this.suppressingSelectionUpdates = false;
4480
+ this.lastChangedTextNode = null;
4475
4481
  this.observer = window.MutationObserver &&
4476
4482
  new window.MutationObserver(mutations => {
4477
4483
  for (let i = 0; i < mutations.length; i++)
@@ -4661,8 +4667,12 @@ class DOMObserver {
4661
4667
  if (!desc || desc.ignoreMutation(mut))
4662
4668
  return null;
4663
4669
  if (mut.type == "childList") {
4664
- for (let i = 0; i < mut.addedNodes.length; i++)
4665
- added.push(mut.addedNodes[i]);
4670
+ for (let i = 0; i < mut.addedNodes.length; i++) {
4671
+ let node = mut.addedNodes[i];
4672
+ added.push(node);
4673
+ if (node.nodeType == 3)
4674
+ this.lastChangedTextNode = node;
4675
+ }
4666
4676
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
4667
4677
  return { from: desc.posBefore, to: desc.posAfter };
4668
4678
  let prev = mut.previousSibling, next = mut.nextSibling;
@@ -4689,6 +4699,7 @@ class DOMObserver {
4689
4699
  return { from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border };
4690
4700
  }
4691
4701
  else { // "characterData"
4702
+ this.lastChangedTextNode = mut.target;
4692
4703
  return {
4693
4704
  from: desc.posAtStart,
4694
4705
  to: desc.posAtEnd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.33.7",
3
+ "version": "1.33.9",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -43,6 +43,7 @@ export class DOMObserver {
43
43
  currentSelection = new SelectionState
44
44
  onCharData: ((e: Event) => void) | null = null
45
45
  suppressingSelectionUpdates = false
46
+ lastChangedTextNode: Text | null = null
46
47
 
47
48
  constructor(
48
49
  readonly view: EditorView,
@@ -235,7 +236,11 @@ export class DOMObserver {
235
236
  if (!desc || desc.ignoreMutation(mut)) return null
236
237
 
237
238
  if (mut.type == "childList") {
238
- for (let i = 0; i < mut.addedNodes.length; i++) added.push(mut.addedNodes[i])
239
+ for (let i = 0; i < mut.addedNodes.length; i++) {
240
+ let node = mut.addedNodes[i]
241
+ added.push(node)
242
+ if (node.nodeType == 3) this.lastChangedTextNode = node as Text
243
+ }
239
244
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
240
245
  return {from: desc.posBefore, to: desc.posAfter}
241
246
  let prev = mut.previousSibling, next = mut.nextSibling
@@ -258,6 +263,7 @@ export class DOMObserver {
258
263
  } else if (mut.type == "attributes") {
259
264
  return {from: desc.posAtStart - desc.border, to: desc.posAtEnd + desc.border}
260
265
  } else { // "characterData"
266
+ this.lastChangedTextNode = mut.target as Text
261
267
  return {
262
268
  from: desc.posAtStart,
263
269
  to: desc.posAtEnd,
package/src/input.ts CHANGED
@@ -517,7 +517,8 @@ export function findCompositionNode(view: EditorView) {
517
517
  let textBefore = textNodeBefore(sel.focusNode, sel.focusOffset)
518
518
  let textAfter = textNodeAfter(sel.focusNode, sel.focusOffset)
519
519
  if (textBefore && textAfter && textBefore != textAfter) {
520
- let descAfter = textAfter.pmViewDesc
520
+ let descAfter = textAfter.pmViewDesc, lastChanged = view.domObserver.lastChangedTextNode
521
+ if (textBefore == lastChanged || textAfter == lastChanged) return lastChanged
521
522
  if (!descAfter || !descAfter.isText(textAfter.nodeValue!)) {
522
523
  return textAfter
523
524
  } else if (view.input.compositionNode == textAfter) {
@@ -676,7 +677,9 @@ handlers.dragstart = (view, _event) => {
676
677
  }
677
678
  let draggedSlice = (node || view.state.selection).content()
678
679
  let {dom, text, slice} = serializeForClipboard(view, draggedSlice)
679
- event.dataTransfer.clearData()
680
+ // Pre-120 Chrome versions clear files when calling `clearData` (#1472)
681
+ if (!event.dataTransfer.files.length || !browser.chrome || browser.chrome_version > 120)
682
+ event.dataTransfer.clearData()
680
683
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML)
681
684
  // See https://github.com/ProseMirror/prosemirror/issues/1156
682
685
  event.dataTransfer.effectAllowed = "copyMove"
package/src/viewdesc.ts CHANGED
@@ -572,7 +572,7 @@ class MarkViewDesc extends ViewDesc {
572
572
  let custom = view.nodeViews[mark.type.name]
573
573
  let spec: {dom: HTMLElement, contentDOM?: HTMLElement} = custom && (custom as any)(mark, view, inline)
574
574
  if (!spec || !spec.dom)
575
- spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM!(mark, inline)) as any
575
+ spec = (DOMSerializer.renderSpec as any)(document, mark.type.spec.toDOM!(mark, inline), null, mark.attrs) as any
576
576
  return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom as HTMLElement)
577
577
  }
578
578
 
@@ -647,7 +647,8 @@ export class NodeViewDesc extends ViewDesc {
647
647
  if (!dom) dom = document.createTextNode(node.text!)
648
648
  else if (dom.nodeType != 3) throw new RangeError("Text must be rendered as a DOM text node")
649
649
  } else if (!dom) {
650
- ;({dom, contentDOM} = DOMSerializer.renderSpec(document, node.type.spec.toDOM!(node)))
650
+ let spec = (DOMSerializer.renderSpec as any)(document, node.type.spec.toDOM!(node), null, node.attrs)
651
+ ;({dom, contentDOM} = spec as {dom: DOMNode, contentDOM?: HTMLElement})
651
652
  }
652
653
  if (!contentDOM && !node.isText && dom.nodeName != "BR") { // Chrome gets confused by <br contenteditable=false>
653
654
  if (!(dom as HTMLElement).hasAttribute("contenteditable")) (dom as HTMLElement).contentEditable = "false"