/* eslint-disable max-classes-per-file */
import DG from "./config.js";
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
/**
* Base class for all setting forms.
*
* Note: This class is abstract and should not be instantiated directly.
*
* @extends {ApplicationV2}
*/
const SettingForm = class extends HandlebarsApplicationMixin(ApplicationV2) {
/** @type {"automation"|"handler"|null} */
static _namespace = null;
/**
* The namespace for the settings defined by this class. This is necessary
* to register the settings with the game.
*
* @returns {string}
*/
static get namespace() {
return this._namespace;
}
/**
* A getter that returns an object with all the settings defined by the subclass.
* Used to register settings with the game.
*
* @abstract
* @returns {object} An object with all the settings defined by the subclass
* @throws Will throw an error if this method is not defined by a subclass.
*/
static get settings() {
throw new Error("This static getter must be defined by a subclass");
}
/**
* Registers the settings for each defined SettingForm subclass.
* @returns {void}
*/
static register() {
const { settings } = this;
for (const [settingID, setting] of Object.entries(settings)) {
game.settings.register(DG.ID, settingID, {
scope: "world",
config: false,
name: game.i18n.localize(`DG.Settings.${settingID}.name`),
hint: game.i18n.localize(`DG.Settings.${settingID}.hint`),
...setting,
});
}
}
/** @override */
static DEFAULT_OPTIONS = {
tag: "form",
id: "deltagreen-settings",
classes: [DG.ID, "settings-menu"],
window: { contentClasses: ["standard-form"], resizable: true },
position: { width: 500, height: "auto" },
actions: {},
form: {
handler: this.onSubmit,
submitOnChange: false,
closeOnSubmit: false,
},
};
/** @override */
static PARTS = {
form: { template: `systems/${DG.ID}/templates/settings.hbs` },
footer: { template: `systems/${DG.ID}/templates/save.hbs` },
};
/** @override */
static async onSubmit(event, form, formData) {
event.preventDefault();
// Get form data into a standard object.
const data = foundry.utils.expandObject(formData.object);
const settingsPromises = [];
// Set each setting with the new value, if any.
for (const [key, value] of Object.entries(data)) {
settingsPromises.push(game.settings.set(DG.ID, key, value));
}
// Once all promises resolve, show a notification.
Promise.allSettled(settingsPromises).then((values) => {
ui.notifications.info(game.i18n.localize("DG.Settings.Saved"));
});
}
/** @override */
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
// Get Foundry's built-in input creation functions.
const {
createCheckboxInput,
createNumberInput,
createSelectInput,
createTextInput,
createFormGroup,
} = foundry.applications.fields;
context.formGroups = [];
// Iterate over each setting and create the appropriate input element.
const { settings } = this.constructor;
for (const settingID of Object.keys(settings)) {
// The setting config object, not the value of the setting itself.
const settingConfig = game.settings.settings.get(`${DG.ID}.${settingID}`);
// Default input settings.
const inputConfig = {
name: `${DG.ID}.${settingID}`,
value: game.settings.get(DG.ID, settingID), // The value that the setting is currently set to.
label: settingConfig.name,
};
// Use Foundry's built-in /