Make the DialogManager more ESM-y

This commit is contained in:
Oliver 2025-11-21 19:56:07 -07:00
parent 382ca50bb5
commit 41034854eb

View file

@ -1,108 +1,114 @@
import { Ask } from "../apps/Ask.mjs"; import { Ask } from "../apps/Ask.mjs";
export class DialogManager { /** @type {Map<string, Promise>} */
/** @type {Map<string, Promise>} */ const promises = new Map();
static #promises = new Map();
static #dialogs = new Map();
static async close(id) { /** @type {Map<string, ApplicationV2>} */
this.#dialogs.get(id)?.close(); const dialogs = new Map();
this.#dialogs.delete(id);
this.#promises.delete(id);
};
/** export function close(id) {
* Asks the user to provide a simple piece of information, this is primarily dialogs.get(id)?.close();
* intended to be used within macros so that it can have better info gathering dialogs.delete(id);
* as needed. This returns an object of input keys/labels to the value the user promises.delete(id);
* input for that label, if there is only one input, this will return the value };
* without an object wrapper, allowing for easier access.
* /**
* @param {AskConfig} data * Asks the user to provide a simple piece of information, this is primarily
* @param {AskOptions} opts * intended to be used within macros so that it can have better info gathering
* @returns {AskResult} * as needed. This returns an object of input keys/labels to the value the user
*/ * input for that label, if there is only one input, this will return the value
static async ask( * without an object wrapper, allowing for easier access.
data, *
{ * @param {AskConfig} data
onlyOneWaiting = true, * @param {AskOptions} opts
alwaysUseAnswerObject = true, * @returns {AskResult}
} = {}, */
) { export async function ask(
if (!data.id) { data,
return { {
state: `errored`, onlyOneWaiting = true,
error: `An ID must be provided`, alwaysUseAnswerObject = true,
}; } = {},
}; ) {
if (!data.inputs.length) { if (!data.id) {
return { return {
state: `errored`, state: `errored`,
error: `At least one input must be provided`, error: `An ID must be provided`,
}; };
}; };
const id = data.id; if (!data.inputs.length) {
return {
// Don't do multi-thread waiting state: `errored`,
if (this.#dialogs.has(id)) { error: `At least one input must be provided`,
const app = this.#dialogs.get(id); };
app.bringToFront(); };
if (onlyOneWaiting) { const id = data.id;
return { state: `fronted` };
} else { // Don't do multi-thread waiting
return this.#promises.get(id); if (dialogs.has(id)) {
}; const app = dialogs.get(id);
}; app.bringToFront();
if (onlyOneWaiting) {
let autofocusClaimed = false; return { state: `fronted` };
for (const i of data.inputs) { } else {
i.id ??= foundry.utils.randomID(16); return promises.get(id);
i.key ??= i.label; };
};
switch (i.type) {
case `input`: { let autofocusClaimed = false;
i.inputType ??= `text`; for (const i of data.inputs) {
} i.id ??= foundry.utils.randomID(16);
} i.key ??= i.label;
// Only ever allow one input to claim autofocus switch (i.type) {
i.autofocus &&= !autofocusClaimed; case `input`: {
autofocusClaimed ||= i.autofocus; i.inputType ??= `text`;
}
// Set the value's attribute name if it isn't specified explicitly }
if (!i.valueAttribute) {
switch (i.inputType) { // Only ever allow one input to claim autofocus
case `checkbox`: i.autofocus &&= !autofocusClaimed;
i.type = `checkbox`; autofocusClaimed ||= i.autofocus;
delete i.valueAttribute;
delete i.inputType; // Set the value's attribute name if it isn't specified explicitly
break; if (!i.valueAttribute) {
default: switch (i.inputType) {
i.valueAttribute = `value`; case `checkbox`:
}; i.type = `checkbox`;
}; delete i.valueAttribute;
}; delete i.inputType;
break;
const promise = new Promise((resolve) => { default:
const app = new Ask({ i.valueAttribute = `value`;
...data, };
alwaysUseAnswerObject, };
onClose: () => { };
this.#dialogs.delete(id);
this.#promises.delete(id); const promise = new Promise((resolve) => {
resolve({ state: `prompted` }); const app = new Ask({
}, ...data,
onConfirm: (answers) => resolve({ state: `prompted`, answers }), alwaysUseAnswerObject,
}); onClose: () => {
app.render({ force: true }); dialogs.delete(id);
this.#dialogs.set(id, app); promises.delete(id);
}); resolve({ state: `prompted` });
},
this.#promises.set(id, promise); onConfirm: (answers) => resolve({ state: `prompted`, answers }),
return promise; });
}; app.render({ force: true });
dialogs.set(id, app);
static get size() { });
return this.#dialogs.size;
}; promises.set(id, promise);
return promise;
};
export function size() {
return dialogs.size;
};
export const DialogManager = {
close,
ask,
size,
}; };