${foundry.utils.escapeHTML(state.opName || "SLA Operation")}
Stage: ${foundry.utils.escapeHTML(state.stage || "Unstated")}
Clock: ${state.clock}/8 | Heat: ${state.heat} | Collateral: ${state.collateral} | Pressure: ${state.pressure}
Escalation Trigger: ${foundry.utils.escapeHTML(state.trigger || "None")}
${state.notes ? `GM Notes: ${foundry.utils.escapeHTML(state.notes)}
` : ""}
`;
}
function getHtmlRoot(html) {
return html instanceof HTMLElement ? html : html?.[0] ?? null;
}
class SlaOpsClockApp extends FormApplication {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "sla-ops-clock-app",
title: "SLA Ops Clock",
template: "modules/sla-ops-clock/templates/ops-clock.hbs",
classes: ["sla-ops-clock"],
width: 560,
height: "auto",
submitOnChange: false,
closeOnSubmit: false,
resizable: true
});
}
async getData() {
const state = getState();
return {
state,
segments: Array.from({ length: 8 }, (_value, index) => ({
index,
filled: index < Number(state.clock || 0)
}))
};
}
activateListeners(html) {
super.activateListeners(html);
html.find("[data-action='advance']").on("click", async () => {
const current = await this._collectState();
current.clock = Math.min(8, Number(current.clock || 0) + 1);
current.pressure = Math.min(9, Number(current.pressure || 0) + 1);
await setState(current);
this.render(false);
});
html.find("[data-action='post']").on("click", async () => {
const current = await this._collectState();
await setState(current);
await ChatMessage.create({
user: game.user.id,
speaker: { alias: "SLA Ops Clock" },
content: renderChatSummary(current)
});
});
html.find("[data-action='reset']").on("click", async () => {
await setState(defaultState());
this.render(false);
});
}
async _collectState() {
const form = this.form;
if (!form) return getState();
const fd = new foundry.applications.ux.FormDataExtended(form);
return foundry.utils.mergeObject(getState(), fd.object);
}
async _updateObject(_event, formData) {
await setState(formData);
ui.notifications.info("SLA Ops Clock saved.");
}
static open() {
return new SlaOpsClockApp().render(true);
}
}
function installSceneButton(app, html) {
if (!game.user?.isGM) return;
const root = getHtmlRoot(html);
const header = root?.querySelector(".directory-header .header-actions, .directory-header .action-buttons");
if (!header || header.querySelector(".sla-ops-clock-open")) return;
const button = document.createElement("button");
button.type = "button";
button.className = "sla-ops-clock-open";
button.innerHTML = `