impress/app/assets/javascripts/outfit-viewer.js

60 lines
1.3 KiB
JavaScript
Raw Normal View History

class OutfitLayer extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
}
connectedCallback() {
setTimeout(() => this.#connectToChildren(), 0);
}
disconnectedCallback() {
window.removeEventListener("message", this.#onMessage);
}
#connectToChildren() {
const image = this.querySelector("img");
const iframe = this.querySelector("iframe");
if (image) {
image.addEventListener("load", () => this.#setStatus("loaded"));
image.addEventListener("error", () => this.#setStatus("error"));
this.#setStatus(image.complete ? "loaded" : "loading");
} else if (iframe) {
this.iframe = iframe;
window.addEventListener("message", (m) => this.#onMessage(m));
this.#setStatus("loading");
} else {
throw new Error(
`<outfit-layer> must contain an <img> or <iframe> tag`,
);
}
}
#onMessage({ source, data }) {
if (source !== this.iframe.contentWindow) {
return;
}
if (
data.type === "status" &&
["loaded", "error"].includes(data.status)
) {
this.#setStatus(data.status);
} else {
throw new Error(
`<outfit-layer> got unexpected message: ${JSON.stringify(data)}`,
);
}
}
#setStatus(newStatus) {
this.#internals.states.clear();
this.#internals.states.add(newStatus);
}
}
customElements.define("outfit-layer", OutfitLayer);