prosemirror-view 1.34.3 → 1.36.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 +16 -0
- package/dist/index.cjs +17 -13
- package/dist/index.d.cts +47 -19
- package/dist/index.d.ts +47 -19
- package/dist/index.js +16 -11
- package/package.json +1 -1
- package/src/README.md +2 -0
- package/src/clipboard.ts +4 -1
- package/src/domobserver.ts +2 -5
- package/src/index.ts +3 -3
- package/src/input.ts +1 -3
- package/src/viewdesc.ts +47 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 1.36.0 (2024-11-05)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Don't recreated `TrustedTypePolicy` objects for every paste.
|
|
6
|
+
|
|
7
|
+
### New features
|
|
8
|
+
|
|
9
|
+
Add support for a `destroy` method on custom mark views. Add MarkView to the doc template
|
|
10
|
+
|
|
11
|
+
## 1.35.0 (2024-10-29)
|
|
12
|
+
|
|
13
|
+
### New features
|
|
14
|
+
|
|
15
|
+
The new `NodeView.multiType` flag is now required to opt into handling different node types in a single node view. It used to be the default, but this tripped too many people up.
|
|
16
|
+
|
|
1
17
|
## 1.34.3 (2024-09-19)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1167,11 +1167,12 @@ var CompositionViewDesc = function (_ViewDesc2) {
|
|
|
1167
1167
|
var MarkViewDesc = function (_ViewDesc3) {
|
|
1168
1168
|
_inherits(MarkViewDesc, _ViewDesc3);
|
|
1169
1169
|
var _super3 = _createSuper(MarkViewDesc);
|
|
1170
|
-
function MarkViewDesc(parent, mark, dom, contentDOM) {
|
|
1170
|
+
function MarkViewDesc(parent, mark, dom, contentDOM, spec) {
|
|
1171
1171
|
var _this3;
|
|
1172
1172
|
_classCallCheck(this, MarkViewDesc);
|
|
1173
1173
|
_this3 = _super3.call(this, parent, [], dom, contentDOM);
|
|
1174
1174
|
_this3.mark = mark;
|
|
1175
|
+
_this3.spec = spec;
|
|
1175
1176
|
return _this3;
|
|
1176
1177
|
}
|
|
1177
1178
|
_createClass(MarkViewDesc, [{
|
|
@@ -1212,13 +1213,19 @@ var MarkViewDesc = function (_ViewDesc3) {
|
|
|
1212
1213
|
copy.children = nodes;
|
|
1213
1214
|
return copy;
|
|
1214
1215
|
}
|
|
1216
|
+
}, {
|
|
1217
|
+
key: "destroy",
|
|
1218
|
+
value: function destroy() {
|
|
1219
|
+
if (this.spec.destroy) this.spec.destroy();
|
|
1220
|
+
_get(_getPrototypeOf(MarkViewDesc.prototype), "destroy", this).call(this);
|
|
1221
|
+
}
|
|
1215
1222
|
}], [{
|
|
1216
1223
|
key: "create",
|
|
1217
1224
|
value: function create(parent, mark, inline, view) {
|
|
1218
1225
|
var custom = view.nodeViews[mark.type.name];
|
|
1219
1226
|
var spec = custom && custom(mark, view, inline);
|
|
1220
1227
|
if (!spec || !spec.dom) spec = prosemirrorModel.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
|
|
1221
|
-
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
|
|
1228
|
+
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);
|
|
1222
1229
|
}
|
|
1223
1230
|
}]);
|
|
1224
1231
|
return MarkViewDesc;
|
|
@@ -1564,7 +1571,7 @@ var CustomNodeViewDesc = function (_NodeViewDesc2) {
|
|
|
1564
1571
|
key: "update",
|
|
1565
1572
|
value: function update(node, outerDeco, innerDeco, view) {
|
|
1566
1573
|
if (this.dirty == NODE_DIRTY) return false;
|
|
1567
|
-
if (this.spec.update) {
|
|
1574
|
+
if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) {
|
|
1568
1575
|
var result = this.spec.update(node, outerDeco, innerDeco);
|
|
1569
1576
|
if (result) this.updateInner(node, outerDeco, innerDeco, view);
|
|
1570
1577
|
return result;
|
|
@@ -2783,14 +2790,16 @@ var _detachedDoc = null;
|
|
|
2783
2790
|
function detachedDoc() {
|
|
2784
2791
|
return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
|
|
2785
2792
|
}
|
|
2793
|
+
var _policy = null;
|
|
2786
2794
|
function maybeWrapTrusted(html) {
|
|
2787
2795
|
var trustedTypes = window.trustedTypes;
|
|
2788
2796
|
if (!trustedTypes) return html;
|
|
2789
|
-
|
|
2797
|
+
if (!_policy) _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {
|
|
2790
2798
|
createHTML: function createHTML(s) {
|
|
2791
2799
|
return s;
|
|
2792
2800
|
}
|
|
2793
|
-
})
|
|
2801
|
+
});
|
|
2802
|
+
return _policy.createHTML(html);
|
|
2794
2803
|
}
|
|
2795
2804
|
function readHTML(html) {
|
|
2796
2805
|
var metas = /^(\s*<meta [^>]*>)*/.exec(html);
|
|
@@ -2927,7 +2936,7 @@ editHandlers.keydown = function (view, _event) {
|
|
|
2927
2936
|
view.input.lastKeyCode = event.keyCode;
|
|
2928
2937
|
view.input.lastKeyCodeTime = Date.now();
|
|
2929
2938
|
if (android && chrome && event.keyCode == 13) return;
|
|
2930
|
-
if (
|
|
2939
|
+
if (event.keyCode != 229) view.domObserver.forceFlush();
|
|
2931
2940
|
if (ios && event.keyCode == 13 && !event.ctrlKey && !event.altKey && !event.metaKey) {
|
|
2932
2941
|
var now = Date.now();
|
|
2933
2942
|
view.input.lastIOSEnter = now;
|
|
@@ -4292,11 +4301,6 @@ var DOMObserver = function () {
|
|
|
4292
4301
|
}
|
|
4293
4302
|
return this.queue;
|
|
4294
4303
|
}
|
|
4295
|
-
}, {
|
|
4296
|
-
key: "selectionChanged",
|
|
4297
|
-
value: function selectionChanged(sel) {
|
|
4298
|
-
return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
|
|
4299
|
-
}
|
|
4300
4304
|
}, {
|
|
4301
4305
|
key: "flush",
|
|
4302
4306
|
value: function flush() {
|
|
@@ -4304,8 +4308,8 @@ var DOMObserver = function () {
|
|
|
4304
4308
|
if (!view.docView || this.flushingSoon > -1) return;
|
|
4305
4309
|
var mutations = this.pendingRecords();
|
|
4306
4310
|
if (mutations.length) this.queue = [];
|
|
4307
|
-
var sel = view.domSelectionRange()
|
|
4308
|
-
|
|
4311
|
+
var sel = view.domSelectionRange();
|
|
4312
|
+
var newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4309
4313
|
var from = -1,
|
|
4310
4314
|
to = -1,
|
|
4311
4315
|
typeOver = false,
|
package/dist/index.d.cts
CHANGED
|
@@ -245,9 +245,6 @@ node-specific editing interfaces, you want more control over
|
|
|
245
245
|
the behavior of a node's in-editor representation, and need to
|
|
246
246
|
[define](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) a custom node view.
|
|
247
247
|
|
|
248
|
-
Mark views only support `dom` and `contentDOM`, and don't support
|
|
249
|
-
any of the node view methods.
|
|
250
|
-
|
|
251
248
|
Objects returned as node views must conform to this interface.
|
|
252
249
|
*/
|
|
253
250
|
interface NodeView {
|
|
@@ -265,19 +262,28 @@ interface NodeView {
|
|
|
265
262
|
*/
|
|
266
263
|
contentDOM?: HTMLElement | null;
|
|
267
264
|
/**
|
|
268
|
-
When given, this will be called when the view is updating
|
|
269
|
-
It will be given a node
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
265
|
+
When given, this will be called when the view is updating
|
|
266
|
+
itself. It will be given a node, an array of active decorations
|
|
267
|
+
around the node (which are automatically drawn, and the node
|
|
268
|
+
view may ignore if it isn't interested in them), and a
|
|
269
|
+
[decoration source](https://prosemirror.net/docs/ref/#view.DecorationSource) that represents any
|
|
270
|
+
decorations that apply to the content of the node (which again
|
|
271
|
+
may be ignored). It should return true if it was able to update
|
|
272
|
+
to that node, and false otherwise. If the node view has a
|
|
273
|
+
`contentDOM` property (or no `dom` property), updating its child
|
|
274
|
+
nodes will be handled by ProseMirror.
|
|
278
275
|
*/
|
|
279
276
|
update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean;
|
|
280
277
|
/**
|
|
278
|
+
By default, `update` will only be called when a node of the same
|
|
279
|
+
node type appears in this view's position. When you set this to
|
|
280
|
+
true, it will be called for any node, making it possible to have
|
|
281
|
+
a node view that representsmultiple types of nodes. You will
|
|
282
|
+
need to check the type of the nodes you get in `update` and
|
|
283
|
+
return `false` for types you cannot handle.
|
|
284
|
+
*/
|
|
285
|
+
multiType?: boolean;
|
|
286
|
+
/**
|
|
281
287
|
Can be used to override the way the node's selected status (as a
|
|
282
288
|
node selection) is displayed.
|
|
283
289
|
*/
|
|
@@ -314,7 +320,32 @@ interface NodeView {
|
|
|
314
320
|
ignoreMutation?: (mutation: MutationRecord) => boolean;
|
|
315
321
|
/**
|
|
316
322
|
Called when the node view is removed from the editor or the whole
|
|
317
|
-
editor is destroyed.
|
|
323
|
+
editor is destroyed.
|
|
324
|
+
*/
|
|
325
|
+
destroy?: () => void;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
By default, document marks are rendered using the result of the
|
|
329
|
+
[`toDOM`](https://prosemirror.net/docs/ref/#model.MarkSpec.toDOM) method of their spec, and managed entirely
|
|
330
|
+
by the editor. For some use cases, you want more control over the behavior
|
|
331
|
+
of a mark's in-editor representation, and need to
|
|
332
|
+
[define](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) a custom mark view.
|
|
333
|
+
|
|
334
|
+
Objects returned as mark views must conform to this interface.
|
|
335
|
+
*/
|
|
336
|
+
interface MarkView {
|
|
337
|
+
/**
|
|
338
|
+
The outer DOM node that represents the document node.
|
|
339
|
+
*/
|
|
340
|
+
dom: DOMNode;
|
|
341
|
+
/**
|
|
342
|
+
The DOM node that should hold the mark's content. When this is not
|
|
343
|
+
present, the `dom` property is used as the content DOM.
|
|
344
|
+
*/
|
|
345
|
+
contentDOM?: HTMLElement | null;
|
|
346
|
+
/**
|
|
347
|
+
Called when the mark view is removed from the editor or the whole
|
|
348
|
+
editor is destroyed.
|
|
318
349
|
*/
|
|
319
350
|
destroy?: () => void;
|
|
320
351
|
}
|
|
@@ -641,10 +672,7 @@ type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number |
|
|
|
641
672
|
The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
|
|
642
673
|
mark views.
|
|
643
674
|
*/
|
|
644
|
-
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) =>
|
|
645
|
-
dom: HTMLElement;
|
|
646
|
-
contentDOM?: HTMLElement;
|
|
647
|
-
};
|
|
675
|
+
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView;
|
|
648
676
|
/**
|
|
649
677
|
Helper type that maps event names to event object types, but
|
|
650
678
|
includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
@@ -927,4 +955,4 @@ interface DirectEditorProps extends EditorProps {
|
|
|
927
955
|
dispatchTransaction?: (tr: Transaction) => void;
|
|
928
956
|
}
|
|
929
957
|
|
|
930
|
-
export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
|
|
958
|
+
export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
|
package/dist/index.d.ts
CHANGED
|
@@ -245,9 +245,6 @@ node-specific editing interfaces, you want more control over
|
|
|
245
245
|
the behavior of a node's in-editor representation, and need to
|
|
246
246
|
[define](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) a custom node view.
|
|
247
247
|
|
|
248
|
-
Mark views only support `dom` and `contentDOM`, and don't support
|
|
249
|
-
any of the node view methods.
|
|
250
|
-
|
|
251
248
|
Objects returned as node views must conform to this interface.
|
|
252
249
|
*/
|
|
253
250
|
interface NodeView {
|
|
@@ -265,19 +262,28 @@ interface NodeView {
|
|
|
265
262
|
*/
|
|
266
263
|
contentDOM?: HTMLElement | null;
|
|
267
264
|
/**
|
|
268
|
-
When given, this will be called when the view is updating
|
|
269
|
-
It will be given a node
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
265
|
+
When given, this will be called when the view is updating
|
|
266
|
+
itself. It will be given a node, an array of active decorations
|
|
267
|
+
around the node (which are automatically drawn, and the node
|
|
268
|
+
view may ignore if it isn't interested in them), and a
|
|
269
|
+
[decoration source](https://prosemirror.net/docs/ref/#view.DecorationSource) that represents any
|
|
270
|
+
decorations that apply to the content of the node (which again
|
|
271
|
+
may be ignored). It should return true if it was able to update
|
|
272
|
+
to that node, and false otherwise. If the node view has a
|
|
273
|
+
`contentDOM` property (or no `dom` property), updating its child
|
|
274
|
+
nodes will be handled by ProseMirror.
|
|
278
275
|
*/
|
|
279
276
|
update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean;
|
|
280
277
|
/**
|
|
278
|
+
By default, `update` will only be called when a node of the same
|
|
279
|
+
node type appears in this view's position. When you set this to
|
|
280
|
+
true, it will be called for any node, making it possible to have
|
|
281
|
+
a node view that representsmultiple types of nodes. You will
|
|
282
|
+
need to check the type of the nodes you get in `update` and
|
|
283
|
+
return `false` for types you cannot handle.
|
|
284
|
+
*/
|
|
285
|
+
multiType?: boolean;
|
|
286
|
+
/**
|
|
281
287
|
Can be used to override the way the node's selected status (as a
|
|
282
288
|
node selection) is displayed.
|
|
283
289
|
*/
|
|
@@ -314,7 +320,32 @@ interface NodeView {
|
|
|
314
320
|
ignoreMutation?: (mutation: MutationRecord) => boolean;
|
|
315
321
|
/**
|
|
316
322
|
Called when the node view is removed from the editor or the whole
|
|
317
|
-
editor is destroyed.
|
|
323
|
+
editor is destroyed.
|
|
324
|
+
*/
|
|
325
|
+
destroy?: () => void;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
By default, document marks are rendered using the result of the
|
|
329
|
+
[`toDOM`](https://prosemirror.net/docs/ref/#model.MarkSpec.toDOM) method of their spec, and managed entirely
|
|
330
|
+
by the editor. For some use cases, you want more control over the behavior
|
|
331
|
+
of a mark's in-editor representation, and need to
|
|
332
|
+
[define](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) a custom mark view.
|
|
333
|
+
|
|
334
|
+
Objects returned as mark views must conform to this interface.
|
|
335
|
+
*/
|
|
336
|
+
interface MarkView {
|
|
337
|
+
/**
|
|
338
|
+
The outer DOM node that represents the document node.
|
|
339
|
+
*/
|
|
340
|
+
dom: DOMNode;
|
|
341
|
+
/**
|
|
342
|
+
The DOM node that should hold the mark's content. When this is not
|
|
343
|
+
present, the `dom` property is used as the content DOM.
|
|
344
|
+
*/
|
|
345
|
+
contentDOM?: HTMLElement | null;
|
|
346
|
+
/**
|
|
347
|
+
Called when the mark view is removed from the editor or the whole
|
|
348
|
+
editor is destroyed.
|
|
318
349
|
*/
|
|
319
350
|
destroy?: () => void;
|
|
320
351
|
}
|
|
@@ -641,10 +672,7 @@ type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number |
|
|
|
641
672
|
The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
|
|
642
673
|
mark views.
|
|
643
674
|
*/
|
|
644
|
-
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) =>
|
|
645
|
-
dom: HTMLElement;
|
|
646
|
-
contentDOM?: HTMLElement;
|
|
647
|
-
};
|
|
675
|
+
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView;
|
|
648
676
|
/**
|
|
649
677
|
Helper type that maps event names to event object types, but
|
|
650
678
|
includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
@@ -927,4 +955,4 @@ interface DirectEditorProps extends EditorProps {
|
|
|
927
955
|
dispatchTransaction?: (tr: Transaction) => void;
|
|
928
956
|
}
|
|
929
957
|
|
|
930
|
-
export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
|
|
958
|
+
export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
|
package/dist/index.js
CHANGED
|
@@ -1192,16 +1192,17 @@ class CompositionViewDesc extends ViewDesc {
|
|
|
1192
1192
|
// some cases they will be split more often than would appear
|
|
1193
1193
|
// necessary.
|
|
1194
1194
|
class MarkViewDesc extends ViewDesc {
|
|
1195
|
-
constructor(parent, mark, dom, contentDOM) {
|
|
1195
|
+
constructor(parent, mark, dom, contentDOM, spec) {
|
|
1196
1196
|
super(parent, [], dom, contentDOM);
|
|
1197
1197
|
this.mark = mark;
|
|
1198
|
+
this.spec = spec;
|
|
1198
1199
|
}
|
|
1199
1200
|
static create(parent, mark, inline, view) {
|
|
1200
1201
|
let custom = view.nodeViews[mark.type.name];
|
|
1201
1202
|
let spec = custom && custom(mark, view, inline);
|
|
1202
1203
|
if (!spec || !spec.dom)
|
|
1203
1204
|
spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
|
|
1204
|
-
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
|
|
1205
|
+
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);
|
|
1205
1206
|
}
|
|
1206
1207
|
parseRule() {
|
|
1207
1208
|
if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)
|
|
@@ -1233,6 +1234,11 @@ class MarkViewDesc extends ViewDesc {
|
|
|
1233
1234
|
copy.children = nodes;
|
|
1234
1235
|
return copy;
|
|
1235
1236
|
}
|
|
1237
|
+
destroy() {
|
|
1238
|
+
if (this.spec.destroy)
|
|
1239
|
+
this.spec.destroy();
|
|
1240
|
+
super.destroy();
|
|
1241
|
+
}
|
|
1236
1242
|
}
|
|
1237
1243
|
// Node view descs are the main, most common type of view desc, and
|
|
1238
1244
|
// correspond to an actual node in the document. Unlike mark descs,
|
|
@@ -1552,7 +1558,7 @@ class CustomNodeViewDesc extends NodeViewDesc {
|
|
|
1552
1558
|
update(node, outerDeco, innerDeco, view) {
|
|
1553
1559
|
if (this.dirty == NODE_DIRTY)
|
|
1554
1560
|
return false;
|
|
1555
|
-
if (this.spec.update) {
|
|
1561
|
+
if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) {
|
|
1556
1562
|
let result = this.spec.update(node, outerDeco, innerDeco);
|
|
1557
1563
|
if (result)
|
|
1558
1564
|
this.updateInner(node, outerDeco, innerDeco, view);
|
|
@@ -2953,6 +2959,7 @@ let _detachedDoc = null;
|
|
|
2953
2959
|
function detachedDoc() {
|
|
2954
2960
|
return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
|
|
2955
2961
|
}
|
|
2962
|
+
let _policy = null;
|
|
2956
2963
|
function maybeWrapTrusted(html) {
|
|
2957
2964
|
let trustedTypes = window.trustedTypes;
|
|
2958
2965
|
if (!trustedTypes)
|
|
@@ -2960,7 +2967,9 @@ function maybeWrapTrusted(html) {
|
|
|
2960
2967
|
// With the require-trusted-types-for CSP, Chrome will block
|
|
2961
2968
|
// innerHTML, even on a detached document. This wraps the string in
|
|
2962
2969
|
// a way that makes the browser allow us to use its parser again.
|
|
2963
|
-
|
|
2970
|
+
if (!_policy)
|
|
2971
|
+
_policy = trustedTypes.createPolicy("ProseMirrorClipboard", { createHTML: (s) => s });
|
|
2972
|
+
return _policy.createHTML(html);
|
|
2964
2973
|
}
|
|
2965
2974
|
function readHTML(html) {
|
|
2966
2975
|
let metas = /^(\s*<meta [^>]*>)*/.exec(html);
|
|
@@ -3111,9 +3120,7 @@ editHandlers.keydown = (view, _event) => {
|
|
|
3111
3120
|
// and handling them eagerly tends to corrupt the input.
|
|
3112
3121
|
if (android && chrome && event.keyCode == 13)
|
|
3113
3122
|
return;
|
|
3114
|
-
if (
|
|
3115
|
-
view.domObserver.flush();
|
|
3116
|
-
else if (event.keyCode != 229)
|
|
3123
|
+
if (event.keyCode != 229)
|
|
3117
3124
|
view.domObserver.forceFlush();
|
|
3118
3125
|
// On iOS, if we preventDefault enter key presses, the virtual
|
|
3119
3126
|
// keyboard gets confused. So the hack here is to set a flag that
|
|
@@ -4636,9 +4643,6 @@ class DOMObserver {
|
|
|
4636
4643
|
this.queue.push(mut);
|
|
4637
4644
|
return this.queue;
|
|
4638
4645
|
}
|
|
4639
|
-
selectionChanged(sel) {
|
|
4640
|
-
return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
|
|
4641
|
-
}
|
|
4642
4646
|
flush() {
|
|
4643
4647
|
let { view } = this;
|
|
4644
4648
|
if (!view.docView || this.flushingSoon > -1)
|
|
@@ -4646,7 +4650,8 @@ class DOMObserver {
|
|
|
4646
4650
|
let mutations = this.pendingRecords();
|
|
4647
4651
|
if (mutations.length)
|
|
4648
4652
|
this.queue = [];
|
|
4649
|
-
let sel = view.domSelectionRange()
|
|
4653
|
+
let sel = view.domSelectionRange();
|
|
4654
|
+
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4650
4655
|
let from = -1, to = -1, typeOver = false, added = [];
|
|
4651
4656
|
if (view.editable) {
|
|
4652
4657
|
for (let i = 0; i < mutations.length; i++) {
|
package/package.json
CHANGED
package/src/README.md
CHANGED
package/src/clipboard.ts
CHANGED
|
@@ -204,13 +204,16 @@ function detachedDoc() {
|
|
|
204
204
|
return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
let _policy: any = null
|
|
208
|
+
|
|
207
209
|
function maybeWrapTrusted(html: string): string {
|
|
208
210
|
let trustedTypes = (window as any).trustedTypes
|
|
209
211
|
if (!trustedTypes) return html
|
|
210
212
|
// With the require-trusted-types-for CSP, Chrome will block
|
|
211
213
|
// innerHTML, even on a detached document. This wraps the string in
|
|
212
214
|
// a way that makes the browser allow us to use its parser again.
|
|
213
|
-
|
|
215
|
+
if (!_policy) _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {createHTML: (s: string) => s})
|
|
216
|
+
return _policy.createHTML(html)
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
function readHTML(html: string) {
|
package/src/domobserver.ts
CHANGED
|
@@ -163,17 +163,14 @@ 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
|
-
|
|
170
166
|
flush() {
|
|
171
167
|
let {view} = this
|
|
172
168
|
if (!view.docView || this.flushingSoon > -1) return
|
|
173
169
|
let mutations = this.pendingRecords()
|
|
174
170
|
if (mutations.length) this.queue = []
|
|
175
171
|
|
|
176
|
-
let sel = view.domSelectionRange()
|
|
172
|
+
let sel = view.domSelectionRange()
|
|
173
|
+
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel)
|
|
177
174
|
|
|
178
175
|
let from = -1, to = -1, typeOver = false, added: Node[] = []
|
|
179
176
|
if (view.editable) {
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {Slice, ResolvedPos, DOMParser, DOMSerializer, Node, Mark} from "prosemir
|
|
|
3
3
|
|
|
4
4
|
import {scrollRectIntoView, posAtCoords, coordsAtPos, endOfTextblock, storeScrollPos,
|
|
5
5
|
resetScrollPos, focusPreventScroll} from "./domcoords"
|
|
6
|
-
import {docViewDesc, ViewDesc, NodeView, NodeViewDesc} from "./viewdesc"
|
|
6
|
+
import {docViewDesc, ViewDesc, NodeView, NodeViewDesc, MarkView} from "./viewdesc"
|
|
7
7
|
import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition,
|
|
8
8
|
InputState, doPaste, Dragging, findCompositionNode} from "./input"
|
|
9
9
|
import {selectionToDOM, anchorInRightPlace, syncNodeSelection} from "./selection"
|
|
@@ -14,7 +14,7 @@ import {DOMSelection, DOMNode, DOMSelectionRange, deepActiveElement, clearReused
|
|
|
14
14
|
import * as browser from "./browser"
|
|
15
15
|
|
|
16
16
|
export {Decoration, DecorationSet, DecorationAttrs, DecorationSource} from "./decoration"
|
|
17
|
-
export {NodeView} from "./viewdesc"
|
|
17
|
+
export {NodeView, MarkView} from "./viewdesc"
|
|
18
18
|
|
|
19
19
|
// Exported for testing
|
|
20
20
|
import {serializeForClipboard, parseFromClipboard} from "./clipboard"
|
|
@@ -576,7 +576,7 @@ export type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => n
|
|
|
576
576
|
|
|
577
577
|
/// The function types [used](#view.EditorProps.markViews) to create
|
|
578
578
|
/// mark views.
|
|
579
|
-
export type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) =>
|
|
579
|
+
export type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView
|
|
580
580
|
|
|
581
581
|
type NodeViewSet = {[name: string]: NodeViewConstructor | MarkViewConstructor}
|
|
582
582
|
|
package/src/input.ts
CHANGED
|
@@ -112,9 +112,7 @@ 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
|
-
|
|
116
|
-
if (view.domObserver.selectionChanged(view.domSelectionRange())) view.domObserver.flush()
|
|
117
|
-
else if (event.keyCode != 229) view.domObserver.forceFlush()
|
|
115
|
+
if (event.keyCode != 229) view.domObserver.forceFlush()
|
|
118
116
|
|
|
119
117
|
// On iOS, if we preventDefault enter key presses, the virtual
|
|
120
118
|
// keyboard gets confused. So the hack here is to set a flag that
|
package/src/viewdesc.ts
CHANGED
|
@@ -17,9 +17,6 @@ declare global {
|
|
|
17
17
|
/// the behavior of a node's in-editor representation, and need to
|
|
18
18
|
/// [define](#view.EditorProps.nodeViews) a custom node view.
|
|
19
19
|
///
|
|
20
|
-
/// Mark views only support `dom` and `contentDOM`, and don't support
|
|
21
|
-
/// any of the node view methods.
|
|
22
|
-
///
|
|
23
20
|
/// Objects returned as node views must conform to this interface.
|
|
24
21
|
export interface NodeView {
|
|
25
22
|
/// The outer DOM node that represents the document node.
|
|
@@ -33,18 +30,26 @@ export interface NodeView {
|
|
|
33
30
|
/// (or deciding not to render) its child nodes.
|
|
34
31
|
contentDOM?: HTMLElement | null
|
|
35
32
|
|
|
36
|
-
/// When given, this will be called when the view is updating
|
|
37
|
-
/// It will be given a node
|
|
38
|
-
///
|
|
39
|
-
///
|
|
40
|
-
///
|
|
41
|
-
///
|
|
42
|
-
///
|
|
43
|
-
///
|
|
44
|
-
///
|
|
45
|
-
///
|
|
33
|
+
/// When given, this will be called when the view is updating
|
|
34
|
+
/// itself. It will be given a node, an array of active decorations
|
|
35
|
+
/// around the node (which are automatically drawn, and the node
|
|
36
|
+
/// view may ignore if it isn't interested in them), and a
|
|
37
|
+
/// [decoration source](#view.DecorationSource) that represents any
|
|
38
|
+
/// decorations that apply to the content of the node (which again
|
|
39
|
+
/// may be ignored). It should return true if it was able to update
|
|
40
|
+
/// to that node, and false otherwise. If the node view has a
|
|
41
|
+
/// `contentDOM` property (or no `dom` property), updating its child
|
|
42
|
+
/// nodes will be handled by ProseMirror.
|
|
46
43
|
update?: (node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource) => boolean
|
|
47
44
|
|
|
45
|
+
/// By default, `update` will only be called when a node of the same
|
|
46
|
+
/// node type appears in this view's position. When you set this to
|
|
47
|
+
/// true, it will be called for any node, making it possible to have
|
|
48
|
+
/// a node view that representsmultiple types of nodes. You will
|
|
49
|
+
/// need to check the type of the nodes you get in `update` and
|
|
50
|
+
/// return `false` for types you cannot handle.
|
|
51
|
+
multiType?: boolean
|
|
52
|
+
|
|
48
53
|
/// Can be used to override the way the node's selected status (as a
|
|
49
54
|
/// node selection) is displayed.
|
|
50
55
|
selectNode?: () => void
|
|
@@ -76,7 +81,27 @@ export interface NodeView {
|
|
|
76
81
|
ignoreMutation?: (mutation: MutationRecord) => boolean
|
|
77
82
|
|
|
78
83
|
/// Called when the node view is removed from the editor or the whole
|
|
79
|
-
/// editor is destroyed.
|
|
84
|
+
/// editor is destroyed.
|
|
85
|
+
destroy?: () => void
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// By default, document marks are rendered using the result of the
|
|
89
|
+
/// [`toDOM`](#model.MarkSpec.toDOM) method of their spec, and managed entirely
|
|
90
|
+
/// by the editor. For some use cases, you want more control over the behavior
|
|
91
|
+
/// of a mark's in-editor representation, and need to
|
|
92
|
+
/// [define](#view.EditorProps.markViews) a custom mark view.
|
|
93
|
+
///
|
|
94
|
+
/// Objects returned as mark views must conform to this interface.
|
|
95
|
+
export interface MarkView {
|
|
96
|
+
/// The outer DOM node that represents the document node.
|
|
97
|
+
dom: DOMNode
|
|
98
|
+
|
|
99
|
+
/// The DOM node that should hold the mark's content. When this is not
|
|
100
|
+
/// present, the `dom` property is used as the content DOM.
|
|
101
|
+
contentDOM?: HTMLElement | null
|
|
102
|
+
|
|
103
|
+
/// Called when the mark view is removed from the editor or the whole
|
|
104
|
+
/// editor is destroyed.
|
|
80
105
|
destroy?: () => void
|
|
81
106
|
}
|
|
82
107
|
|
|
@@ -564,7 +589,7 @@ class CompositionViewDesc extends ViewDesc {
|
|
|
564
589
|
// some cases they will be split more often than would appear
|
|
565
590
|
// necessary.
|
|
566
591
|
class MarkViewDesc extends ViewDesc {
|
|
567
|
-
constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement) {
|
|
592
|
+
constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement, readonly spec: MarkView) {
|
|
568
593
|
super(parent, [], dom, contentDOM)
|
|
569
594
|
}
|
|
570
595
|
|
|
@@ -573,7 +598,7 @@ class MarkViewDesc extends ViewDesc {
|
|
|
573
598
|
let spec: {dom: HTMLElement, contentDOM?: HTMLElement} = custom && (custom as any)(mark, view, inline)
|
|
574
599
|
if (!spec || !spec.dom)
|
|
575
600
|
spec = (DOMSerializer.renderSpec as any)(document, mark.type.spec.toDOM!(mark, inline), null, mark.attrs) as any
|
|
576
|
-
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom as HTMLElement)
|
|
601
|
+
return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom as HTMLElement, spec)
|
|
577
602
|
}
|
|
578
603
|
|
|
579
604
|
parseRule() {
|
|
@@ -603,6 +628,11 @@ class MarkViewDesc extends ViewDesc {
|
|
|
603
628
|
copy.children = nodes
|
|
604
629
|
return copy
|
|
605
630
|
}
|
|
631
|
+
|
|
632
|
+
destroy() {
|
|
633
|
+
if (this.spec.destroy) this.spec.destroy()
|
|
634
|
+
super.destroy()
|
|
635
|
+
}
|
|
606
636
|
}
|
|
607
637
|
|
|
608
638
|
// Node view descs are the main, most common type of view desc, and
|
|
@@ -938,7 +968,7 @@ class CustomNodeViewDesc extends NodeViewDesc {
|
|
|
938
968
|
// updates the children.
|
|
939
969
|
update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView) {
|
|
940
970
|
if (this.dirty == NODE_DIRTY) return false
|
|
941
|
-
if (this.spec.update) {
|
|
971
|
+
if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) {
|
|
942
972
|
let result = this.spec.update(node, outerDeco, innerDeco)
|
|
943
973
|
if (result) this.updateInner(node, outerDeco, innerDeco, view)
|
|
944
974
|
return result
|