Update the popover management to work with origin rerenders, and rerendering the popovers directly.
This commit is contained in:
parent
69bf712eca
commit
96e4d09e7b
4 changed files with 93 additions and 29 deletions
|
|
@ -82,22 +82,16 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin
|
|||
);
|
||||
};
|
||||
|
||||
/** @type {Map<string, PopoverEventManager>} */
|
||||
#popoverManagers = new Map();
|
||||
/** @type {Map<number, string>} */
|
||||
#hookIDs = new Map();
|
||||
/** @this {HeroSkillsCardV1} */
|
||||
static async _createPopoverListeners() {
|
||||
const ammoInfoIcon = this.element.querySelector(`.ammo-info-icon`);
|
||||
const idPrefix = this.actor.uuid;
|
||||
|
||||
this.#popoverManagers.set(
|
||||
`.ammo-info-icon`,
|
||||
new PopoverEventManager(ammoInfoIcon, AmmoTracker),
|
||||
);
|
||||
|
||||
this.#hookIDs.set(Hooks.on(`get${AmmoTracker.name}Options`, (opts) => {
|
||||
opts.ammo = this.actor.itemTypes.ammo;
|
||||
}), `get${AmmoTracker.name}Options`);
|
||||
const manager = new PopoverEventManager(`${idPrefix}.ammo-info-icon`, ammoInfoIcon, AmmoTracker);
|
||||
this._popoverManagers.set(`.ammo-info-icon`, manager);
|
||||
this._hookIDs.set(Hooks.on(`prepare${manager.id}Context`, (ctx) => {
|
||||
ctx.ammos = this.actor.itemTypes.ammo;
|
||||
}), `prepare${manager.id}Context`);
|
||||
};
|
||||
|
||||
async _preparePartContext(partId, ctx, opts) {
|
||||
|
|
@ -194,17 +188,6 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin
|
|||
}
|
||||
return ctx;
|
||||
};
|
||||
|
||||
_tearDown(options) {
|
||||
for (const manager of this.#popoverManagers.values()) {
|
||||
manager.destroy();
|
||||
};
|
||||
this.#popoverManagers.clear();
|
||||
for (const [id, hook] of this.#hookIDs.entries()) {
|
||||
Hooks.off(hook, id);
|
||||
}
|
||||
super._tearDown(options);
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
};
|
||||
// #endregion
|
||||
|
||||
// #region Instance Data
|
||||
/** @type {Map<string, PopoverEventManager>} */
|
||||
_popoverManagers = new Map();
|
||||
/** @type {Map<number, string>} */
|
||||
_hookIDs = new Map();
|
||||
// #endregion
|
||||
|
||||
// #region Lifecycle
|
||||
/**
|
||||
* @override
|
||||
|
|
@ -45,6 +52,13 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
};
|
||||
};
|
||||
|
||||
async _onRender() {
|
||||
await super._onRender();
|
||||
for (const manager of this._popoverManagers.values()) {
|
||||
manager.render();
|
||||
};
|
||||
};
|
||||
|
||||
async _preparePartContext(partId, ctx, opts) {
|
||||
ctx = await super._preparePartContext(partId, ctx, opts);
|
||||
delete ctx.document;
|
||||
|
|
@ -60,6 +74,22 @@ export function GenericAppMixin(HandlebarsApp) {
|
|||
|
||||
return ctx;
|
||||
};
|
||||
|
||||
_tearDown(options) {
|
||||
// Clear all popovers associated with the app
|
||||
for (const manager of this._popoverManagers.values()) {
|
||||
manager.destroy();
|
||||
};
|
||||
this._popoverManagers.clear();
|
||||
|
||||
// Remove any hooks added for this app
|
||||
for (const [id, hook] of this._hookIDs.entries()) {
|
||||
Hooks.off(hook, id);
|
||||
};
|
||||
this._hookIDs.clear();
|
||||
|
||||
super._tearDown(options);
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ const { ApplicationV2 } = foundry.applications.api;
|
|||
/**
|
||||
* This mixin provides the ability to designate an Application as a "popover",
|
||||
* which means that it will spawn near the x/y coordinates provided it won't
|
||||
* overflow the bounds of the screen.
|
||||
* overflow the bounds of the screen. This also implements a _preparePartContext
|
||||
* in order to allow the parent application passing new data into the popover
|
||||
* whenever it rerenders; how the popover handles this data is up to the
|
||||
* specific implementation.
|
||||
*/
|
||||
export function GenericPopoverMixin(HandlebarsApp) {
|
||||
class GenericRipCryptPopover extends HandlebarsApp {
|
||||
|
|
@ -29,7 +32,6 @@ export function GenericPopoverMixin(HandlebarsApp) {
|
|||
popover.framed ??= true;
|
||||
popover.locked ??= false;
|
||||
|
||||
|
||||
if (popover.framed) {
|
||||
options.window ??= {};
|
||||
options.window.frame = true;
|
||||
|
|
@ -151,6 +153,17 @@ export function GenericPopoverMixin(HandlebarsApp) {
|
|||
scale,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This is here in order allow things that are not this Application
|
||||
* to provide / augment the context data for the lifecycle of the app.
|
||||
*/
|
||||
async _prepareContext(_partId, _context, options) {
|
||||
const context = {};
|
||||
Hooks.callAll(`prepare${this.constructor.name}Context`, context, options);
|
||||
Hooks.callAll(`prepare${this.popover.managerId}Context`, context, options);
|
||||
return context;
|
||||
};
|
||||
};
|
||||
return GenericRipCryptPopover;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,28 @@
|
|||
import { getTooltipDelay } from "../consts.mjs";
|
||||
import { Logger } from "./Logger.mjs";
|
||||
|
||||
export class PopoverEventManager {
|
||||
#options;
|
||||
id;
|
||||
|
||||
/** @type {Map<string, PopoverEventManager>} */
|
||||
static #existing = new Map();
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element The element to attach the listeners to.
|
||||
* @param {GenericPopoverMixin} popoverClass The class reference that represents the popover app
|
||||
*/
|
||||
constructor(element, popoverClass, options = {}) {
|
||||
constructor(id, element, popoverClass, options = {}) {
|
||||
id = `${id}-${popoverClass.name}`;
|
||||
this.id = id;
|
||||
|
||||
if (PopoverEventManager.#existing.has(id)) {
|
||||
const manager = PopoverEventManager.#existing.get(id);
|
||||
manager.#addListeners(element);
|
||||
return manager;
|
||||
};
|
||||
|
||||
options.managerId = id;
|
||||
options.locked ??= false;
|
||||
options.lockable ??= true;
|
||||
|
||||
|
|
@ -15,11 +30,19 @@ export class PopoverEventManager {
|
|||
this.#element = element;
|
||||
this.#class = popoverClass;
|
||||
|
||||
this.#addListeners(element);
|
||||
PopoverEventManager.#existing.set(id, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
#addListeners(element) {
|
||||
element.addEventListener(`pointerenter`, this.#pointerEnterHandler.bind(this));
|
||||
element.addEventListener(`pointerout`, this.#pointerOutHandler.bind(this));
|
||||
element.addEventListener(`click`, this.#clickHandler.bind(this));
|
||||
|
||||
if (options.lockable) {
|
||||
if (this.#options.lockable) {
|
||||
element.addEventListener(`pointerup`, this.#pointerUpHandler.bind(this));
|
||||
};
|
||||
};
|
||||
|
|
@ -55,6 +78,19 @@ export class PopoverEventManager {
|
|||
}
|
||||
};
|
||||
|
||||
get rendered() {
|
||||
return Boolean(this.#frameless?.rendered || this.#framed?.rendered);
|
||||
};
|
||||
|
||||
render(options) {
|
||||
if (this.#framed?.rendered) {
|
||||
this.#framed.render(options);
|
||||
};
|
||||
if (this.#frameless?.rendered) {
|
||||
this.#frameless.render(options);
|
||||
};
|
||||
};
|
||||
|
||||
#element;
|
||||
#class;
|
||||
#openTimeout = null;
|
||||
|
|
@ -64,12 +100,14 @@ export class PopoverEventManager {
|
|||
#framed;
|
||||
|
||||
#construct(options) {
|
||||
const valid = Hooks.call(`get${this.#class.name}Options`, options);
|
||||
if (!valid) { return };
|
||||
options.popover ??= {};
|
||||
options.popover.managerId = this.id;
|
||||
|
||||
return new this.#class(options);
|
||||
};
|
||||
|
||||
#clickHandler() {
|
||||
Logger.debug(`click event handler`);
|
||||
// Cleanup for the frameless lifecycle
|
||||
this.stopOpen();
|
||||
this.stopClose();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue