mi-element 0.9.3 → 0.9.5
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/dist/html.js +36 -24
- package/package.json +1 -1
- package/src/html.js +48 -26
- package/types/html.d.ts +1 -1
package/dist/html.js
CHANGED
|
@@ -33,9 +33,10 @@ const unsafeHtml = str => new UnsafeHtml(str), escMap = {
|
|
|
33
33
|
'>': '>',
|
|
34
34
|
'"': '"',
|
|
35
35
|
"'": '''
|
|
36
|
-
}, esc = string => string.replace(
|
|
36
|
+
}, escRe = /[&<>"']/g, esc = string => string.replace(escRe, tag => escMap[tag]), escHtml = string => string instanceof UnsafeHtml ? string : unsafeHtml(esc('' + string)), escValue = any => {
|
|
37
37
|
if (any instanceof UnsafeHtml) return any;
|
|
38
|
-
|
|
38
|
+
const t = typeof any;
|
|
39
|
+
if ("object" === t || "function" === t) {
|
|
39
40
|
const key = globalRenderCache.set(any);
|
|
40
41
|
return unsafeHtml(key);
|
|
41
42
|
}
|
|
@@ -45,33 +46,44 @@ const unsafeHtml = str => new UnsafeHtml(str), escMap = {
|
|
|
45
46
|
}, ...values.map(val => Array.isArray(val) ? val.map(escValue).join('') : escValue(val))));
|
|
46
47
|
|
|
47
48
|
function render(node, template, handlers = {}) {
|
|
48
|
-
const refs = {}
|
|
49
|
-
|
|
50
|
-
for (let
|
|
51
|
-
node.appendChild(child);
|
|
49
|
+
const refs = {};
|
|
50
|
+
node.innerHTML = template.toString();
|
|
51
|
+
for (let i = 0, l = node.children.length; i < l; i++) renderAttrs(node.children[i], handlers, refs);
|
|
52
52
|
return refs;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const REF = 'ref', REF_Q = '[ref]';
|
|
56
|
+
|
|
55
57
|
function renderAttrs(node, handlers = {}, refs = {}) {
|
|
56
|
-
if (node.nodeType === Node.ELEMENT_NODE)
|
|
57
|
-
const
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
59
|
+
const rmAttrs = [], attrs = node.attributes;
|
|
60
|
+
for (let i = 0, l = attrs.length; i < l; i++) {
|
|
61
|
+
const attr = attrs[i], attrName = attr.name, code = attrName.charCodeAt(0), name = attrName.slice(1);
|
|
62
|
+
let rm = 0;
|
|
63
|
+
if (63 === code) toJson(attr.value) ? node.setAttribute(name, '') : node.removeAttribute(name),
|
|
64
|
+
rm = 1; else if ('...' === attr.name) {
|
|
65
|
+
const obj = globalRenderCache.get(attr.value);
|
|
66
|
+
if (obj && "object" == typeof obj) for (const [k, v] of Object.entries(obj)) node[k] = v;
|
|
67
|
+
rm = 1;
|
|
68
|
+
} else if (46 === code) node[name] = globalRenderCache.get(attr.value) ?? attr.value,
|
|
69
|
+
rm = 1; else if (64 === code) {
|
|
70
|
+
const handlerName = attr.value, fn = globalRenderCache.get(handlerName);
|
|
71
|
+
fn ? node.addEventListener(name, fn) : "function" == typeof handlers[handlerName] && node.addEventListener(name, handlers[handlerName]),
|
|
72
|
+
rm = 1;
|
|
73
|
+
} else attr.name === REF && (refs[attr.value] = node, rm = 1);
|
|
74
|
+
rm && rmAttrs.push(attr.name);
|
|
75
|
+
}
|
|
76
|
+
for (let i = 0, l = rmAttrs.length; i < l; i++) node.removeAttribute(rmAttrs[i]);
|
|
77
|
+
}
|
|
78
|
+
if (customElements.get(node.localName)) {
|
|
79
|
+
const q = node.querySelectorAll(REF_Q);
|
|
80
|
+
for (let el of q) {
|
|
81
|
+
const refName = el.getAttribute(REF);
|
|
82
|
+
refName && !refs[refName] && (refs[refName] = el);
|
|
83
|
+
}
|
|
84
|
+
return refs;
|
|
73
85
|
}
|
|
74
|
-
if (!node.children?.length
|
|
86
|
+
if (!node.children?.length) return refs;
|
|
75
87
|
for (let child of Array.from(node.children)) renderAttrs(child, handlers, refs);
|
|
76
88
|
return refs;
|
|
77
89
|
}
|
package/package.json
CHANGED
package/src/html.js
CHANGED
|
@@ -63,7 +63,9 @@ const escMap = {
|
|
|
63
63
|
"'": '''
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const
|
|
66
|
+
const escRe = /[&<>"']/g
|
|
67
|
+
|
|
68
|
+
const esc = (string) => string.replace(escRe, (tag) => escMap[tag])
|
|
67
69
|
|
|
68
70
|
/**
|
|
69
71
|
* escape HTML and prevent double escaping of '&'
|
|
@@ -77,6 +79,9 @@ export const escHtml = (string) =>
|
|
|
77
79
|
// @ts-expect-error
|
|
78
80
|
string instanceof UnsafeHtml ? string : unsafeHtml(esc('' + string))
|
|
79
81
|
|
|
82
|
+
const OBJECT = 'object'
|
|
83
|
+
const FUNCTION = 'function'
|
|
84
|
+
|
|
80
85
|
/**
|
|
81
86
|
* escape any value for HTML context; objects and functions are stored in the render cache
|
|
82
87
|
* @param {any} any
|
|
@@ -87,7 +92,8 @@ const escValue = (any) => {
|
|
|
87
92
|
// @ts-expect-error
|
|
88
93
|
return any
|
|
89
94
|
}
|
|
90
|
-
|
|
95
|
+
const t = typeof any
|
|
96
|
+
if (t === OBJECT || t === FUNCTION) {
|
|
91
97
|
const key = globalRenderCache.set(any)
|
|
92
98
|
return unsafeHtml(key)
|
|
93
99
|
}
|
|
@@ -117,25 +123,26 @@ export const html = (strings, ...values) =>
|
|
|
117
123
|
/**
|
|
118
124
|
* render HTML template into given node with support for special attributes
|
|
119
125
|
*
|
|
120
|
-
* @param {Element} node to
|
|
126
|
+
* @param {Element} node to render content
|
|
121
127
|
* @param {string|UnsafeHtml} template HTML template string
|
|
122
128
|
* @param {Record<string, Function>|HTMLElement} [handlers={}] event handlers or HTMLElement for method lookup
|
|
123
129
|
* @returns {Record<string, Element>} references collected
|
|
124
130
|
*/
|
|
125
131
|
export function render(node, template, handlers = {}) {
|
|
126
132
|
const refs = {}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
for (let child of Array.from(div.children)) {
|
|
133
|
+
node.innerHTML = template.toString()
|
|
134
|
+
for (let i = 0, l = node.children.length; i < l; i++) {
|
|
135
|
+
const child = node.children[i]
|
|
131
136
|
// @ts-expect-error
|
|
132
137
|
renderAttrs(child, handlers, refs)
|
|
133
|
-
node.appendChild(child)
|
|
134
138
|
}
|
|
135
139
|
// @ts-expect-error
|
|
136
140
|
return refs
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
const REF = 'ref'
|
|
144
|
+
const REF_Q = '[ref]'
|
|
145
|
+
|
|
139
146
|
/**
|
|
140
147
|
* Post-processing of rendered nodes to handle special attributes:
|
|
141
148
|
*
|
|
@@ -156,11 +163,15 @@ export function render(node, template, handlers = {}) {
|
|
|
156
163
|
*/
|
|
157
164
|
export function renderAttrs(node, handlers = {}, refs = {}) {
|
|
158
165
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
const rmAttrs = []
|
|
167
|
+
const attrs = node.attributes
|
|
168
|
+
for (let i = 0, l = attrs.length; i < l; i++) {
|
|
169
|
+
const attr = attrs[i]
|
|
170
|
+
const attrName = attr.name
|
|
171
|
+
const code = attrName.charCodeAt(0)
|
|
172
|
+
const name = attrName.slice(1)
|
|
162
173
|
let rm = 0
|
|
163
|
-
if (
|
|
174
|
+
if (code === 63 /* '?' */) {
|
|
164
175
|
// boolean attributes
|
|
165
176
|
if (toJson(attr.value)) {
|
|
166
177
|
node.setAttribute(name, '')
|
|
@@ -171,41 +182,52 @@ export function renderAttrs(node, handlers = {}, refs = {}) {
|
|
|
171
182
|
} else if (attr.name === '...') {
|
|
172
183
|
// spread attribute
|
|
173
184
|
const obj = globalRenderCache.get(attr.value)
|
|
174
|
-
if (obj && typeof obj ===
|
|
185
|
+
if (obj && typeof obj === OBJECT) {
|
|
175
186
|
for (const [k, v] of Object.entries(obj)) {
|
|
176
187
|
node[k] = v
|
|
177
188
|
}
|
|
178
189
|
}
|
|
179
190
|
rm = 1
|
|
180
|
-
} else if (
|
|
191
|
+
} else if (code === 46 /* '.' */) {
|
|
181
192
|
// property binding
|
|
182
193
|
node[name] = globalRenderCache.get(attr.value) ?? attr.value
|
|
183
194
|
rm = 1
|
|
184
|
-
} else if (
|
|
195
|
+
} else if (code === 64 /* '@' */) {
|
|
185
196
|
// event listener
|
|
186
197
|
const handlerName = attr.value
|
|
187
198
|
const fn = globalRenderCache.get(handlerName)
|
|
188
199
|
if (fn) {
|
|
189
|
-
node.addEventListener(name,
|
|
190
|
-
} else if (typeof handlers[handlerName] ===
|
|
191
|
-
node.addEventListener(name,
|
|
200
|
+
node.addEventListener(name, fn)
|
|
201
|
+
} else if (typeof handlers[handlerName] === FUNCTION) {
|
|
202
|
+
node.addEventListener(name, handlers[handlerName])
|
|
192
203
|
}
|
|
193
204
|
rm = 1
|
|
194
|
-
} else if (attr.name ===
|
|
205
|
+
} else if (attr.name === REF) {
|
|
195
206
|
// element reference - remove as well to prevent collection by other processors
|
|
196
|
-
|
|
197
|
-
refs[refName] = node
|
|
207
|
+
refs[attr.value] = node
|
|
198
208
|
rm = 1
|
|
199
209
|
}
|
|
200
210
|
if (rm) {
|
|
201
|
-
|
|
202
|
-
node.removeAttribute(attr.name)
|
|
203
|
-
})
|
|
211
|
+
rmAttrs.push(attr.name)
|
|
204
212
|
}
|
|
205
213
|
}
|
|
214
|
+
for (let i = 0, l = rmAttrs.length; i < l; i++) {
|
|
215
|
+
node.removeAttribute(rmAttrs[i])
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// early abort if custom element but resolve slotted refs
|
|
219
|
+
if (customElements.get(node.localName)) {
|
|
220
|
+
const q = node.querySelectorAll(REF_Q)
|
|
221
|
+
for (let el of q) {
|
|
222
|
+
const refName = el.getAttribute(REF)
|
|
223
|
+
if (refName && !refs[refName]) {
|
|
224
|
+
refs[refName] = el
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return refs
|
|
206
228
|
}
|
|
207
|
-
// early abort if no children
|
|
208
|
-
if (!node.children?.length
|
|
229
|
+
// early abort if no children
|
|
230
|
+
if (!node.children?.length) {
|
|
209
231
|
return refs
|
|
210
232
|
}
|
|
211
233
|
for (let child of Array.from(node.children)) {
|
package/types/html.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* render HTML template into given node with support for special attributes
|
|
3
3
|
*
|
|
4
|
-
* @param {Element} node to
|
|
4
|
+
* @param {Element} node to render content
|
|
5
5
|
* @param {string|UnsafeHtml} template HTML template string
|
|
6
6
|
* @param {Record<string, Function>|HTMLElement} [handlers={}] event handlers or HTMLElement for method lookup
|
|
7
7
|
* @returns {Record<string, Element>} references collected
|