Files

172 lines
6.6 KiB
JavaScript

"use strict";
(function () {
const blocks = [...document.querySelectorAll(".try[data-scene]")];
if (!blocks.length) return;
const starters = new Map();
const texts = new Map();
let api = null;
let active = null;
let canvas = null;
function boot(report) {
return globalThis.aegoRuntime("try", "aego-docs.wasm", "aegoDocsReady", "aegoDocs", report);
}
function call(method, payload) {
return JSON.parse(api.call(method, JSON.stringify(payload || {})));
}
function status(b, text, error) {
const s = b.querySelector(".try-status");
s.textContent = text;
s.classList.toggle("error", !!error);
}
function setValue(cell, value) {
if (cell.dataset.kind === "color") {
cell.textContent = "";
const sw = document.createElement("i");
sw.className = "sw";
sw.style.background = value;
cell.append(sw, value);
} else {
cell.textContent = value;
}
}
function show(b, text, values) {
texts.set(b, text);
if (!values) return;
for (const cell of b.querySelectorAll(".st-fields .v[data-k]")) {
if (!(cell.dataset.k in values)) continue;
if (cell.dataset.orig === undefined) cell.dataset.orig = cell.textContent;
const v = values[cell.dataset.k];
if (cell.textContent !== v) setValue(cell, v);
cell.classList.toggle("changed", v !== cell.dataset.orig);
}
}
globalThis.aegoDocsChanged = (text, values) => {
if (active) show(active, text, values ? JSON.parse(values) : null);
};
function progress(b) {
const box = document.createElement("div");
box.className = "try-progress";
box.innerHTML = '<div class="label">Loading the engine</div><div class="bar"><i></i></div><div class="phase"></div>';
const bar = box.querySelector(".bar i");
const phase = box.querySelector(".phase");
const label = box.querySelector(".label");
const update = (s) => {
if (active !== b) return;
const pct = s.total ? Math.min(100, (s.got * 100) / s.total) : 0;
if (s.phase === "download") {
bar.style.width = pct + "%";
phase.textContent = s.total ? `${globalThis.aegoMB(s.got)} of ${globalThis.aegoMB(s.total)}` : globalThis.aegoMB(s.got);
} else if (s.phase === "cache") {
label.textContent = "Starting the engine";
phase.textContent = "From the browser cache";
} else if (s.phase === "compile") {
bar.style.width = "100%";
label.textContent = "Compiling";
phase.textContent = "";
} else if (s.phase === "start") {
label.textContent = "Starting the scene";
}
};
return { box, update };
}
function release(b) {
b.classList.remove("active");
const stage = b.querySelector(".try-stage");
stage.textContent = "";
for (const el of starters.get(b)) stage.appendChild(el);
b.querySelector(".try-reset").disabled = true;
texts.set(b, b.dataset.scene);
for (const cell of b.querySelectorAll(".st-fields .v[data-k]")) {
if (cell.dataset.orig !== undefined) setValue(cell, cell.dataset.orig);
cell.classList.remove("changed");
}
status(b, "");
}
async function activate(b) {
if (active === b) return;
if (active) release(active);
active = b;
if (!canvas) {
canvas = document.createElement("canvas");
canvas.setAttribute("data-aego", "");
canvas.tabIndex = 0;
canvas.setAttribute("aria-label", "Interactive scene with the Inspector");
}
const stage = b.querySelector(".try-stage");
stage.textContent = "";
stage.appendChild(canvas);
const p = progress(b);
if (!api) stage.appendChild(p.box);
b.classList.add("active");
try {
api = await boot(p.update);
p.box.remove();
if (active !== b) return;
const res = call("load", { scene: b.dataset.scene, select: b.dataset.select || "" });
if (res.error) throw new Error(res.error);
show(b, res.text, res.values);
b.querySelector(".try-reset").disabled = false;
status(b, "Change a field on the right: the scene restarts with it. Click the view to send input.");
} catch (e) {
p.box.remove();
status(b, e.message, true);
}
}
function download(b) {
const blob = new Blob([texts.get(b) || b.dataset.scene], { type: "text/plain" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = (b.dataset.name || "scene") + ".aescene";
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(a.href), 1000);
status(b, "Saved " + a.download + "; open it from the editor's Scenes panel or File → Open");
}
for (const b of blocks) {
starters.set(b, [...b.querySelector(".try-stage").childNodes]);
texts.set(b, b.dataset.scene);
b.querySelector(".try-start").addEventListener("click", () => activate(b));
b.querySelector(".try-reset").addEventListener("click", () => {
if (active !== b || !api) return;
const res = call("reset");
if (res.error) status(b, res.error, true);
else show(b, res.text, res.values);
});
b.querySelector(".try-open").addEventListener("click", () => download(b));
b.querySelector(".try-copy").addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(texts.get(b));
status(b, "Copied; paste it into a .aescene file in your project");
} catch (_) {
status(b, "The browser blocked the clipboard", true);
}
});
}
globalThis.aegoRuntimeCached("try", "aego-docs.wasm").then((warm) => {
if (!warm || !("IntersectionObserver" in window)) return;
const seen = new IntersectionObserver((list) => {
for (const it of list) {
if (!it.isIntersecting || active) continue;
seen.disconnect();
activate(it.target.closest(".try"));
return;
}
}, { threshold: 0.35 });
for (const b of blocks) seen.observe(b.querySelector(".try-stage"));
});
})();