[Feature] Custom Resources (#1714)

* Initial

* .

* Fixed positioning

* .

* Only showing the menu if there are extra resources

* Improved resourceManager clickable

* .

* Changed variable name

* Refactor resources selection and data prep (#1721)

* Move resources select to scrolly text and accept actor object

* Convert isReversed to prepared data and add label

* Removed unused imports

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>

* Naming

* [Feature] Custom Homebrew Resources (#1718)

* Added resources to the Homebrew Menu

* Fixed translations

* .

* Inverted from isImage to isIcon. Should be more logical for users

* Removed testing resources

* Refactor resource settings to not be a method (#1723)

* Fix editing homebrew resources with a custom ResourcesField

* Fix removing homebrew resources

* Remove vestigial code

* Use custom config for module data instead of including in all (#1724)

* Use custom config for module data instead of including in all

* More simple

* base highest priority

---------

Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>
Co-authored-by: Carlos Fernandez <cfern1990@gmail.com>
This commit is contained in:
WBHarry 2026-03-11 11:10:28 +01:00 committed by GitHub
parent af04fb33d0
commit 552c62adc1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 970 additions and 189 deletions

View file

@ -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) {
@ -270,6 +364,12 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
return clone;
}
/**@inheritdoc */
dismissLockedTooltips() {
super.dismissLockedTooltips();
Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.lockedTooltipDismissed);
}
/** Get HTML for Battlepoints tooltip */
async getBattlepointHTML(combatId) {
const combat = game.combats.get(combatId);