From 4a8ce9b0994c1a8bea2445e1b64cd139b0146711 Mon Sep 17 00:00:00 2001 From: Eldritch-Oliver Date: Sun, 12 Oct 2025 18:01:47 -0600 Subject: [PATCH] Update the GenericAppMixin so that it persists focus better --- module/Apps/mixins/GenericApp.mjs | 40 +++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/module/Apps/mixins/GenericApp.mjs b/module/Apps/mixins/GenericApp.mjs index ae2eb94..ffb3666 100644 --- a/module/Apps/mixins/GenericApp.mjs +++ b/module/Apps/mixins/GenericApp.mjs @@ -37,6 +37,8 @@ export function GenericAppMixin(HandlebarsApp) { _popoverManagers = new Map(); /** @type {Map} */ _hookIDs = new Map(); + /** @type {string | null} */ + #focus = null; // #endregion // #region Lifecycle @@ -53,6 +55,26 @@ export function GenericAppMixin(HandlebarsApp) { }; }; + /** + * @override + * This method overrides Foundry's default behaviour for caching the focused + * element so that it actually works when the application has a root partial + */ + async _preRender(...args) { + if (this.rendered) { + const target = this.element.querySelector(`:focus`); + if (target) { + if (target.id) { + this.#focus = `#${CSS.escape(target.id)}`; + } + else if (target.name) { + this.#focus = `${target.tagName}[name="${target.name}"]`; + }; + }; + }; + return super._preRender(...args); + }; + /** @override */ async _onRender(...args) { await super._onRender(...args); @@ -83,11 +105,25 @@ export function GenericAppMixin(HandlebarsApp) { }); }; - async _prepareContext() { + /** + * @override + * This method overrides Foundry's default behaviour for caching the focused + * element so that it actually works when the application has a root partial + */ + async _postRender(...args) { + if (this.rendered) { + const target = this.element.querySelector(this.#focus); + target?.focus(); + }; + this.#focus = null; + return super._postRender(...args); + }; + + async _prepareContext(_options) { const ctx = {}; ctx.meta ??= {}; - ctx.meta.idp = this.document?.uuid ?? this.id; + ctx.meta.idp = this.id; if (this.document) { ctx.meta.limited = this.document.limited; ctx.meta.editable = this.isEditable || game.user.isGM;