prosemirror-view 1.34.1 → 1.34.2

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,11 @@
1
+ ## 1.34.2 (2024-09-03)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix pasting in Chrome with the require-trusted-types-for CSP enabled.
6
+
7
+ Fix an issue where, for some kinds of IME on Windows, pressing Enter while in a composition would execute the resulting command on the wrong selection, erasing some typed content.
8
+
1
9
  ## 1.34.1 (2024-08-26)
2
10
 
3
11
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2766,6 +2766,15 @@ var _detachedDoc = null;
2766
2766
  function detachedDoc() {
2767
2767
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
2768
2768
  }
2769
+ function maybeWrapTrusted(html) {
2770
+ var trustedTypes = window.trustedTypes;
2771
+ if (!trustedTypes) return html;
2772
+ return trustedTypes.createPolicy("detachedDocument", {
2773
+ createHTML: function createHTML(s) {
2774
+ return s;
2775
+ }
2776
+ }).createHTML(html);
2777
+ }
2769
2778
  function readHTML(html) {
2770
2779
  var metas = /^(\s*<meta [^>]*>)*/.exec(html);
2771
2780
  if (metas) html = html.slice(metas[0].length);
@@ -2777,7 +2786,7 @@ function readHTML(html) {
2777
2786
  }).join("") + html + wrap.map(function (n) {
2778
2787
  return "</" + n + ">";
2779
2788
  }).reverse().join("");
2780
- elt.innerHTML = html;
2789
+ elt.innerHTML = maybeWrapTrusted(html);
2781
2790
  if (wrap) for (var i = 0; i < wrap.length; i++) elt = elt.querySelector(wrap[i]) || elt;
2782
2791
  return elt;
2783
2792
  }
@@ -2901,7 +2910,7 @@ editHandlers.keydown = function (view, _event) {
2901
2910
  view.input.lastKeyCode = event.keyCode;
2902
2911
  view.input.lastKeyCodeTime = Date.now();
2903
2912
  if (android && chrome && event.keyCode == 13) return;
2904
- if (event.keyCode != 229) view.domObserver.forceFlush();
2913
+ if (view.domObserver.selectionChanged(view.domSelectionRange())) view.domObserver.flush();else if (event.keyCode != 229) view.domObserver.forceFlush();
2905
2914
  if (ios && event.keyCode == 13 && !event.ctrlKey && !event.altKey && !event.metaKey) {
2906
2915
  var now = Date.now();
2907
2916
  view.input.lastIOSEnter = now;
@@ -4266,6 +4275,11 @@ var DOMObserver = function () {
4266
4275
  }
4267
4276
  return this.queue;
4268
4277
  }
4278
+ }, {
4279
+ key: "selectionChanged",
4280
+ value: function selectionChanged(sel) {
4281
+ return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
4282
+ }
4269
4283
  }, {
4270
4284
  key: "flush",
4271
4285
  value: function flush() {
@@ -4273,8 +4287,8 @@ var DOMObserver = function () {
4273
4287
  if (!view.docView || this.flushingSoon > -1) return;
4274
4288
  var mutations = this.pendingRecords();
4275
4289
  if (mutations.length) this.queue = [];
4276
- var sel = view.domSelectionRange();
4277
- var newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
4290
+ var sel = view.domSelectionRange(),
4291
+ newSel = this.selectionChanged(sel);
4278
4292
  var from = -1,
4279
4293
  to = -1,
4280
4294
  typeOver = false,
package/dist/index.js CHANGED
@@ -2937,6 +2937,15 @@ let _detachedDoc = null;
2937
2937
  function detachedDoc() {
2938
2938
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
2939
2939
  }
2940
+ function maybeWrapTrusted(html) {
2941
+ let trustedTypes = window.trustedTypes;
2942
+ if (!trustedTypes)
2943
+ return html;
2944
+ // With the require-trusted-types-for CSP, Chrome will block
2945
+ // innerHTML, even on a detached document. This wraps the string in
2946
+ // a way that makes the browser allow us to use its parser again.
2947
+ return trustedTypes.createPolicy("detachedDocument", { createHTML: (s) => s }).createHTML(html);
2948
+ }
2940
2949
  function readHTML(html) {
2941
2950
  let metas = /^(\s*<meta [^>]*>)*/.exec(html);
2942
2951
  if (metas)
@@ -2945,7 +2954,7 @@ function readHTML(html) {
2945
2954
  let firstTag = /<([a-z][^>\s]+)/i.exec(html), wrap;
2946
2955
  if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])
2947
2956
  html = wrap.map(n => "<" + n + ">").join("") + html + wrap.map(n => "</" + n + ">").reverse().join("");
2948
- elt.innerHTML = html;
2957
+ elt.innerHTML = maybeWrapTrusted(html);
2949
2958
  if (wrap)
2950
2959
  for (let i = 0; i < wrap.length; i++)
2951
2960
  elt = elt.querySelector(wrap[i]) || elt;
@@ -3086,7 +3095,9 @@ editHandlers.keydown = (view, _event) => {
3086
3095
  // and handling them eagerly tends to corrupt the input.
3087
3096
  if (android && chrome && event.keyCode == 13)
3088
3097
  return;
3089
- if (event.keyCode != 229)
3098
+ if (view.domObserver.selectionChanged(view.domSelectionRange()))
3099
+ view.domObserver.flush();
3100
+ else if (event.keyCode != 229)
3090
3101
  view.domObserver.forceFlush();
3091
3102
  // On iOS, if we preventDefault enter key presses, the virtual
3092
3103
  // keyboard gets confused. So the hack here is to set a flag that
@@ -4609,6 +4620,9 @@ class DOMObserver {
4609
4620
  this.queue.push(mut);
4610
4621
  return this.queue;
4611
4622
  }
4623
+ selectionChanged(sel) {
4624
+ return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
4625
+ }
4612
4626
  flush() {
4613
4627
  let { view } = this;
4614
4628
  if (!view.docView || this.flushingSoon > -1)
@@ -4616,8 +4630,7 @@ class DOMObserver {
4616
4630
  let mutations = this.pendingRecords();
4617
4631
  if (mutations.length)
4618
4632
  this.queue = [];
4619
- let sel = view.domSelectionRange();
4620
- let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
4633
+ let sel = view.domSelectionRange(), newSel = this.selectionChanged(sel);
4621
4634
  let from = -1, to = -1, typeOver = false, added = [];
4622
4635
  if (view.editable) {
4623
4636
  for (let i = 0; i < mutations.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.34.1",
3
+ "version": "1.34.2",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -204,6 +204,15 @@ function detachedDoc() {
204
204
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
205
205
  }
206
206
 
207
+ function maybeWrapTrusted(html: string): string {
208
+ let trustedTypes = (window as any).trustedTypes
209
+ if (!trustedTypes) return html
210
+ // With the require-trusted-types-for CSP, Chrome will block
211
+ // innerHTML, even on a detached document. This wraps the string in
212
+ // a way that makes the browser allow us to use its parser again.
213
+ return trustedTypes.createPolicy("detachedDocument", {createHTML: (s: string) => s}).createHTML(html)
214
+ }
215
+
207
216
  function readHTML(html: string) {
208
217
  let metas = /^(\s*<meta [^>]*>)*/.exec(html)
209
218
  if (metas) html = html.slice(metas[0].length)
@@ -211,7 +220,7 @@ function readHTML(html: string) {
211
220
  let firstTag = /<([a-z][^>\s]+)/i.exec(html), wrap
212
221
  if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])
213
222
  html = wrap.map(n => "<" + n + ">").join("") + html + wrap.map(n => "</" + n + ">").reverse().join("")
214
- elt.innerHTML = html
223
+ elt.innerHTML = maybeWrapTrusted(html)
215
224
  if (wrap) for (let i = 0; i < wrap.length; i++) elt = elt.querySelector(wrap[i]) || elt
216
225
  return elt
217
226
  }
@@ -163,14 +163,17 @@ export class DOMObserver {
163
163
  return this.queue
164
164
  }
165
165
 
166
+ selectionChanged(sel: DOMSelectionRange) {
167
+ return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel)
168
+ }
169
+
166
170
  flush() {
167
171
  let {view} = this
168
172
  if (!view.docView || this.flushingSoon > -1) return
169
173
  let mutations = this.pendingRecords()
170
174
  if (mutations.length) this.queue = []
171
175
 
172
- let sel = view.domSelectionRange()
173
- let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel)
176
+ let sel = view.domSelectionRange(), newSel = this.selectionChanged(sel)
174
177
 
175
178
  let from = -1, to = -1, typeOver = false, added: Node[] = []
176
179
  if (view.editable) {
package/src/input.ts CHANGED
@@ -112,7 +112,9 @@ editHandlers.keydown = (view: EditorView, _event: Event) => {
112
112
  // to be part of a confused sequence of composition events fired,
113
113
  // and handling them eagerly tends to corrupt the input.
114
114
  if (browser.android && browser.chrome && event.keyCode == 13) return
115
- if (event.keyCode != 229) view.domObserver.forceFlush()
115
+
116
+ if (view.domObserver.selectionChanged(view.domSelectionRange())) view.domObserver.flush()
117
+ else if (event.keyCode != 229) view.domObserver.forceFlush()
116
118
 
117
119
  // On iOS, if we preventDefault enter key presses, the virtual
118
120
  // keyboard gets confused. So the hack here is to set a flag that