76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
const JST = {
|
|
|
|
_cachedTemplates: {},
|
|
|
|
_fetchTemplate: (name) => {
|
|
if (JST._cachedTemplates[name] !== undefined) {
|
|
return new Promise(resolve => resolve(JST._cachedTemplates[name]));
|
|
}
|
|
|
|
return fetch(`/templates/${name}.html`).then(resp => resp.text()).then(resp => {
|
|
const div = document.createElement("div");
|
|
div.innerHTML = resp;
|
|
const template = div.querySelector("template");
|
|
JST._cachedTemplates[name] = template;
|
|
return template;
|
|
});
|
|
},
|
|
|
|
// load returns a Promise for the template node
|
|
load: (templateName, visitedTemplates) => {
|
|
visitedTemplates = visitedTemplates ?? [];
|
|
|
|
const visited = visitedTemplates.includes(templateName);
|
|
visitedTemplates.push(templateName);
|
|
if (visited) {
|
|
const errorMsg = document.createElement("span");
|
|
errorMsg.textContent = `recursive templates: ${visitedTemplates.join(" → ")}`;
|
|
errorMsg.style.color = "red";
|
|
return new Promise(resolve => resolve(errorMsg));
|
|
}
|
|
|
|
return JST._fetchTemplate(templateName).then(template => {
|
|
const c = template.content.cloneNode(true);
|
|
JST.init(c, visitedTemplates);
|
|
return c;
|
|
});
|
|
},
|
|
|
|
// replaceElement replaces the given element with the template node
|
|
replaceElement: async (templateName, element) => {
|
|
await JST._replaceElement(templateName, element, []);
|
|
},
|
|
|
|
_replaceElement: async (templateName, element, visitedTemplates) => {
|
|
element.textContent = "";
|
|
await JST.load(templateName, visitedTemplates).then(node => element.replaceWith(node))
|
|
},
|
|
|
|
// replaceChildren removes all children in element and adds the template node
|
|
replaceChildren: async (templateName, element) => {
|
|
element = element ?? document.querySelector("main");
|
|
|
|
const node = await JST.load(templateName);
|
|
|
|
while (element.hasChildNodes()) {
|
|
element.removeChild(element.firstChild);
|
|
}
|
|
element.appendChild(node);
|
|
},
|
|
|
|
// append appends the template node to elements childrens
|
|
append: async (templateName, element) => {
|
|
element = element ?? document.querySelector("main");
|
|
const node = await JST.load(templateName);
|
|
element.appendChild(node);
|
|
},
|
|
|
|
init: (element, visitedTemplates) => {
|
|
element = element ?? document;
|
|
visitedTemplates = visitedTemplates ?? [];
|
|
element.querySelectorAll("jst-template").forEach(element => JST._replaceElement(element.textContent, element, visitedTemplates));
|
|
}
|
|
|
|
}
|
|
|
|
window.addEventListener("load", () => JST.init()); |