diff --git a/dev/dev.mjs b/dev/dev.mjs new file mode 100644 index 0000000..ccb796e --- /dev/null +++ b/dev/dev.mjs @@ -0,0 +1,2 @@ +// Hooks +import "./hooks/ready.mjs"; diff --git a/dev/hooks/ready.mjs b/dev/hooks/ready.mjs new file mode 100644 index 0000000..d7bea64 --- /dev/null +++ b/dev/hooks/ready.mjs @@ -0,0 +1,5 @@ +import { __ID__ } from "../../module/consts.mjs"; + +Hooks.on(`ready`, () => { + console.table(game.modules.get(__ID__).api.settings); +}); diff --git a/langs/en-ca.json b/langs/en-ca.json index fc4f428..02cd095 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -9,6 +9,10 @@ "name": "Auto Unpause On Load", "hint": "(v13+, GM-Only) Automatically unpauses the game when you load into the world. This will happen EVERY time you load into the world, including if you reload the website." }, + "chatImageLinks": { + "name": "Image Shortcuts", + "hint": "(v13+) When attempting to send an image/gif in chat, this allows you to easily embed the actual image in the text by changing \"http\"/\"https\" into \"image\", automatically displaying the image after sending the message." + }, "chatSidebarBackground": { "name": "Chat Background", "hint": "(v13+) Adds a background to the chat tab of the right-hand sidebar." @@ -21,9 +25,17 @@ "name": "Hotbar Button Size", "hint": "(v13+) Changes the size of the hotbar buttons to a size you prefer." }, + "preventMovementHistory": { + "name": "Prevent Movement History", + "hint": "(v13+, GM-Only) This prevents Foundry from recording movement history of a token, but not disabling the movement ruler." + }, + "preventTokenRotation": { + "name": "Prevent Token Auto-Rotation", + "hint": "(v13+, GM-Only) This prevents tokens from rotating while you are moving them allowing you to more easily use POG-style tokens without them being rotated automatically by Foundry." + }, "preventUserConfigOpen": { "name": "Prevent Auto User Config", - "hint": "(v13+) Prevents Foundry from opening the User Configuration when a player loads into the world." + "hint": "(v13+, Non-GMs) Prevents Foundry from opening the User Configuration when a player loads into the world." }, "repositionHotbar": { "name": "Reposition Hotbar", @@ -46,11 +58,25 @@ "name": "Developer Settings", "hint": "Tweaks that are relevant if you are developing something within Foundry, but are rarely useful outside of that context.", "label": "Configure Dev Settings" + }, + "hotbarSettings": { + "name": "Hotbar Settings", + "hint": "Tweaks that modify Foundry's hotbar", + "label": "Configure Hotbar" } }, "apps": { "no-settings-to-display": "No settings to display", "make-global-reference": "Make Global Reference" + }, + "dialogs": { + "chatImageLinks": { + "didYouKnowImageLink": "", + "convertAndDontShowAgain": "", + "justConvert": "", + "ignoreAndDontShowAgain": "", + "disableEntirely": "" + } } } } diff --git a/module.json b/module.json index 86fedc1..61d9791 100644 --- a/module.json +++ b/module.json @@ -1,7 +1,7 @@ { "id": "oft", "title": "Oliver's Foundry Tweaks", - "version": "1.0.0", + "version": "1.1.0", "authors": [ { "name": "Oliver" } ], @@ -14,7 +14,8 @@ "maximum": 13 }, "esmodules": [ - "module/oft.mjs" + "module/oft.mjs", + "dev/dev.mjs" ], "styles": [ { diff --git a/module/apps/DevSettingsMenu.mjs b/module/apps/DevSettingsMenu.mjs index 909fbab..81a14e8 100644 --- a/module/apps/DevSettingsMenu.mjs +++ b/module/apps/DevSettingsMenu.mjs @@ -1,4 +1,4 @@ -import { devSettings } from "../utils/DevSettings.mjs"; +import { categories } from "../utils/SubMenuSettings.mjs"; import { OFTSettingsMenu } from "./OFTSettingsMenu.mjs"; export class DevSettingsMenu extends OFTSettingsMenu { @@ -9,6 +9,7 @@ export class DevSettingsMenu extends OFTSettingsMenu { }; static get _SETTINGS() { + const devSettings = categories.get(`dev`); const settingIDs = []; for (const [settingID, shown] of devSettings.entries()) { if (shown) { diff --git a/module/apps/HotbarSettingsMenu.mjs b/module/apps/HotbarSettingsMenu.mjs new file mode 100644 index 0000000..0c7fb9e --- /dev/null +++ b/module/apps/HotbarSettingsMenu.mjs @@ -0,0 +1,21 @@ +import { categories } from "../utils/SubMenuSettings.mjs"; +import { OFTSettingsMenu } from "./OFTSettingsMenu.mjs"; + +export class HotbarSettingsMenu extends OFTSettingsMenu { + static DEFAULT_OPTIONS = { + window: { + title: `OFT.menu.hotbarSettings.name`, + }, + }; + + static get _SETTINGS() { + const settings = categories.get(`hotbar`); + const settingIDs = []; + for (const [settingID, shown] of settings.entries()) { + if (shown) { + settingIDs.push(settingID); + }; + }; + return settingIDs; + }; +}; diff --git a/module/apps/OFTSettingsMenu.mjs b/module/apps/OFTSettingsMenu.mjs index 1506c25..74ddf97 100644 --- a/module/apps/OFTSettingsMenu.mjs +++ b/module/apps/OFTSettingsMenu.mjs @@ -1,4 +1,4 @@ -import { filePath } from "../consts.mjs"; +import { __ID__, filePath } from "../consts.mjs"; const { HandlebarsApplicationMixin: HAM, ApplicationV2 } = foundry.applications.api; @@ -7,6 +7,7 @@ export class OFTSettingsMenu extends HAM(ApplicationV2) { // #region Options static DEFAULT_OPTIONS = { tag: `form`, + classes: [ __ID__ ], window: { icon: `fa-solid fa-gears`, resizable: true, diff --git a/module/hooks/init.mjs b/module/hooks/init.mjs new file mode 100644 index 0000000..60cde1b --- /dev/null +++ b/module/hooks/init.mjs @@ -0,0 +1,17 @@ +// Settings +import { preventMovementHistory } from "../settings/preventMovementHistory.mjs"; + +// Utils +import { Logger } from "../utils/Logger.mjs"; + +/* +This is only here for setting that **require** being registered during +initialization due to documentClass changes. If there is any way that +these settings can be implemented to work during the setup hook, that is +where they ideally should be implemented. +*/ +Hooks.on(`init`, () => { + Logger.log(`Initializing`); + + preventMovementHistory(); +}); diff --git a/module/hooks/oft.preventSetting.mjs b/module/hooks/oft.preventSetting.mjs index 31026ac..500dc8e 100644 --- a/module/hooks/oft.preventSetting.mjs +++ b/module/hooks/oft.preventSetting.mjs @@ -5,7 +5,8 @@ of incompatabilities for whatever reason. This can also be used internally within this module if we discover incompatabilites with systems and want to disable it on our side. -This file is more as documentation than anything at this point in time. +This file is meant more documentation than anything at this point in +time. -Call Signature: (settingKey: string) => {} +Call Signature: (settingKey: string) => (void | boolean) */ diff --git a/module/hooks/oft.settingStatuses.mjs b/module/hooks/oft.settingStatuses.mjs new file mode 100644 index 0000000..46bef18 --- /dev/null +++ b/module/hooks/oft.settingStatuses.mjs @@ -0,0 +1,13 @@ +/* +This hook is used to enable any modules that attempt to disable settings +or just want to investigate what settings are enabled to be able to get +a ping with information about which settings where registered entirely +and which weren't. The object that is passed to this is frozen and is +not meant to be edited as you cannot de-register nor prevent setting +registration from this hook. For that see the "oft.preventSetting" hook. + +This file is meant more documentation than anything at this point in +time. + +Call Signature: (settings: Record) => void +*/ diff --git a/module/hooks/setup.mjs b/module/hooks/setup.mjs new file mode 100644 index 0000000..ae63ec6 --- /dev/null +++ b/module/hooks/setup.mjs @@ -0,0 +1,58 @@ +// Settings +import { addGlobalDocReferrer } from "../settings/addGlobalDocReferrer.mjs"; +import { autoUnpauseOnLoad } from "../settings/autoUnpauseOnLoad.mjs"; +import { chatImageLinks } from "../settings/chatImageLinks.mjs"; +import { chatSidebarBackground } from "../settings/chatSidebarBackground.mjs"; +import { hotbarButtonGap } from "../settings/hotbarButtonGap.mjs"; +import { hotbarButtonSize } from "../settings/hotbarButtonSize.mjs"; +import { preventTokenRotation } from "../settings/preventTokenRotation.mjs"; +import { preventUserConfigOpen } from "../settings/preventUserConfigOpen.mjs"; +import { repositionHotbar } from "../settings/repositionHotbar.mjs"; +import { startingSidebarTab } from "../settings/startingSidebarTab.mjs"; +import { startSidebarExpanded } from "../settings/startSidebarExpanded.mjs"; + +// Apps +import { DevSettingsMenu } from "../apps/DevSettingsMenu.mjs"; +import { HotbarSettingsMenu } from "../apps/HotbarSettingsMenu.mjs"; + +// Misc +import { __ID__ } from "../consts.mjs"; +import { status } from "../utils/SettingStatus.mjs"; + +const { deepFreeze } = foundry.utils; + +Hooks.on(`setup`, () => { + + game.settings.registerMenu(__ID__, `devSettings`, { + name: `OFT.menu.devSettings.name`, + hint: `OFT.menu.devSettings.hint`, + label: `OFT.menu.devSettings.label`, + restricted: false, + type: DevSettingsMenu, + }); + addGlobalDocReferrer(); + autoUnpauseOnLoad(); + + game.settings.registerMenu(__ID__, `hotbarSettings`, { + name: `OFT.menu.hotbarSettings.name`, + hint: `OFT.menu.hotbarSettings.hint`, + label: `OFT.menu.hotbarSettings.label`, + restricted: false, + type: HotbarSettingsMenu, + }); + hotbarButtonSize(); + hotbarButtonGap(); + repositionHotbar(); + + chatImageLinks(); + chatSidebarBackground(); + startSidebarExpanded(); + startingSidebarTab(); + preventTokenRotation(); + preventUserConfigOpen(); + + Hooks.callAll(`oft.settingStatuses`, deepFreeze(status)); + game.modules.get(__ID__).api = deepFreeze({ + settings: status, + }); +}); diff --git a/module/oft.mjs b/module/oft.mjs index 5765c9d..8740d00 100644 --- a/module/oft.mjs +++ b/module/oft.mjs @@ -1,40 +1,4 @@ // Hooks +import "./hooks/init.mjs"; +import "./hooks/setup.mjs"; import "./hooks/renderSettingsConfig.mjs"; - -// Settings -import { addGlobalDocReferrer } from "./settings/addGlobalDocReferrer.mjs"; -import { autoUnpauseOnLoad } from "./settings/autoUnpauseOnLoad.mjs"; -import { chatSidebarBackground } from "./settings/chatSidebarBackground.mjs"; -import { hotbarButtonGap } from "./settings/hotbarButtonGap.mjs"; -import { hotbarButtonSize } from "./settings/hotbarButtonSize.mjs"; -import { preventUserConfigOpen } from "./settings/preventUserConfigOpen.mjs"; -import { repositionHotbar } from "./settings/repositionHotbar.mjs"; -import { startingSidebarTab } from "./settings/startingSidebarTab.mjs"; -import { startSidebarExpanded } from "./settings/startSidebarExpanded.mjs"; - -// Apps -import { DevSettingsMenu } from "./apps/DevSettingsMenu.mjs"; - -// Misc -import { __ID__ } from "./consts.mjs"; - -Hooks.on(`setup`, () => { - - game.settings.registerMenu(__ID__, `devSettings`, { - name: `OFT.menu.devSettings.name`, - hint: `OFT.menu.devSettings.hint`, - label: `OFT.menu.devSettings.label`, - restricted: false, - type: DevSettingsMenu, - }); - addGlobalDocReferrer(); - autoUnpauseOnLoad(); - - chatSidebarBackground(); - startSidebarExpanded(); - startingSidebarTab(); - hotbarButtonSize(); - hotbarButtonGap(); - repositionHotbar(); - preventUserConfigOpen(); -}); diff --git a/module/settings/addGlobalDocReferrer.mjs b/module/settings/addGlobalDocReferrer.mjs index 0700606..d955d40 100644 --- a/module/settings/addGlobalDocReferrer.mjs +++ b/module/settings/addGlobalDocReferrer.mjs @@ -1,10 +1,12 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; -import { registerDevSetting } from "../utils/DevSettings.mjs"; +import { registerDevSetting } from "../utils/SubMenuSettings.mjs"; const key = `addGlobalDocReferrer`; export function addGlobalDocReferrer() { + status[key] = SettingStatusEnum.Unknown; // #region Registration Logger.log(`Registering setting: ${key}`); @@ -33,4 +35,5 @@ export function addGlobalDocReferrer() { }); // #endregion Implementation + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/autoUnpauseOnLoad.mjs b/module/settings/autoUnpauseOnLoad.mjs index 03ddea4..de15fa4 100644 --- a/module/settings/autoUnpauseOnLoad.mjs +++ b/module/settings/autoUnpauseOnLoad.mjs @@ -1,14 +1,17 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; -import { registerDevSetting } from "../utils/DevSettings.mjs"; +import { registerDevSetting } from "../utils/SubMenuSettings.mjs"; const key = `autoUnpauseOnLoad`; export function autoUnpauseOnLoad() { + status[key] = SettingStatusEnum.Unknown; const prevented = Hooks.call(`${__ID__}.preventSetting`, key); if (!prevented) { Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; return; }; @@ -34,4 +37,6 @@ export function autoUnpauseOnLoad() { }; }); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/chatImageLinks.mjs b/module/settings/chatImageLinks.mjs new file mode 100644 index 0000000..c25d56f --- /dev/null +++ b/module/settings/chatImageLinks.mjs @@ -0,0 +1,130 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; +import { __ID__ } from "../consts.mjs"; +import { Logger } from "../utils/Logger.mjs"; + +const { DialogV2 } = foundry.applications.api; + +const key = `chatImageLinks`; +const IMAGE_TYPES = [ + `png`, + `jpg`, + `jpeg`, + `webp`, + `svg`, +]; + +export function chatImageLinks() { + status[key] = SettingStatusEnum.Unknown; + + const prevented = Hooks.call(`${__ID__}.preventSetting`, key); + if (!prevented) { + Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; + return; + }; + + // #region Registration + Logger.log(`Registering setting: ${key}`); + game.settings.register(__ID__, key, { + name: `OFT.setting.${key}.name`, + hint: `OFT.setting.${key}.hint`, + scope: `user`, + type: Boolean, + default: true, + config: true, + requiresReload: true, + }); + + game.settings.register(__ID__, key + `-showPromptAgain`, { + scope: `user`, + type: Boolean, + default: true, + config: false, + }); + // #endregion Registration + + // #region Implementation + if (game.settings.get(__ID__, key)) { + Logger.log(`setting:${key} | Adding text enricher`); + + // MARK: Enricher + const pattern = new RegExp( + `(? { + Logger.debug(url); + url = url[0].replace(/^image:\/\//, ``); + const secure = `https://${url}`; + const insecure = `http://${url}`; + + if (await isAcceptableImage(secure)) { + const img = document.createElement(`img`); + img.src = secure; + img.alt = secure; + return img; + }; + + if (await isAcceptableImage(insecure)) { + const img = document.createElement(`img`); + img.src = insecure; + img.alt = insecure; + return img; + }; + + return null; + }, + }); + + // MARK: Chat Input + // Hooks.on(`chatMessage`, (chatLog, message, options) => { + // if (!game.settings.get(__ID__, key)) { return }; + + // const match = message.match(pattern); + // if (!match) { return }; + + // DialogV2.wait({ + // rejectClose: false, + // content: game.i18n.localize(`OFT.dialogs.chatImageLinks.didYouKnowImageLink`), + // buttons: [ + // { action: ``, label: `OFT.dialogs.chatImageLinks.convertAndDontShowAgain` }, + // { action: ``, label: `OFT.dialogs.chatImageLinks.justConvert` }, + // { action: ``, label: `OFT.dialogs.chatImageLinks.ignoreAndDontShowAgain` }, + // { action: ``, label: `OFT.dialogs.chatImageLinks.disableEntirely` }, + // ], + // }) + // .then((selected) => { + // chatLog.processMessage(message, options); + // }); + + // return false; + // }); + } + // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; +}; + +// #region Helpers +async function isAcceptableImage(url) { + try { + const response = await fetch(url, { method: `HEAD` }); + const contentType = response.headers.get(`Content-Type`); + Logger.debug(`Image data:`, { url, contentType }); + let [ superType, subtype ] = contentType.split(`/`); + if (superType !== `image`) { + return false; + }; + if (subtype.includes(`+`)) { + subtype = subtype.split(`+`, 2).at(0); + }; + return IMAGE_TYPES.includes(subtype); + } catch { + return false; + }; +}; +// #endregion Helpers diff --git a/module/settings/chatSidebarBackground.mjs b/module/settings/chatSidebarBackground.mjs index 6fab03d..5fce77a 100644 --- a/module/settings/chatSidebarBackground.mjs +++ b/module/settings/chatSidebarBackground.mjs @@ -1,9 +1,11 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; const key = `chatSidebarBackground`; export function chatSidebarBackground() { + status[key] = SettingStatusEnum.Unknown; // #region Registration Logger.log(`Registering setting: ${key}`); @@ -28,4 +30,6 @@ export function chatSidebarBackground() { document.body.classList.add(`${__ID__}-${key}`); }; // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/hotbarButtonGap.mjs b/module/settings/hotbarButtonGap.mjs index e381508..98c7cbf 100644 --- a/module/settings/hotbarButtonGap.mjs +++ b/module/settings/hotbarButtonGap.mjs @@ -1,20 +1,24 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; +import { registerCategorySetting } from "../utils/SubMenuSettings.mjs"; const key = `hotbarButtonGap`; export function hotbarButtonGap() { + status[key] = SettingStatusEnum.Unknown; const prevented = Hooks.call(`${__ID__}.preventSetting`, key); if (!prevented) { Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; return; }; // #region Registration Logger.log(`Registering setting: ${key}`); document.body.classList.add(`${__ID__}-${key}`); - game.settings.register(__ID__, key, { + registerCategorySetting(`hotbar`, __ID__, key, { name: `OFT.setting.${key}.name`, hint: `OFT.setting.${key}.hint`, scope: `user`, @@ -36,4 +40,6 @@ export function hotbarButtonGap() { const buttonGap = game.settings.get(__ID__, key); document.body.style.setProperty(`--hotbar-button-gap`, `${buttonGap}px`); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/hotbarButtonSize.mjs b/module/settings/hotbarButtonSize.mjs index 6bd1bba..7b4797b 100644 --- a/module/settings/hotbarButtonSize.mjs +++ b/module/settings/hotbarButtonSize.mjs @@ -1,20 +1,24 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; +import { registerCategorySetting } from "../utils/SubMenuSettings.mjs"; const key = `hotbarButtonSize`; export function hotbarButtonSize() { + status[key] = SettingStatusEnum.Unknown; const prevented = Hooks.call(`${__ID__}.preventSetting`, key); if (!prevented) { Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; return; }; // #region Registration Logger.log(`Registering setting: ${key}`); document.body.classList.add(`${__ID__}-${key}`); - game.settings.register(__ID__, key, { + registerCategorySetting(`hotbar`, __ID__, key, { name: `OFT.setting.${key}.name`, hint: `OFT.setting.${key}.hint`, scope: `user`, @@ -36,4 +40,6 @@ export function hotbarButtonSize() { const hotbarSize = game.settings.get(__ID__, key); document.body.style.setProperty(`--hotbar-size`, `${hotbarSize}px`); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/preventMovementHistory.mjs b/module/settings/preventMovementHistory.mjs new file mode 100644 index 0000000..8f4d18c --- /dev/null +++ b/module/settings/preventMovementHistory.mjs @@ -0,0 +1,42 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; +import { __ID__ } from "../consts.mjs"; +import { Logger } from "../utils/Logger.mjs"; + +const key = `preventMovementHistory`; + +export function preventMovementHistory() { + status[key] = SettingStatusEnum.Unknown; + + const prevented = Hooks.call(`${__ID__}.preventSetting`, key); + if (!prevented) { + Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; + return; + }; + + // #region Registration + Logger.log(`Registering setting: ${key}`); + game.settings.register(__ID__, key, { + name: `OFT.setting.${key}.name`, + hint: `OFT.setting.${key}.hint`, + scope: `world`, + type: Boolean, + default: false, + config: true, + reloadRequired: true, + }); + // #endregion Registration + + // #region Implementation + if (game.settings.get(__ID__, key)) { + class OFTTokenDocument extends CONFIG.Token.documentClass { + _shouldRecordMovementHistory() { + return false; + }; + }; + CONFIG.Token.documentClass = OFTTokenDocument; + }; + // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; +}; diff --git a/module/settings/preventTokenRotation.mjs b/module/settings/preventTokenRotation.mjs new file mode 100644 index 0000000..258920c --- /dev/null +++ b/module/settings/preventTokenRotation.mjs @@ -0,0 +1,53 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; +import { __ID__ } from "../consts.mjs"; +import { Logger } from "../utils/Logger.mjs"; + +const key = `preventTokenRotation`; + +export function preventTokenRotation() { + status[key] = SettingStatusEnum.Unknown; + + const prevented = Hooks.call(`${__ID__}.preventSetting`, key); + if (!prevented) { + Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; + return; + }; + + /** @type {number|null} */ + let hookID = null; + + // #region Registration + Logger.log(`Registering setting: ${key}`); + game.settings.register(__ID__, key, { + name: `OFT.setting.${key}.name`, + hint: `OFT.setting.${key}.hint`, + scope: `world`, + type: Boolean, + default: true, + config: true, + requiresReload: false, + onChange: (newValue) => { + if (newValue) { + hookID = Hooks.on(`preMoveToken`, preMoveTokenHandler); + } else if (hookID != null) { + Hooks.off(`preMoveToken`, hookID); + }; + }, + }); + // #endregion Registration + + // #region Implementation + if (game.settings.get(__ID__, key)) { + hookID = Hooks.on(`preMoveToken`, preMoveTokenHandler); + }; + // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; +}; + +// #region Helpers +function preMoveTokenHandler(_token, update) { + update.autoRotate = false; +}; +// #endregion Helpers diff --git a/module/settings/preventUserConfigOpen.mjs b/module/settings/preventUserConfigOpen.mjs index 6377228..3b7646d 100644 --- a/module/settings/preventUserConfigOpen.mjs +++ b/module/settings/preventUserConfigOpen.mjs @@ -1,13 +1,16 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; const key = `preventUserConfigOpen`; export function preventUserConfigOpen() { + status[key] = SettingStatusEnum.Unknown; const prevented = Hooks.call(`${__ID__}.preventSetting`, key); if (!prevented) { Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; return; }; @@ -19,7 +22,7 @@ export function preventUserConfigOpen() { scope: `user`, type: Boolean, default: false, - config: true, + config: !game.user.isGM, requiresReload: false, }); // #endregion Registration @@ -32,4 +35,6 @@ export function preventUserConfigOpen() { }; }); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/repositionHotbar.mjs b/module/settings/repositionHotbar.mjs index 601e580..cce0c5f 100644 --- a/module/settings/repositionHotbar.mjs +++ b/module/settings/repositionHotbar.mjs @@ -1,19 +1,23 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; +import { registerCategorySetting } from "../utils/SubMenuSettings.mjs"; const key = `repositionHotbar`; export function repositionHotbar() { + status[key] = SettingStatusEnum.Unknown; const prevented = Hooks.call(`${__ID__}.preventSetting`, key); if (!prevented) { Logger.log(`Preventing setting "${key}" from being registered`); + status[key] = SettingStatusEnum.Blocked; return; }; // #region Registration Logger.log(`Registering setting: ${key}`); - game.settings.register(__ID__, key, { + registerCategorySetting(`hotbar`, __ID__, key, { name: `OFT.setting.${key}.name`, hint: `OFT.setting.${key}.hint`, scope: `user`, @@ -42,4 +46,6 @@ export function repositionHotbar() { uiPosition.insertAdjacentElement(`beforeend`, container); }; // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/startSidebarExpanded.mjs b/module/settings/startSidebarExpanded.mjs index 0e76033..4cf9f2d 100644 --- a/module/settings/startSidebarExpanded.mjs +++ b/module/settings/startSidebarExpanded.mjs @@ -1,9 +1,11 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; const key = `startSidebarExpanded`; export function startSidebarExpanded() { + status[key] = SettingStatusEnum.Unknown; // #region Registration Logger.log(`Registering setting: ${key}`); @@ -26,4 +28,6 @@ export function startSidebarExpanded() { }; }); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/settings/startingSidebarTab.mjs b/module/settings/startingSidebarTab.mjs index 94c6496..02fab17 100644 --- a/module/settings/startingSidebarTab.mjs +++ b/module/settings/startingSidebarTab.mjs @@ -1,9 +1,11 @@ +import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs"; import { __ID__ } from "../consts.mjs"; import { Logger } from "../utils/Logger.mjs"; const key = `startingSidebarTab`; export function startingSidebarTab() { + status[key] = SettingStatusEnum.Unknown; // #region Registration Logger.log(`Registering setting: ${key}`); @@ -42,10 +44,19 @@ export function startingSidebarTab() { // #region Implementation Hooks.once(`ready`, () => { const defaultTab = game.settings.get(__ID__, key); + if (defaultTab === ``) { return }; + + if (!(defaultTab in CONFIG.ui.sidebar.TABS)) { + Logger.error(`Failed to find starting tab with ID "${defaultTab}", skipping`); + return; + }; + if (defaultTab) { Logger.debug(`Changing tab to:`, defaultTab); ui.sidebar.changeTab(defaultTab, `primary`); }; }); // #endregion Implementation + + status[key] = SettingStatusEnum.Registered; }; diff --git a/module/utils/DevSettings.mjs b/module/utils/DevSettings.mjs deleted file mode 100644 index 7d847fa..0000000 --- a/module/utils/DevSettings.mjs +++ /dev/null @@ -1,9 +0,0 @@ -/** @type {Map} */ -export const devSettings = new Map(); - -export function registerDevSetting(namespace, key, config) { - const visible = config.config; - config.config = false; - game.settings.register(namespace, key, config); - devSettings.set(`${namespace}.${key}`, visible); -}; diff --git a/module/utils/SettingStatus.mjs b/module/utils/SettingStatus.mjs new file mode 100644 index 0000000..d3f1dd5 --- /dev/null +++ b/module/utils/SettingStatus.mjs @@ -0,0 +1,11 @@ +/** @typedef {typeof SettingStatusEnum[keyof typeof SettingStatusEnum]} SettingStatus */ + +export const SettingStatusEnum = foundry.utils.deepFreeze({ + Registered: `registered`, + Blocked: `blocked`, + Incompatible: `incompatible`, + Unknown: `unknown`, +}); + +/** @type {Record} */ +export const status = {}; diff --git a/module/utils/SubMenuSettings.mjs b/module/utils/SubMenuSettings.mjs new file mode 100644 index 0000000..77d73f9 --- /dev/null +++ b/module/utils/SubMenuSettings.mjs @@ -0,0 +1,22 @@ +/** @type {Map>} */ +export const categories = new Map(); + +export function registerCategorySetting(category, namespace, key, config) { + let cat = categories.get(category); + if (!cat) { + cat = new Map(); + categories.set(category, cat); + }; + const visible = config.config; + config.config = false; + game.settings.register(namespace, key, config); + cat.set(`${namespace}.${key}`, visible); +}; + +/** + * A helper function that registers the setting to the "dev" + * category + */ +export function registerDevSetting(namespace, key, config) { + registerCategorySetting(`dev`, namespace, key, config); +}; diff --git a/styles/apps.css b/styles/apps.css new file mode 100644 index 0000000..5b2c628 --- /dev/null +++ b/styles/apps.css @@ -0,0 +1,8 @@ +.application.oft { + > .window-content.standard-form .setting-list { + flex-grow: 1; + display: flex; + flex-direction: column; + gap: 1rem; + } +} diff --git a/styles/main.css b/styles/main.css index 7c87f40..2312044 100644 --- a/styles/main.css +++ b/styles/main.css @@ -3,5 +3,7 @@ @import url("./hotbarButtonSize.css"); @import url("./repositionHotbar.css"); +@import url("./apps.css"); + /* Make the chat sidebar the same width as all the other tabs */ .chat-sidebar:not(.sidebar-popout) { width: unset; }