zischenstand
This commit is contained in:
@@ -0,0 +1,465 @@
|
||||
import { GeneralSettings } from "../../interface/GeneralSettings.js";
|
||||
import { ObjectsInteractionsFX as OIF } from "../../ObjectsInteractionsFX.js";
|
||||
|
||||
export class SettingsSkeleton extends FormApplication
|
||||
{
|
||||
static get defaultOptions() {
|
||||
const DefaultOptions = super.defaultOptions;
|
||||
|
||||
const OverrideOptions = {
|
||||
closeOnSubmit: false,
|
||||
height: 'auto',
|
||||
with: 600,
|
||||
submitOnChange: true,
|
||||
template: OIF.TEMPLATES.SETTINGS_SKELETON
|
||||
};
|
||||
|
||||
const MergedOptions = foundry.utils.mergeObject(DefaultOptions, OverrideOptions);
|
||||
return MergedOptions;
|
||||
}
|
||||
|
||||
static Settings = {}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Prototype function used to register custom settings
|
||||
////////////////////////////////////////////////////////////
|
||||
static _protoRegister(config, name, options)
|
||||
{
|
||||
if (SettingsSkeleton.Settings[config] == undefined)
|
||||
{
|
||||
SettingsSkeleton.Settings[config] = {};
|
||||
}
|
||||
|
||||
// Prepare the internal foundry setting options
|
||||
let FoundrySettingOptions = {
|
||||
name: options['name'],
|
||||
hint: options['hint'],
|
||||
scope: options['scope'],
|
||||
default: options['default'],
|
||||
config: false
|
||||
}
|
||||
|
||||
// Detect and convert custom type to be used by foundry
|
||||
if (options['type'] != undefined)
|
||||
{
|
||||
// Sets a value inside option, named after the type name, as true
|
||||
// This is used inside .hbs templates to select which option
|
||||
// display/editor will be shown
|
||||
options[options['type']] = true;
|
||||
|
||||
// Convert type to a foundry compatible
|
||||
switch (options['type'])
|
||||
{
|
||||
case 'checkbox':
|
||||
FoundrySettingOptions['type'] = Boolean;
|
||||
break;
|
||||
|
||||
case 'slider':
|
||||
FoundrySettingOptions['type'] = Number;
|
||||
FoundrySettingOptions['range'] = options['range'];
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
FoundrySettingOptions['type'] = String;
|
||||
break;
|
||||
|
||||
case 'dropdown':
|
||||
FoundrySettingOptions['type'] = String;
|
||||
FoundrySettingOptions['choices'] = options['choices'];
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error(`Cannot register setting, ${options['type']} is not a valid type`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Register setting inside foundry
|
||||
game.settings.register(OIF.ID, name, FoundrySettingOptions);
|
||||
|
||||
// Get currently set value to be displayed
|
||||
options['value'] = game.settings.get(OIF.ID, name);
|
||||
|
||||
// Dropdown types are handled differently
|
||||
if (options['type'] == 'dropdown')
|
||||
{
|
||||
// Iterate through the choices and set them as selected
|
||||
// or not
|
||||
options['choices'].forEach((element) => {
|
||||
if (element.value == options['value'])
|
||||
{
|
||||
element['selected'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
element['selected'] = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the ID to be used as reference later
|
||||
options['referenceID'] = name;
|
||||
|
||||
// Check there are required modules
|
||||
let RequiredModule = options['requiredModule'];
|
||||
if (RequiredModule != undefined)
|
||||
{
|
||||
// Check if the required module is active
|
||||
if (!RequiredModule.active)
|
||||
{
|
||||
options['disabled'] = true;
|
||||
options['disabledMessage'] = game.i18n.localize('OIF.Settings.ModuleRequired').replace("${module}", `"${RequiredModule.name}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Register inside OIF
|
||||
SettingsSkeleton.Settings[config][name] = options;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Prototype function used to get custom settings
|
||||
////////////////////////////////////////////////////////////
|
||||
static _protoGet(config, name)
|
||||
{
|
||||
let CurrentSetting = SettingsSkeleton.Settings[config][name];
|
||||
switch (CurrentSetting['type'])
|
||||
{
|
||||
case 'checkbox':
|
||||
return CurrentSetting['value'] && !CurrentSetting['disabled'];
|
||||
break;
|
||||
|
||||
case 'slider':
|
||||
case 'string':
|
||||
case 'dropdown':
|
||||
return CurrentSetting['disabled'] ? CurrentSetting['default'] : CurrentSetting['value'];
|
||||
break;
|
||||
|
||||
default:
|
||||
return CurrentSetting['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Internal function that checks if restart is required
|
||||
////////////////////////////////////////////////////////////
|
||||
async _checkForRestart(config, id)
|
||||
{
|
||||
if (SettingsSkeleton.Settings[config][id]['restart'] != null && SettingsSkeleton.Settings[config][id]['restart'] != undefined && SettingsSkeleton.Settings[config][id]['restart'])
|
||||
{
|
||||
SettingsSkeleton.Settings[config][id]['requiresRestart'] = true;
|
||||
SettingsSkeleton.Settings[config][id]['restartMessage'] = 'OIF.Settings.RestartRequired';
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Internal function for handling Checkbox interactions
|
||||
////////////////////////////////////////////////////////////
|
||||
async _handleCheckBoxInteraction(config, event)
|
||||
{
|
||||
let ClickedElement = $(event.currentTarget)[0];
|
||||
game.settings.set(OIF.ID, ClickedElement.id, ClickedElement.checked);
|
||||
SettingsSkeleton.Settings[config][ClickedElement.id]['value'] = ClickedElement.checked;
|
||||
|
||||
this._checkForRestart(config, ClickedElement.id);
|
||||
SettingsSkeleton._protoUpdateSettings(config);
|
||||
this.render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Internal function for handling Slider interactions
|
||||
////////////////////////////////////////////////////////////
|
||||
async _handleSliderInteraction(config, event)
|
||||
{
|
||||
let ClickedElement = $(event.currentTarget)[0];
|
||||
game.settings.set(OIF.ID, ClickedElement.id, ClickedElement.value);
|
||||
|
||||
// Check value
|
||||
let CurrentValue = Number(ClickedElement.value);
|
||||
if (CurrentValue > ClickedElement.max)
|
||||
{
|
||||
CurrentValue = ClickedElement.max;
|
||||
}
|
||||
else if (CurrentValue < ClickedElement.min)
|
||||
{
|
||||
CurrentValue = ClickedElement.min;
|
||||
}
|
||||
|
||||
SettingsSkeleton.Settings[config][ClickedElement.id]['value'] = CurrentValue;
|
||||
|
||||
this._checkForRestart(config, ClickedElement.id);
|
||||
SettingsSkeleton._protoUpdateSettings(config);
|
||||
this.render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Internal function for handling String interactions
|
||||
////////////////////////////////////////////////////////////
|
||||
async _handleStringInteraction(config, event)
|
||||
{
|
||||
let ClickedElement = $(event.currentTarget)[0];
|
||||
game.settings.set(OIF.ID, ClickedElement.id, ClickedElement.value);
|
||||
SettingsSkeleton.Settings[config]['value'] = ClickedElement.value;
|
||||
|
||||
this._checkForRestart(config, ClickedElement.id);
|
||||
SettingsSkeleton._protoUpdateSettings(config);
|
||||
this.render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Internal function for handling Dropdown interactions
|
||||
////////////////////////////////////////////////////////////
|
||||
async _handleDropdownInteraction(config, event)
|
||||
{
|
||||
let ClickedElement = $(event.currentTarget)[0];
|
||||
game.settings.set(OIF.ID, ClickedElement.id, ClickedElement.value);
|
||||
SettingsSkeleton.Settings[config][ClickedElement.id]['value'] = ClickedElement.value;
|
||||
|
||||
SettingsSkeleton.Settings[config][ClickedElement.id]['choices'].forEach(function(element)
|
||||
{
|
||||
element['selected'] = false;
|
||||
if (element.value == ClickedElement.value)
|
||||
{
|
||||
element['selected'] = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._checkForRestart(config, ClickedElement.id);
|
||||
SettingsSkeleton._protoUpdateSettings(config);
|
||||
this.render();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Prototype function that updates settings
|
||||
////////////////////////////////////////////////////////////
|
||||
static _protoUpdateSettings(config)
|
||||
{
|
||||
for (const key in SettingsSkeleton.Settings[config])
|
||||
{
|
||||
// Check if current element has a dependecy
|
||||
let CurrentSetting = SettingsSkeleton.Settings[config][key];
|
||||
let CurrentDependencies = CurrentSetting['dependsOn'];
|
||||
let CurrentUndependencies = CurrentSetting['excludesOn'];
|
||||
|
||||
// Check if setting requires a module to be used
|
||||
let RequiredModule = CurrentSetting.requiredModule;
|
||||
if (RequiredModule != null && RequiredModule != undefined)
|
||||
{
|
||||
// Check if required module isn't loaded
|
||||
if (!RequiredModule.active)
|
||||
{
|
||||
CurrentSetting['disabled'] = true;
|
||||
CurrentSetting['disabledMessage'] = game.i18n.localize('OIF.Settings.ModuleRequired').replace("${module}", `"${RequiredModule.name}"`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if setting has dependencies
|
||||
let AllRequirementsMet = true;
|
||||
if (CurrentDependencies != null && CurrentDependencies != undefined)
|
||||
{
|
||||
// Loop through all dependencies to check if the are Boolean
|
||||
let BoolCheck = true;
|
||||
for (let index = 0; index < CurrentDependencies.length; index++)
|
||||
{
|
||||
// Check if the current dependency is a Boolean
|
||||
const CurrentDependency = CurrentDependencies[index];
|
||||
if (SettingsSkeleton.Settings[config][CurrentDependency]['type'] != 'checkbox')
|
||||
{
|
||||
BoolCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If one of the dependencies isn't a Boolean, skip the rest
|
||||
if (BoolCheck == false)
|
||||
{
|
||||
console.error(`OIF | ${config} | ${key} | Dependency isn't a Boolean`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the dependecies exist
|
||||
let CurrentRequirements = [];
|
||||
for (let index = 0; index < CurrentDependencies.length; index++)
|
||||
{
|
||||
// Check if the current dependency exists
|
||||
const CurrentDependency = CurrentDependencies[index];
|
||||
let CurrentRequirement = SettingsSkeleton.Settings[config][CurrentDependency];
|
||||
if (CurrentRequirement != null && CurrentRequirement != undefined)
|
||||
{
|
||||
CurrentRequirements.push(CurrentRequirement);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all dependencies are met
|
||||
for (let index = 0; index < CurrentRequirements.length; index++)
|
||||
{
|
||||
// Check if the current dependency is met
|
||||
const CurrentRequirement = CurrentRequirements[index];
|
||||
if (!SettingsSkeleton._protoGet(config, CurrentRequirement.referenceID))
|
||||
{
|
||||
AllRequirementsMet = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all dependencies are met, enable the setting
|
||||
if (AllRequirementsMet)
|
||||
{
|
||||
CurrentSetting['disabled'] = false;
|
||||
CurrentSetting['disabledMessage'] = '';
|
||||
}
|
||||
// If not, disable the setting
|
||||
else
|
||||
{
|
||||
// Create a string with all dependencies, so the user knows which ones are missing
|
||||
// separeted all dependencies with a comma, except the last one, which is separeted with 'and'
|
||||
let DependenciesString = '';
|
||||
for (let index = 0; index < CurrentRequirements.length; index++)
|
||||
{
|
||||
const CurrentRequirement = CurrentRequirements[index];
|
||||
if (index == CurrentRequirements.length - 1)
|
||||
{
|
||||
DependenciesString += ` and "${game.i18n.localize(CurrentRequirement['name'])}"`;
|
||||
}
|
||||
else
|
||||
{
|
||||
DependenciesString += `"${game.i18n.localize(CurrentRequirement['name'])}", `;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable the setting and add a message
|
||||
CurrentSetting['disabled'] = true;
|
||||
CurrentSetting['disabledMessage'] = game.i18n.localize('OIF.Settings.OptionRequired').replace("${option}", DependenciesString);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if setting has undependencies
|
||||
if (CurrentUndependencies != null && CurrentUndependencies != undefined && AllRequirementsMet)
|
||||
{
|
||||
// Loop through all undependencies to check if the are Boolean
|
||||
let BoolCheck = true;
|
||||
for (let index = 0; index < CurrentUndependencies.length; index++)
|
||||
{
|
||||
// Check if the current undependency is a Boolean
|
||||
const CurrentUndependency = CurrentUndependencies[index];
|
||||
if (SettingsSkeleton.Settings[config][CurrentUndependency]['type'] != 'checkbox')
|
||||
{
|
||||
BoolCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If one of the undependencies isn't a Boolean, skip the rest
|
||||
if (BoolCheck == false)
|
||||
{
|
||||
console.error(`OIF | ${config} | ${key} | Undependency isn't a Boolean`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the undependecies exist
|
||||
let CurrentUnrequirements = [];
|
||||
for (let index = 0; index < CurrentUndependencies.length; index++)
|
||||
{
|
||||
// Check if the current undependency exists
|
||||
const CurrentUndependency = CurrentUndependencies[index];
|
||||
let CurrentRequirement = SettingsSkeleton.Settings[config][CurrentUndependency];
|
||||
if (CurrentRequirement != null && CurrentRequirement != undefined)
|
||||
{
|
||||
CurrentUnrequirements.push(CurrentRequirement);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all undependencies are met
|
||||
let AllUnrequirementsMet = true;
|
||||
for (let index = 0; index < CurrentUnrequirements.length; index++)
|
||||
{
|
||||
// Check if the current undependency is met
|
||||
const CurrentUnrequirement = CurrentUnrequirements[index];
|
||||
if (SettingsSkeleton._protoGet(config, CurrentUnrequirement.referenceID))
|
||||
{
|
||||
AllUnrequirementsMet = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all undependencies are met, enable the setting
|
||||
if (AllUnrequirementsMet)
|
||||
{
|
||||
CurrentSetting['disabled'] = false;
|
||||
CurrentSetting['disabledMessage'] = '';
|
||||
}
|
||||
// If not, disable the setting
|
||||
else
|
||||
{
|
||||
// Create a string with all undependencies, so the user knows which ones are missing
|
||||
// separeted all undependencies with a comma, except the last one, which is separeted with 'and'
|
||||
let UndependenciesString = '';
|
||||
for (let index = 0; index < CurrentUnrequirements.length; index++)
|
||||
{
|
||||
const CurrentUnrequirement = CurrentUnrequirements[index];
|
||||
if (index == CurrentUnrequirements.length - 1)
|
||||
{
|
||||
UndependenciesString += ` and "${game.i18n.localize(CurrentUnrequirement['name'])}"`;
|
||||
}
|
||||
else
|
||||
{
|
||||
UndependenciesString += `"${game.i18n.localize(CurrentUnrequirement['name'])}", `;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable the setting and add a message
|
||||
CurrentSetting['disabled'] = true;
|
||||
CurrentSetting['disabledMessage'] = game.i18n.localize('OIF.Settings.OptionUnrequired').replace("${option}", UndependenciesString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Hooks.call(OIF.HOOKS.CHANGE_SETTINGS, SettingsSkeleton.Settings[config]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Prototype function to get data for rendering .hbs
|
||||
////////////////////////////////////////////////////////////
|
||||
static _protoGetData(config, options)
|
||||
{
|
||||
// Only return settings that are in the 'world' scope
|
||||
// for GMs
|
||||
let ReturnedSettings = {};
|
||||
for (const key in SettingsSkeleton.Settings[config])
|
||||
{
|
||||
let CurrentSetting = SettingsSkeleton.Settings[config][key];
|
||||
if (CurrentSetting.scope == 'world')
|
||||
{
|
||||
if (game.user.isGM)
|
||||
{
|
||||
ReturnedSettings[key] = CurrentSetting;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnedSettings[key] = CurrentSetting;
|
||||
}
|
||||
}
|
||||
|
||||
return { settings: ReturnedSettings }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Activate listeners
|
||||
////////////////////////////////////////////////////////////
|
||||
activateListeners(html, config)
|
||||
{
|
||||
super.activateListeners(html);
|
||||
|
||||
// Checkbox
|
||||
html.on('change', 'input[type=checkbox]', this._handleCheckBoxInteraction.bind(this, config));
|
||||
// Slider
|
||||
html.on('change', 'input[type=range]', this._handleSliderInteraction.bind(this, config));
|
||||
html.on('change', 'input[type=number]', this._handleSliderInteraction.bind(this, config));
|
||||
// String
|
||||
html.on('change', 'input[type=text]', this._handleStringInteraction.bind(this, config));
|
||||
// Dropdown
|
||||
html.on('change', 'select', this._handleDropdownInteraction.bind(this, config));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user