-
Notifications
You must be signed in to change notification settings - Fork 1
/
createInstance.ts
93 lines (81 loc) · 3.01 KB
/
createInstance.ts
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
86
87
88
89
90
91
92
93
import TemplatePart from './TemplatePart.js'
import TemplateInstance from './TemplateInstance.js'
import NodeTemplatePart from './NodeTemplatePart.js'
import Anchor from './Anchor.js'
import descendantNodes from './descendantNodes.js';
import parseATemplateString from './parseATemplateString.js';
import defaultProcessor from './defaultTemplateProcessor.js'
import AttributeTemplatePart, {
applyPartListToElement
} from './AttributeTemplatePart.js'
type TemplateProcessor = {
create?: (templateInstance: TemplateInstance, state: any) => void,
process: (templateInstance: TemplateInstance, state: any) => void,
}
type CreateInstanceOptions = {
state?: any,
processor?: TemplateProcessor,
}
export default function createInstance(
htmlTemplate: HTMLTemplateElement,
{ state={}, processor=defaultProcessor }: CreateInstanceOptions={},
) {
const clonedTree = htmlTemplate.content.cloneNode(true)
clonedTree.normalize()
const parts: Array<TemplatePart> = []
const instance = new TemplateInstance(parts, processor)
instance.appendChild(clonedTree)
for (const currentNode of [...descendantNodes(instance)]) {
if (currentNode instanceof Text) {
const value = currentNode.data.trim()
const tokens = parseATemplateString(value)
if (tokens.length === 1 && tokens[0][0] === 'string') {
continue
}
const parentNode = currentNode.parentNode!
const nextSibling = currentNode.nextSibling
currentNode.remove()
for (const [tokenType, tokenValue] of tokens) {
if (tokenType === 'string') {
parentNode.insertBefore(new Text(tokenValue), nextSibling)
} else {
const anchorNode = new Anchor()
const nodePart = new NodeTemplatePart(tokenValue, anchorNode)
parts.push(nodePart)
parentNode.insertBefore(anchorNode, nextSibling)
}
}
} else if (currentNode instanceof HTMLTemplateElement) {
const anchor = new Anchor()
const parentNode = currentNode.parentNode!
const nextSibling = currentNode.nextSibling
currentNode.remove()
parentNode.insertBefore(anchor, nextSibling)
} else if (currentNode instanceof Element) {
for (const attribute of currentNode.attributes) {
const value = attribute.value.trim()
const tokens = parseATemplateString(value)
if (tokens.length === 1 && tokens[0][0] === 'string') {
continue
}
const partList: Array<string | AttributeTemplatePart> = []
for (const [tokenType, tokenValue] of tokens) {
if (tokenType === 'string') {
partList.push(tokenValue)
} else {
const attributePart = new AttributeTemplatePart({
expression: tokenValue,
element: currentNode,
attribute,
partList,
})
partList.push(attributePart)
parts.push(attributePart)
}
}
applyPartListToElement(currentNode, attribute, partList)
}
}
}
return instance
}