/** * 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 = ' 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
element "header .action-buttons", // v13 variant ".header-actions", // any version, loose ".action-buttons", // any version, loose ".directory-header", // fallback: whole header "header", // fallback:
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); } });