-
Notifications
You must be signed in to change notification settings - Fork 125
Expand file tree
/
Copy pathhtml.ts
More file actions
85 lines (72 loc) · 2.7 KB
/
html.ts
File metadata and controls
85 lines (72 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { DOMNode, Descendant, Editor, Element, Text, isDOMText } from '@editablejs/models'
export interface HTMLDeserializerOptions {
element?: Omit<Element, 'children'>
text?: Omit<Text, 'text'>
matchNewline?: true | ((text: string) => boolean)
}
export type HTMLDeserializerTransform = typeof HTMLDeserializer.transform
export type HTMLDeserializerWithTransform<T = HTMLDeserializerOptions> = (
next: HTMLDeserializerTransform,
deserializer: typeof HTMLDeserializer,
options: T,
) => HTMLDeserializerTransform
export interface EditorHTMLDeserializerWithTransform<T = HTMLDeserializerOptions> {
transform: HTMLDeserializerWithTransform<T>
options: T
}
const HTML_DESERIALIZER_TRANSFORMS: WeakMap<Editor, EditorHTMLDeserializerWithTransform[]> =
new WeakMap()
export const HTMLDeserializer = {
transform(node: DOMNode, options: HTMLDeserializerOptions = {}): Descendant[] {
const { element, text, matchNewline } = options
if (isDOMText(node)) {
const content = node.textContent ?? ''
if (
matchNewline &&
/^\s{0,}(\r\n|\n)+\s{0,}$/.test(content) &&
(typeof matchNewline === 'boolean' || matchNewline(content))
) {
return []
}
const dataArray = content.split(/\r\n|\n/)
return dataArray.map(data => ({ ...text, text: data }))
}
const children = []
for (const child of node.childNodes) {
children.push(...this.transform(child, { text }))
}
switch (node.nodeName) {
case 'P':
case 'DIV':
if (children.length === 0) children.push({ text: '' })
return [{ ...element, type: 'paragraph', children }]
default:
return children
}
},
with<T = HTMLDeserializerOptions>(transform: HTMLDeserializerWithTransform<T>, options: T) {
const { transform: t } = this
this.transform = transform(t.bind(this), this, options)
},
withEditor<T = HTMLDeserializerOptions>(
editor: Editor,
transform: HTMLDeserializerWithTransform<T>,
options: T,
) {
const fns = HTML_DESERIALIZER_TRANSFORMS.get(editor) ?? []
if (fns.find(fn => fn.transform === transform)) return
fns.push({
transform: transform as HTMLDeserializerWithTransform,
options: options as HTMLDeserializerOptions,
})
HTML_DESERIALIZER_TRANSFORMS.set(editor, fns)
},
transformWithEditor(editor: Editor, node: DOMNode, options: HTMLDeserializerOptions = {}) {
const HTMLDeserializerEditor = Object.assign({}, HTMLDeserializer)
const transforms = HTML_DESERIALIZER_TRANSFORMS.get(editor) ?? []
for (const { transform, options } of transforms) {
HTMLDeserializerEditor.with(transform, options)
}
return HTMLDeserializerEditor.transform(node, options)
},
}