Files
npc-quick-cards/scripts/main.js
T

110 lines
4.6 KiB
JavaScript

/**
* main.js
* Module entry point for NPC Quick Card Deck.
*
* Load order:
* 1. Hooks.once("init") — register Handlebars helpers before any template renders
* 2. Hooks.once("ready") — create the singleton deck, register token hooks,
* and inject the toolbar button into the Actor Directory
*/
import { NPCCardDeck } from "./card-deck.js";
import { registerTokenHooks } from "./token-hooks.js";
// ── init ───────────────────────────────────────────────────────────────────────
Hooks.once("init", () => {
console.log("NPC Quick Cards | Initialising");
// Register Handlebars helpers.
// `eq` is built-in from Foundry v10 onward but we register defensively
// in case a stripped-down environment doesn't have it.
if (!Handlebars.helpers["eq"]) {
Handlebars.registerHelper("eq", (a, b) => a === b);
}
// Useful for attitude slider label comparisons in templates
Handlebars.registerHelper("nqc-gt", (a, b) => Number(a) > Number(b));
Handlebars.registerHelper("nqc-lt", (a, b) => Number(a) < Number(b));
// Pre-load templates so they are cached before the deck first opens.
// v13 moved loadTemplates under foundry.applications.handlebars; fall back
// to the global for v12 compatibility.
const _loadTemplates =
foundry.applications?.handlebars?.loadTemplates?.bind(foundry.applications.handlebars)
?? globalThis.loadTemplates;
_loadTemplates([
"modules/npc-quick-cards/templates/card-deck.hbs",
"modules/npc-quick-cards/templates/npc-card.hbs",
"modules/npc-quick-cards/templates/card-tooltip.hbs",
]);
});
// ── ready ──────────────────────────────────────────────────────────────────────
Hooks.once("ready", () => {
// Only the GM needs the deck; bail out for players
if (!game.user.isGM) return;
// Create singleton and expose on game so macros can call game.npcCardDeck.toggle()
game.npcCardDeck = new NPCCardDeck();
// Register canvas token interaction hooks
registerTokenHooks(game.npcCardDeck);
console.log("NPC Quick Cards | Ready");
});
// ── Actor Directory toolbar button ─────────────────────────────────────────────
// Injected here (outside "ready") so it re-fires every time the directory re-renders.
//
// Foundry v13 passes a plain HTMLElement as the second argument; v12 passed a
// jQuery object. We normalise to a plain element so the same code works on both.
// We also try every known selector for the header actions area across v12 / v13
// because the DOM structure changed between versions.
Hooks.on("renderActorDirectory", (_app, html) => {
if (!game.user?.isGM) return;
if (!game.npcCardDeck) return;
// Resolve to a plain HTMLElement regardless of Foundry version
const root = (html instanceof HTMLElement) ? html : (html[0] ?? html);
if (!(root instanceof HTMLElement)) return;
if (root.querySelector(".npc-deck-toggle")) return; // prevent duplicates
const btn = document.createElement("button");
btn.type = "button";
btn.className = "npc-deck-toggle";
btn.title = "NPC Quick Card Deck";
btn.innerHTML = '<i class="fas fa-address-card"></i> NPC Deck';
btn.addEventListener("click", () => game.npcCardDeck.toggle());
// Try every known header-action selector across Foundry v12 and v13.
// Log which one we find so the console makes it easy to debug.
const SELECTORS = [
".directory-header .header-actions", // v12 standard
".directory-header .action-buttons", // v13 variant
"header .header-actions", // v13 <header> element
"header .action-buttons", // v13 variant
".header-actions", // any version, loose
".action-buttons", // any version, loose
".directory-header", // fallback: whole header
"header", // fallback: <header> element
];
let target = null;
for (const sel of SELECTORS) {
target = root.querySelector(sel);
if (target) {
console.log(`NPC Quick Cards | Injecting button into "${sel}"`);
break;
}
}
if (target) {
target.prepend(btn);
} else {
// Absolute last resort — prepend directly to the directory root
console.warn("NPC Quick Cards | Could not find a header target; prepending to root.");
root.prepend(btn);
}
});