export abstract class TesoftComponent extends HTMLElement {
private ready: boolean;
protected constructor() {
super();
this.ready = false;
}
// noinspection JSUnusedGlobalSymbols
async connectedCallback() {
const promises = [];
for (const child of findComponents(this.shadowRoot)) {
promises.push(new Promise(resolve =>
window.customElements.whenDefined(child.tagName.toLowerCase()).then(() => {
if (child.isConnected) {
resolve(void {});
} else {
child.addEventListener("ready", (e: any) => {
e.preventDefault();
resolve(void {});
}, {once: true});
}
})
));
}
await Promise.all(promises);
await this.populate();
this.ready = true;
this.dispatchEvent(new CustomEvent("ready", {
bubbles: true,
cancelable: true,
}));
}
async populate() {
// Overwrite if necessary in components
}
get isReady(): boolean {
return this.ready;
}
}
function findComponents(root: any | null): TesoftComponent[] {
const components = [];
for (const child of root?.querySelectorAll("*") ?? []) {
if (child.tagName.toLowerCase().startsWith("snz-")) {
components.push(child);
}
}
return components;
}
export function onReady(callback: () => void, ...components: TesoftComponent[]) {
async function domLoaded() {
if (components.length === 0) {
components = findComponents(document);
}
const promises = [];
for (const component of components) {
if (!component.isReady) {
promises.push(new Promise(resolve => {
component.addEventListener("ready", resolve, {once: true});
}));
}
}
await Promise.all(promises);
callback();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", domLoaded, {once: true});
} else {
// noinspection JSIgnoredPromiseFromCall
domLoaded();
}
}