@oscarpalmer/atoms 0.68.0 → 0.69.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/dist/js/element/attribute.mjs +61 -0
- package/dist/js/element/index.js +59 -0
- package/dist/js/element/index.mjs +1 -0
- package/dist/js/html/index.js +124 -0
- package/dist/js/html/index.mjs +46 -0
- package/dist/js/html/sanitise.mjs +36 -0
- package/dist/js/index.js +134 -5
- package/dist/js/index.mjs +1 -0
- package/package.json +7 -1
- package/src/js/element/attribute.ts +99 -0
- package/src/js/element/index.ts +1 -0
- package/src/js/html/index.ts +99 -0
- package/src/js/html/sanitise.ts +66 -0
- package/src/js/index.ts +1 -0
- package/src/js/timer/is.ts +1 -0
- package/types/element/attribute.d.ts +26 -0
- package/types/element/index.d.ts +1 -0
- package/types/html/index.d.ts +15 -0
- package/types/html/sanitise.d.ts +12 -0
- package/types/index.d.cts +880 -349
- package/types/index.d.ts +1 -0
- package/types/timer/is.d.ts +1 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/js/element/attribute.ts
|
|
2
|
+
function isBadAttribute(name, value) {
|
|
3
|
+
return onPrefix.test(name) || sourcePrefix.test(name) && valuePrefix.test(value);
|
|
4
|
+
}
|
|
5
|
+
function isBooleanAttribute(name) {
|
|
6
|
+
return booleanAttributes.includes(name.toLowerCase());
|
|
7
|
+
}
|
|
8
|
+
function isEmptyNonBooleanAttribute(name, value) {
|
|
9
|
+
return !booleanAttributes.includes(name) && value.trim().length === 0;
|
|
10
|
+
}
|
|
11
|
+
function isInvalidBooleanAttribute(name, value) {
|
|
12
|
+
if (!booleanAttributes.includes(name)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
const normalised = value.toLowerCase().trim();
|
|
16
|
+
return !(normalised.length === 0 || normalised === name || name === "hidden" && normalised === "until-found");
|
|
17
|
+
}
|
|
18
|
+
function setAttribute(element, name, value) {
|
|
19
|
+
if (value == null) {
|
|
20
|
+
element.removeAttribute(name);
|
|
21
|
+
} else {
|
|
22
|
+
element.setAttribute(name, typeof value === "string" ? value : JSON.stringify(value));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var booleanAttributes = Object.freeze([
|
|
26
|
+
"async",
|
|
27
|
+
"autofocus",
|
|
28
|
+
"autoplay",
|
|
29
|
+
"checked",
|
|
30
|
+
"controls",
|
|
31
|
+
"default",
|
|
32
|
+
"defer",
|
|
33
|
+
"disabled",
|
|
34
|
+
"formnovalidate",
|
|
35
|
+
"hidden",
|
|
36
|
+
"inert",
|
|
37
|
+
"ismap",
|
|
38
|
+
"itemscope",
|
|
39
|
+
"loop",
|
|
40
|
+
"multiple",
|
|
41
|
+
"muted",
|
|
42
|
+
"nomodule",
|
|
43
|
+
"novalidate",
|
|
44
|
+
"open",
|
|
45
|
+
"playsinline",
|
|
46
|
+
"readonly",
|
|
47
|
+
"required",
|
|
48
|
+
"reversed",
|
|
49
|
+
"selected"
|
|
50
|
+
]);
|
|
51
|
+
var onPrefix = /^on/i;
|
|
52
|
+
var sourcePrefix = /^(href|src|xlink:href)$/i;
|
|
53
|
+
var valuePrefix = /(data:text\/html|javascript:)/i;
|
|
54
|
+
export {
|
|
55
|
+
setAttribute,
|
|
56
|
+
isInvalidBooleanAttribute,
|
|
57
|
+
isEmptyNonBooleanAttribute,
|
|
58
|
+
isBooleanAttribute,
|
|
59
|
+
isBadAttribute,
|
|
60
|
+
booleanAttributes
|
|
61
|
+
};
|
package/dist/js/element/index.js
CHANGED
|
@@ -17,6 +17,59 @@ function getTextDirection(element) {
|
|
|
17
17
|
return getComputedStyle?.(element)?.direction === "rtl" ? "rtl" : "ltr";
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// src/js/element/attribute.ts
|
|
21
|
+
function isBadAttribute(name, value) {
|
|
22
|
+
return onPrefix.test(name) || sourcePrefix.test(name) && valuePrefix.test(value);
|
|
23
|
+
}
|
|
24
|
+
function isBooleanAttribute(name) {
|
|
25
|
+
return booleanAttributes.includes(name.toLowerCase());
|
|
26
|
+
}
|
|
27
|
+
function isEmptyNonBooleanAttribute(name, value) {
|
|
28
|
+
return !booleanAttributes.includes(name) && value.trim().length === 0;
|
|
29
|
+
}
|
|
30
|
+
function isInvalidBooleanAttribute(name, value) {
|
|
31
|
+
if (!booleanAttributes.includes(name)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const normalised = value.toLowerCase().trim();
|
|
35
|
+
return !(normalised.length === 0 || normalised === name || name === "hidden" && normalised === "until-found");
|
|
36
|
+
}
|
|
37
|
+
function setAttribute(element, name, value) {
|
|
38
|
+
if (value == null) {
|
|
39
|
+
element.removeAttribute(name);
|
|
40
|
+
} else {
|
|
41
|
+
element.setAttribute(name, typeof value === "string" ? value : JSON.stringify(value));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
var booleanAttributes = Object.freeze([
|
|
45
|
+
"async",
|
|
46
|
+
"autofocus",
|
|
47
|
+
"autoplay",
|
|
48
|
+
"checked",
|
|
49
|
+
"controls",
|
|
50
|
+
"default",
|
|
51
|
+
"defer",
|
|
52
|
+
"disabled",
|
|
53
|
+
"formnovalidate",
|
|
54
|
+
"hidden",
|
|
55
|
+
"inert",
|
|
56
|
+
"ismap",
|
|
57
|
+
"itemscope",
|
|
58
|
+
"loop",
|
|
59
|
+
"multiple",
|
|
60
|
+
"muted",
|
|
61
|
+
"nomodule",
|
|
62
|
+
"novalidate",
|
|
63
|
+
"open",
|
|
64
|
+
"playsinline",
|
|
65
|
+
"readonly",
|
|
66
|
+
"required",
|
|
67
|
+
"reversed",
|
|
68
|
+
"selected"
|
|
69
|
+
]);
|
|
70
|
+
var onPrefix = /^on/i;
|
|
71
|
+
var sourcePrefix = /^(href|src|xlink:href)$/i;
|
|
72
|
+
var valuePrefix = /(data:text\/html|javascript:)/i;
|
|
20
73
|
// src/js/element/closest.ts
|
|
21
74
|
function calculateDistance(origin, target) {
|
|
22
75
|
if (origin === target || origin.parentElement === target) {
|
|
@@ -236,6 +289,11 @@ function updateStyleProperty(element, key, value2) {
|
|
|
236
289
|
export {
|
|
237
290
|
setStyles,
|
|
238
291
|
setData,
|
|
292
|
+
setAttribute,
|
|
293
|
+
isInvalidBooleanAttribute,
|
|
294
|
+
isEmptyNonBooleanAttribute,
|
|
295
|
+
isBooleanAttribute,
|
|
296
|
+
isBadAttribute,
|
|
239
297
|
getTextDirection,
|
|
240
298
|
getElementUnderPointer,
|
|
241
299
|
getData,
|
|
@@ -243,6 +301,7 @@ export {
|
|
|
243
301
|
findElements,
|
|
244
302
|
findElement,
|
|
245
303
|
closest,
|
|
304
|
+
booleanAttributes,
|
|
246
305
|
findElements as $$,
|
|
247
306
|
findElement as $
|
|
248
307
|
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// src/js/is.ts
|
|
2
|
+
function isPlainObject(value2) {
|
|
3
|
+
if (typeof value2 !== "object" || value2 === null) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const prototype = Object.getPrototypeOf(value2);
|
|
7
|
+
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value2) && !(Symbol.iterator in value2);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// src/js/element/attribute.ts
|
|
11
|
+
function isBadAttribute(name, value2) {
|
|
12
|
+
return onPrefix.test(name) || sourcePrefix.test(name) && valuePrefix.test(value2);
|
|
13
|
+
}
|
|
14
|
+
function isEmptyNonBooleanAttribute(name, value2) {
|
|
15
|
+
return !booleanAttributes.includes(name) && value2.trim().length === 0;
|
|
16
|
+
}
|
|
17
|
+
function isInvalidBooleanAttribute(name, value2) {
|
|
18
|
+
if (!booleanAttributes.includes(name)) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const normalised = value2.toLowerCase().trim();
|
|
22
|
+
return !(normalised.length === 0 || normalised === name || name === "hidden" && normalised === "until-found");
|
|
23
|
+
}
|
|
24
|
+
var booleanAttributes = Object.freeze([
|
|
25
|
+
"async",
|
|
26
|
+
"autofocus",
|
|
27
|
+
"autoplay",
|
|
28
|
+
"checked",
|
|
29
|
+
"controls",
|
|
30
|
+
"default",
|
|
31
|
+
"defer",
|
|
32
|
+
"disabled",
|
|
33
|
+
"formnovalidate",
|
|
34
|
+
"hidden",
|
|
35
|
+
"inert",
|
|
36
|
+
"ismap",
|
|
37
|
+
"itemscope",
|
|
38
|
+
"loop",
|
|
39
|
+
"multiple",
|
|
40
|
+
"muted",
|
|
41
|
+
"nomodule",
|
|
42
|
+
"novalidate",
|
|
43
|
+
"open",
|
|
44
|
+
"playsinline",
|
|
45
|
+
"readonly",
|
|
46
|
+
"required",
|
|
47
|
+
"reversed",
|
|
48
|
+
"selected"
|
|
49
|
+
]);
|
|
50
|
+
var onPrefix = /^on/i;
|
|
51
|
+
var sourcePrefix = /^(href|src|xlink:href)$/i;
|
|
52
|
+
var valuePrefix = /(data:text\/html|javascript:)/i;
|
|
53
|
+
// src/js/html/sanitise.ts
|
|
54
|
+
function sanitise(value2, options) {
|
|
55
|
+
return sanitiseNodes(Array.isArray(value2) ? value2 : [value2], {
|
|
56
|
+
sanitiseBooleanAttributes: options?.sanitiseBooleanAttributes ?? true
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function sanitiseAttributes(element2, attributes, options) {
|
|
60
|
+
const { length } = attributes;
|
|
61
|
+
for (let index = 0;index < length; index += 1) {
|
|
62
|
+
const { name, value: value2 } = attributes[index];
|
|
63
|
+
if (isBadAttribute(name, value2) || isEmptyNonBooleanAttribute(name, value2)) {
|
|
64
|
+
element2.removeAttribute(name);
|
|
65
|
+
} else if (options.sanitiseBooleanAttributes && isInvalidBooleanAttribute(name, value2)) {
|
|
66
|
+
element2.setAttribute(name, "");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function sanitiseNodes(nodes, options) {
|
|
71
|
+
const { length } = nodes;
|
|
72
|
+
for (let index = 0;index < length; index += 1) {
|
|
73
|
+
const node = nodes[index];
|
|
74
|
+
if (node instanceof Element) {
|
|
75
|
+
sanitiseAttributes(node, [...node.attributes], options);
|
|
76
|
+
}
|
|
77
|
+
sanitiseNodes([...node.childNodes], options);
|
|
78
|
+
}
|
|
79
|
+
return nodes;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/js/html/index.ts
|
|
83
|
+
function createTemplate(html) {
|
|
84
|
+
const template2 = document.createElement("template");
|
|
85
|
+
template2.innerHTML = html;
|
|
86
|
+
templates[html] = template2;
|
|
87
|
+
return template2;
|
|
88
|
+
}
|
|
89
|
+
function getNodes(node) {
|
|
90
|
+
return /^documentfragment$/i.test(node.constructor.name) ? [...node.childNodes] : [node];
|
|
91
|
+
}
|
|
92
|
+
function getTemplate(value2) {
|
|
93
|
+
if (value2.trim().length === 0) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
let template2;
|
|
97
|
+
if (/^[\w-]+$/.test(value2)) {
|
|
98
|
+
template2 = document.querySelector(`#${value2}`);
|
|
99
|
+
}
|
|
100
|
+
if (template2 instanceof HTMLTemplateElement) {
|
|
101
|
+
return template2;
|
|
102
|
+
}
|
|
103
|
+
return templates[value2] ?? createTemplate(value2);
|
|
104
|
+
}
|
|
105
|
+
function html(value2, sanitisation) {
|
|
106
|
+
const options = sanitisation == null || sanitisation === true ? {} : isPlainObject(sanitisation) ? { ...sanitisation } : null;
|
|
107
|
+
const template2 = value2 instanceof HTMLTemplateElement ? value2 : typeof value2 === "string" ? getTemplate(value2) : null;
|
|
108
|
+
if (template2 == null) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
const cloned = template2.content.cloneNode(true);
|
|
112
|
+
const scripts = cloned.querySelectorAll("script");
|
|
113
|
+
const { length } = scripts;
|
|
114
|
+
for (let index = 0;index < length; index += 1) {
|
|
115
|
+
scripts[index].remove();
|
|
116
|
+
}
|
|
117
|
+
cloned.normalize();
|
|
118
|
+
return options != null ? sanitise(getNodes(cloned), options) : getNodes(cloned);
|
|
119
|
+
}
|
|
120
|
+
var templates = {};
|
|
121
|
+
export {
|
|
122
|
+
sanitise,
|
|
123
|
+
html
|
|
124
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/js/html/index.ts
|
|
2
|
+
import {isPlainObject} from "../is";
|
|
3
|
+
import {sanitise as sanitise2} from "./sanitise";
|
|
4
|
+
function createTemplate(html) {
|
|
5
|
+
const template = document.createElement("template");
|
|
6
|
+
template.innerHTML = html;
|
|
7
|
+
templates[html] = template;
|
|
8
|
+
return template;
|
|
9
|
+
}
|
|
10
|
+
function getNodes(node) {
|
|
11
|
+
return /^documentfragment$/i.test(node.constructor.name) ? [...node.childNodes] : [node];
|
|
12
|
+
}
|
|
13
|
+
function getTemplate(value) {
|
|
14
|
+
if (value.trim().length === 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let template;
|
|
18
|
+
if (/^[\w-]+$/.test(value)) {
|
|
19
|
+
template = document.querySelector(`#${value}`);
|
|
20
|
+
}
|
|
21
|
+
if (template instanceof HTMLTemplateElement) {
|
|
22
|
+
return template;
|
|
23
|
+
}
|
|
24
|
+
return templates[value] ?? createTemplate(value);
|
|
25
|
+
}
|
|
26
|
+
function html(value, sanitisation) {
|
|
27
|
+
const options = sanitisation == null || sanitisation === true ? {} : isPlainObject(sanitisation) ? { ...sanitisation } : null;
|
|
28
|
+
const template = value instanceof HTMLTemplateElement ? value : typeof value === "string" ? getTemplate(value) : null;
|
|
29
|
+
if (template == null) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const cloned = template.content.cloneNode(true);
|
|
33
|
+
const scripts = cloned.querySelectorAll("script");
|
|
34
|
+
const { length } = scripts;
|
|
35
|
+
for (let index = 0;index < length; index += 1) {
|
|
36
|
+
scripts[index].remove();
|
|
37
|
+
}
|
|
38
|
+
cloned.normalize();
|
|
39
|
+
return options != null ? sanitise2(getNodes(cloned), options) : getNodes(cloned);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export * from "./sanitise";
|
|
43
|
+
var templates = {};
|
|
44
|
+
export {
|
|
45
|
+
html
|
|
46
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/js/html/sanitise.ts
|
|
2
|
+
import {
|
|
3
|
+
isBadAttribute,
|
|
4
|
+
isEmptyNonBooleanAttribute,
|
|
5
|
+
isInvalidBooleanAttribute
|
|
6
|
+
} from "../element";
|
|
7
|
+
function sanitise(value, options) {
|
|
8
|
+
return sanitiseNodes(Array.isArray(value) ? value : [value], {
|
|
9
|
+
sanitiseBooleanAttributes: options?.sanitiseBooleanAttributes ?? true
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function sanitiseAttributes(element2, attributes, options) {
|
|
13
|
+
const { length } = attributes;
|
|
14
|
+
for (let index = 0;index < length; index += 1) {
|
|
15
|
+
const { name, value } = attributes[index];
|
|
16
|
+
if (isBadAttribute(name, value) || isEmptyNonBooleanAttribute(name, value)) {
|
|
17
|
+
element2.removeAttribute(name);
|
|
18
|
+
} else if (options.sanitiseBooleanAttributes && isInvalidBooleanAttribute(name, value)) {
|
|
19
|
+
element2.setAttribute(name, "");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function sanitiseNodes(nodes, options) {
|
|
24
|
+
const { length } = nodes;
|
|
25
|
+
for (let index = 0;index < length; index += 1) {
|
|
26
|
+
const node = nodes[index];
|
|
27
|
+
if (node instanceof Element) {
|
|
28
|
+
sanitiseAttributes(node, [...node.attributes], options);
|
|
29
|
+
}
|
|
30
|
+
sanitiseNodes([...node.childNodes], options);
|
|
31
|
+
}
|
|
32
|
+
return nodes;
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
sanitise
|
|
36
|
+
};
|
package/dist/js/index.js
CHANGED
|
@@ -1271,6 +1271,59 @@ function getTextDirection(element) {
|
|
|
1271
1271
|
return getComputedStyle?.(element)?.direction === "rtl" ? "rtl" : "ltr";
|
|
1272
1272
|
}
|
|
1273
1273
|
|
|
1274
|
+
// src/js/element/attribute.ts
|
|
1275
|
+
function isBadAttribute(name, value2) {
|
|
1276
|
+
return onPrefix.test(name) || sourcePrefix.test(name) && valuePrefix.test(value2);
|
|
1277
|
+
}
|
|
1278
|
+
function isBooleanAttribute(name) {
|
|
1279
|
+
return booleanAttributes.includes(name.toLowerCase());
|
|
1280
|
+
}
|
|
1281
|
+
function isEmptyNonBooleanAttribute(name, value2) {
|
|
1282
|
+
return !booleanAttributes.includes(name) && value2.trim().length === 0;
|
|
1283
|
+
}
|
|
1284
|
+
function isInvalidBooleanAttribute(name, value2) {
|
|
1285
|
+
if (!booleanAttributes.includes(name)) {
|
|
1286
|
+
return true;
|
|
1287
|
+
}
|
|
1288
|
+
const normalised = value2.toLowerCase().trim();
|
|
1289
|
+
return !(normalised.length === 0 || normalised === name || name === "hidden" && normalised === "until-found");
|
|
1290
|
+
}
|
|
1291
|
+
function setAttribute(element, name, value2) {
|
|
1292
|
+
if (value2 == null) {
|
|
1293
|
+
element.removeAttribute(name);
|
|
1294
|
+
} else {
|
|
1295
|
+
element.setAttribute(name, typeof value2 === "string" ? value2 : JSON.stringify(value2));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
var booleanAttributes = Object.freeze([
|
|
1299
|
+
"async",
|
|
1300
|
+
"autofocus",
|
|
1301
|
+
"autoplay",
|
|
1302
|
+
"checked",
|
|
1303
|
+
"controls",
|
|
1304
|
+
"default",
|
|
1305
|
+
"defer",
|
|
1306
|
+
"disabled",
|
|
1307
|
+
"formnovalidate",
|
|
1308
|
+
"hidden",
|
|
1309
|
+
"inert",
|
|
1310
|
+
"ismap",
|
|
1311
|
+
"itemscope",
|
|
1312
|
+
"loop",
|
|
1313
|
+
"multiple",
|
|
1314
|
+
"muted",
|
|
1315
|
+
"nomodule",
|
|
1316
|
+
"novalidate",
|
|
1317
|
+
"open",
|
|
1318
|
+
"playsinline",
|
|
1319
|
+
"readonly",
|
|
1320
|
+
"required",
|
|
1321
|
+
"reversed",
|
|
1322
|
+
"selected"
|
|
1323
|
+
]);
|
|
1324
|
+
var onPrefix = /^on/i;
|
|
1325
|
+
var sourcePrefix = /^(href|src|xlink:href)$/i;
|
|
1326
|
+
var valuePrefix = /(data:text\/html|javascript:)/i;
|
|
1274
1327
|
// src/js/element/closest.ts
|
|
1275
1328
|
function calculateDistance(origin, target) {
|
|
1276
1329
|
if (origin === target || origin.parentElement === target) {
|
|
@@ -1657,6 +1710,74 @@ function getPosition(event) {
|
|
|
1657
1710
|
}
|
|
1658
1711
|
return typeof x === "number" && typeof y === "number" ? { x, y } : undefined;
|
|
1659
1712
|
}
|
|
1713
|
+
// src/js/html/sanitise.ts
|
|
1714
|
+
function sanitise(value2, options) {
|
|
1715
|
+
return sanitiseNodes(Array.isArray(value2) ? value2 : [value2], {
|
|
1716
|
+
sanitiseBooleanAttributes: options?.sanitiseBooleanAttributes ?? true
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
function sanitiseAttributes(element2, attributes, options) {
|
|
1720
|
+
const { length } = attributes;
|
|
1721
|
+
for (let index = 0;index < length; index += 1) {
|
|
1722
|
+
const { name, value: value2 } = attributes[index];
|
|
1723
|
+
if (isBadAttribute(name, value2) || isEmptyNonBooleanAttribute(name, value2)) {
|
|
1724
|
+
element2.removeAttribute(name);
|
|
1725
|
+
} else if (options.sanitiseBooleanAttributes && isInvalidBooleanAttribute(name, value2)) {
|
|
1726
|
+
element2.setAttribute(name, "");
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
function sanitiseNodes(nodes, options) {
|
|
1731
|
+
const { length } = nodes;
|
|
1732
|
+
for (let index = 0;index < length; index += 1) {
|
|
1733
|
+
const node = nodes[index];
|
|
1734
|
+
if (node instanceof Element) {
|
|
1735
|
+
sanitiseAttributes(node, [...node.attributes], options);
|
|
1736
|
+
}
|
|
1737
|
+
sanitiseNodes([...node.childNodes], options);
|
|
1738
|
+
}
|
|
1739
|
+
return nodes;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// src/js/html/index.ts
|
|
1743
|
+
function createTemplate(html) {
|
|
1744
|
+
const template3 = document.createElement("template");
|
|
1745
|
+
template3.innerHTML = html;
|
|
1746
|
+
templates[html] = template3;
|
|
1747
|
+
return template3;
|
|
1748
|
+
}
|
|
1749
|
+
function getNodes(node) {
|
|
1750
|
+
return /^documentfragment$/i.test(node.constructor.name) ? [...node.childNodes] : [node];
|
|
1751
|
+
}
|
|
1752
|
+
function getTemplate(value2) {
|
|
1753
|
+
if (value2.trim().length === 0) {
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
let template3;
|
|
1757
|
+
if (/^[\w-]+$/.test(value2)) {
|
|
1758
|
+
template3 = document.querySelector(`#${value2}`);
|
|
1759
|
+
}
|
|
1760
|
+
if (template3 instanceof HTMLTemplateElement) {
|
|
1761
|
+
return template3;
|
|
1762
|
+
}
|
|
1763
|
+
return templates[value2] ?? createTemplate(value2);
|
|
1764
|
+
}
|
|
1765
|
+
function html(value2, sanitisation) {
|
|
1766
|
+
const options = sanitisation == null || sanitisation === true ? {} : isPlainObject(sanitisation) ? { ...sanitisation } : null;
|
|
1767
|
+
const template3 = value2 instanceof HTMLTemplateElement ? value2 : typeof value2 === "string" ? getTemplate(value2) : null;
|
|
1768
|
+
if (template3 == null) {
|
|
1769
|
+
return [];
|
|
1770
|
+
}
|
|
1771
|
+
const cloned = template3.content.cloneNode(true);
|
|
1772
|
+
const scripts = cloned.querySelectorAll("script");
|
|
1773
|
+
const { length } = scripts;
|
|
1774
|
+
for (let index = 0;index < length; index += 1) {
|
|
1775
|
+
scripts[index].remove();
|
|
1776
|
+
}
|
|
1777
|
+
cloned.normalize();
|
|
1778
|
+
return options != null ? sanitise(getNodes(cloned), options) : getNodes(cloned);
|
|
1779
|
+
}
|
|
1780
|
+
var templates = {};
|
|
1660
1781
|
// src/js/logger.ts
|
|
1661
1782
|
if (globalThis._atomic_logging == null) {
|
|
1662
1783
|
globalThis._atomic_logging = true;
|
|
@@ -1998,20 +2119,20 @@ function delay(time, timeout) {
|
|
|
1998
2119
|
}
|
|
1999
2120
|
|
|
2000
2121
|
// src/js/timer/is.ts
|
|
2001
|
-
function
|
|
2122
|
+
function is12(pattern, value3) {
|
|
2002
2123
|
return pattern.test(value3?.$timer);
|
|
2003
2124
|
}
|
|
2004
2125
|
function isRepeated(value3) {
|
|
2005
|
-
return
|
|
2126
|
+
return is12(/^repeat$/, value3);
|
|
2006
2127
|
}
|
|
2007
2128
|
function isTimer(value3) {
|
|
2008
|
-
return
|
|
2129
|
+
return is12(/^repeat|wait$/, value3);
|
|
2009
2130
|
}
|
|
2010
2131
|
function isWaited(value3) {
|
|
2011
|
-
return
|
|
2132
|
+
return is12(/^wait$/, value3);
|
|
2012
2133
|
}
|
|
2013
2134
|
function isWhen(value3) {
|
|
2014
|
-
return
|
|
2135
|
+
return is12(/^when$/, value3) && typeof value3.then === "function";
|
|
2015
2136
|
}
|
|
2016
2137
|
// src/js/timer/when.ts
|
|
2017
2138
|
function when(condition, options) {
|
|
@@ -2138,6 +2259,8 @@ export {
|
|
|
2138
2259
|
setValue,
|
|
2139
2260
|
setStyles,
|
|
2140
2261
|
setData,
|
|
2262
|
+
setAttribute,
|
|
2263
|
+
sanitise,
|
|
2141
2264
|
round,
|
|
2142
2265
|
repeat,
|
|
2143
2266
|
queue,
|
|
@@ -2168,14 +2291,19 @@ export {
|
|
|
2168
2291
|
isNullableOrEmpty,
|
|
2169
2292
|
isNullable,
|
|
2170
2293
|
isKey,
|
|
2294
|
+
isInvalidBooleanAttribute,
|
|
2171
2295
|
isHexColour,
|
|
2172
2296
|
isHSLColour,
|
|
2173
2297
|
isFocusableElement,
|
|
2298
|
+
isEmptyNonBooleanAttribute,
|
|
2174
2299
|
isEmpty,
|
|
2175
2300
|
isColour,
|
|
2301
|
+
isBooleanAttribute,
|
|
2302
|
+
isBadAttribute,
|
|
2176
2303
|
isArrayOrPlainObject,
|
|
2177
2304
|
insert,
|
|
2178
2305
|
indexOf,
|
|
2306
|
+
html,
|
|
2179
2307
|
groupBy,
|
|
2180
2308
|
getValue,
|
|
2181
2309
|
getTextDirection,
|
|
@@ -2221,6 +2349,7 @@ export {
|
|
|
2221
2349
|
chunk,
|
|
2222
2350
|
capitalise,
|
|
2223
2351
|
camelCase,
|
|
2352
|
+
booleanAttributes,
|
|
2224
2353
|
between,
|
|
2225
2354
|
average,
|
|
2226
2355
|
RGBColour,
|
package/dist/js/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -82,6 +82,12 @@
|
|
|
82
82
|
"import": "./dist/js/function.mjs",
|
|
83
83
|
"require": "./dist/js/function.js"
|
|
84
84
|
},
|
|
85
|
+
"./html": {
|
|
86
|
+
"types": "./types/html/index.d.ts",
|
|
87
|
+
"bun": "./src/js/html/index.ts",
|
|
88
|
+
"import": "./dist/js/html/index.mjs",
|
|
89
|
+
"require": "./dist/js/html/index.js"
|
|
90
|
+
},
|
|
85
91
|
"./is": {
|
|
86
92
|
"types": "./types/is.d.ts",
|
|
87
93
|
"bun": "./src/js/is.ts",
|
|
@@ -186,5 +192,5 @@
|
|
|
186
192
|
},
|
|
187
193
|
"type": "module",
|
|
188
194
|
"types": "./types/index.d.cts",
|
|
189
|
-
"version": "0.
|
|
195
|
+
"version": "0.69.0"
|
|
190
196
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List of boolean attributes
|
|
3
|
+
*/
|
|
4
|
+
export const booleanAttributes = Object.freeze([
|
|
5
|
+
'async',
|
|
6
|
+
'autofocus',
|
|
7
|
+
'autoplay',
|
|
8
|
+
'checked',
|
|
9
|
+
'controls',
|
|
10
|
+
'default',
|
|
11
|
+
'defer',
|
|
12
|
+
'disabled',
|
|
13
|
+
'formnovalidate',
|
|
14
|
+
'hidden',
|
|
15
|
+
'inert',
|
|
16
|
+
'ismap',
|
|
17
|
+
'itemscope',
|
|
18
|
+
'loop',
|
|
19
|
+
'multiple',
|
|
20
|
+
'muted',
|
|
21
|
+
'nomodule',
|
|
22
|
+
'novalidate',
|
|
23
|
+
'open',
|
|
24
|
+
'playsinline',
|
|
25
|
+
'readonly',
|
|
26
|
+
'required',
|
|
27
|
+
'reversed',
|
|
28
|
+
'selected',
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const onPrefix = /^on/i;
|
|
32
|
+
const sourcePrefix = /^(href|src|xlink:href)$/i;
|
|
33
|
+
const valuePrefix = /(data:text\/html|javascript:)/i;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Is the attribute considered bad and potentially harmful?
|
|
37
|
+
*/
|
|
38
|
+
export function isBadAttribute(name: string, value: string): boolean {
|
|
39
|
+
return (
|
|
40
|
+
onPrefix.test(name) || (sourcePrefix.test(name) && valuePrefix.test(value))
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Is the attribute a boolean attribute?
|
|
46
|
+
*/
|
|
47
|
+
export function isBooleanAttribute(name: string): boolean {
|
|
48
|
+
return booleanAttributes.includes(name.toLowerCase());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Is the attribute empty and not a boolean attribute?
|
|
53
|
+
*/
|
|
54
|
+
export function isEmptyNonBooleanAttribute(
|
|
55
|
+
name: string,
|
|
56
|
+
value: string,
|
|
57
|
+
): boolean {
|
|
58
|
+
return !booleanAttributes.includes(name) && value.trim().length === 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* - Is the attribute an invalid boolean attribute?
|
|
63
|
+
* - I.e., its value is not empty or the same as its name?
|
|
64
|
+
*/
|
|
65
|
+
export function isInvalidBooleanAttribute(
|
|
66
|
+
name: string,
|
|
67
|
+
value: string,
|
|
68
|
+
): boolean {
|
|
69
|
+
if (!booleanAttributes.includes(name)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const normalised = value.toLowerCase().trim();
|
|
74
|
+
|
|
75
|
+
return !(
|
|
76
|
+
normalised.length === 0 ||
|
|
77
|
+
normalised === name ||
|
|
78
|
+
(name === 'hidden' && normalised === 'until-found')
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* - Sets an attribute for an element
|
|
84
|
+
* - If the value is nullable, the attribute is removed
|
|
85
|
+
*/
|
|
86
|
+
export function setAttribute(
|
|
87
|
+
element: Element,
|
|
88
|
+
name: string,
|
|
89
|
+
value: unknown,
|
|
90
|
+
): void {
|
|
91
|
+
if (value == null) {
|
|
92
|
+
element.removeAttribute(name);
|
|
93
|
+
} else {
|
|
94
|
+
element.setAttribute(
|
|
95
|
+
name,
|
|
96
|
+
typeof value === 'string' ? value : JSON.stringify(value),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|