prosemirror-view 1.40.1 → 1.41.1
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 +20 -0
- package/dist/index.cjs +19 -15
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -17
- package/package.json +1 -1
- package/src/clipboard.ts +7 -3
- package/src/index.ts +3 -2
- package/src/input.ts +2 -2
- package/src/selection.ts +3 -6
- package/src/viewdesc.ts +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 1.41.1 (2025-09-19)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Consistently set `draggable` on a node's inner DOM representation, not a decoration wrapper element.
|
|
6
|
+
|
|
7
|
+
## 1.41.0 (2025-09-06)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Make sure `transformPasted` is properly called when pasting into a code block.
|
|
12
|
+
|
|
13
|
+
Fix an issue where the editor didn't properly set the DOM selection in a shadow DOM on Safari in some situations.
|
|
14
|
+
|
|
15
|
+
Work around a Safari issue that broke composition right after changing the set of active marks.
|
|
16
|
+
|
|
17
|
+
### New features
|
|
18
|
+
|
|
19
|
+
Pass an argument to `transformPasted` that tells the handler whether the paste is plain text. Call transformPasted when pasting into a code block
|
|
20
|
+
|
|
1
21
|
## 1.40.1 (2025-07-18)
|
|
2
22
|
|
|
3
23
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -998,7 +998,7 @@ var ViewDesc = function () {
|
|
|
998
998
|
}
|
|
999
999
|
if (!(force || brKludge && safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset)) return;
|
|
1000
1000
|
var domSelExtended = false;
|
|
1001
|
-
if ((domSel.extend || anchor == head) && !brKludge) {
|
|
1001
|
+
if ((domSel.extend || anchor == head) && !(brKludge && gecko)) {
|
|
1002
1002
|
domSel.collapse(anchorDOM.node, anchorDOM.offset);
|
|
1003
1003
|
try {
|
|
1004
1004
|
if (anchor != head) domSel.extend(headDOM.node, headDOM.offset);
|
|
@@ -1427,15 +1427,17 @@ var NodeViewDesc = function (_ViewDesc4) {
|
|
|
1427
1427
|
}, {
|
|
1428
1428
|
key: "selectNode",
|
|
1429
1429
|
value: function selectNode() {
|
|
1430
|
-
if (this.nodeDOM.nodeType == 1)
|
|
1431
|
-
|
|
1430
|
+
if (this.nodeDOM.nodeType == 1) {
|
|
1431
|
+
this.nodeDOM.classList.add("ProseMirror-selectednode");
|
|
1432
|
+
if (this.contentDOM || !this.node.type.spec.draggable) this.nodeDOM.draggable = true;
|
|
1433
|
+
}
|
|
1432
1434
|
}
|
|
1433
1435
|
}, {
|
|
1434
1436
|
key: "deselectNode",
|
|
1435
1437
|
value: function deselectNode() {
|
|
1436
1438
|
if (this.nodeDOM.nodeType == 1) {
|
|
1437
1439
|
this.nodeDOM.classList.remove("ProseMirror-selectednode");
|
|
1438
|
-
if (this.contentDOM || !this.node.type.spec.draggable) this.
|
|
1440
|
+
if (this.contentDOM || !this.node.type.spec.draggable) this.nodeDOM.removeAttribute("draggable");
|
|
1439
1441
|
}
|
|
1440
1442
|
}
|
|
1441
1443
|
}, {
|
|
@@ -2271,15 +2273,11 @@ function removeClassOnSelectionChange(view) {
|
|
|
2271
2273
|
});
|
|
2272
2274
|
}
|
|
2273
2275
|
function selectCursorWrapper(view) {
|
|
2274
|
-
var domSel = view.domSelection()
|
|
2275
|
-
range = document.createRange();
|
|
2276
|
+
var domSel = view.domSelection();
|
|
2276
2277
|
if (!domSel) return;
|
|
2277
2278
|
var node = view.cursorWrapper.dom,
|
|
2278
2279
|
img = node.nodeName == "IMG";
|
|
2279
|
-
if (img)
|
|
2280
|
-
range.collapse(true);
|
|
2281
|
-
domSel.removeAllRanges();
|
|
2282
|
-
domSel.addRange(range);
|
|
2280
|
+
if (img) domSel.collapse(node.parentNode, domIndex(node) + 1);else domSel.collapse(node, 0);
|
|
2283
2281
|
if (!img && !view.state.selection.visible && ie && ie_version <= 11) {
|
|
2284
2282
|
node.disabled = true;
|
|
2285
2283
|
node.disabled = false;
|
|
@@ -2677,12 +2675,18 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2677
2675
|
var inCode = $context.parent.type.spec.code;
|
|
2678
2676
|
var dom, slice;
|
|
2679
2677
|
if (!html && !text) return null;
|
|
2680
|
-
var asText = text && (plainText || inCode || !html);
|
|
2678
|
+
var asText = !!text && (plainText || inCode || !html);
|
|
2681
2679
|
if (asText) {
|
|
2682
2680
|
view.someProp("transformPastedText", function (f) {
|
|
2683
2681
|
text = f(text, inCode || plainText, view);
|
|
2684
2682
|
});
|
|
2685
|
-
if (inCode)
|
|
2683
|
+
if (inCode) {
|
|
2684
|
+
slice = new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0);
|
|
2685
|
+
view.someProp("transformPasted", function (f) {
|
|
2686
|
+
slice = f(slice, view, true);
|
|
2687
|
+
});
|
|
2688
|
+
return slice;
|
|
2689
|
+
}
|
|
2686
2690
|
var parsed = view.someProp("clipboardTextParser", function (f) {
|
|
2687
2691
|
return f(text, $context, plainText, view);
|
|
2688
2692
|
});
|
|
@@ -2739,7 +2743,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2739
2743
|
}
|
|
2740
2744
|
}
|
|
2741
2745
|
view.someProp("transformPasted", function (f) {
|
|
2742
|
-
slice = f(slice, view);
|
|
2746
|
+
slice = f(slice, view, asText);
|
|
2743
2747
|
});
|
|
2744
2748
|
return slice;
|
|
2745
2749
|
}
|
|
@@ -3169,7 +3173,7 @@ var MouseDown = function () {
|
|
|
3169
3173
|
}
|
|
3170
3174
|
var target = flushed ? null : event.target;
|
|
3171
3175
|
var targetDesc = target ? view.docView.nearestDesc(target, true) : null;
|
|
3172
|
-
this.target = targetDesc && targetDesc.
|
|
3176
|
+
this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
|
|
3173
3177
|
var selection = view.state.selection;
|
|
3174
3178
|
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 = {
|
|
3175
3179
|
node: targetNode,
|
|
@@ -3492,7 +3496,7 @@ editHandlers.drop = function (view, _event) {
|
|
|
3492
3496
|
var slice = dragging && dragging.slice;
|
|
3493
3497
|
if (slice) {
|
|
3494
3498
|
view.someProp("transformPasted", function (f) {
|
|
3495
|
-
slice = f(slice, view);
|
|
3499
|
+
slice = f(slice, view, false);
|
|
3496
3500
|
});
|
|
3497
3501
|
} else {
|
|
3498
3502
|
slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
|
package/dist/index.d.cts
CHANGED
|
@@ -757,9 +757,10 @@ interface EditorProps<P = any> {
|
|
|
757
757
|
clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
|
|
758
758
|
/**
|
|
759
759
|
Can be used to transform pasted or dragged-and-dropped content
|
|
760
|
-
before it is applied to the document.
|
|
760
|
+
before it is applied to the document. The `plain` flag will be
|
|
761
|
+
true when the text is pasted as plain text.
|
|
761
762
|
*/
|
|
762
|
-
transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
|
|
763
|
+
transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice;
|
|
763
764
|
/**
|
|
764
765
|
Can be used to transform copied or cut content before it is
|
|
765
766
|
serialized to the clipboard.
|
package/dist/index.d.ts
CHANGED
|
@@ -757,9 +757,10 @@ interface EditorProps<P = any> {
|
|
|
757
757
|
clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
|
|
758
758
|
/**
|
|
759
759
|
Can be used to transform pasted or dragged-and-dropped content
|
|
760
|
-
before it is applied to the document.
|
|
760
|
+
before it is applied to the document. The `plain` flag will be
|
|
761
|
+
true when the text is pasted as plain text.
|
|
761
762
|
*/
|
|
762
|
-
transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
|
|
763
|
+
transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice;
|
|
763
764
|
/**
|
|
764
765
|
Can be used to transform copied or cut content before it is
|
|
765
766
|
serialized to the clipboard.
|
package/dist/index.js
CHANGED
|
@@ -1072,7 +1072,7 @@ class ViewDesc {
|
|
|
1072
1072
|
// (one where the focus is before the anchor), but not all
|
|
1073
1073
|
// browsers support it yet.
|
|
1074
1074
|
let domSelExtended = false;
|
|
1075
|
-
if ((domSel.extend || anchor == head) && !brKludge) {
|
|
1075
|
+
if ((domSel.extend || anchor == head) && !(brKludge && gecko)) {
|
|
1076
1076
|
domSel.collapse(anchorDOM.node, anchorDOM.offset);
|
|
1077
1077
|
try {
|
|
1078
1078
|
if (anchor != head)
|
|
@@ -1484,17 +1484,18 @@ class NodeViewDesc extends ViewDesc {
|
|
|
1484
1484
|
}
|
|
1485
1485
|
// Mark this node as being the selected node.
|
|
1486
1486
|
selectNode() {
|
|
1487
|
-
if (this.nodeDOM.nodeType == 1)
|
|
1487
|
+
if (this.nodeDOM.nodeType == 1) {
|
|
1488
1488
|
this.nodeDOM.classList.add("ProseMirror-selectednode");
|
|
1489
|
-
|
|
1490
|
-
|
|
1489
|
+
if (this.contentDOM || !this.node.type.spec.draggable)
|
|
1490
|
+
this.nodeDOM.draggable = true;
|
|
1491
|
+
}
|
|
1491
1492
|
}
|
|
1492
1493
|
// Remove selected node marking from this node.
|
|
1493
1494
|
deselectNode() {
|
|
1494
1495
|
if (this.nodeDOM.nodeType == 1) {
|
|
1495
1496
|
this.nodeDOM.classList.remove("ProseMirror-selectednode");
|
|
1496
1497
|
if (this.contentDOM || !this.node.type.spec.draggable)
|
|
1497
|
-
this.
|
|
1498
|
+
this.nodeDOM.removeAttribute("draggable");
|
|
1498
1499
|
}
|
|
1499
1500
|
}
|
|
1500
1501
|
get domAtom() { return this.node.isAtom; }
|
|
@@ -2333,17 +2334,14 @@ function removeClassOnSelectionChange(view) {
|
|
|
2333
2334
|
});
|
|
2334
2335
|
}
|
|
2335
2336
|
function selectCursorWrapper(view) {
|
|
2336
|
-
let domSel = view.domSelection()
|
|
2337
|
+
let domSel = view.domSelection();
|
|
2337
2338
|
if (!domSel)
|
|
2338
2339
|
return;
|
|
2339
2340
|
let node = view.cursorWrapper.dom, img = node.nodeName == "IMG";
|
|
2340
2341
|
if (img)
|
|
2341
|
-
|
|
2342
|
+
domSel.collapse(node.parentNode, domIndex(node) + 1);
|
|
2342
2343
|
else
|
|
2343
|
-
|
|
2344
|
-
range.collapse(true);
|
|
2345
|
-
domSel.removeAllRanges();
|
|
2346
|
-
domSel.addRange(range);
|
|
2344
|
+
domSel.collapse(node, 0);
|
|
2347
2345
|
// Kludge to kill 'control selection' in IE11 when selecting an
|
|
2348
2346
|
// invisible cursor wrapper, since that would result in those weird
|
|
2349
2347
|
// resize handles and a selection that considers the absolutely
|
|
@@ -2821,11 +2819,14 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2821
2819
|
let dom, slice;
|
|
2822
2820
|
if (!html && !text)
|
|
2823
2821
|
return null;
|
|
2824
|
-
let asText = text && (plainText || inCode || !html);
|
|
2822
|
+
let asText = !!text && (plainText || inCode || !html);
|
|
2825
2823
|
if (asText) {
|
|
2826
2824
|
view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view); });
|
|
2827
|
-
if (inCode)
|
|
2828
|
-
|
|
2825
|
+
if (inCode) {
|
|
2826
|
+
slice = new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0);
|
|
2827
|
+
view.someProp("transformPasted", f => { slice = f(slice, view, true); });
|
|
2828
|
+
return slice;
|
|
2829
|
+
}
|
|
2829
2830
|
let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view));
|
|
2830
2831
|
if (parsed) {
|
|
2831
2832
|
slice = parsed;
|
|
@@ -2883,7 +2884,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2883
2884
|
slice = closeSlice(slice, openStart, openEnd);
|
|
2884
2885
|
}
|
|
2885
2886
|
}
|
|
2886
|
-
view.someProp("transformPasted", f => { slice = f(slice, view); });
|
|
2887
|
+
view.someProp("transformPasted", f => { slice = f(slice, view, asText); });
|
|
2887
2888
|
return slice;
|
|
2888
2889
|
}
|
|
2889
2890
|
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;
|
|
@@ -3346,7 +3347,7 @@ class MouseDown {
|
|
|
3346
3347
|
}
|
|
3347
3348
|
const target = flushed ? null : event.target;
|
|
3348
3349
|
const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
|
|
3349
|
-
this.target = targetDesc && targetDesc.
|
|
3350
|
+
this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
|
|
3350
3351
|
let { selection } = view.state;
|
|
3351
3352
|
if (event.button == 0 &&
|
|
3352
3353
|
targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
|
|
@@ -3743,7 +3744,7 @@ editHandlers.drop = (view, _event) => {
|
|
|
3743
3744
|
let $mouse = view.state.doc.resolve(eventPos.pos);
|
|
3744
3745
|
let slice = dragging && dragging.slice;
|
|
3745
3746
|
if (slice) {
|
|
3746
|
-
view.someProp("transformPasted", f => { slice = f(slice, view); });
|
|
3747
|
+
view.someProp("transformPasted", f => { slice = f(slice, view, false); });
|
|
3747
3748
|
}
|
|
3748
3749
|
else {
|
|
3749
3750
|
slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
|
package/package.json
CHANGED
package/src/clipboard.ts
CHANGED
|
@@ -44,10 +44,14 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
|
|
|
44
44
|
let inCode = $context.parent.type.spec.code
|
|
45
45
|
let dom: HTMLElement | undefined, slice: Slice | undefined
|
|
46
46
|
if (!html && !text) return null
|
|
47
|
-
let asText = text && (plainText || inCode || !html)
|
|
47
|
+
let asText = !!text && (plainText || inCode || !html)
|
|
48
48
|
if (asText) {
|
|
49
49
|
view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view) })
|
|
50
|
-
if (inCode)
|
|
50
|
+
if (inCode) {
|
|
51
|
+
slice = new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0)
|
|
52
|
+
view.someProp("transformPasted", f => { slice = f(slice!, view, true) })
|
|
53
|
+
return slice
|
|
54
|
+
}
|
|
51
55
|
let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view))
|
|
52
56
|
if (parsed) {
|
|
53
57
|
slice = parsed
|
|
@@ -101,7 +105,7 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
view.someProp("transformPasted", f => { slice = f(slice!, view) })
|
|
108
|
+
view.someProp("transformPasted", f => { slice = f(slice!, view, asText) })
|
|
105
109
|
return slice
|
|
106
110
|
}
|
|
107
111
|
|
package/src/index.ts
CHANGED
|
@@ -714,8 +714,9 @@ export interface EditorProps<P = any> {
|
|
|
714
714
|
clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice
|
|
715
715
|
|
|
716
716
|
/// Can be used to transform pasted or dragged-and-dropped content
|
|
717
|
-
/// before it is applied to the document.
|
|
718
|
-
|
|
717
|
+
/// before it is applied to the document. The `plain` flag will be
|
|
718
|
+
/// true when the text is pasted as plain text.
|
|
719
|
+
transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice
|
|
719
720
|
|
|
720
721
|
/// Can be used to transform copied or cut content before it is
|
|
721
722
|
/// serialized to the clipboard.
|
package/src/input.ts
CHANGED
|
@@ -329,7 +329,7 @@ class MouseDown {
|
|
|
329
329
|
|
|
330
330
|
const target = flushed ? null : event.target as HTMLElement
|
|
331
331
|
const targetDesc = target ? view.docView.nearestDesc(target, true) : null
|
|
332
|
-
this.target = targetDesc && targetDesc.
|
|
332
|
+
this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM as HTMLElement : null
|
|
333
333
|
|
|
334
334
|
let {selection} = view.state
|
|
335
335
|
if (event.button == 0 &&
|
|
@@ -718,7 +718,7 @@ editHandlers.drop = (view, _event) => {
|
|
|
718
718
|
let $mouse = view.state.doc.resolve(eventPos.pos)
|
|
719
719
|
let slice = dragging && dragging.slice
|
|
720
720
|
if (slice) {
|
|
721
|
-
view.someProp("transformPasted", f => { slice = f(slice!, view) })
|
|
721
|
+
view.someProp("transformPasted", f => { slice = f(slice!, view, false) })
|
|
722
722
|
} else {
|
|
723
723
|
slice = parseFromClipboard(view, getText(event.dataTransfer),
|
|
724
724
|
brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse)
|
package/src/selection.ts
CHANGED
|
@@ -147,14 +147,11 @@ function removeClassOnSelectionChange(view: EditorView) {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
function selectCursorWrapper(view: EditorView) {
|
|
150
|
-
let domSel = view.domSelection()
|
|
150
|
+
let domSel = view.domSelection()
|
|
151
151
|
if (!domSel) return
|
|
152
152
|
let node = view.cursorWrapper!.dom, img = node.nodeName == "IMG"
|
|
153
|
-
if (img)
|
|
154
|
-
else
|
|
155
|
-
range.collapse(true)
|
|
156
|
-
domSel.removeAllRanges()
|
|
157
|
-
domSel.addRange(range)
|
|
153
|
+
if (img) domSel.collapse(node.parentNode!, domIndex(node) + 1)
|
|
154
|
+
else domSel.collapse(node, 0)
|
|
158
155
|
// Kludge to kill 'control selection' in IE11 when selecting an
|
|
159
156
|
// invisible cursor wrapper, since that would result in those weird
|
|
160
157
|
// resize handles and a selection that considers the absolutely
|
package/src/viewdesc.ts
CHANGED
|
@@ -460,7 +460,7 @@ export class ViewDesc {
|
|
|
460
460
|
// (one where the focus is before the anchor), but not all
|
|
461
461
|
// browsers support it yet.
|
|
462
462
|
let domSelExtended = false
|
|
463
|
-
if ((domSel.extend || anchor == head) && !brKludge) {
|
|
463
|
+
if ((domSel.extend || anchor == head) && !(brKludge && browser.gecko)) {
|
|
464
464
|
domSel.collapse(anchorDOM.node, anchorDOM.offset)
|
|
465
465
|
try {
|
|
466
466
|
if (anchor != head)
|
|
@@ -884,15 +884,17 @@ export class NodeViewDesc extends ViewDesc {
|
|
|
884
884
|
|
|
885
885
|
// Mark this node as being the selected node.
|
|
886
886
|
selectNode() {
|
|
887
|
-
if (this.nodeDOM.nodeType == 1)
|
|
888
|
-
|
|
887
|
+
if (this.nodeDOM.nodeType == 1) {
|
|
888
|
+
;(this.nodeDOM as HTMLElement).classList.add("ProseMirror-selectednode")
|
|
889
|
+
if (this.contentDOM || !this.node.type.spec.draggable) (this.nodeDOM as HTMLElement).draggable = true
|
|
890
|
+
}
|
|
889
891
|
}
|
|
890
892
|
|
|
891
893
|
// Remove selected node marking from this node.
|
|
892
894
|
deselectNode() {
|
|
893
895
|
if (this.nodeDOM.nodeType == 1) {
|
|
894
896
|
;(this.nodeDOM as HTMLElement).classList.remove("ProseMirror-selectednode")
|
|
895
|
-
if (this.contentDOM || !this.node.type.spec.draggable) (this.
|
|
897
|
+
if (this.contentDOM || !this.node.type.spec.draggable) (this.nodeDOM as HTMLElement).removeAttribute("draggable")
|
|
896
898
|
}
|
|
897
899
|
}
|
|
898
900
|
|