import { __ID__, filePath } from "../consts.mjs"; const { HandlebarsApplicationMixin: HAM, ApplicationV2 } = foundry.applications.api; export class OFTSettingsMenu extends HAM(ApplicationV2) { // #region Options static DEFAULT_OPTIONS = { tag: `form`, classes: [ __ID__ ], window: { icon: `fa-solid fa-gears`, resizable: true, contentClasses: [ `standard-form`, ], controls: [ { icon: `fa-solid fa-arrow-rotate-left`, label: `PACKAGECONFIG.Reset`, visible: true, action: `resetDefaults`, }, ], }, form: { handler: this.#handleSubmit, closeOnSubmit: true, submitOnChange: false, }, position: { width: 544, }, actions: { resetDefaults: this.#resetDefaults, }, }; static PARTS = { settingsList: { template: filePath(`templates/OFTSettingsMenu/settingsList.hbs`), scrollable: [``], }, footer: { template: filePath(`templates/OFTSettingsMenu/footer.hbs`), }, }; static _SETTINGS = []; // #endregion Options // #region Data Prep async _prepareContext() { return { meta: { idp: this.id, }, }; }; #partContextPrep = { settingsList: this._prepareSettingsListContext, }; async _preparePartContext(partID, ctx) { ctx = foundry.utils.deepClone(ctx); const prepper = this.#partContextPrep[partID]; if (prepper && typeof prepper === `function`) { await prepper.call(this, ctx); }; return ctx; }; async _prepareSettingsListContext(ctx) { const canConfigure = game.user.can(`SETTINGS_MODIFY`); ctx.settings = []; const settingIDs = this.constructor._SETTINGS; for ( const settingID of settingIDs ) { const setting = game.settings.settings.get(settingID); if ( !canConfigure && setting.scope === CONST.SETTING_SCOPES.WORLD ) { continue } const data = { label: setting.value, value: game.settings.get(setting.namespace, setting.key), menu: false, }; // Define a DataField for each setting not originally defined with one const fields = foundry.data.fields; if ( setting.type instanceof fields.DataField ) { data.field = setting.type; } else if ( setting.type === Boolean ) { data.field = new fields.BooleanField({initial: setting.default ?? false}); } else if ( setting.type === Number ) { const {min, max, step} = setting.range ?? {}; data.field = new fields.NumberField({ required: true, choices: setting.choices, initial: setting.default, min, max, step, }); } else if ( setting.filePicker ) { const categories = { audio: [`AUDIO`], folder: [], font: [`FONT`], graphics: [`GRAPHICS`], image: [`IMAGE`], imagevideo: [`IMAGE`, `VIDEO`], text: [`TEXT`], video: [`VIDEO`], }[setting.filePicker] ?? Object.keys(CONST.FILE_CATEGORIES).filter(c => c !== `HTML`); if ( categories.length ) { data.field = new fields.FilePathField({required: true, blank: true, categories}); } else { data.field = new fields.StringField({required: true}); // Folder paths cannot be FilePathFields data.folderPicker = true; } } else { data.field = new fields.StringField({required: true, choices: setting.choices}); } data.field.name = `${setting.namespace}.${setting.key}`; data.field.label ||= game.i18n.localize(setting.name ?? ``); data.field.hint ||= game.i18n.localize(setting.hint ?? ``); // Categorize setting ctx.settings.push(data); }; }; // #endregion Data Prep // #region Actions /** @this {OFTSettingsMenu} */ static async #handleSubmit(_event, _form, formData) { let requiresClientReload = false; let requiresWorldReload = false; for ( const [key, value] of Object.entries(formData.object) ) { const setting = game.settings.settings.get(key); if ( !setting ) { continue }; const priorValue = game.settings.get(setting.namespace, setting.key, {document: true})?._source.value; let newSetting; try { newSetting = await game.settings.set(setting.namespace, setting.key, value, {document: true}); } catch(error) { ui.notifications.error(error); } if ( priorValue === newSetting?._source.value ) { continue }; // Compare JSON strings requiresClientReload ||= (setting.scope !== CONST.SETTING_SCOPES.WORLD) && setting.requiresReload; requiresWorldReload ||= (setting.scope === CONST.SETTING_SCOPES.WORLD) && setting.requiresReload; } if ( requiresClientReload || requiresWorldReload ) { await foundry.applications.settings.SettingsConfig.reloadConfirm({world: requiresWorldReload}); } }; /** @this {OFTSettingsMenu} */ static async #resetDefaults() { const form = this.form; for ( const settingID of this.constructor._SETTINGS ) { const setting = game.settings.settings.get(settingID); console.log({ settingID, setting }); const input = form[settingID]; if ( !input || !setting ) { continue }; if ( input.type === `checkbox` ) { input.checked = setting.default; } else { input.value = setting.default; }; input.dispatchEvent(new Event(`change`)); } ui.notifications.info(`SETTINGS.ResetInfo`, {localize: true}); }; // #endregion Actions };