prosemirror-view 1.42.2 → 1.42.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,21 @@
1
+ ## 1.42.4 (2026-09-18)
2
+
3
+ ### Bug fixes
4
+
5
+ Prevent uneditable elements rendered as part of node or mark view from blocking cursor motion.
6
+
7
+ Fix a bug that could break some types of composition input starting with a non-empty selection.
8
+
9
+ ## 1.42.3 (2026-08-25)
10
+
11
+ ### Bug fixes
12
+
13
+ Don't set `contenteditable=false` on widgets that already have a `contenteditable` attribute.
14
+
15
+ Fix a bug that broke pasting when there was a default trusted type policy defined without a `createHTML` function.
16
+
17
+ Run attribute validators on attributes provided via slice context in clipboard content. This closes an XSS vulnerability (found by Pedro Paniago).
18
+
1
19
  ## 1.42.2 (2026-07-24)
2
20
 
3
21
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1105,7 +1105,7 @@ var WidgetViewDesc = function (_ViewDesc) {
1105
1105
  wrap.appendChild(dom);
1106
1106
  dom = wrap;
1107
1107
  }
1108
- dom.contentEditable = "false";
1108
+ if (!dom.hasAttribute("contenteditable")) dom.contentEditable = "false";
1109
1109
  dom.classList.add("ProseMirror-widget");
1110
1110
  }
1111
1111
  _this = _super.call(this, parent, [], dom, null);
@@ -2400,7 +2400,7 @@ function nodeLen(node) {
2400
2400
  }
2401
2401
  function isIgnorable(dom, dir) {
2402
2402
  var desc = dom.pmViewDesc;
2403
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
2403
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR") : dom.nodeType == 1 && dom.contentEditable == "false";
2404
2404
  }
2405
2405
  function skipIgnoredNodes(view, dir) {
2406
2406
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -2852,11 +2852,16 @@ var _policy = null;
2852
2852
  function maybeWrapTrusted(html) {
2853
2853
  var trustedTypes = window.trustedTypes;
2854
2854
  if (!trustedTypes) return html;
2855
- if (!_policy) _policy = trustedTypes.defaultPolicy || trustedTypes.createPolicy("ProseMirrorClipboard", {
2856
- createHTML: function createHTML(s) {
2857
- return s;
2858
- }
2859
- });
2855
+ if (!_policy) {
2856
+ if (_policy = trustedTypes.defaultPolicy) try {
2857
+ return _policy.createHTML(html);
2858
+ } catch (_a) {}
2859
+ _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {
2860
+ createHTML: function createHTML(s) {
2861
+ return s;
2862
+ }
2863
+ });
2864
+ }
2860
2865
  return _policy.createHTML(html);
2861
2866
  }
2862
2867
  function readHTML(html) {
@@ -2907,6 +2912,11 @@ function addContext(slice, context) {
2907
2912
  for (var i = array.length - 2; i >= 0; i -= 2) {
2908
2913
  var type = schema.nodes[array[i]];
2909
2914
  if (!type || type.hasRequiredAttrs()) break;
2915
+ try {
2916
+ type.checkAttrs(array[i + 1]);
2917
+ } catch (e) {
2918
+ break;
2919
+ }
2910
2920
  content = prosemirrorModel.Fragment.from(type.create(array[i + 1], content));
2911
2921
  openStart++;
2912
2922
  openEnd++;
@@ -3377,7 +3387,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
3377
3387
  view.domObserver.flush();
3378
3388
  var state = view.state,
3379
3389
  $pos = state.selection.$to;
3380
- if (state.selection instanceof prosemirrorState.TextSelection && (state.storedMarks || !$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) {
3390
+ if (state.selection instanceof prosemirrorState.TextSelection && state.selection.empty && (state.storedMarks || !$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) {
3381
3391
  return m.type.spec.inclusive === false;
3382
3392
  }) || chrome && windows && selectionBeforeUneditable(view))) {
3383
3393
  view.markCursor = view.state.storedMarks || $pos.marks();
package/dist/index.js CHANGED
@@ -1169,7 +1169,8 @@ class WidgetViewDesc extends ViewDesc {
1169
1169
  wrap.appendChild(dom);
1170
1170
  dom = wrap;
1171
1171
  }
1172
- dom.contentEditable = "false";
1172
+ if (!dom.hasAttribute("contenteditable"))
1173
+ dom.contentEditable = "false";
1173
1174
  dom.classList.add("ProseMirror-widget");
1174
1175
  }
1175
1176
  super(parent, [], dom, null);
@@ -2493,7 +2494,8 @@ function nodeLen(node) {
2493
2494
  }
2494
2495
  function isIgnorable(dom, dir) {
2495
2496
  let desc = dom.pmViewDesc;
2496
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
2497
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
2498
+ : dom.nodeType == 1 && dom.contentEditable == "false";
2497
2499
  }
2498
2500
  function skipIgnoredNodes(view, dir) {
2499
2501
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -3017,8 +3019,14 @@ function maybeWrapTrusted(html) {
3017
3019
  // With the require-trusted-types-for CSP, Chrome will block
3018
3020
  // innerHTML, even on a detached document. This wraps the string in
3019
3021
  // a way that makes the browser allow us to use its parser again.
3020
- if (!_policy)
3021
- _policy = trustedTypes.defaultPolicy || trustedTypes.createPolicy("ProseMirrorClipboard", { createHTML: (s) => s });
3022
+ if (!_policy) {
3023
+ if (_policy = trustedTypes.defaultPolicy)
3024
+ try {
3025
+ return _policy.createHTML(html);
3026
+ }
3027
+ catch (_a) { }
3028
+ _policy = trustedTypes.createPolicy("ProseMirrorClipboard", { createHTML: (s) => s });
3029
+ }
3022
3030
  return _policy.createHTML(html);
3023
3031
  }
3024
3032
  function readHTML(html) {
@@ -3075,6 +3083,12 @@ function addContext(slice, context) {
3075
3083
  let type = schema.nodes[array[i]];
3076
3084
  if (!type || type.hasRequiredAttrs())
3077
3085
  break;
3086
+ try {
3087
+ type.checkAttrs(array[i + 1]);
3088
+ }
3089
+ catch (e) {
3090
+ break;
3091
+ }
3078
3092
  content = Fragment.from(type.create(array[i + 1], content));
3079
3093
  openStart++;
3080
3094
  openEnd++;
@@ -3556,7 +3570,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
3556
3570
  if (!view.composing) {
3557
3571
  view.domObserver.flush();
3558
3572
  let { state } = view, $pos = state.selection.$to;
3559
- if (state.selection instanceof TextSelection &&
3573
+ if (state.selection instanceof TextSelection && state.selection.empty &&
3560
3574
  (state.storedMarks ||
3561
3575
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
3562
3576
  chrome && windows && selectionBeforeUneditable(view))) { // Issue #1500
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.42.2",
3
+ "version": "1.42.4",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -61,7 +61,8 @@ function nodeLen(node: Node) {
61
61
 
62
62
  function isIgnorable(dom: Node, dir: number) {
63
63
  let desc = dom.pmViewDesc
64
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
64
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
65
+ : dom.nodeType == 1 && (dom as HTMLElement).contentEditable == "false"
65
66
  }
66
67
 
67
68
  function skipIgnoredNodes(view: EditorView, dir: number) {
package/src/clipboard.ts CHANGED
@@ -215,8 +215,11 @@ function maybeWrapTrusted(html: string): string {
215
215
  // With the require-trusted-types-for CSP, Chrome will block
216
216
  // innerHTML, even on a detached document. This wraps the string in
217
217
  // a way that makes the browser allow us to use its parser again.
218
- if (!_policy)
219
- _policy = trustedTypes.defaultPolicy || trustedTypes.createPolicy("ProseMirrorClipboard", {createHTML: (s: string) => s})
218
+ if (!_policy) {
219
+ if (_policy = trustedTypes.defaultPolicy)
220
+ try { return _policy.createHTML(html) } catch {}
221
+ _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {createHTML: (s: string) => s})
222
+ }
220
223
  return _policy.createHTML(html)
221
224
  }
222
225
 
@@ -267,6 +270,8 @@ function addContext(slice: Slice, context: string) {
267
270
  for (let i = array.length - 2; i >= 0; i -= 2) {
268
271
  let type = schema.nodes[array[i]]
269
272
  if (!type || type.hasRequiredAttrs()) break
273
+ try { type.checkAttrs(array[i + 1]) }
274
+ catch(e) { break }
270
275
  content = Fragment.from(type.create(array[i + 1], content))
271
276
  openStart++; openEnd++
272
277
  }
package/src/input.ts CHANGED
@@ -518,7 +518,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
518
518
  if (!view.composing) {
519
519
  view.domObserver.flush()
520
520
  let {state} = view, $pos = state.selection.$to
521
- if (state.selection instanceof TextSelection &&
521
+ if (state.selection instanceof TextSelection && state.selection.empty &&
522
522
  (state.storedMarks ||
523
523
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore!.marks.some(m => m.type.spec.inclusive === false)) ||
524
524
  browser.chrome && browser.windows && selectionBeforeUneditable(view))) { // Issue #1500
package/src/viewdesc.ts CHANGED
@@ -555,7 +555,8 @@ class WidgetViewDesc extends ViewDesc {
555
555
  wrap.appendChild(dom)
556
556
  dom = wrap
557
557
  }
558
- ;(dom as HTMLElement).contentEditable = "false"
558
+ if (!(dom as HTMLElement).hasAttribute("contenteditable"))
559
+ (dom as HTMLElement).contentEditable = "false"
559
560
  ;(dom as HTMLElement).classList.add("ProseMirror-widget")
560
561
  }
561
562
  super(parent, [], dom, null)