@react-x11/components 0.8.0 → 0.9.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/README.md +95 -34
- package/dist/charts/node.d.ts +1 -1
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +6 -2
- package/dist/charts/node.js.map +1 -1
- package/dist/embed/client.d.ts +48 -3
- package/dist/embed/client.d.ts.map +1 -1
- package/dist/embed/client.js +79 -5
- package/dist/embed/client.js.map +1 -1
- package/dist/embed/index.d.ts +1 -1
- package/dist/embed/index.d.ts.map +1 -1
- package/dist/embed/index.js +1 -1
- package/dist/embed/index.js.map +1 -1
- package/dist/html/node.d.ts +3 -1
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +7 -5
- package/dist/html/node.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{markdown → internal/markdown}/ast.d.ts +12 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -0
- package/dist/internal/markdown/ast.js +22 -0
- package/dist/internal/markdown/ast.js.map +1 -0
- package/dist/internal/markdown/parse.d.ts.map +1 -0
- package/dist/{markdown → internal/markdown}/parse.js +112 -22
- package/dist/internal/markdown/parse.js.map +1 -0
- package/dist/internal/markdown/stringify.d.ts +4 -0
- package/dist/internal/markdown/stringify.d.ts.map +1 -0
- package/dist/internal/markdown/stringify.js +684 -0
- package/dist/internal/markdown/stringify.js.map +1 -0
- package/dist/internal/markdown/tags.d.ts.map +1 -0
- package/dist/internal/markdown/tags.js.map +1 -0
- package/dist/internal/scroll.d.ts +3 -2
- package/dist/internal/scroll.d.ts.map +1 -1
- package/dist/internal/scroll.js +1 -0
- package/dist/internal/scroll.js.map +1 -1
- package/dist/maps/anchors.d.ts +98 -0
- package/dist/maps/anchors.d.ts.map +1 -0
- package/dist/maps/anchors.js +531 -0
- package/dist/maps/anchors.js.map +1 -0
- package/dist/maps/controller.d.ts +283 -0
- package/dist/maps/controller.d.ts.map +1 -0
- package/dist/maps/controller.js +743 -0
- package/dist/maps/controller.js.map +1 -0
- package/dist/maps/gl/buckets.d.ts +95 -0
- package/dist/maps/gl/buckets.d.ts.map +1 -0
- package/dist/maps/gl/buckets.js +362 -0
- package/dist/maps/gl/buckets.js.map +1 -0
- package/dist/maps/gl/build-worker.d.ts +13 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -0
- package/dist/maps/gl/build-worker.js +44 -0
- package/dist/maps/gl/build-worker.js.map +1 -0
- package/dist/maps/gl/color.d.ts +8 -0
- package/dist/maps/gl/color.d.ts.map +1 -0
- package/dist/maps/gl/color.js +57 -0
- package/dist/maps/gl/color.js.map +1 -0
- package/dist/maps/gl/cover.d.ts +51 -0
- package/dist/maps/gl/cover.d.ts.map +1 -0
- package/dist/maps/gl/cover.js +124 -0
- package/dist/maps/gl/cover.js.map +1 -0
- package/dist/maps/gl/index.d.ts +3 -0
- package/dist/maps/gl/index.d.ts.map +1 -0
- package/dist/maps/gl/index.js +20 -0
- package/dist/maps/gl/index.js.map +1 -0
- package/dist/maps/gl/markers.d.ts +28 -0
- package/dist/maps/gl/markers.d.ts.map +1 -0
- package/dist/maps/gl/markers.js +60 -0
- package/dist/maps/gl/markers.js.map +1 -0
- package/dist/maps/gl/overlays.d.ts +68 -0
- package/dist/maps/gl/overlays.d.ts.map +1 -0
- package/dist/maps/gl/overlays.js +300 -0
- package/dist/maps/gl/overlays.js.map +1 -0
- package/dist/maps/gl/pane.d.ts +12 -0
- package/dist/maps/gl/pane.d.ts.map +1 -0
- package/dist/maps/gl/pane.js +37 -0
- package/dist/maps/gl/pane.js.map +1 -0
- package/dist/maps/gl/placement.d.ts +111 -0
- package/dist/maps/gl/placement.d.ts.map +1 -0
- package/dist/maps/gl/placement.js +567 -0
- package/dist/maps/gl/placement.js.map +1 -0
- package/dist/maps/gl/renderer.d.ts +352 -0
- package/dist/maps/gl/renderer.d.ts.map +1 -0
- package/dist/maps/gl/renderer.js +1127 -0
- package/dist/maps/gl/renderer.js.map +1 -0
- package/dist/maps/gl/shaders.d.ts +120 -0
- package/dist/maps/gl/shaders.d.ts.map +1 -0
- package/dist/maps/gl/shaders.js +451 -0
- package/dist/maps/gl/shaders.js.map +1 -0
- package/dist/maps/gl/store.d.ts +115 -0
- package/dist/maps/gl/store.d.ts.map +1 -0
- package/dist/maps/gl/store.js +469 -0
- package/dist/maps/gl/store.js.map +1 -0
- package/dist/maps/gl/text.d.ts +154 -0
- package/dist/maps/gl/text.d.ts.map +1 -0
- package/dist/maps/gl/text.js +382 -0
- package/dist/maps/gl/text.js.map +1 -0
- package/dist/maps/gl/view.d.ts +54 -0
- package/dist/maps/gl/view.d.ts.map +1 -0
- package/dist/maps/gl/view.js +974 -0
- package/dist/maps/gl/view.js.map +1 -0
- package/dist/maps/index.d.ts +1 -1
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +216 -52
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +37 -16
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +188 -119
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +162 -56
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +607 -515
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/overlay.d.ts +72 -9
- package/dist/maps/overlay.d.ts.map +1 -1
- package/dist/maps/overlay.js +108 -28
- package/dist/maps/overlay.js.map +1 -1
- package/dist/maps/paint.d.ts +3 -0
- package/dist/maps/paint.d.ts.map +1 -1
- package/dist/maps/paint.js.map +1 -1
- package/dist/maps/proj.d.ts +14 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +28 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/renderer.d.ts +69 -0
- package/dist/maps/renderer.d.ts.map +1 -0
- package/dist/maps/renderer.js +66 -0
- package/dist/maps/renderer.js.map +1 -0
- package/dist/maps/sources.d.ts +25 -3
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +17 -0
- package/dist/maps/sources.js.map +1 -1
- package/dist/maps/theme.d.ts +19 -0
- package/dist/maps/theme.d.ts.map +1 -0
- package/dist/maps/theme.js +44 -0
- package/dist/maps/theme.js.map +1 -0
- package/dist/maps/tiles.d.ts +117 -17
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +163 -30
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +188 -20
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/expressions.d.ts +1 -1
- package/dist/markdown/expressions.d.ts.map +1 -1
- package/dist/markdown/expressions.js.map +1 -1
- package/dist/markdown/index.d.ts +7 -6
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +9 -7
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/media-player/index.d.ts +11 -3
- package/dist/media-player/index.d.ts.map +1 -1
- package/dist/media-player/index.js +13 -2
- package/dist/media-player/index.js.map +1 -1
- package/dist/rich-text-editor/clipboard.d.ts +23 -0
- package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
- package/dist/rich-text-editor/clipboard.js +307 -0
- package/dist/rich-text-editor/clipboard.js.map +1 -0
- package/dist/rich-text-editor/collab.d.ts +32 -0
- package/dist/rich-text-editor/collab.d.ts.map +1 -0
- package/dist/rich-text-editor/collab.js +55 -0
- package/dist/rich-text-editor/collab.js.map +1 -0
- package/dist/rich-text-editor/commands.d.ts +50 -0
- package/dist/rich-text-editor/commands.d.ts.map +1 -0
- package/dist/rich-text-editor/commands.js +376 -0
- package/dist/rich-text-editor/commands.js.map +1 -0
- package/dist/rich-text-editor/drag.d.ts +68 -0
- package/dist/rich-text-editor/drag.d.ts.map +1 -0
- package/dist/rich-text-editor/drag.js +148 -0
- package/dist/rich-text-editor/drag.js.map +1 -0
- package/dist/rich-text-editor/html.d.ts +145 -0
- package/dist/rich-text-editor/html.d.ts.map +1 -0
- package/dist/rich-text-editor/html.js +516 -0
- package/dist/rich-text-editor/html.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +263 -0
- package/dist/rich-text-editor/index.d.ts.map +1 -0
- package/dist/rich-text-editor/index.js +822 -0
- package/dist/rich-text-editor/index.js.map +1 -0
- package/dist/rich-text-editor/inline.d.ts +94 -0
- package/dist/rich-text-editor/inline.d.ts.map +1 -0
- package/dist/rich-text-editor/inline.js +252 -0
- package/dist/rich-text-editor/inline.js.map +1 -0
- package/dist/rich-text-editor/keymap.d.ts +71 -0
- package/dist/rich-text-editor/keymap.d.ts.map +1 -0
- package/dist/rich-text-editor/keymap.js +393 -0
- package/dist/rich-text-editor/keymap.js.map +1 -0
- package/dist/rich-text-editor/keys.d.ts +29 -0
- package/dist/rich-text-editor/keys.d.ts.map +1 -0
- package/dist/rich-text-editor/keys.js +93 -0
- package/dist/rich-text-editor/keys.js.map +1 -0
- package/dist/rich-text-editor/look.d.ts +71 -0
- package/dist/rich-text-editor/look.d.ts.map +1 -0
- package/dist/rich-text-editor/look.js +342 -0
- package/dist/rich-text-editor/look.js.map +1 -0
- package/dist/rich-text-editor/markdown.d.ts +18 -0
- package/dist/rich-text-editor/markdown.d.ts.map +1 -0
- package/dist/rich-text-editor/markdown.js +496 -0
- package/dist/rich-text-editor/markdown.js.map +1 -0
- package/dist/rich-text-editor/nodes.d.ts +135 -0
- package/dist/rich-text-editor/nodes.d.ts.map +1 -0
- package/dist/rich-text-editor/nodes.js +397 -0
- package/dist/rich-text-editor/nodes.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts +68 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -0
- package/dist/rich-text-editor/render.js +500 -0
- package/dist/rich-text-editor/render.js.map +1 -0
- package/dist/rich-text-editor/schema.d.ts +16 -0
- package/dist/rich-text-editor/schema.d.ts.map +1 -0
- package/dist/rich-text-editor/schema.js +386 -0
- package/dist/rich-text-editor/schema.js.map +1 -0
- package/dist/rich-text-editor/store.d.ts +11 -0
- package/dist/rich-text-editor/store.d.ts.map +1 -0
- package/dist/rich-text-editor/store.js +43 -0
- package/dist/rich-text-editor/store.js.map +1 -0
- package/dist/rich-text-editor/suggest.d.ts +127 -0
- package/dist/rich-text-editor/suggest.d.ts.map +1 -0
- package/dist/rich-text-editor/suggest.js +0 -0
- package/dist/rich-text-editor/suggest.js.map +1 -0
- package/dist/rich-text-editor/tables.d.ts +41 -0
- package/dist/rich-text-editor/tables.d.ts.map +1 -0
- package/dist/rich-text-editor/tables.js +204 -0
- package/dist/rich-text-editor/tables.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts +58 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
- package/dist/rich-text-editor/toolbar.js +548 -0
- package/dist/rich-text-editor/toolbar.js.map +1 -0
- package/dist/rich-text-editor/view.d.ts +368 -0
- package/dist/rich-text-editor/view.d.ts.map +1 -0
- package/dist/rich-text-editor/view.js +1968 -0
- package/dist/rich-text-editor/view.js.map +1 -0
- package/dist/rich-text-editor/virtual.d.ts +54 -0
- package/dist/rich-text-editor/virtual.d.ts.map +1 -0
- package/dist/rich-text-editor/virtual.js +262 -0
- package/dist/rich-text-editor/virtual.js.map +1 -0
- package/dist/richtext/node.d.ts +25 -2
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +46 -24
- package/dist/richtext/node.js.map +1 -1
- package/dist/terminal/backends.d.ts +4 -1
- package/dist/terminal/backends.d.ts.map +1 -1
- package/dist/terminal/backends.js.map +1 -1
- package/dist/terminal/index.d.ts +18 -7
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +28 -11
- package/dist/terminal/index.js.map +1 -1
- package/package.json +23 -4
- package/src/charts/node.ts +6 -2
- package/src/embed/client.ts +102 -8
- package/src/embed/index.ts +2 -0
- package/src/html/node.ts +7 -5
- package/src/index.ts +2 -0
- package/src/{markdown → internal/markdown}/ast.ts +24 -7
- package/src/{markdown → internal/markdown}/parse.ts +134 -24
- package/src/internal/markdown/stringify.ts +772 -0
- package/src/internal/scroll.ts +5 -3
- package/src/maps/anchors.ts +607 -0
- package/src/maps/controller.ts +999 -0
- package/src/maps/gl/buckets.ts +457 -0
- package/src/maps/gl/build-worker.ts +55 -0
- package/src/maps/gl/color.ts +62 -0
- package/src/maps/gl/cover.ts +170 -0
- package/src/maps/gl/index.ts +23 -0
- package/src/maps/gl/markers.ts +83 -0
- package/src/maps/gl/overlays.ts +379 -0
- package/src/maps/gl/pane.ts +42 -0
- package/src/maps/gl/placement.ts +816 -0
- package/src/maps/gl/renderer.ts +1576 -0
- package/src/maps/gl/shaders.ts +486 -0
- package/src/maps/gl/store.ts +566 -0
- package/src/maps/gl/text.ts +495 -0
- package/src/maps/gl/view.ts +1224 -0
- package/src/maps/index.ts +270 -81
- package/src/maps/labels.ts +214 -121
- package/src/maps/node.ts +763 -629
- package/src/maps/overlay.ts +148 -43
- package/src/maps/paint.ts +3 -0
- package/src/maps/proj.ts +31 -0
- package/src/maps/renderer.ts +155 -0
- package/src/maps/sources.ts +38 -3
- package/src/maps/theme.ts +51 -0
- package/src/maps/tiles.ts +191 -33
- package/src/maps/types.ts +188 -20
- package/src/markdown/expressions.ts +5 -1
- package/src/markdown/index.ts +14 -11
- package/src/markdown/spans.ts +1 -1
- package/src/media-player/index.ts +18 -4
- package/src/rich-text-editor/clipboard.ts +439 -0
- package/src/rich-text-editor/collab.ts +91 -0
- package/src/rich-text-editor/commands.ts +448 -0
- package/src/rich-text-editor/dom-globals.d.ts +23 -0
- package/src/rich-text-editor/drag.ts +211 -0
- package/src/rich-text-editor/html.ts +619 -0
- package/src/rich-text-editor/index.ts +1331 -0
- package/src/rich-text-editor/inline.ts +345 -0
- package/src/rich-text-editor/keymap.ts +510 -0
- package/src/rich-text-editor/keys.ts +119 -0
- package/src/rich-text-editor/look.ts +427 -0
- package/src/rich-text-editor/markdown.ts +653 -0
- package/src/rich-text-editor/nodes.ts +497 -0
- package/src/rich-text-editor/render.ts +800 -0
- package/src/rich-text-editor/schema.ts +431 -0
- package/src/rich-text-editor/store.ts +39 -0
- package/src/rich-text-editor/suggest.ts +597 -0
- package/src/rich-text-editor/tables.ts +272 -0
- package/src/rich-text-editor/toolbar.ts +724 -0
- package/src/rich-text-editor/view.ts +2287 -0
- package/src/rich-text-editor/virtual.ts +347 -0
- package/src/richtext/node.ts +59 -30
- package/src/terminal/backends.ts +4 -1
- package/src/terminal/index.ts +43 -15
- package/dist/markdown/ast.d.ts.map +0 -1
- package/dist/markdown/ast.js +0 -17
- package/dist/markdown/ast.js.map +0 -1
- package/dist/markdown/parse.d.ts.map +0 -1
- package/dist/markdown/parse.js.map +0 -1
- package/dist/markdown/tags.d.ts.map +0 -1
- package/dist/markdown/tags.js.map +0 -1
- /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.js +0 -0
- /package/src/{markdown → internal/markdown}/tags.ts +0 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
// HTML in and out of a document, through ProseMirror's own DOMParser and
|
|
2
|
+
// DOMSerializer — with no DOM.
|
|
3
|
+
//
|
|
4
|
+
// Both classes are written against the browser's DOM, and both are still the
|
|
5
|
+
// right thing to use: every schema in the ecosystem already says how it reads
|
|
6
|
+
// HTML (`parseDOM` rules) and how it writes it (`toDOM`), so going through
|
|
7
|
+
// them makes a paste from a browser, `format="html"` and a copy another
|
|
8
|
+
// application can read work for *any* schema — the default one here,
|
|
9
|
+
// prosemirror-schema-basic's, a TipTap extension's — with nothing written per
|
|
10
|
+
// node. Reimplementing either would mean a second reading of every schema's
|
|
11
|
+
// rules, and the first one to disagree with ProseMirror's would be a bug.
|
|
12
|
+
//
|
|
13
|
+
// So this module supplies the smallest DOM each of them touches.
|
|
14
|
+
//
|
|
15
|
+
// **Reading.** htmlparser2 builds the tree — already installed, for the
|
|
16
|
+
// reason `src/html/dom.ts` gives — and it is re-dressed in nodes that answer
|
|
17
|
+
// what `DOMParser` asks: `nodeType`/`nodeName`, the sibling links, the
|
|
18
|
+
// attributes, `style` as a declaration block, `matches`/`querySelector`
|
|
19
|
+
// through css-select, `appendChild` (its list normalization moves nodes), and
|
|
20
|
+
// an `ownerDocument` that can make a text node. Selector matching runs on the
|
|
21
|
+
// parser's own tree, so a structural selector sees the markup as written,
|
|
22
|
+
// not after that normalization; the rules schemas actually write are a tag
|
|
23
|
+
// and an attribute, which do not care.
|
|
24
|
+
//
|
|
25
|
+
// **Writing.** `DOMSerializer` takes a `document` option, and a four-method
|
|
26
|
+
// one that builds plain objects is all it calls; they are then printed.
|
|
27
|
+
import { Parser } from 'htmlparser2';
|
|
28
|
+
import { DomHandler } from 'domhandler';
|
|
29
|
+
import type { ChildNode, Element as DhElement } from 'domhandler';
|
|
30
|
+
import { is, selectAll, selectOne } from 'css-select';
|
|
31
|
+
import { DOMParser, DOMSerializer, Fragment } from 'prosemirror-model';
|
|
32
|
+
import type {
|
|
33
|
+
Node as PMNode,
|
|
34
|
+
ParseOptions,
|
|
35
|
+
Schema,
|
|
36
|
+
Slice,
|
|
37
|
+
} from 'prosemirror-model';
|
|
38
|
+
|
|
39
|
+
/** What `DOMParser` is typed to take, which the shim stands in for. */
|
|
40
|
+
type DomArg = Parameters<DOMParser['parse']>[0];
|
|
41
|
+
|
|
42
|
+
const HTML_NS = 'http://www.w3.org/1999/xhtml';
|
|
43
|
+
|
|
44
|
+
// --- reading ---------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
/** `font-weight` → `fontWeight`, the name a `getAttrs` reads off `style`. */
|
|
47
|
+
function camel(name: string): string {
|
|
48
|
+
return name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Split a declaration block on the semicolons that end declarations — not
|
|
52
|
+
* the ones inside a `url(…)` or a quoted string. */
|
|
53
|
+
function declarations(css: string): string[] {
|
|
54
|
+
const out: string[] = [];
|
|
55
|
+
let depth = 0;
|
|
56
|
+
let quote = '';
|
|
57
|
+
let start = 0;
|
|
58
|
+
for (let i = 0; i < css.length; i++) {
|
|
59
|
+
const ch = css[i];
|
|
60
|
+
if (quote) {
|
|
61
|
+
if (ch === quote && css[i - 1] !== '\\') quote = '';
|
|
62
|
+
} else if (ch === '"' || ch === "'") quote = ch;
|
|
63
|
+
else if (ch === '(') depth++;
|
|
64
|
+
else if (ch === ')') depth = Math.max(0, depth - 1);
|
|
65
|
+
else if (ch === ';' && depth === 0) {
|
|
66
|
+
out.push(css.slice(start, i));
|
|
67
|
+
start = i + 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
out.push(css.slice(start));
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const STYLE_MEMBERS = new Set([
|
|
75
|
+
'length',
|
|
76
|
+
'item',
|
|
77
|
+
'getPropertyValue',
|
|
78
|
+
'cssText',
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
/** A `style` attribute, as the declaration object `DOMParser`'s style rules
|
|
82
|
+
* and a schema's `getAttrs` read: `getPropertyValue` for the former,
|
|
83
|
+
* camelCase properties for the latter. */
|
|
84
|
+
export class ShimStyle {
|
|
85
|
+
[property: string]: unknown;
|
|
86
|
+
private readonly _names: string[] = [];
|
|
87
|
+
private readonly _values = new Map<string, string>();
|
|
88
|
+
|
|
89
|
+
constructor(css: string) {
|
|
90
|
+
for (const decl of declarations(css)) {
|
|
91
|
+
const colon = decl.indexOf(':');
|
|
92
|
+
if (colon <= 0) continue;
|
|
93
|
+
const name = decl.slice(0, colon).trim().toLowerCase();
|
|
94
|
+
const value = decl
|
|
95
|
+
.slice(colon + 1)
|
|
96
|
+
.replace(/!\s*important\s*$/i, '')
|
|
97
|
+
.trim();
|
|
98
|
+
if (!name || !value) continue;
|
|
99
|
+
this._set(name, value);
|
|
100
|
+
// a browser reports the shorthand's longhand too, and rules are
|
|
101
|
+
// written against either
|
|
102
|
+
if (name === 'text-decoration') this._set('text-decoration-line', value);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private _set(name: string, value: string): void {
|
|
107
|
+
if (!this._values.has(name)) this._names.push(name);
|
|
108
|
+
this._values.set(name, value);
|
|
109
|
+
const prop = camel(name);
|
|
110
|
+
if (!STYLE_MEMBERS.has(prop)) this[prop] = value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get length(): number {
|
|
114
|
+
return this._names.length;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
item(index: number): string {
|
|
118
|
+
return this._names[index] ?? '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getPropertyValue(name: string): string {
|
|
122
|
+
return this._values.get(name.toLowerCase()) ?? '';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get cssText(): string {
|
|
126
|
+
return this._names.map((n) => `${n}: ${this._values.get(n)}`).join('; ');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
abstract class ShimNode {
|
|
131
|
+
abstract readonly nodeType: number;
|
|
132
|
+
abstract readonly nodeName: string;
|
|
133
|
+
ownerDocument!: ShimDocument;
|
|
134
|
+
parentNode: ShimParent | null = null;
|
|
135
|
+
nextSibling: ShimNode | null = null;
|
|
136
|
+
previousSibling: ShimNode | null = null;
|
|
137
|
+
|
|
138
|
+
abstract get textContent(): string;
|
|
139
|
+
|
|
140
|
+
contains(other: ShimNode | null): boolean {
|
|
141
|
+
for (let n: ShimNode | null = other; n; n = n.parentNode) {
|
|
142
|
+
if (n === this) return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
abstract class ShimParent extends ShimNode {
|
|
149
|
+
readonly childNodes: ShimNode[] = [];
|
|
150
|
+
|
|
151
|
+
get firstChild(): ShimNode | null {
|
|
152
|
+
return this.childNodes[0] ?? null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
get lastChild(): ShimNode | null {
|
|
156
|
+
return this.childNodes[this.childNodes.length - 1] ?? null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get textContent(): string {
|
|
160
|
+
let out = '';
|
|
161
|
+
for (const child of this.childNodes) out += child.textContent;
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
appendChild<T extends ShimNode>(child: T): T {
|
|
166
|
+
child.parentNode?.removeChild(child);
|
|
167
|
+
const last = this.lastChild;
|
|
168
|
+
child.parentNode = this;
|
|
169
|
+
child.previousSibling = last;
|
|
170
|
+
child.nextSibling = null;
|
|
171
|
+
if (last) last.nextSibling = child;
|
|
172
|
+
this.childNodes.push(child);
|
|
173
|
+
return child;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
removeChild<T extends ShimNode>(child: T): T {
|
|
177
|
+
const at = this.childNodes.indexOf(child);
|
|
178
|
+
if (at < 0) return child;
|
|
179
|
+
this.childNodes.splice(at, 1);
|
|
180
|
+
if (child.previousSibling)
|
|
181
|
+
child.previousSibling.nextSibling = child.nextSibling;
|
|
182
|
+
if (child.nextSibling)
|
|
183
|
+
child.nextSibling.previousSibling = child.previousSibling;
|
|
184
|
+
child.parentNode = null;
|
|
185
|
+
child.previousSibling = null;
|
|
186
|
+
child.nextSibling = null;
|
|
187
|
+
return child;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export class ShimText extends ShimNode {
|
|
192
|
+
readonly nodeType = 3;
|
|
193
|
+
readonly nodeName = '#text';
|
|
194
|
+
|
|
195
|
+
constructor(
|
|
196
|
+
doc: ShimDocument,
|
|
197
|
+
public nodeValue: string,
|
|
198
|
+
) {
|
|
199
|
+
super();
|
|
200
|
+
this.ownerDocument = doc;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get textContent(): string {
|
|
204
|
+
return this.nodeValue;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export class ShimElement extends ShimParent {
|
|
209
|
+
readonly nodeType = 1;
|
|
210
|
+
readonly nodeName: string;
|
|
211
|
+
readonly tagName: string;
|
|
212
|
+
readonly localName: string;
|
|
213
|
+
readonly namespaceURI = HTML_NS;
|
|
214
|
+
readonly style: ShimStyle;
|
|
215
|
+
private readonly _attrs: Map<string, string>;
|
|
216
|
+
|
|
217
|
+
constructor(
|
|
218
|
+
doc: ShimDocument,
|
|
219
|
+
/** The parser's node, which selectors are matched against. */
|
|
220
|
+
readonly source: DhElement,
|
|
221
|
+
) {
|
|
222
|
+
super();
|
|
223
|
+
this.ownerDocument = doc;
|
|
224
|
+
this.localName = source.name.toLowerCase();
|
|
225
|
+
this.tagName = this.localName.toUpperCase();
|
|
226
|
+
this.nodeName = this.tagName;
|
|
227
|
+
this._attrs = new Map(
|
|
228
|
+
Object.entries(source.attribs ?? {}).map(([k, v]) => [
|
|
229
|
+
k.toLowerCase(),
|
|
230
|
+
v,
|
|
231
|
+
]),
|
|
232
|
+
);
|
|
233
|
+
this.style = new ShimStyle(this._attrs.get('style') ?? '');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
getAttribute(name: string): string | null {
|
|
237
|
+
return this._attrs.get(name.toLowerCase()) ?? null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
hasAttribute(name: string): boolean {
|
|
241
|
+
return this._attrs.has(name.toLowerCase());
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
get attributes(): { name: string; value: string }[] {
|
|
245
|
+
return [...this._attrs].map(([name, value]) => ({ name, value }));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
get id(): string {
|
|
249
|
+
return this.getAttribute('id') ?? '';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
get className(): string {
|
|
253
|
+
return this.getAttribute('class') ?? '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
get classList(): { contains(name: string): boolean; length: number } {
|
|
257
|
+
const list = this.className.split(/\s+/).filter(Boolean);
|
|
258
|
+
return { contains: (name) => list.includes(name), length: list.length };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
matches(selector: string): boolean {
|
|
262
|
+
try {
|
|
263
|
+
return is(this.source, selector);
|
|
264
|
+
} catch {
|
|
265
|
+
return false; // a selector css-select cannot read matches nothing
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
querySelector(selector: string): ShimElement | null {
|
|
270
|
+
try {
|
|
271
|
+
const found = selectOne<ChildNode, DhElement>(
|
|
272
|
+
selector,
|
|
273
|
+
this.source.children,
|
|
274
|
+
);
|
|
275
|
+
return found ? this.ownerDocument.shimOf(found) : null;
|
|
276
|
+
} catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
querySelectorAll(selector: string): ShimElement[] {
|
|
282
|
+
try {
|
|
283
|
+
return selectAll<ChildNode, DhElement>(selector, this.source.children)
|
|
284
|
+
.map((found) => this.ownerDocument.shimOf(found))
|
|
285
|
+
.filter((e): e is ShimElement => e !== null);
|
|
286
|
+
} catch {
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export class ShimDocument extends ShimParent {
|
|
293
|
+
readonly nodeType = 9;
|
|
294
|
+
readonly nodeName = '#document';
|
|
295
|
+
private readonly _shims = new WeakMap<DhElement, ShimElement>();
|
|
296
|
+
|
|
297
|
+
constructor() {
|
|
298
|
+
super();
|
|
299
|
+
this.ownerDocument = this;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
createTextNode(text: string): ShimText {
|
|
303
|
+
return new ShimText(this, text);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** @internal — the shim a parser element became. */
|
|
307
|
+
shimOf(node: DhElement): ShimElement | null {
|
|
308
|
+
return this._shims.get(node) ?? null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** @internal */
|
|
312
|
+
adopt(node: DhElement): ShimElement {
|
|
313
|
+
const shim = new ShimElement(this, node);
|
|
314
|
+
this._shims.set(node, shim);
|
|
315
|
+
return shim;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function isElementNode(node: ChildNode): node is DhElement {
|
|
320
|
+
return node.type === 'tag' || node.type === 'script' || node.type === 'style';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* The shim tree for a parsed fragment, under `into`. An explicit stack
|
|
325
|
+
* rather than recursion: a pasted document is somebody else's markup, and a
|
|
326
|
+
* degenerately nested one should not be the thing that finds the call-stack
|
|
327
|
+
* limit (`src/html/dom.ts` measured the same walk).
|
|
328
|
+
*/
|
|
329
|
+
function build(doc: ShimDocument, into: ShimParent, nodes: ChildNode[]): void {
|
|
330
|
+
const stack: [ShimParent, ChildNode[]][] = [[into, nodes]];
|
|
331
|
+
while (stack.length > 0) {
|
|
332
|
+
const [parent, kids] = stack.pop()!;
|
|
333
|
+
for (const kid of kids) {
|
|
334
|
+
if (kid.type === 'text') {
|
|
335
|
+
parent.appendChild(new ShimText(doc, kid.data));
|
|
336
|
+
} else if (isElementNode(kid)) {
|
|
337
|
+
const shim = parent.appendChild(doc.adopt(kid));
|
|
338
|
+
if (kid.children.length > 0) stack.push([shim, kid.children]);
|
|
339
|
+
}
|
|
340
|
+
// comments, directives and CDATA: DOMParser skips them anyway
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Elements that only parse inside a table — ProseMirror's (and jQuery's)
|
|
346
|
+
* list, so a copied cell pastes as a cell. */
|
|
347
|
+
const WRAP_MAP: Record<string, string[]> = {
|
|
348
|
+
thead: ['table'],
|
|
349
|
+
tbody: ['table'],
|
|
350
|
+
tfoot: ['table'],
|
|
351
|
+
caption: ['table'],
|
|
352
|
+
colgroup: ['table'],
|
|
353
|
+
col: ['table', 'colgroup'],
|
|
354
|
+
tr: ['table', 'tbody'],
|
|
355
|
+
td: ['table', 'tbody', 'tr'],
|
|
356
|
+
th: ['table', 'tbody', 'tr'],
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* HTML → the element DOMParser reads — the counterpart of prosemirror-view's
|
|
361
|
+
* `readHTML`: leading `<meta>`s dropped (a browser's clipboard starts with
|
|
362
|
+
* one), and a fragment that begins inside a table given its table back.
|
|
363
|
+
*/
|
|
364
|
+
export function readHTML(html: string): ShimElement {
|
|
365
|
+
const metas = /^(\s*<meta [^>]*>)*/i.exec(html);
|
|
366
|
+
if (metas) html = html.slice(metas[0].length);
|
|
367
|
+
const first = /<([a-z][^>\s]+)/i.exec(html);
|
|
368
|
+
const wrap = first ? WRAP_MAP[first[1].toLowerCase()] : undefined;
|
|
369
|
+
if (wrap) {
|
|
370
|
+
html =
|
|
371
|
+
wrap.map((n) => `<${n}>`).join('') +
|
|
372
|
+
html +
|
|
373
|
+
wrap
|
|
374
|
+
.map((n) => `</${n}>`)
|
|
375
|
+
.reverse()
|
|
376
|
+
.join('');
|
|
377
|
+
}
|
|
378
|
+
const handler = new DomHandler();
|
|
379
|
+
const parser = new Parser(handler);
|
|
380
|
+
parser.write(`<body>${html}</body>`);
|
|
381
|
+
parser.end();
|
|
382
|
+
const doc = new ShimDocument();
|
|
383
|
+
build(doc, doc, handler.root.children);
|
|
384
|
+
let body = doc.childNodes.find(
|
|
385
|
+
(n): n is ShimElement => n instanceof ShimElement && n.localName === 'body',
|
|
386
|
+
);
|
|
387
|
+
if (!body) throw new Error('readHTML: the parser lost its <body>');
|
|
388
|
+
if (wrap) {
|
|
389
|
+
for (const name of wrap) body = body.querySelector(name) ?? body;
|
|
390
|
+
}
|
|
391
|
+
return body;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** A whole document of `schema`, from HTML. */
|
|
395
|
+
export function docFromHTML(
|
|
396
|
+
schema: Schema,
|
|
397
|
+
html: string,
|
|
398
|
+
options?: ParseOptions,
|
|
399
|
+
): PMNode {
|
|
400
|
+
return DOMParser.fromSchema(schema).parse(
|
|
401
|
+
readHTML(html) as unknown as DomArg,
|
|
402
|
+
options,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** A slice of `schema`, from HTML — open at the sides, the shape
|
|
407
|
+
* `replaceSelection` wants. */
|
|
408
|
+
export function sliceFromHTML(
|
|
409
|
+
schema: Schema,
|
|
410
|
+
html: string,
|
|
411
|
+
options?: ParseOptions,
|
|
412
|
+
): Slice {
|
|
413
|
+
return DOMParser.fromSchema(schema).parseSlice(
|
|
414
|
+
readHTML(html) as unknown as DomArg,
|
|
415
|
+
options,
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Parse an element already read with {@link readHTML}. */
|
|
420
|
+
export function sliceFromElement(
|
|
421
|
+
parser: DOMParser,
|
|
422
|
+
dom: ShimElement,
|
|
423
|
+
options?: ParseOptions,
|
|
424
|
+
): Slice {
|
|
425
|
+
return parser.parseSlice(dom as unknown as DomArg, options);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// --- writing ---------------------------------------------------------------
|
|
429
|
+
|
|
430
|
+
type OutNode = OutElement | OutText | OutFragment;
|
|
431
|
+
|
|
432
|
+
class OutText {
|
|
433
|
+
readonly nodeType = 3;
|
|
434
|
+
constructor(public nodeValue: string) {}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
class OutFragment {
|
|
438
|
+
readonly nodeType = 11;
|
|
439
|
+
readonly childNodes: OutNode[] = [];
|
|
440
|
+
|
|
441
|
+
appendChild<T extends OutNode>(child: T): T {
|
|
442
|
+
append(this.childNodes, child);
|
|
443
|
+
return child;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
get firstChild(): OutNode | null {
|
|
447
|
+
return this.childNodes[0] ?? null;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
class OutElement {
|
|
452
|
+
readonly nodeType = 1;
|
|
453
|
+
readonly tagName: string;
|
|
454
|
+
readonly nodeName: string;
|
|
455
|
+
readonly attrs = new Map<string, string>();
|
|
456
|
+
readonly childNodes: OutNode[] = [];
|
|
457
|
+
/** DOMSerializer writes a `style` attribute as `style.cssText`. */
|
|
458
|
+
readonly style = { cssText: '' };
|
|
459
|
+
|
|
460
|
+
constructor(tag: string) {
|
|
461
|
+
this.tagName = tag.toLowerCase();
|
|
462
|
+
this.nodeName = this.tagName.toUpperCase();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
setAttribute(name: string, value: unknown): void {
|
|
466
|
+
this.attrs.set(name, String(value));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
setAttributeNS(_ns: string, name: string, value: unknown): void {
|
|
470
|
+
this.setAttribute(name, value);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
getAttribute(name: string): string | null {
|
|
474
|
+
return this.attrs.get(name) ?? null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
removeAttribute(name: string): void {
|
|
478
|
+
this.attrs.delete(name);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
appendChild<T extends OutNode>(child: T): T {
|
|
482
|
+
append(this.childNodes, child);
|
|
483
|
+
return child;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
get firstChild(): OutNode | null {
|
|
487
|
+
return this.childNodes[0] ?? null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function append(list: OutNode[], child: OutNode): void {
|
|
492
|
+
if (child instanceof OutFragment) {
|
|
493
|
+
list.push(...child.childNodes);
|
|
494
|
+
child.childNodes.length = 0;
|
|
495
|
+
} else list.push(child);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/** The whole of the `document` DOMSerializer calls. */
|
|
499
|
+
const OUT_DOCUMENT = {
|
|
500
|
+
createElement: (tag: string) => new OutElement(tag),
|
|
501
|
+
createElementNS: (_ns: string, tag: string) => new OutElement(tag),
|
|
502
|
+
createTextNode: (text: string) => new OutText(text),
|
|
503
|
+
createDocumentFragment: () => new OutFragment(),
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const VOID = new Set([
|
|
507
|
+
'area',
|
|
508
|
+
'base',
|
|
509
|
+
'br',
|
|
510
|
+
'col',
|
|
511
|
+
'embed',
|
|
512
|
+
'hr',
|
|
513
|
+
'img',
|
|
514
|
+
'input',
|
|
515
|
+
'link',
|
|
516
|
+
'meta',
|
|
517
|
+
'source',
|
|
518
|
+
'track',
|
|
519
|
+
'wbr',
|
|
520
|
+
]);
|
|
521
|
+
|
|
522
|
+
function escapeText(text: string): string {
|
|
523
|
+
return text
|
|
524
|
+
.replace(/&/g, '&')
|
|
525
|
+
.replace(/</g, '<')
|
|
526
|
+
.replace(/>/g, '>')
|
|
527
|
+
.replace(/ /g, ' ');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function escapeAttr(text: string): string {
|
|
531
|
+
return escapeText(text).replace(/"/g, '"');
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function print(node: OutNode): string {
|
|
535
|
+
if (node instanceof OutText) return escapeText(node.nodeValue);
|
|
536
|
+
if (node instanceof OutFragment) return node.childNodes.map(print).join('');
|
|
537
|
+
let attrs = '';
|
|
538
|
+
for (const [name, value] of node.attrs) {
|
|
539
|
+
attrs += ` ${name}="${escapeAttr(value)}"`;
|
|
540
|
+
}
|
|
541
|
+
if (node.style.cssText && !node.attrs.has('style')) {
|
|
542
|
+
attrs += ` style="${escapeAttr(node.style.cssText)}"`;
|
|
543
|
+
}
|
|
544
|
+
if (VOID.has(node.tagName)) return `<${node.tagName}${attrs}>`;
|
|
545
|
+
return `<${node.tagName}${attrs}>${node.childNodes.map(print).join('')}</${node.tagName}>`;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** Serialize content through the schema's `toDOM`, as a fragment of the
|
|
549
|
+
* printed tree — the clipboard adds its own attribute before printing. */
|
|
550
|
+
export function renderFragment(
|
|
551
|
+
schema: Schema,
|
|
552
|
+
content: Fragment,
|
|
553
|
+
): { html(): string; firstElement(): OutElement | null } {
|
|
554
|
+
const out = DOMSerializer.fromSchema(schema).serializeFragment(content, {
|
|
555
|
+
document: OUT_DOCUMENT as unknown as Parameters<
|
|
556
|
+
DOMSerializer['serializeFragment']
|
|
557
|
+
>[1] extends infer O
|
|
558
|
+
? O extends { document?: infer D }
|
|
559
|
+
? D
|
|
560
|
+
: never
|
|
561
|
+
: never,
|
|
562
|
+
}) as unknown as OutFragment;
|
|
563
|
+
return {
|
|
564
|
+
html: () => print(out),
|
|
565
|
+
firstElement: () =>
|
|
566
|
+
(out.childNodes.find((n) => n instanceof OutElement) as OutElement) ??
|
|
567
|
+
null,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* The HTML a copy offers other applications — prosemirror-view's
|
|
573
|
+
* `serializeForClipboard`, printed rather than put in a DOM: the content
|
|
574
|
+
* through `serializer`, wrapped in a table when it starts with a table's
|
|
575
|
+
* parts (a cell alone is not HTML any reader keeps), and ProseMirror's
|
|
576
|
+
* `data-pm-slice` marker on the first element, so a ProseMirror editor
|
|
577
|
+
* anywhere — this one, or one in a browser — pastes it back with its open
|
|
578
|
+
* sides and its context intact.
|
|
579
|
+
*/
|
|
580
|
+
export function clipboardHTML(
|
|
581
|
+
serializer: DOMSerializer,
|
|
582
|
+
content: Fragment,
|
|
583
|
+
openStart: number,
|
|
584
|
+
openEnd: number,
|
|
585
|
+
context: unknown[],
|
|
586
|
+
): string {
|
|
587
|
+
const out = serializer.serializeFragment(content, {
|
|
588
|
+
document: OUT_DOCUMENT as never,
|
|
589
|
+
}) as unknown as OutFragment;
|
|
590
|
+
let top: OutNode[] = out.childNodes;
|
|
591
|
+
let wrappers = 0;
|
|
592
|
+
let first = top[0];
|
|
593
|
+
let needs: string[] | undefined;
|
|
594
|
+
if (first instanceof OutElement && (needs = WRAP_MAP[first.tagName])) {
|
|
595
|
+
for (let i = needs.length - 1; i >= 0; i--) {
|
|
596
|
+
const wrapper = new OutElement(needs[i]);
|
|
597
|
+
wrapper.childNodes.push(...top);
|
|
598
|
+
top = [wrapper];
|
|
599
|
+
wrappers++;
|
|
600
|
+
}
|
|
601
|
+
first = top[0];
|
|
602
|
+
}
|
|
603
|
+
if (first instanceof OutElement) {
|
|
604
|
+
first.setAttribute(
|
|
605
|
+
'data-pm-slice',
|
|
606
|
+
`${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ''} ${JSON.stringify(context)}`,
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
return top.map(print).join('');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** A document or a fragment as HTML, through the schema's `toDOM`. */
|
|
613
|
+
export function htmlFromContent(
|
|
614
|
+
schema: Schema,
|
|
615
|
+
content: Fragment | PMNode,
|
|
616
|
+
): string {
|
|
617
|
+
const fragment = content instanceof Fragment ? content : content.content;
|
|
618
|
+
return renderFragment(schema, fragment).html();
|
|
619
|
+
}
|