prosemirror-view 1.24.0-beta.1 → 1.24.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 +14 -0
- package/dist/index.cjs +30 -27
- package/dist/index.d.ts +24 -16
- package/dist/index.js +17 -16
- package/package.json +1 -1
- package/src/README.md +2 -0
- package/src/capturekeys.ts +4 -4
- package/src/clipboard.ts +9 -8
- package/src/decoration.ts +1 -1
- package/src/dom.ts +2 -2
- package/src/domchange.ts +5 -4
- package/src/index.ts +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 1.24.0 (2022-05-30)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where bogus table wrappers could be added when copy-pasting table content nodes within an editor.
|
|
6
|
+
|
|
7
|
+
Fix a crash that could occur when two textblocks were joined in the editor DOM.
|
|
8
|
+
|
|
9
|
+
Treat ctrl-b/f/p/n on macOS similar to arrow key presses, anticipating cursor motion.
|
|
10
|
+
|
|
11
|
+
### New features
|
|
12
|
+
|
|
13
|
+
Include TypeScript type declarations.
|
|
14
|
+
|
|
1
15
|
## 1.23.13 (2022-04-26)
|
|
2
16
|
|
|
3
17
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1774,9 +1774,10 @@ var CustomNodeViewDesc = function (_NodeViewDesc2) {
|
|
|
1774
1774
|
if (this.dirty == NODE_DIRTY) return false;
|
|
1775
1775
|
|
|
1776
1776
|
if (this.spec.update) {
|
|
1777
|
-
var
|
|
1778
|
-
|
|
1779
|
-
|
|
1777
|
+
var _result = this.spec.update(node, outerDeco, innerDeco);
|
|
1778
|
+
|
|
1779
|
+
if (_result) this.updateInner(node, outerDeco, innerDeco, view);
|
|
1780
|
+
return _result;
|
|
1780
1781
|
} else if (!this.contentDOM && !node.isLeaf) {
|
|
1781
1782
|
return false;
|
|
1782
1783
|
} else {
|
|
@@ -2866,13 +2867,13 @@ function captureKeyDown(view, event) {
|
|
|
2866
2867
|
return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodesRight(view);
|
|
2867
2868
|
} else if (code == 13 || code == 27) {
|
|
2868
2869
|
return true;
|
|
2869
|
-
} else if (code == 37) {
|
|
2870
|
+
} else if (code == 37 || result.mac && code == 66 && mods == "c") {
|
|
2870
2871
|
return selectHorizontally(view, -1, mods) || skipIgnoredNodesLeft(view);
|
|
2871
|
-
} else if (code == 39) {
|
|
2872
|
+
} else if (code == 39 || result.mac && code == 70 && mods == "c") {
|
|
2872
2873
|
return selectHorizontally(view, 1, mods) || skipIgnoredNodesRight(view);
|
|
2873
|
-
} else if (code == 38) {
|
|
2874
|
+
} else if (code == 38 || result.mac && code == 80 && mods == "c") {
|
|
2874
2875
|
return selectVertically(view, -1, mods) || skipIgnoredNodesLeft(view);
|
|
2875
|
-
} else if (code == 40) {
|
|
2876
|
+
} else if (code == 40 || result.mac && code == 78 && mods == "c") {
|
|
2876
2877
|
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodesRight(view);
|
|
2877
2878
|
} else if (mods == (mac ? "m" : "c") && (code == 66 || code == 73 || code == 89 || code == 90)) {
|
|
2878
2879
|
return true;
|
|
@@ -2902,7 +2903,8 @@ function serializeForClipboard(view, slice) {
|
|
|
2902
2903
|
document: doc
|
|
2903
2904
|
}));
|
|
2904
2905
|
var firstChild = wrap.firstChild,
|
|
2905
|
-
needsWrap
|
|
2906
|
+
needsWrap,
|
|
2907
|
+
wrappers = 0;
|
|
2906
2908
|
|
|
2907
2909
|
while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
|
|
2908
2910
|
for (var i = needsWrap.length - 1; i >= 0; i--) {
|
|
@@ -2913,17 +2915,13 @@ function serializeForClipboard(view, slice) {
|
|
|
2913
2915
|
}
|
|
2914
2916
|
|
|
2915
2917
|
wrap.appendChild(wrapper);
|
|
2916
|
-
|
|
2917
|
-
if (needsWrap[i] != "tbody") {
|
|
2918
|
-
openStart++;
|
|
2919
|
-
openEnd++;
|
|
2920
|
-
}
|
|
2918
|
+
wrappers++;
|
|
2921
2919
|
}
|
|
2922
2920
|
|
|
2923
2921
|
firstChild = wrap.firstChild;
|
|
2924
2922
|
}
|
|
2925
2923
|
|
|
2926
|
-
if (firstChild && firstChild.nodeType == 1) firstChild.setAttribute("data-pm-slice", "".concat(openStart, " ").concat(openEnd, " ").concat(JSON.stringify(context)));
|
|
2924
|
+
if (firstChild && firstChild.nodeType == 1) firstChild.setAttribute("data-pm-slice", "".concat(openStart, " ").concat(openEnd).concat(wrappers ? " -".concat(wrappers) : "", " ").concat(JSON.stringify(context)));
|
|
2927
2925
|
var text = view.someProp("clipboardTextSerializer", function (f) {
|
|
2928
2926
|
return f(slice);
|
|
2929
2927
|
}) || slice.content.textBetween(0, slice.content.size, "\n\n");
|
|
@@ -2969,7 +2967,10 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2969
2967
|
}
|
|
2970
2968
|
|
|
2971
2969
|
var contextNode = dom && dom.querySelector("[data-pm-slice]");
|
|
2972
|
-
var sliceData = contextNode && /^(\d+) (\d+) (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
|
|
2970
|
+
var sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
|
|
2971
|
+
if (sliceData && sliceData[3]) for (var i = +sliceData[3]; i > 0 && dom.firstChild; i--) {
|
|
2972
|
+
dom = dom.firstChild;
|
|
2973
|
+
}
|
|
2973
2974
|
|
|
2974
2975
|
if (!slice) {
|
|
2975
2976
|
var parser = view.someProp("clipboardParser") || view.someProp("domParser") || prosemirrorModel.DOMParser.fromSchema(view.state.schema);
|
|
@@ -2986,7 +2987,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2986
2987
|
}
|
|
2987
2988
|
|
|
2988
2989
|
if (sliceData) {
|
|
2989
|
-
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[
|
|
2990
|
+
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[4]);
|
|
2990
2991
|
} else {
|
|
2991
2992
|
slice = prosemirrorModel.Slice.maxOpen(normalizeSiblings(slice.content, $context), true);
|
|
2992
2993
|
|
|
@@ -4330,9 +4331,10 @@ var DecorationGroup = function () {
|
|
|
4330
4331
|
var found = [];
|
|
4331
4332
|
|
|
4332
4333
|
for (var i = 0; i < this.members.length; i++) {
|
|
4333
|
-
var
|
|
4334
|
-
|
|
4335
|
-
if (
|
|
4334
|
+
var _result2 = this.members[i].forChild(offset, child);
|
|
4335
|
+
|
|
4336
|
+
if (_result2 == empty) continue;
|
|
4337
|
+
if (_result2 instanceof DecorationGroup) found = found.concat(_result2.members);else found.push(_result2);
|
|
4336
4338
|
}
|
|
4337
4339
|
|
|
4338
4340
|
return DecorationGroup.from(found);
|
|
@@ -4825,12 +4827,12 @@ var DOMObserver = function () {
|
|
|
4825
4827
|
|
|
4826
4828
|
if (this.view.editable) {
|
|
4827
4829
|
for (var i = 0; i < mutations.length; i++) {
|
|
4828
|
-
var
|
|
4830
|
+
var _result3 = this.registerMutation(mutations[i], added);
|
|
4829
4831
|
|
|
4830
|
-
if (
|
|
4831
|
-
from = from < 0 ?
|
|
4832
|
-
to = to < 0 ?
|
|
4833
|
-
if (
|
|
4832
|
+
if (_result3) {
|
|
4833
|
+
from = from < 0 ? _result3.from : Math.min(_result3.from, from);
|
|
4834
|
+
to = to < 0 ? _result3.to : Math.max(_result3.to, to);
|
|
4835
|
+
if (_result3.typeOver) typeOver = true;
|
|
4834
4836
|
}
|
|
4835
4837
|
}
|
|
4836
4838
|
}
|
|
@@ -5111,7 +5113,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5111
5113
|
|
|
5112
5114
|
var $from = parse.doc.resolveNoCache(change.start - parse.from);
|
|
5113
5115
|
var $to = parse.doc.resolveNoCache(change.endB - parse.from);
|
|
5114
|
-
var
|
|
5116
|
+
var $fromA = doc.resolve(change.start);
|
|
5117
|
+
var inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;
|
|
5115
5118
|
var nextSel;
|
|
5116
5119
|
|
|
5117
5120
|
if ((ios && view.input.lastIOSEnter > Date.now() - 225 && (!inlineChange || addedNodes.some(function (n) {
|
|
@@ -5144,7 +5147,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5144
5147
|
|
|
5145
5148
|
var chFrom = change.start,
|
|
5146
5149
|
chTo = change.endA;
|
|
5147
|
-
var tr, storedMarks, markChange
|
|
5150
|
+
var tr, storedMarks, markChange;
|
|
5148
5151
|
|
|
5149
5152
|
if (inlineChange) {
|
|
5150
5153
|
if ($from.pos == $to.pos) {
|
|
@@ -5157,7 +5160,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5157
5160
|
|
|
5158
5161
|
tr = view.state.tr["delete"](chFrom, chTo);
|
|
5159
5162
|
storedMarks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA));
|
|
5160
|
-
} else if (change.endA == change.endB && (
|
|
5163
|
+
} else if (change.endA == change.endB && (markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))) {
|
|
5161
5164
|
tr = view.state.tr;
|
|
5162
5165
|
if (markChange.type == "add") tr.addMark(chFrom, chTo, markChange.mark);else tr.removeMark(chFrom, chTo, markChange.mark);
|
|
5163
5166
|
} else if ($from.parent.child($from.index()).isText && $from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
|
|
2
|
-
import { Mark, Node
|
|
2
|
+
import { Mark, Node, ParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
|
|
3
3
|
import { Mapping } from 'prosemirror-transform';
|
|
4
4
|
|
|
5
|
-
declare type DOMNode = Node
|
|
5
|
+
declare type DOMNode = InstanceType<typeof window.Node>;
|
|
6
6
|
|
|
7
7
|
declare type WidgetConstructor = ((view: EditorView, getPos: () => number | undefined) => DOMNode) | DOMNode;
|
|
8
8
|
/**
|
|
@@ -147,7 +147,7 @@ interface DecorationSource {
|
|
|
147
147
|
Map the set of decorations in response to a change in the
|
|
148
148
|
document.
|
|
149
149
|
*/
|
|
150
|
-
map: (mapping: Mapping, node: Node
|
|
150
|
+
map: (mapping: Mapping, node: Node) => DecorationSource;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
153
|
A collection of [decorations](https://prosemirror.net/docs/ref/#view.Decoration), organized in such
|
|
@@ -160,7 +160,7 @@ declare class DecorationSet implements DecorationSource {
|
|
|
160
160
|
Create a set of decorations, using the structure of the given
|
|
161
161
|
document.
|
|
162
162
|
*/
|
|
163
|
-
static create(doc: Node
|
|
163
|
+
static create(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
164
164
|
/**
|
|
165
165
|
Find all decorations in this set which touch the given range
|
|
166
166
|
(including decorations that start or end directly at the
|
|
@@ -169,13 +169,13 @@ declare class DecorationSet implements DecorationSource {
|
|
|
169
169
|
considered. When `predicate` isn't given, all decorations are
|
|
170
170
|
assumed to match.
|
|
171
171
|
*/
|
|
172
|
-
find(start?: number, end?: number, predicate?: (spec: any) => boolean):
|
|
172
|
+
find(start?: number, end?: number, predicate?: (spec: any) => boolean): Decoration[];
|
|
173
173
|
private findInner;
|
|
174
174
|
/**
|
|
175
175
|
Map the set of decorations in response to a change in the
|
|
176
176
|
document.
|
|
177
177
|
*/
|
|
178
|
-
map(mapping: Mapping, doc: Node
|
|
178
|
+
map(mapping: Mapping, doc: Node, options?: {
|
|
179
179
|
/**
|
|
180
180
|
When given, this function will be called for each decoration
|
|
181
181
|
that gets dropped as a result of the mapping, passing the
|
|
@@ -188,7 +188,7 @@ declare class DecorationSet implements DecorationSource {
|
|
|
188
188
|
producing a new set. Needs access to the current document to
|
|
189
189
|
create the appropriate tree structure.
|
|
190
190
|
*/
|
|
191
|
-
add(doc: Node
|
|
191
|
+
add(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
192
192
|
private addInner;
|
|
193
193
|
/**
|
|
194
194
|
Create a new set that contains the decorations in this set, minus
|
|
@@ -246,7 +246,7 @@ interface NodeView {
|
|
|
246
246
|
view has a `contentDOM` property (or no `dom` property), updating
|
|
247
247
|
its child nodes will be handled by ProseMirror.
|
|
248
248
|
*/
|
|
249
|
-
update?: (node: Node
|
|
249
|
+
update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean;
|
|
250
250
|
/**
|
|
251
251
|
Can be used to override the way the node's selected status (as a
|
|
252
252
|
node selection) is displayed.
|
|
@@ -294,11 +294,11 @@ declare class ViewDesc {
|
|
|
294
294
|
dom: DOMNode;
|
|
295
295
|
contentDOM: HTMLElement | null;
|
|
296
296
|
dirty: number;
|
|
297
|
-
node: Node
|
|
297
|
+
node: Node | null;
|
|
298
298
|
constructor(parent: ViewDesc | undefined, children: ViewDesc[], dom: DOMNode, contentDOM: HTMLElement | null);
|
|
299
299
|
matchesWidget(widget: Decoration): boolean;
|
|
300
300
|
matchesMark(mark: Mark): boolean;
|
|
301
|
-
matchesNode(node: Node
|
|
301
|
+
matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
|
|
302
302
|
matchesHack(nodeName: string): boolean;
|
|
303
303
|
parseRule(): ParseRule | null;
|
|
304
304
|
stopEvent(event: Event): boolean;
|
|
@@ -536,7 +536,15 @@ declare class EditorView {
|
|
|
536
536
|
*/
|
|
537
537
|
dispatch(tr: Transaction): void;
|
|
538
538
|
}
|
|
539
|
-
declare type NodeViewConstructor = (node: Node
|
|
539
|
+
declare type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number | undefined, decorations: readonly Decoration[], innerDecorations: DecorationSource) => NodeView;
|
|
540
|
+
/**
|
|
541
|
+
Helper type that maps event names to event object types, but
|
|
542
|
+
includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
543
|
+
about.
|
|
544
|
+
*/
|
|
545
|
+
interface DOMEventMap extends HTMLElementEventMap {
|
|
546
|
+
[event: string]: Event;
|
|
547
|
+
}
|
|
540
548
|
/**
|
|
541
549
|
Props are configuration values that can be passed to an editor view
|
|
542
550
|
or included in a plugin. This interface lists the supported props.
|
|
@@ -563,7 +571,7 @@ interface EditorProps {
|
|
|
563
571
|
default behavior).
|
|
564
572
|
*/
|
|
565
573
|
handleDOMEvents?: {
|
|
566
|
-
[event
|
|
574
|
+
[event in string]: (view: EditorView, event: DOMEventMap[event]) => boolean | void;
|
|
567
575
|
};
|
|
568
576
|
/**
|
|
569
577
|
Called when the editor receives a `keydown` event.
|
|
@@ -583,7 +591,7 @@ interface EditorProps {
|
|
|
583
591
|
Called for each node around a click, from the inside out. The
|
|
584
592
|
`direct` flag will be true for the inner node.
|
|
585
593
|
*/
|
|
586
|
-
handleClickOn?: (view: EditorView, pos: number, node: Node
|
|
594
|
+
handleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
587
595
|
/**
|
|
588
596
|
Called when the editor is clicked, after `handleClickOn` handlers
|
|
589
597
|
have been called.
|
|
@@ -592,7 +600,7 @@ interface EditorProps {
|
|
|
592
600
|
/**
|
|
593
601
|
Called for each node around a double click.
|
|
594
602
|
*/
|
|
595
|
-
handleDoubleClickOn?: (view: EditorView, pos: number, node: Node
|
|
603
|
+
handleDoubleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
596
604
|
/**
|
|
597
605
|
Called when the editor is double-clicked, after `handleDoubleClickOn`.
|
|
598
606
|
*/
|
|
@@ -600,7 +608,7 @@ interface EditorProps {
|
|
|
600
608
|
/**
|
|
601
609
|
Called for each node around a triple click.
|
|
602
610
|
*/
|
|
603
|
-
handleTripleClickOn?: (view: EditorView, pos: number, node: Node
|
|
611
|
+
handleTripleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
604
612
|
/**
|
|
605
613
|
Called when the editor is triple-clicked, after `handleTripleClickOn`.
|
|
606
614
|
*/
|
|
@@ -788,4 +796,4 @@ interface DirectEditorProps extends EditorProps {
|
|
|
788
796
|
dispatchTransaction?: (tr: Transaction) => void;
|
|
789
797
|
}
|
|
790
798
|
|
|
791
|
-
export { Decoration, DecorationAttrs, DecorationSet, DecorationSource, DirectEditorProps, EditorProps, EditorView, NodeView };
|
|
799
|
+
export { DOMEventMap, Decoration, DecorationAttrs, DecorationSet, DecorationSource, DirectEditorProps, EditorProps, EditorView, NodeView };
|
package/dist/index.js
CHANGED
|
@@ -2509,16 +2509,16 @@ function captureKeyDown(view, event) {
|
|
|
2509
2509
|
else if (code == 13 || code == 27) { // Enter, Esc
|
|
2510
2510
|
return true;
|
|
2511
2511
|
}
|
|
2512
|
-
else if (code == 37) { // Left arrow
|
|
2512
|
+
else if (code == 37 || (result.mac && code == 66 && mods == "c")) { // Left arrow, Ctrl-b on Mac
|
|
2513
2513
|
return selectHorizontally(view, -1, mods) || skipIgnoredNodesLeft(view);
|
|
2514
2514
|
}
|
|
2515
|
-
else if (code == 39) { // Right arrow
|
|
2515
|
+
else if (code == 39 || (result.mac && code == 70 && mods == "c")) { // Right arrow, Ctrl-f on Mac
|
|
2516
2516
|
return selectHorizontally(view, 1, mods) || skipIgnoredNodesRight(view);
|
|
2517
2517
|
}
|
|
2518
|
-
else if (code == 38) { // Up arrow
|
|
2518
|
+
else if (code == 38 || (result.mac && code == 80 && mods == "c")) { // Up arrow, Ctrl-p on Mac
|
|
2519
2519
|
return selectVertically(view, -1, mods) || skipIgnoredNodesLeft(view);
|
|
2520
2520
|
}
|
|
2521
|
-
else if (code == 40) { // Down arrow
|
|
2521
|
+
else if (code == 40 || (result.mac && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac
|
|
2522
2522
|
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodesRight(view);
|
|
2523
2523
|
}
|
|
2524
2524
|
else if (mods == (mac ? "m" : "c") &&
|
|
@@ -2540,22 +2540,19 @@ function serializeForClipboard(view, slice) {
|
|
|
2540
2540
|
let serializer = view.someProp("clipboardSerializer") || DOMSerializer.fromSchema(view.state.schema);
|
|
2541
2541
|
let doc = detachedDoc(), wrap = doc.createElement("div");
|
|
2542
2542
|
wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
|
|
2543
|
-
let firstChild = wrap.firstChild, needsWrap;
|
|
2543
|
+
let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
|
|
2544
2544
|
while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
|
|
2545
2545
|
for (let i = needsWrap.length - 1; i >= 0; i--) {
|
|
2546
2546
|
let wrapper = doc.createElement(needsWrap[i]);
|
|
2547
2547
|
while (wrap.firstChild)
|
|
2548
2548
|
wrapper.appendChild(wrap.firstChild);
|
|
2549
2549
|
wrap.appendChild(wrapper);
|
|
2550
|
-
|
|
2551
|
-
openStart++;
|
|
2552
|
-
openEnd++;
|
|
2553
|
-
}
|
|
2550
|
+
wrappers++;
|
|
2554
2551
|
}
|
|
2555
2552
|
firstChild = wrap.firstChild;
|
|
2556
2553
|
}
|
|
2557
2554
|
if (firstChild && firstChild.nodeType == 1)
|
|
2558
|
-
firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd} ${JSON.stringify(context)}`);
|
|
2555
|
+
firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
|
|
2559
2556
|
let text = view.someProp("clipboardTextSerializer", f => f(slice)) ||
|
|
2560
2557
|
slice.content.textBetween(0, slice.content.size, "\n\n");
|
|
2561
2558
|
return { dom: wrap, text };
|
|
@@ -2593,7 +2590,10 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2593
2590
|
restoreReplacedSpaces(dom);
|
|
2594
2591
|
}
|
|
2595
2592
|
let contextNode = dom && dom.querySelector("[data-pm-slice]");
|
|
2596
|
-
let sliceData = contextNode && /^(\d+) (\d+) (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
|
|
2593
|
+
let sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "");
|
|
2594
|
+
if (sliceData && sliceData[3])
|
|
2595
|
+
for (let i = +sliceData[3]; i > 0 && dom.firstChild; i--)
|
|
2596
|
+
dom = dom.firstChild;
|
|
2597
2597
|
if (!slice) {
|
|
2598
2598
|
let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
|
|
2599
2599
|
slice = parser.parseSlice(dom, {
|
|
@@ -2608,7 +2608,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
|
|
|
2608
2608
|
});
|
|
2609
2609
|
}
|
|
2610
2610
|
if (sliceData) {
|
|
2611
|
-
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[
|
|
2611
|
+
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[4]);
|
|
2612
2612
|
}
|
|
2613
2613
|
else { // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent
|
|
2614
2614
|
slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), true);
|
|
@@ -4566,7 +4566,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4566
4566
|
}
|
|
4567
4567
|
let $from = parse.doc.resolveNoCache(change.start - parse.from);
|
|
4568
4568
|
let $to = parse.doc.resolveNoCache(change.endB - parse.from);
|
|
4569
|
-
let
|
|
4569
|
+
let $fromA = doc.resolve(change.start);
|
|
4570
|
+
let inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;
|
|
4570
4571
|
let nextSel;
|
|
4571
4572
|
// If this looks like the effect of pressing Enter (or was recorded
|
|
4572
4573
|
// as being an iOS enter press), just dispatch an Enter key instead.
|
|
@@ -4609,7 +4610,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4609
4610
|
}, 20);
|
|
4610
4611
|
}
|
|
4611
4612
|
let chFrom = change.start, chTo = change.endA;
|
|
4612
|
-
let tr, storedMarks, markChange
|
|
4613
|
+
let tr, storedMarks, markChange;
|
|
4613
4614
|
if (inlineChange) {
|
|
4614
4615
|
if ($from.pos == $to.pos) { // Deletion
|
|
4615
4616
|
// IE11 sometimes weirdly moves the DOM selection around after
|
|
@@ -4622,8 +4623,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4622
4623
|
storedMarks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA));
|
|
4623
4624
|
}
|
|
4624
4625
|
else if ( // Adding or removing a mark
|
|
4625
|
-
change.endA == change.endB &&
|
|
4626
|
-
(markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $
|
|
4626
|
+
change.endA == change.endB &&
|
|
4627
|
+
(markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))) {
|
|
4627
4628
|
tr = view.state.tr;
|
|
4628
4629
|
if (markChange.type == "add")
|
|
4629
4630
|
tr.addMark(chFrom, chTo, markChange.mark);
|
package/package.json
CHANGED
package/src/README.md
CHANGED
package/src/capturekeys.ts
CHANGED
|
@@ -256,13 +256,13 @@ export function captureKeyDown(view: EditorView, event: KeyboardEvent) {
|
|
|
256
256
|
return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodesRight(view)
|
|
257
257
|
} else if (code == 13 || code == 27) { // Enter, Esc
|
|
258
258
|
return true
|
|
259
|
-
} else if (code == 37) { // Left arrow
|
|
259
|
+
} else if (code == 37 || (result.mac && code == 66 && mods == "c")) { // Left arrow, Ctrl-b on Mac
|
|
260
260
|
return selectHorizontally(view, -1, mods) || skipIgnoredNodesLeft(view)
|
|
261
|
-
} else if (code == 39) { // Right arrow
|
|
261
|
+
} else if (code == 39 || (result.mac && code == 70 && mods == "c")) { // Right arrow, Ctrl-f on Mac
|
|
262
262
|
return selectHorizontally(view, 1, mods) || skipIgnoredNodesRight(view)
|
|
263
|
-
} else if (code == 38) { // Up arrow
|
|
263
|
+
} else if (code == 38 || (result.mac && code == 80 && mods == "c")) { // Up arrow, Ctrl-p on Mac
|
|
264
264
|
return selectVertically(view, -1, mods) || skipIgnoredNodesLeft(view)
|
|
265
|
-
} else if (code == 40) { // Down arrow
|
|
265
|
+
} else if (code == 40 || (result.mac && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac
|
|
266
266
|
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodesRight(view)
|
|
267
267
|
} else if (mods == (browser.mac ? "m" : "c") &&
|
|
268
268
|
(code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
|
package/src/clipboard.ts
CHANGED
|
@@ -16,22 +16,20 @@ export function serializeForClipboard(view: EditorView, slice: Slice) {
|
|
|
16
16
|
let doc = detachedDoc(), wrap = doc.createElement("div")
|
|
17
17
|
wrap.appendChild(serializer.serializeFragment(content, {document: doc}))
|
|
18
18
|
|
|
19
|
-
let firstChild = wrap.firstChild, needsWrap
|
|
19
|
+
let firstChild = wrap.firstChild, needsWrap, wrappers = 0
|
|
20
20
|
while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
|
|
21
21
|
for (let i = needsWrap.length - 1; i >= 0; i--) {
|
|
22
22
|
let wrapper = doc.createElement(needsWrap[i])
|
|
23
23
|
while (wrap.firstChild) wrapper.appendChild(wrap.firstChild)
|
|
24
24
|
wrap.appendChild(wrapper)
|
|
25
|
-
|
|
26
|
-
openStart++
|
|
27
|
-
openEnd++
|
|
28
|
-
}
|
|
25
|
+
wrappers++
|
|
29
26
|
}
|
|
30
27
|
firstChild = wrap.firstChild
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
if (firstChild && firstChild.nodeType == 1)
|
|
34
|
-
(firstChild as HTMLElement).setAttribute(
|
|
31
|
+
(firstChild as HTMLElement).setAttribute(
|
|
32
|
+
"data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`)
|
|
35
33
|
|
|
36
34
|
let text = view.someProp("clipboardTextSerializer", f => f(slice)) ||
|
|
37
35
|
slice.content.textBetween(0, slice.content.size, "\n\n")
|
|
@@ -67,7 +65,10 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
|
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
let contextNode = dom && dom.querySelector("[data-pm-slice]")
|
|
70
|
-
let sliceData = contextNode && /^(\d+) (\d+) (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "")
|
|
68
|
+
let sliceData = contextNode && /^(\d+) (\d+)(?: -(\d+))? (.*)/.exec(contextNode.getAttribute("data-pm-slice") || "")
|
|
69
|
+
if (sliceData && sliceData[3]) for (let i = +sliceData[3]; i > 0 && dom!.firstChild; i--)
|
|
70
|
+
dom = dom!.firstChild as HTMLElement
|
|
71
|
+
|
|
71
72
|
if (!slice) {
|
|
72
73
|
let parser = view.someProp("clipboardParser") || view.someProp("domParser") || DOMParser.fromSchema(view.state.schema)
|
|
73
74
|
slice = parser.parseSlice(dom!, {
|
|
@@ -81,7 +82,7 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
|
|
|
81
82
|
})
|
|
82
83
|
}
|
|
83
84
|
if (sliceData) {
|
|
84
|
-
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[
|
|
85
|
+
slice = addContext(closeSlice(slice, +sliceData[1], +sliceData[2]), sliceData[4])
|
|
85
86
|
} else { // HTML wasn't created by ProseMirror. Make sure top-level siblings are coherent
|
|
86
87
|
slice = Slice.maxOpen(normalizeSiblings(slice.content, $context), true)
|
|
87
88
|
if (slice.openStart || slice.openEnd) {
|
package/src/decoration.ts
CHANGED
|
@@ -283,7 +283,7 @@ export class DecorationSet implements DecorationSource {
|
|
|
283
283
|
/// `start` and `end` are omitted, all decorations in the set are
|
|
284
284
|
/// considered. When `predicate` isn't given, all decorations are
|
|
285
285
|
/// assumed to match.
|
|
286
|
-
find(start?: number, end?: number, predicate?: (spec: any) => boolean):
|
|
286
|
+
find(start?: number, end?: number, predicate?: (spec: any) => boolean): Decoration[] {
|
|
287
287
|
let result: Decoration[] = []
|
|
288
288
|
this.findInner(start == null ? 0 : start, end == null ? 1e9 : end, result, 0, predicate)
|
|
289
289
|
return result
|
package/src/dom.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as browser from "./browser"
|
|
2
2
|
|
|
3
|
-
export type DOMNode = Node
|
|
4
|
-
export type DOMSelection = Selection
|
|
3
|
+
export type DOMNode = InstanceType<typeof window.Node>
|
|
4
|
+
export type DOMSelection = InstanceType<typeof window.Selection>
|
|
5
5
|
|
|
6
6
|
export const domIndex = function(node: Node) {
|
|
7
7
|
for (var index = 0;; index++) {
|
package/src/domchange.ts
CHANGED
|
@@ -167,7 +167,8 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
167
167
|
|
|
168
168
|
let $from = parse.doc.resolveNoCache(change.start - parse.from)
|
|
169
169
|
let $to = parse.doc.resolveNoCache(change.endB - parse.from)
|
|
170
|
-
let
|
|
170
|
+
let $fromA = doc.resolve(change.start)
|
|
171
|
+
let inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA
|
|
171
172
|
let nextSel
|
|
172
173
|
// If this looks like the effect of pressing Enter (or was recorded
|
|
173
174
|
// as being an iOS enter press), just dispatch an Enter key instead.
|
|
@@ -213,7 +214,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
213
214
|
|
|
214
215
|
let chFrom = change.start, chTo = change.endA
|
|
215
216
|
|
|
216
|
-
let tr, storedMarks, markChange
|
|
217
|
+
let tr, storedMarks, markChange
|
|
217
218
|
if (inlineChange) {
|
|
218
219
|
if ($from.pos == $to.pos) { // Deletion
|
|
219
220
|
// IE11 sometimes weirdly moves the DOM selection around after
|
|
@@ -225,9 +226,9 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
225
226
|
tr = view.state.tr.delete(chFrom, chTo)
|
|
226
227
|
storedMarks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA))
|
|
227
228
|
} else if ( // Adding or removing a mark
|
|
228
|
-
change.endA == change.endB &&
|
|
229
|
+
change.endA == change.endB &&
|
|
229
230
|
(markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset),
|
|
230
|
-
$
|
|
231
|
+
$fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))
|
|
231
232
|
) {
|
|
232
233
|
tr = view.state.tr
|
|
233
234
|
if (markChange.type == "add") tr.addMark(chFrom, chTo, markChange.mark)
|
package/src/index.ts
CHANGED
|
@@ -498,6 +498,13 @@ function checkStateComponent(plugin: Plugin) {
|
|
|
498
498
|
type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number | undefined,
|
|
499
499
|
decorations: readonly Decoration[], innerDecorations: DecorationSource) => NodeView
|
|
500
500
|
|
|
501
|
+
/// Helper type that maps event names to event object types, but
|
|
502
|
+
/// includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
503
|
+
/// about.
|
|
504
|
+
export interface DOMEventMap extends HTMLElementEventMap {
|
|
505
|
+
[event: string]: Event
|
|
506
|
+
}
|
|
507
|
+
|
|
501
508
|
/// Props are configuration values that can be passed to an editor view
|
|
502
509
|
/// or included in a plugin. This interface lists the supported props.
|
|
503
510
|
///
|
|
@@ -519,7 +526,9 @@ export interface EditorProps {
|
|
|
519
526
|
/// from such a function, you are responsible for calling
|
|
520
527
|
/// `preventDefault` yourself (or not, if you want to allow the
|
|
521
528
|
/// default behavior).
|
|
522
|
-
handleDOMEvents?: {
|
|
529
|
+
handleDOMEvents?: {
|
|
530
|
+
[event in string]: (view: EditorView, event: DOMEventMap[event]) => boolean | void
|
|
531
|
+
}
|
|
523
532
|
|
|
524
533
|
/// Called when the editor receives a `keydown` event.
|
|
525
534
|
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean | void
|