prosemirror-view 1.33.5 → 1.33.7

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,19 @@
1
+ ## 1.33.7 (2024-05-31)
2
+
3
+ ### Bug fixes
4
+
5
+ Ignore stray `<br>` nodes added to parent list elements when backspacing near uneditable content in Firefox.
6
+
7
+ Fix a crash where the editor tried to call `removeAttribute` on a text node.
8
+
9
+ Fix an issue where coordinates near nested blocks could inappropriately be assigned to be inside those blocks.
10
+
11
+ ## 1.33.6 (2024-04-30)
12
+
13
+ ### Bug fixes
14
+
15
+ Make sure the content slice stored for an in-editor drag is the one that was transformed by `transformCopied`.
16
+
1
17
  ## 1.33.5 (2024-04-22)
2
18
 
3
19
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
4
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
3
7
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
4
8
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
5
9
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
@@ -387,11 +391,11 @@ function posFromCaret(view, node, offset, coords) {
387
391
  if (cur == view.dom) break;
388
392
  var desc = view.docView.nearestDesc(cur, true);
389
393
  if (!desc) return null;
390
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent && !sawBlock || !desc.contentDOM)) {
394
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
391
395
  var rect = desc.dom.getBoundingClientRect();
392
- if (desc.node.isBlock && desc.parent && !sawBlock) {
396
+ if (desc.node.isBlock && desc.parent) {
397
+ if (!sawBlock && rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore;else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter;
393
398
  sawBlock = true;
394
- if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore;else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter;
395
399
  }
396
400
  if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
397
401
  var before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2 : coords.left < (rect.left + rect.right) / 2;
@@ -1387,8 +1391,10 @@ var NodeViewDesc = function (_ViewDesc4) {
1387
1391
  }, {
1388
1392
  key: "deselectNode",
1389
1393
  value: function deselectNode() {
1390
- if (this.nodeDOM.nodeType == 1) this.nodeDOM.classList.remove("ProseMirror-selectednode");
1391
- if (this.contentDOM || !this.node.type.spec.draggable) this.dom.removeAttribute("draggable");
1394
+ if (this.nodeDOM.nodeType == 1) {
1395
+ this.nodeDOM.classList.remove("ProseMirror-selectednode");
1396
+ if (this.contentDOM || !this.node.type.spec.draggable) this.dom.removeAttribute("draggable");
1397
+ }
1392
1398
  }
1393
1399
  }, {
1394
1400
  key: "domAtom",
@@ -2602,7 +2608,8 @@ function serializeForClipboard(view, slice) {
2602
2608
  }) || slice.content.textBetween(0, slice.content.size, "\n\n");
2603
2609
  return {
2604
2610
  dom: wrap,
2605
- text: text
2611
+ text: text,
2612
+ slice: slice
2606
2613
  };
2607
2614
  }
2608
2615
  function parseFromClipboard(view, text, html, plainText, $context) {
@@ -3084,7 +3091,7 @@ var MouseDown = function () {
3084
3091
  }
3085
3092
  var target = flushed ? null : event.target;
3086
3093
  var targetDesc = target ? view.docView.nearestDesc(target, true) : null;
3087
- this.target = targetDesc ? targetDesc.dom : null;
3094
+ this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom : null;
3088
3095
  var selection = view.state.selection;
3089
3096
  if (event.button == 0 && targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false || selection instanceof prosemirrorState.NodeSelection && selection.from <= targetPos && selection.to > targetPos) this.mightDrag = {
3090
3097
  node: targetNode,
@@ -3366,10 +3373,11 @@ handlers.dragstart = function (view, _event) {
3366
3373
  var desc = view.docView.nearestDesc(event.target, true);
3367
3374
  if (desc && desc.node.type.spec.draggable && desc != view.docView) node = prosemirrorState.NodeSelection.create(view.state.doc, desc.posBefore);
3368
3375
  }
3369
- var slice = (node || view.state.selection).content(),
3370
- _serializeForClipboar2 = serializeForClipboard(view, slice),
3376
+ var draggedSlice = (node || view.state.selection).content();
3377
+ var _serializeForClipboar2 = serializeForClipboard(view, draggedSlice),
3371
3378
  dom = _serializeForClipboar2.dom,
3372
- text = _serializeForClipboar2.text;
3379
+ text = _serializeForClipboar2.text,
3380
+ slice = _serializeForClipboar2.slice;
3373
3381
  event.dataTransfer.clearData();
3374
3382
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3375
3383
  event.dataTransfer.effectAllowed = "copyMove";
@@ -4263,14 +4271,30 @@ var DOMObserver = function () {
4263
4271
  }
4264
4272
  }
4265
4273
  }
4266
- if (gecko && added.length > 1) {
4274
+ if (gecko && added.length) {
4267
4275
  var brs = added.filter(function (n) {
4268
4276
  return n.nodeName == "BR";
4269
4277
  });
4270
4278
  if (brs.length == 2) {
4271
- var a = brs[0],
4272
- b = brs[1];
4279
+ var _brs = _slicedToArray(brs, 2),
4280
+ a = _brs[0],
4281
+ b = _brs[1];
4273
4282
  if (a.parentNode && a.parentNode.parentNode == b.parentNode) b.remove();else a.remove();
4283
+ } else {
4284
+ var focusNode = this.currentSelection.focusNode;
4285
+ var _iterator3 = _createForOfIteratorHelper(brs),
4286
+ _step3;
4287
+ try {
4288
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
4289
+ var br = _step3.value;
4290
+ var parent = br.parentNode;
4291
+ if (parent && parent.nodeName == "LI" && (!focusNode || blockParent(view, focusNode) != parent)) br.remove();
4292
+ }
4293
+ } catch (err) {
4294
+ _iterator3.e(err);
4295
+ } finally {
4296
+ _iterator3.f();
4297
+ }
4274
4298
  }
4275
4299
  }
4276
4300
  var readSel = null;
@@ -4385,6 +4409,13 @@ function safariShadowSelectionRange(view, selection) {
4385
4409
  view.dom.removeEventListener("beforeinput", read, true);
4386
4410
  return found ? rangeToSelectionRange(view, found) : null;
4387
4411
  }
4412
+ function blockParent(view, node) {
4413
+ for (var p = node.parentNode; p && p != view.dom; p = p.parentNode) {
4414
+ var desc = view.docView.nearestDesc(p, true);
4415
+ if (desc && desc.node.isBlock) return p;
4416
+ }
4417
+ return null;
4418
+ }
4388
4419
  function parseBetween(view, from_, to_) {
4389
4420
  var _view$docView$parseRa = view.docView.parseRange(from_, to_),
4390
4421
  parent = _view$docView$parseRa.node,
package/dist/index.js CHANGED
@@ -396,14 +396,15 @@ function posFromCaret(view, node, offset, coords) {
396
396
  let desc = view.docView.nearestDesc(cur, true);
397
397
  if (!desc)
398
398
  return null;
399
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent && !sawBlock || !desc.contentDOM)) {
399
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
400
400
  let rect = desc.dom.getBoundingClientRect();
401
- if (desc.node.isBlock && desc.parent && !sawBlock) {
402
- sawBlock = true;
403
- if (rect.left > coords.left || rect.top > coords.top)
401
+ if (desc.node.isBlock && desc.parent) {
402
+ // Only apply the horizontal test to the innermost block. Vertical for any parent.
403
+ if (!sawBlock && rect.left > coords.left || rect.top > coords.top)
404
404
  outsideBlock = desc.posBefore;
405
- else if (rect.right < coords.left || rect.bottom < coords.top)
405
+ else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top)
406
406
  outsideBlock = desc.posAfter;
407
+ sawBlock = true;
407
408
  }
408
409
  if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
409
410
  // If we are inside a leaf, return the side of the leaf closer to the coords
@@ -1452,10 +1453,11 @@ class NodeViewDesc extends ViewDesc {
1452
1453
  }
1453
1454
  // Remove selected node marking from this node.
1454
1455
  deselectNode() {
1455
- if (this.nodeDOM.nodeType == 1)
1456
+ if (this.nodeDOM.nodeType == 1) {
1456
1457
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
1457
- if (this.contentDOM || !this.node.type.spec.draggable)
1458
- this.dom.removeAttribute("draggable");
1458
+ if (this.contentDOM || !this.node.type.spec.draggable)
1459
+ this.dom.removeAttribute("draggable");
1460
+ }
1459
1461
  }
1460
1462
  get domAtom() { return this.node.isAtom; }
1461
1463
  }
@@ -2753,7 +2755,7 @@ function serializeForClipboard(view, slice) {
2753
2755
  firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
2754
2756
  let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
2755
2757
  slice.content.textBetween(0, slice.content.size, "\n\n");
2756
- return { dom: wrap, text };
2758
+ return { dom: wrap, text, slice };
2757
2759
  }
2758
2760
  // Read a slice of content from the clipboard (or drop data).
2759
2761
  function parseFromClipboard(view, text, html, plainText, $context) {
@@ -3270,7 +3272,7 @@ class MouseDown {
3270
3272
  }
3271
3273
  const target = flushed ? null : event.target;
3272
3274
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
3273
- this.target = targetDesc ? targetDesc.dom : null;
3275
+ this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom : null;
3274
3276
  let { selection } = view.state;
3275
3277
  if (event.button == 0 &&
3276
3278
  targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
@@ -3625,7 +3627,8 @@ handlers.dragstart = (view, _event) => {
3625
3627
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
3626
3628
  node = NodeSelection.create(view.state.doc, desc.posBefore);
3627
3629
  }
3628
- let slice = (node || view.state.selection).content(), { dom, text } = serializeForClipboard(view, slice);
3630
+ let draggedSlice = (node || view.state.selection).content();
3631
+ let { dom, text, slice } = serializeForClipboard(view, draggedSlice);
3629
3632
  event.dataTransfer.clearData();
3630
3633
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3631
3634
  // See https://github.com/ProseMirror/prosemirror/issues/1156
@@ -4601,15 +4604,23 @@ class DOMObserver {
4601
4604
  }
4602
4605
  }
4603
4606
  }
4604
- if (gecko && added.length > 1) {
4607
+ if (gecko && added.length) {
4605
4608
  let brs = added.filter(n => n.nodeName == "BR");
4606
4609
  if (brs.length == 2) {
4607
- let a = brs[0], b = brs[1];
4610
+ let [a, b] = brs;
4608
4611
  if (a.parentNode && a.parentNode.parentNode == b.parentNode)
4609
4612
  b.remove();
4610
4613
  else
4611
4614
  a.remove();
4612
4615
  }
4616
+ else {
4617
+ let { focusNode } = this.currentSelection;
4618
+ for (let br of brs) {
4619
+ let parent = br.parentNode;
4620
+ if (parent && parent.nodeName == "LI" && (!focusNode || blockParent(view, focusNode) != parent))
4621
+ br.remove();
4622
+ }
4623
+ }
4613
4624
  }
4614
4625
  let readSel = null;
4615
4626
  // If it looks like the browser has reset the selection to the
@@ -4739,6 +4750,14 @@ function safariShadowSelectionRange(view, selection) {
4739
4750
  view.dom.removeEventListener("beforeinput", read, true);
4740
4751
  return found ? rangeToSelectionRange(view, found) : null;
4741
4752
  }
4753
+ function blockParent(view, node) {
4754
+ for (let p = node.parentNode; p && p != view.dom; p = p.parentNode) {
4755
+ let desc = view.docView.nearestDesc(p, true);
4756
+ if (desc && desc.node.isBlock)
4757
+ return p;
4758
+ }
4759
+ return null;
4760
+ }
4742
4761
 
4743
4762
  // Note that all referencing and parsing is done with the
4744
4763
  // start-of-operation selection and document, since that's the one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.33.5",
3
+ "version": "1.33.7",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -36,7 +36,7 @@ export function serializeForClipboard(view: EditorView, slice: Slice) {
36
36
  let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
37
37
  slice.content.textBetween(0, slice.content.size, "\n\n")
38
38
 
39
- return {dom: wrap, text}
39
+ return {dom: wrap, text, slice}
40
40
  }
41
41
 
42
42
  // Read a slice of content from the clipboard (or drop data).
package/src/domcoords.ts CHANGED
@@ -227,12 +227,13 @@ function posFromCaret(view: EditorView, node: Node, offset: number, coords: {top
227
227
  if (cur == view.dom) break
228
228
  let desc = view.docView.nearestDesc(cur, true)
229
229
  if (!desc) return null
230
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent && !sawBlock || !desc.contentDOM)) {
230
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
231
231
  let rect = (desc.dom as HTMLElement).getBoundingClientRect()
232
- if (desc.node.isBlock && desc.parent && !sawBlock) {
232
+ if (desc.node.isBlock && desc.parent) {
233
+ // Only apply the horizontal test to the innermost block. Vertical for any parent.
234
+ if (!sawBlock && rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore
235
+ else if (!sawBlock && rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter
233
236
  sawBlock = true
234
- if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore
235
- else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter
236
237
  }
237
238
  if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
238
239
  // If we are inside a leaf, return the side of the leaf closer to the coords
@@ -183,12 +183,19 @@ export class DOMObserver {
183
183
  }
184
184
  }
185
185
 
186
- if (browser.gecko && added.length > 1) {
187
- let brs = added.filter(n => n.nodeName == "BR")
186
+ if (browser.gecko && added.length) {
187
+ let brs = added.filter(n => n.nodeName == "BR") as HTMLElement[]
188
188
  if (brs.length == 2) {
189
- let a = brs[0] as HTMLElement, b = brs[1] as HTMLElement
189
+ let [a, b] = brs
190
190
  if (a.parentNode && a.parentNode.parentNode == b.parentNode) b.remove()
191
191
  else a.remove()
192
+ } else {
193
+ let {focusNode} = this.currentSelection
194
+ for (let br of brs) {
195
+ let parent = br.parentNode
196
+ if (parent && parent.nodeName == "LI" && (!focusNode || blockParent(view, focusNode) != parent))
197
+ br.remove()
198
+ }
192
199
  }
193
200
  }
194
201
 
@@ -317,3 +324,11 @@ export function safariShadowSelectionRange(view: EditorView, selection: DOMSelec
317
324
 
318
325
  return found ? rangeToSelectionRange(view, found) : null
319
326
  }
327
+
328
+ function blockParent(view: EditorView, node: DOMNode): Node | null {
329
+ for (let p = node.parentNode; p && p != view.dom; p = p.parentNode) {
330
+ let desc = view.docView.nearestDesc(p, true)
331
+ if (desc && desc.node.isBlock) return p
332
+ }
333
+ return null
334
+ }
package/src/input.ts CHANGED
@@ -326,7 +326,7 @@ class MouseDown {
326
326
 
327
327
  const target = flushed ? null : event.target as HTMLElement
328
328
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null
329
- this.target = targetDesc ? targetDesc.dom as HTMLElement : null
329
+ this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom as HTMLElement : null
330
330
 
331
331
  let {selection} = view.state
332
332
  if (event.button == 0 &&
@@ -674,7 +674,8 @@ handlers.dragstart = (view, _event) => {
674
674
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
675
675
  node = NodeSelection.create(view.state.doc, desc.posBefore)
676
676
  }
677
- let slice = (node || view.state.selection).content(), {dom, text} = serializeForClipboard(view, slice)
677
+ let draggedSlice = (node || view.state.selection).content()
678
+ let {dom, text, slice} = serializeForClipboard(view, draggedSlice)
678
679
  event.dataTransfer.clearData()
679
680
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML)
680
681
  // See https://github.com/ProseMirror/prosemirror/issues/1156
package/src/viewdesc.ts CHANGED
@@ -834,8 +834,10 @@ export class NodeViewDesc extends ViewDesc {
834
834
 
835
835
  // Remove selected node marking from this node.
836
836
  deselectNode() {
837
- if (this.nodeDOM.nodeType == 1) (this.nodeDOM as HTMLElement).classList.remove("ProseMirror-selectednode")
838
- if (this.contentDOM || !this.node.type.spec.draggable) (this.dom as HTMLElement).removeAttribute("draggable")
837
+ if (this.nodeDOM.nodeType == 1) {
838
+ ;(this.nodeDOM as HTMLElement).classList.remove("ProseMirror-selectednode")
839
+ if (this.contentDOM || !this.node.type.spec.draggable) (this.dom as HTMLElement).removeAttribute("draggable")
840
+ }
839
841
  }
840
842
 
841
843
  get domAtom() { return this.node.isAtom }