-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathponys.js
81 lines (71 loc) · 2.04 KB
/
ponys.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
/* ponys v0.3.7
* 2024 jhuddle
*
* Declarative creation of browser-native web components.
*/
export default class {
static define(name, template, options, url = '')
{
if (!template.content) {
let templateElement = document.createElement('template');
templateElement.innerHTML = template;
template = templateElement;
}
template = template.content;
url = new URL(url, location.href);
let script = template.querySelector('script[setup]') || template.querySelector('script');
return import(
'data:text/javascript;base64,' + btoa(
script?.text?.replace(
/(import|from)\s*("|')(\.{0,2}\/.*?[^\\])\2/g, // relative imports
(match, keyword, quote, path) => keyword + quote + new URL(path, url) + quote
)
)
).then(module => {
script?.remove();
class Component extends (module.default || HTMLElement) {
constructor() {
super();
let root = this;
try { root = root.attachShadow({mode: 'open'}); } catch {}
this.$ = selector => root.querySelector(selector);
this.$$ = selector => root.querySelectorAll(selector);
let content = template.cloneNode(true);
propagateHost(this, content);
root.append(content);
}
}
customElements.define(name, Component, options);
return Component;
});
}
static defineAll(container = document)
{
return Promise.allSettled(
[...container.querySelectorAll('template[name]')].map(template => {
let options = {};
for (let {name, value} of template.attributes) {
options[name] = value;
}
return options.src?
this.import(options.name, options.src, options):
this.define(options.name, template, options);
})
);
}
static import(name, url, options)
{
return fetch(url)
.then(response => response.ok ? response.text() : Promise.reject(Error(url)))
.then(text => this.define(name, text, options, url));
}
}
function propagateHost(host, parentElement)
{
for (let element of parentElement.children) {
element.host = host;
element.$ = host.$;
element.$$ = host.$$;
propagateHost(host, element);
}
}