Potentially improve loading state in new item page preview
I thiiiink I've seen the status of a movie `<outfit-layer>` sometimes be `loading` even when it's clearly already loaded and running. I haven't been able to track down where and how that happens exactly, so this is me acting on a hunch: that maybe the I-would-have-thought-very-unlikely event that the iframe finishes loading before the `<outfit-layer>` connects with its children maybe happens more often than one might think! In this change, we set up the iframe to receive `requestStatus` messages, which it responds to with the status immediately. And we send one of these when the `<outfit-layer>` first discovers the iframe. Fingers crossed!
This commit is contained in:
parent
b03fee8c7e
commit
20202b5cd9
2 changed files with 43 additions and 22 deletions
|
@ -71,11 +71,11 @@ class OutfitLayer extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
play() {
|
play() {
|
||||||
this.#forwardIsPlaying(true);
|
this.#sendMessageToIframe({ type: "play" });
|
||||||
}
|
}
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
this.#forwardIsPlaying(false);
|
this.#sendMessageToIframe({ type: "pause" });
|
||||||
}
|
}
|
||||||
|
|
||||||
#connectToChildren() {
|
#connectToChildren() {
|
||||||
|
@ -83,14 +83,23 @@ class OutfitLayer extends HTMLElement {
|
||||||
const iframe = this.querySelector("iframe");
|
const iframe = this.querySelector("iframe");
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
|
// Initialize status based on the image's current `complete` attribute,
|
||||||
|
// then wait for load/error events to update it further if needed.
|
||||||
|
this.#setStatus(image.complete ? "loaded" : "loading");
|
||||||
image.addEventListener("load", () => this.#setStatus("loaded"));
|
image.addEventListener("load", () => this.#setStatus("loaded"));
|
||||||
image.addEventListener("error", () => this.#setStatus("error"));
|
image.addEventListener("error", () => this.#setStatus("error"));
|
||||||
this.#setStatus(image.complete ? "loaded" : "loading");
|
|
||||||
} else if (iframe) {
|
} else if (iframe) {
|
||||||
this.iframe = iframe;
|
this.iframe = iframe;
|
||||||
|
|
||||||
|
// Initialize status to `loading`, and asynchronously request a status
|
||||||
|
// message from the iframe if it managed to load before this triggers
|
||||||
|
// (impressive, but I think I've seen it happen!). Then, wait for
|
||||||
|
// messages or error events from the iframe to update status further if
|
||||||
|
// needed.
|
||||||
|
this.#setStatus("loading");
|
||||||
|
this.#sendMessageToIframe({ type: "requestStatus" });
|
||||||
window.addEventListener("message", (m) => this.#onMessage(m));
|
window.addEventListener("message", (m) => this.#onMessage(m));
|
||||||
this.iframe.addEventListener("error", () => this.#setStatus("error"));
|
this.iframe.addEventListener("error", () => this.#setStatus("error"));
|
||||||
this.#setStatus("loading");
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`<outfit-layer> must contain an <img> or <iframe> tag`);
|
throw new Error(`<outfit-layer> must contain an <img> or <iframe> tag`);
|
||||||
}
|
}
|
||||||
|
@ -134,15 +143,13 @@ class OutfitLayer extends HTMLElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#forwardIsPlaying(isPlaying) {
|
#sendMessageToIframe(message) {
|
||||||
if (this.iframe == null) {
|
if (this.iframe?.contentWindow == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.iframe.contentWindow.postMessage(
|
// The frame is sandboxed (origin == null), so send to Any origin.
|
||||||
{ type: isPlaying ? "play" : "pause" },
|
this.iframe.contentWindow.postMessage(message, "*");
|
||||||
"*", // The frame is sandboxed (origin == null), so send to Any origin.
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,28 @@ function hasAnimations(createjsNode) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendStatus() {
|
||||||
|
if (loadingStatus === "loading") {
|
||||||
|
sendMessage({ type: "status", status: "loading" });
|
||||||
|
} else if (loadingStatus === "loaded") {
|
||||||
|
sendMessage({
|
||||||
|
type: "status",
|
||||||
|
status: "loaded",
|
||||||
|
hasAnimations: hasAnimations(movieClip),
|
||||||
|
});
|
||||||
|
} else if (loadingStatus === "error") {
|
||||||
|
sendMessage({ type: "status", status: "error" });
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`unexpected loadingStatus ${JSON.stringify(loadingStatus)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage(message) {
|
||||||
|
parent.postMessage(message, document.location.origin);
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
updateCanvasDimensions();
|
updateCanvasDimensions();
|
||||||
|
|
||||||
|
@ -310,6 +332,8 @@ window.addEventListener("message", ({ data }) => {
|
||||||
play();
|
play();
|
||||||
} else if (data.type === "pause") {
|
} else if (data.type === "pause") {
|
||||||
pause();
|
pause();
|
||||||
|
} else if (data.type === "requestStatus") {
|
||||||
|
sendStatus();
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`unexpected message: ${JSON.stringify(data)}`);
|
throw new Error(`unexpected message: ${JSON.stringify(data)}`);
|
||||||
}
|
}
|
||||||
|
@ -317,23 +341,13 @@ window.addEventListener("message", ({ data }) => {
|
||||||
|
|
||||||
startMovie()
|
startMovie()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
parent.postMessage(
|
sendStatus();
|
||||||
{
|
|
||||||
type: "status",
|
|
||||||
status: "loaded",
|
|
||||||
hasAnimations: hasAnimations(movieClip),
|
|
||||||
},
|
|
||||||
document.location.origin,
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(logPrefix, error);
|
console.error(logPrefix, error);
|
||||||
|
|
||||||
loadingStatus = "error";
|
loadingStatus = "error";
|
||||||
parent.postMessage(
|
sendStatus();
|
||||||
{ type: "status", status: "error" },
|
|
||||||
document.location.origin,
|
|
||||||
);
|
|
||||||
|
|
||||||
// If loading the movie fails, show the fallback image instead, by moving
|
// If loading the movie fails, show the fallback image instead, by moving
|
||||||
// it out of the canvas content and into the body.
|
// it out of the canvas content and into the body.
|
||||||
|
|
Loading…
Reference in a new issue