diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index f304a6ff..0b33244b 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -943,7 +943,8 @@ export default class CharacterSheet extends DHBaseActorSheet { }); } - static async #toggleResourceManagement(_event, button) { + static async #toggleResourceManagement(event, button) { + event.stopPropagation(); const existingTooltip = document.body.querySelector('.locked-tooltip .resource-management-container'); if (existingTooltip) { game.tooltip.dismissLockedTooltips(); @@ -976,12 +977,13 @@ export default class CharacterSheet extends DHBaseActorSheet { const target = button.closest('.resource-section'); - game.tooltip.dismissLockedTooltips(); + // game.tooltip.dismissLockedTooltips(); game.tooltip.activate(target, { html, locked: true, cssClass: 'bordered-tooltip', - direction: 'DOWN' + direction: 'DOWN', + noOffset: true }); for (const element of html.querySelectorAll('.resource-value')) diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index c4b52bb5..720b97e7 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -3,6 +3,7 @@ import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounter export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager { #wide = false; #bordered = false; + #active = false; async activate(element, options = {}) { const { TextEditor } = foundry.applications.ux; @@ -168,7 +169,100 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti } } - super.activate(element, { ...options, html: html }); + this.baseActivate(element, { ...options, html: html }); + } + + /* Need to pass more options to _setAnchor, so have to copy whole foundry method >_< */ + async baseActivate(element, options) { + let { text, direction, cssClass, locked = false, html, content } = options; + if (content && !html) { + foundry.utils.logCompatibilityWarning( + 'The content option has been deprecated in favor of the html option', + { since: 13, until: 15, once: true } + ); + html = content; + } + if (text && html) throw new Error('Cannot provide both text and html options to TooltipManager#activate.'); + // Deactivate currently active element + this.deactivate(); + // Check if the element still exists in the DOM. + if (!document.body.contains(element)) return; + // Mark the new element as active + this.#active = true; + this.element = element; + element.setAttribute('aria-describedby', 'tooltip'); + html ||= element.dataset.tooltipHtml; + if (html) { + if (typeof html === 'string') this.tooltip.innerHTML = foundry.utils.cleanHTML(html); + else { + this.tooltip.innerHTML = ''; // Clear existing HTML + this.tooltip.appendChild(html); + } + } else { + text ||= element.dataset.tooltipText; + if (text) this.tooltip.textContent = text; + else { + text = element.dataset.tooltip; + // Localized message should be safe + if (game.i18n.has(text)) this.tooltip.innerHTML = game.i18n.localize(text); + else this.tooltip.innerHTML = foundry.utils.cleanHTML(text); + } + } + + // Activate display of the tooltip + this.tooltip.removeAttribute('class'); + this.tooltip.classList.add('active', 'themed', 'theme-dark'); + this.tooltip.showPopover(); + cssClass ??= element.closest('[data-tooltip-class]')?.dataset.tooltipClass; + if (cssClass) this.tooltip.classList.add(...cssClass.split(' ')); + + // Set tooltip position + direction ??= element.closest('[data-tooltip-direction]')?.dataset.tooltipDirection; + if (!direction) direction = this._determineDirection(); + this._setAnchor(direction, options); + + if (locked || element.dataset.hasOwnProperty('locked')) this.lockTooltip(); + } + + _setAnchor(direction, options) { + const directions = this.constructor.TOOLTIP_DIRECTIONS; + const pad = this.constructor.TOOLTIP_MARGIN_PX; + const pos = this.element.getBoundingClientRect(); + + const { innerHeight, innerWidth } = this.tooltip.ownerDocument.defaultView; + const tooltipPadding = 16; + const horizontalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetWidth / 2 - pos.width / 2; + const verticalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetHeight / 2 - pos.height / 2; + + const style = {}; + switch (direction) { + case directions.DOWN: + style.textAlign = 'center'; + style.left = pos.left - horizontalOffset; + style.top = pos.bottom + pad; + break; + case directions.LEFT: + style.textAlign = 'left'; + style.right = innerWidth - pos.left + pad; + style.top = pos.top - verticalOffset; + break; + case directions.RIGHT: + style.textAlign = 'right'; + style.left = pos.right + pad; + style.top = pos.top - verticalOffset; + break; + case directions.UP: + style.textAlign = 'center'; + style.left = pos.left - horizontalOffset; + style.bottom = innerHeight - pos.top + pad; + break; + case directions.CENTER: + style.textAlign = 'center'; + style.left = pos.left - horizontalOffset; + style.top = pos.top - verticalOffset; + break; + } + return this._setStyle(style); } _determineItemTooltipDirection(element, prefered = this.constructor.TOOLTIP_DIRECTIONS.LEFT) { diff --git a/styles/less/ux/tooltip/resource-management.less b/styles/less/ux/tooltip/resource-management.less index 9c07cd9a..a5d6d51b 100644 --- a/styles/less/ux/tooltip/resource-management.less +++ b/styles/less/ux/tooltip/resource-management.less @@ -1,4 +1,5 @@ -.bordered-tooltip.locked-tooltip .daggerheart.resource-management-container { +.bordered-tooltip.locked-tooltip .daggerheart.resource-management-container, +#tooltip .daggerheart.resource-management-container { display: flex; flex-direction: column; gap: 16px;