prosemirror-view 1.28.3 → 1.29.0

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,15 @@
1
+ ## 1.29.0 (2022-10-12)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where HTML comments added to the clipboard by the OS throw off the clipboard parser.
6
+
7
+ Make sure Chrome Android's native behavior on pressing Enter in an empty nested list item is replaced by the result of the editor's Enter key handler.
8
+
9
+ ### New features
10
+
11
+ The `transformPastedHTML`, `transformPastedText`, `transformPasted`, `transformCopied`, and `clipboardTextSerializer` props are now passed the view instance as last argument.
12
+
1
13
  ## 1.28.3 (2022-10-05)
2
14
 
3
15
  ### Bug fixes
@@ -20,11 +32,11 @@ Fix an issue where the editor would reset its scroll position to the top of the
20
32
 
21
33
  ### Bug fixes
22
34
 
23
- Fix an issue where the editor wouldn't realize it was focused on IE when IE's resize controls are on an element inside the content. Adjust Chrome click-override behavior to only happen for invisible selections
35
+ Fix an issue where the editor wouldn't realize it was focused on IE when IE's resize controls are on an element inside the content.
24
36
 
25
37
  ### New features
26
38
 
27
- The new `transformCopied` prop can be used to transform a copied/cut slice before it is serialized to the clipboard. Adjust doc comment
39
+ The new `transformCopied` prop can be used to transform a copied/cut slice before it is serialized to the clipboard.
28
40
 
29
41
  ## 1.27.2 (2022-08-19)
30
42
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # prosemirror-view
2
2
 
3
- [ [**WEBSITE**](https://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**GITTER**](https://gitter.im/ProseMirror/prosemirror) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md) ]
3
+ [ [**WEBSITE**](https://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md) ]
4
4
 
5
5
  This is a [core module](https://prosemirror.net/docs/ref/#view) of [ProseMirror](https://prosemirror.net).
6
6
  ProseMirror is a well-behaved rich semantic content editor based on
package/dist/index.cjs CHANGED
@@ -2908,7 +2908,7 @@ function captureKeyDown(view, event) {
2908
2908
 
2909
2909
  function serializeForClipboard(view, slice) {
2910
2910
  view.someProp("transformCopied", function (f) {
2911
- slice = f(slice);
2911
+ slice = f(slice, view);
2912
2912
  });
2913
2913
  var context = [],
2914
2914
  _slice = slice,
@@ -2951,7 +2951,7 @@ function serializeForClipboard(view, slice) {
2951
2951
 
2952
2952
  if (firstChild && firstChild.nodeType == 1) firstChild.setAttribute("data-pm-slice", "".concat(openStart, " ").concat(openEnd).concat(wrappers ? " -".concat(wrappers) : "", " ").concat(JSON.stringify(context)));
2953
2953
  var text = view.someProp("clipboardTextSerializer", function (f) {
2954
- return f(slice);
2954
+ return f(slice, view);
2955
2955
  }) || slice.content.textBetween(0, slice.content.size, "\n\n");
2956
2956
  return {
2957
2957
  dom: wrap,
@@ -2967,11 +2967,11 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2967
2967
 
2968
2968
  if (asText) {
2969
2969
  view.someProp("transformPastedText", function (f) {
2970
- text = f(text, inCode || plainText);
2970
+ text = f(text, inCode || plainText, view);
2971
2971
  });
2972
2972
  if (inCode) return text ? new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : prosemirrorModel.Slice.empty;
2973
2973
  var parsed = view.someProp("clipboardTextParser", function (f) {
2974
- return f(text, $context, plainText);
2974
+ return f(text, $context, plainText, view);
2975
2975
  });
2976
2976
 
2977
2977
  if (parsed) {
@@ -2988,7 +2988,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2988
2988
  }
2989
2989
  } else {
2990
2990
  view.someProp("transformPastedHTML", function (f) {
2991
- html = f(html);
2991
+ html = f(html, view);
2992
2992
  });
2993
2993
  dom = readHTML(html);
2994
2994
  if (webkit) restoreReplacedSpaces(dom);
@@ -2996,8 +2996,15 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2996
2996
 
2997
2997
  var contextNode = dom && dom.querySelector("[data-pm-slice]");
2998
2998
  var sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
2999
- if (sliceData && sliceData[3]) for (var i = +sliceData[3]; i > 0 && dom.firstChild; i--) {
3000
- dom = dom.firstChild;
2999
+ if (sliceData && sliceData[3]) for (var i = +sliceData[3]; i > 0; i--) {
3000
+ var child = dom.firstChild;
3001
+
3002
+ while (child && child.nodeType != 1) {
3003
+ child = child.nextSibling;
3004
+ }
3005
+
3006
+ if (!child) break;
3007
+ dom = child;
3001
3008
  }
3002
3009
 
3003
3010
  if (!slice) {
@@ -3032,7 +3039,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
3032
3039
  }
3033
3040
 
3034
3041
  view.someProp("transformPasted", function (f) {
3035
- slice = f(slice);
3042
+ slice = f(slice, view);
3036
3043
  });
3037
3044
  return slice;
3038
3045
  }
@@ -3862,7 +3869,7 @@ editHandlers.drop = function (view, _event) {
3862
3869
 
3863
3870
  if (slice) {
3864
3871
  view.someProp("transformPasted", function (f) {
3865
- slice = f(slice);
3872
+ slice = f(slice, view);
3866
3873
  });
3867
3874
  } else {
3868
3875
  slice = parseFromClipboard(view, event.dataTransfer.getData(brokenClipboardAPI ? "Text" : "text/plain"), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
@@ -5180,7 +5187,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
5180
5187
  var change = findDiff(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide);
5181
5188
 
5182
5189
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) && addedNodes.some(function (n) {
5183
- return n.nodeName == "DIV" || n.nodeName == "P";
5190
+ return n.nodeName == "DIV" || n.nodeName == "P" || n.nodeName == "LI";
5184
5191
  }) && (!change || change.endA >= change.endB) && view.someProp("handleKeyDown", function (f) {
5185
5192
  return f(view, keyEvent(13, "Enter"));
5186
5193
  })) {
package/dist/index.d.ts CHANGED
@@ -673,7 +673,7 @@ interface EditorProps<P = any> {
673
673
  Can be used to transform pasted HTML text, _before_ it is parsed,
674
674
  for example to clean it up.
675
675
  */
676
- transformPastedHTML?: (this: P, html: string) => string;
676
+ transformPastedHTML?: (this: P, html: string, view: EditorView) => string;
677
677
  /**
678
678
  The [parser](https://prosemirror.net/docs/ref/#model.DOMParser) to use when reading content from
679
679
  the clipboard. When not given, the value of the
@@ -684,7 +684,7 @@ interface EditorProps<P = any> {
684
684
  Transform pasted plain text. The `plain` flag will be true when
685
685
  the text is pasted as plain text.
686
686
  */
687
- transformPastedText?: (this: P, text: string, plain: boolean) => string;
687
+ transformPastedText?: (this: P, text: string, plain: boolean, view: EditorView) => string;
688
688
  /**
689
689
  A function to parse text from the clipboard into a document
690
690
  slice. Called after
@@ -694,17 +694,17 @@ interface EditorProps<P = any> {
694
694
  [`clipboardParser`](https://prosemirror.net/docs/ref/#view.EditorProps.clipboardParser) on it.
695
695
  The `plain` flag will be true when the text is pasted as plain text.
696
696
  */
697
- clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean) => Slice;
697
+ clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
698
698
  /**
699
699
  Can be used to transform pasted or dragged-and-dropped content
700
700
  before it is applied to the document.
701
701
  */
702
- transformPasted?: (this: P, slice: Slice) => Slice;
702
+ transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
703
703
  /**
704
704
  Can be used to transform copied or cut content before it is
705
705
  serialized to the clipboard.
706
706
  */
707
- transformCopied?: (this: P, slice: Slice) => Slice;
707
+ transformCopied?: (this: P, slice: Slice, view: EditorView) => Slice;
708
708
  /**
709
709
  Allows you to pass custom rendering and behavior logic for
710
710
  nodes. Should map node names to constructor functions that
@@ -759,7 +759,7 @@ interface EditorProps<P = any> {
759
759
  editor will use [`textBetween`](https://prosemirror.net/docs/ref/#model.Node.textBetween) on the
760
760
  selected range.
761
761
  */
762
- clipboardTextSerializer?: (this: P, content: Slice) => string;
762
+ clipboardTextSerializer?: (this: P, content: Slice, view: EditorView) => string;
763
763
  /**
764
764
  A set of [document decorations](https://prosemirror.net/docs/ref/#view.Decoration) to show in the
765
765
  view.
package/dist/index.js CHANGED
@@ -2540,7 +2540,7 @@ function captureKeyDown(view, event) {
2540
2540
  }
2541
2541
 
2542
2542
  function serializeForClipboard(view, slice) {
2543
- view.someProp("transformCopied", f => { slice = f(slice); });
2543
+ view.someProp("transformCopied", f => { slice = f(slice, view); });
2544
2544
  let context = [], { content, openStart, openEnd } = slice;
2545
2545
  while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
2546
2546
  openStart--;
@@ -2565,7 +2565,7 @@ function serializeForClipboard(view, slice) {
2565
2565
  }
2566
2566
  if (firstChild && firstChild.nodeType == 1)
2567
2567
  firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
2568
- let text = view.someProp("clipboardTextSerializer", f => f(slice)) ||
2568
+ let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
2569
2569
  slice.content.textBetween(0, slice.content.size, "\n\n");
2570
2570
  return { dom: wrap, text };
2571
2571
  }
@@ -2577,10 +2577,10 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2577
2577
  return null;
2578
2578
  let asText = text && (plainText || inCode || !html);
2579
2579
  if (asText) {
2580
- view.someProp("transformPastedText", f => { text = f(text, inCode || plainText); });
2580
+ view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view); });
2581
2581
  if (inCode)
2582
2582
  return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty;
2583
- let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText));
2583
+ let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view));
2584
2584
  if (parsed) {
2585
2585
  slice = parsed;
2586
2586
  }
@@ -2596,7 +2596,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2596
2596
  }
2597
2597
  }
2598
2598
  else {
2599
- view.someProp("transformPastedHTML", f => { html = f(html); });
2599
+ view.someProp("transformPastedHTML", f => { html = f(html, view); });
2600
2600
  dom = readHTML(html);
2601
2601
  if (webkit)
2602
2602
  restoreReplacedSpaces(dom);
@@ -2604,8 +2604,14 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2604
2604
  let contextNode = dom && dom.querySelector("[data-pm-slice]");
2605
2605
  let sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
2606
2606
  if (sliceData && sliceData[3])
2607
- for (let i = +sliceData[3]; i > 0 && dom.firstChild; i--)
2608
- dom = dom.firstChild;
2607
+ for (let i = +sliceData[3]; i > 0; i--) {
2608
+ let child = dom.firstChild;
2609
+ while (child && child.nodeType != 1)
2610
+ child = child.nextSibling;
2611
+ if (!child)
2612
+ break;
2613
+ dom = child;
2614
+ }
2609
2615
  if (!slice) {
2610
2616
  let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
2611
2617
  slice = parser.parseSlice(dom, {
@@ -2631,7 +2637,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2631
2637
  slice = closeSlice(slice, openStart, openEnd);
2632
2638
  }
2633
2639
  }
2634
- view.someProp("transformPasted", f => { slice = f(slice); });
2640
+ view.someProp("transformPasted", f => { slice = f(slice, view); });
2635
2641
  return slice;
2636
2642
  }
2637
2643
  const inlineParents = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;
@@ -3421,7 +3427,7 @@ editHandlers.drop = (view, _event) => {
3421
3427
  let $mouse = view.state.doc.resolve(eventPos.pos);
3422
3428
  let slice = dragging && dragging.slice;
3423
3429
  if (slice) {
3424
- view.someProp("transformPasted", f => { slice = f(slice); });
3430
+ view.someProp("transformPasted", f => { slice = f(slice, view); });
3425
3431
  }
3426
3432
  else {
3427
3433
  slice = parseFromClipboard(view, event.dataTransfer.getData(brokenClipboardAPI ? "Text" : "text/plain"), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
@@ -4593,7 +4599,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
4593
4599
  view.input.lastKeyCode = null;
4594
4600
  let change = findDiff(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide);
4595
4601
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&
4596
- addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P") &&
4602
+ addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P" || n.nodeName == "LI") &&
4597
4603
  (!change || change.endA >= change.endB) &&
4598
4604
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
4599
4605
  view.input.lastIOSEnter = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.28.3",
3
+ "version": "1.29.0",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -3,7 +3,7 @@ import * as browser from "./browser"
3
3
  import {EditorView} from "./index"
4
4
 
5
5
  export function serializeForClipboard(view: EditorView, slice: Slice) {
6
- view.someProp("transformCopied", f => { slice = f(slice!) })
6
+ view.someProp("transformCopied", f => { slice = f(slice!, view) })
7
7
 
8
8
  let context = [], {content, openStart, openEnd} = slice
9
9
  while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild!.childCount == 1) {
@@ -33,7 +33,7 @@ export function serializeForClipboard(view: EditorView, slice: Slice) {
33
33
  (firstChild as HTMLElement).setAttribute(
34
34
  "data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`)
35
35
 
36
- let text = view.someProp("clipboardTextSerializer", f => f(slice)) ||
36
+ let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
37
37
  slice.content.textBetween(0, slice.content.size, "\n\n")
38
38
 
39
39
  return {dom: wrap, text}
@@ -46,9 +46,9 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
46
46
  if (!html && !text) return null
47
47
  let asText = text && (plainText || inCode || !html)
48
48
  if (asText) {
49
- view.someProp("transformPastedText", f => { text = f(text, inCode || plainText) })
49
+ view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view) })
50
50
  if (inCode) return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty
51
- let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText))
51
+ let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view))
52
52
  if (parsed) {
53
53
  slice = parsed
54
54
  } else {
@@ -61,15 +61,19 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
61
61
  })
62
62
  }
63
63
  } else {
64
- view.someProp("transformPastedHTML", f => { html = f(html!) })
64
+ view.someProp("transformPastedHTML", f => { html = f(html!, view) })
65
65
  dom = readHTML(html!)
66
66
  if (browser.webkit) restoreReplacedSpaces(dom)
67
67
  }
68
68
 
69
69
  let contextNode = dom && dom.querySelector("[data-pm-slice]")
70
70
  let sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "")
71
- if (sliceData && sliceData[3]) for (let i = +sliceData[3]; i > 0 && dom!.firstChild; i--)
72
- dom = dom!.firstChild as HTMLElement
71
+ if (sliceData && sliceData[3]) for (let i = +sliceData[3]; i > 0; i--) {
72
+ let child = dom!.firstChild
73
+ while (child && child.nodeType != 1) child = child.nextSibling
74
+ if (!child) break
75
+ dom = child as HTMLElement
76
+ }
73
77
 
74
78
  if (!slice) {
75
79
  let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema)
@@ -97,7 +101,7 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
97
101
  }
98
102
  }
99
103
 
100
- view.someProp("transformPasted", f => { slice = f(slice!) })
104
+ view.someProp("transformPasted", f => { slice = f(slice!, view) })
101
105
  return slice
102
106
  }
103
107
 
package/src/domchange.ts CHANGED
@@ -111,7 +111,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
111
111
 
112
112
  let change = findDiff(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide)
113
113
  if ((browser.ios && view.input.lastIOSEnter > Date.now() - 225 || browser.android) &&
114
- addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P") &&
114
+ addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P" || n.nodeName == "LI") &&
115
115
  (!change || change.endA >= change.endB) &&
116
116
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
117
117
  view.input.lastIOSEnter = 0
package/src/index.ts CHANGED
@@ -638,7 +638,7 @@ export interface EditorProps<P = any> {
638
638
 
639
639
  /// Can be used to transform pasted HTML text, _before_ it is parsed,
640
640
  /// for example to clean it up.
641
- transformPastedHTML?: (this: P, html: string) => string
641
+ transformPastedHTML?: (this: P, html: string, view: EditorView) => string
642
642
 
643
643
  /// The [parser](#model.DOMParser) to use when reading content from
644
644
  /// the clipboard. When not given, the value of the
@@ -647,7 +647,7 @@ export interface EditorProps<P = any> {
647
647
 
648
648
  /// Transform pasted plain text. The `plain` flag will be true when
649
649
  /// the text is pasted as plain text.
650
- transformPastedText?: (this: P, text: string, plain: boolean) => string
650
+ transformPastedText?: (this: P, text: string, plain: boolean, view: EditorView) => string
651
651
 
652
652
  /// A function to parse text from the clipboard into a document
653
653
  /// slice. Called after
@@ -656,15 +656,15 @@ export interface EditorProps<P = any> {
656
656
  /// in `<p>` tags, and call
657
657
  /// [`clipboardParser`](#view.EditorProps.clipboardParser) on it.
658
658
  /// The `plain` flag will be true when the text is pasted as plain text.
659
- clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean) => Slice
659
+ clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice
660
660
 
661
661
  /// Can be used to transform pasted or dragged-and-dropped content
662
662
  /// before it is applied to the document.
663
- transformPasted?: (this: P, slice: Slice) => Slice
663
+ transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice
664
664
 
665
665
  /// Can be used to transform copied or cut content before it is
666
666
  /// serialized to the clipboard.
667
- transformCopied?: (this: P, slice: Slice) => Slice
667
+ transformCopied?: (this: P, slice: Slice, view: EditorView) => Slice
668
668
 
669
669
  /// Allows you to pass custom rendering and behavior logic for
670
670
  /// nodes. Should map node names to constructor functions that
@@ -711,7 +711,7 @@ export interface EditorProps<P = any> {
711
711
  /// selection when copying text to the clipboard. By default, the
712
712
  /// editor will use [`textBetween`](#model.Node.textBetween) on the
713
713
  /// selected range.
714
- clipboardTextSerializer?: (this: P, content: Slice) => string
714
+ clipboardTextSerializer?: (this: P, content: Slice, view: EditorView) => string
715
715
 
716
716
  /// A set of [document decorations](#view.Decoration) to show in the
717
717
  /// view.
package/src/input.ts CHANGED
@@ -666,7 +666,7 @@ editHandlers.drop = (view, _event) => {
666
666
  let $mouse = view.state.doc.resolve(eventPos.pos)
667
667
  let slice = dragging && dragging.slice
668
668
  if (slice) {
669
- view.someProp("transformPasted", f => { slice = f(slice!) })
669
+ view.someProp("transformPasted", f => { slice = f(slice!, view) })
670
670
  } else {
671
671
  slice = parseFromClipboard(view, event.dataTransfer.getData(brokenClipboardAPI ? "Text" : "text/plain"),
672
672
  brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse)