-
Notifications
You must be signed in to change notification settings - Fork 0
/
template.js
156 lines (123 loc) · 3.61 KB
/
template.js
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import { funcs } from './funcs.js'
export { GelPlate, GelPlates }
class GelPlate {
#tmpl = document.createElement('template')
get tmpl() {
return this.#tmpl
}
get setAttribute() {
return this.tmpl.setAttribute
}
get getAttribute() {
return this.tmpl.getAttribute
}
get hasAttribute() {
return this.tmpl.hasAttribute
}
get removeAttribute() {
return this.tmpl.removeAttribute
}
get content() {
return this.tmpl.content
}
get copy() {
return this.tmpl.content.cloneNode(true)
}
get innerHTML() {
return this.tmpl.content.innerHTML
}
set innerHTML(content) {
if (!content.length) {
return;
}
this.#tmpl.innerHTML = content
}
constructor(init, options) {
if (init && !(typeof init === 'function')) {
let str = init
init = ()=> str
}
this.generate = (...args)=> init(...args)
this.innerHTML = init ?
this.generate()
: '';
if (options?.constructor?.name === 'Object') {
writeAttrs.call(this, options)
}
}
}
// a template element that itself manages a collection of templates
class GelPlates extends GelPlate {
static templify(contents, opts) {
return funcs.templify(contents, opts)
}
constructor(initContent=null, keyProp='name') {
super()
this.keyProp = keyProp
if (initContent instanceof Element && initContent.localName === 'slot') {
this.absorbSlot(initContent)
}
else if (initContent) {
funcs.insertContent.call(this, initContent)
}
}
get list() {
return Array.from(this.content.querySelectorAll('template') ?? [])
}
get size() {
return this.content.querySelectorAll('template')?.length ?? 0
}
find(callback) {
return this.list.find(callback)
}
filter(callback) {
return this.list.filter(callback)
}
map(callback) {
return this.list.map(callback)
}
has(key) {
return this.get(key) != null
}
get(key) {
return this.content.querySelector(`template[${this.keyProp}="${key}"]`)
}
add(content) {
this.content.appendChild(GelPlates.templify(content))
}
remove(key) {
this.get(key)?.remove()
}
// this method takes all of the template elements assigned to a particular
// slot, and clones them over into our GelPlates instance, removing the
// original template elements in the transcluded light DOM
// This provides a way for components to select from a number of different
// templates provided by the user via slotting template element markup
absorbSlot(slotEl) {
slotEl.assignedElements().forEach(el=> {
if (el.localName === 'template') {
this.add(el.cloneNode(true))
}
el.remove()
})
}
// replace a template entry that matches string key
// with a new entry 'newval'
replace(key, newval) {
const old = this.get(key)
this.content.insertBefore(newval, old)
requestAnimationFrame(()=> old.remove());
}
// search the indicated template for a template w/ attr 'attr' of value 'val'
search(hostTmpl, attr, val) {
if (!(hostTmpl instanceof HTMLTemplateElement)) {
hostTmpl = this.get(hostTmpl);
}
if (!hostTmpl) {
return null
}
return Array.from(
hostTmpl.content.querySelectorAll(`[${attr}="${val}"]`)
)
}
}