Hooks.once('init', () => { const originalActivate = CONFIG.ux.TooltipManager.prototype.activate; CONFIG.ux.TooltipManager.prototype.activate = async function(element, options = {}) { if (element.dataset.tooltip?.startsWith('#dhcard#')) { const uuid = element.dataset.tooltip.slice(8); const item = await fromUuid(uuid); if (item) { // Use Daggerheart's enrichText to prepare the item's descriptions if (typeof this.enrichText === 'function') { await this.enrichText(item); } options.html = await renderTemplate('modules/dh-hotbar-cardview/templates/cardview.hbs', { item: item, description: item.system?.enrichedDescription ?? item.enrichedDescription ?? item.system?.description, config: CONFIG.DH, allDomains: CONFIG.DH.DOMAIN?.allDomains ? CONFIG.DH.DOMAIN.allDomains() : {} }); options.direction = this.constructor.TOOLTIP_DIRECTIONS.UP; options.cssClass = 'dh-hotbar-card-tooltip'; } } return originalActivate.call(this, element, options); }; }); // Use a MutationObserver to aggressively update the hotbar tooltips as soon as the DOM changes. // This ensures that the dataset is ready BEFORE the user hovers for the first time. Hooks.once('ready', () => { function processHotbar() { const hotbarEls = document.querySelectorAll('#hotbar, .hotbar, [id^="hotbar"]'); for (const hotbarEl of hotbarEls) { const slots = hotbarEl.querySelectorAll('[data-slot]'); for (const slotEl of slots) { const slot = slotEl.dataset.slot; if (!slot) continue; const macroId = slotEl.dataset.macroId || game.user.hotbar[slot]; if (!macroId) continue; const macro = game.macros.get(macroId); if (macro && macro.command) { const match = macro.command.match(/useItem\s*\(\s*["']([^"']+)["']\s*\)/); if (match) { const uuid = match[1]; const tooltipText = `#dhcard#${uuid}`; // Overwrite the tooltip attribute on the slot and all inner elements slotEl.dataset.tooltip = tooltipText; const innerTooltips = slotEl.querySelectorAll('[data-tooltip]'); for (const inner of innerTooltips) { inner.dataset.tooltip = tooltipText; } } } } } } // Process immediately processHotbar(); // Re-process on hotbar changes Hooks.on('updateUser', processHotbar); Hooks.on('updateMacro', processHotbar); Hooks.on('renderDhHotbar', processHotbar); // Watch for any dynamic DOM changes inside the hotbar container const observer = new MutationObserver((mutations) => { let shouldProcess = false; for (const mutation of mutations) { if (mutation.addedNodes.length > 0 || mutation.type === 'attributes') { shouldProcess = true; break; } } if (shouldProcess) processHotbar(); }); const hotbarWrapper = document.getElementById('ui-bottom') || document.body; observer.observe(hotbarWrapper, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-slot', 'data-macro-id'] }); });