From 067e1dab973c40819a802b70319f369897e9458f Mon Sep 17 00:00:00 2001 From: Anthony Edmonds Date: Sun, 26 Jan 2025 09:35:54 +0000 Subject: [PATCH] Implemented preview handling and end-user restrictions --- AuraRingApi.js | 21 +++++++++--- AuraRingDirectory.js | 80 +++++++++++++++++++++++++------------------ AuraRingFlags.js | 16 +++++++-- AuraRingSettings.js | 23 ++++++++++++- README.md | 22 ++++++++---- directory.html | 4 +-- images/directory.jpg | Bin 0 -> 27240 bytes 7 files changed, 116 insertions(+), 50 deletions(-) create mode 100644 images/directory.jpg diff --git a/AuraRingApi.js b/AuraRingApi.js index 742769f..68b8061 100644 --- a/AuraRingApi.js +++ b/AuraRingApi.js @@ -185,15 +185,26 @@ export class AuraRingApi */ static set(tokenDocument, auraRing) { + const isPreview = tokenDocument.object.hasPreview === true; + + if (isPreview === true) { + tokenDocument = tokenDocument.object._preview.document; + } + const auraRings = AuraRingFlags.getAuraRings(tokenDocument); - const index = AuraRingApi.getAuraRingIndex(auraRings, auraRing.id); - index !== false - ? auraRings.splice(index, 1) - : auraRing.id = AuraRingFlags.nextAvailableId(auraRings); + if (auraRing.id === null) { + auraRing.id = AuraRingFlags.nextAvailableId(auraRings); + } else { + const index = AuraRingApi.getAuraRingIndex(auraRings, auraRing.id); + + index !== false + ? auraRings.splice(index, 1) + : auraRing.id = AuraRingFlags.nextAvailableId(auraRings); + } auraRings.push(auraRing); - AuraRingFlags.setAuraRings(tokenDocument, auraRings); + AuraRingFlags.setAuraRings(tokenDocument, auraRings, isPreview); } /** diff --git a/AuraRingDirectory.js b/AuraRingDirectory.js index f002c76..daa2b71 100644 --- a/AuraRingDirectory.js +++ b/AuraRingDirectory.js @@ -41,16 +41,8 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) static hook = 'directory-update'; - hooks = { - createToken: null, - destroyToken: null, - settings: null, - }; - selectedTokenId = null; - // TODO Limit directory scroll height - // Setup constructor(tokenDocument = null, options={}) { super(options); @@ -59,6 +51,30 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) this.selectedTokenId = tokenDocument?.id ?? null; } + async close(options = {}) + { + this.deregisterHooks(); + return super.close(options); + } + + registerHooks() + { + Hooks.on('createToken', this.renderDirectory); + Hooks.on('destroyToken', this.renderDirectory); + Hooks.on(AuraRingDirectory.hook, this.renderDirectory); + } + + renderDirectory = () => { + this.render(); + } + + deregisterHooks() + { + Hooks.off('createToken', this.renderDirectory); + Hooks.off('destroyToken', this.renderDirectory); + Hooks.off(AuraRingDirectory.hook, this.renderDirectory); + } + _onRender(context, options) { super._onRender(context, options); @@ -72,10 +88,16 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) const tokens = []; for (let index = 0; index < tokenDocuments.length; ++index) { + const token = tokenDocuments[index]; + + if (token.isOwner === false) { + continue; + } + tokens.push({ - id: tokenDocuments[index].id, - name: tokenDocuments[index].name, - selected: tokenDocuments[index].id === this.selectedTokenId, + id: token.id, + name: token.name, + selected: token.id === this.selectedTokenId, }) } @@ -89,12 +111,6 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) }; } - async close(options = {}) - { - this.deregisterHooks(); - super.close(options); - } - static register() { game.settings.register(AuraRingFlags.namespace, AuraRingDirectory.name, { @@ -107,20 +123,14 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) Hooks.call(AuraRingDirectory.hook); }, }); - } - registerHooks() - { - this.hooks.createToken = Hooks.on('createToken', this.render.bind(this)); - this.hooks.destroyToken = Hooks.on('destroyToken', this.render.bind(this)); - this.hooks.settings = Hooks.on(AuraRingDirectory.hook, this.render.bind(this)); - } - - deregisterHooks() - { - Hooks.off('createToken', this.hooks.createToken); - Hooks.off('destroyToken', this.hooks.destroyToken); - Hooks.off(AuraRingDirectory.hook, this.hooks.settings); + game.settings.registerMenu(AuraRingFlags.namespace, 'open-directory', { + name: "Aura Ring Directory", + label: "Open...", + hint: "Open the Aura Ring Directory to apply and manage your stored Aura Rings.", + icon: "fas fa-folder-open", + type: AuraRingDirectory, + }); } // Handlers @@ -175,9 +185,6 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) const tokenDocument = game.scenes.current.tokens.get(tokenId); AuraRingApi.set(tokenDocument, auraRing); - - // TODO May need to handle previews differently - // Correct. Currently causes preview to desync from original } /** @@ -196,11 +203,16 @@ export class AuraRingDirectory extends HandlebarsApplicationMixin(ApplicationV2) */ static get(name) { - return AuraRingApi.getAuraRing( + let auraRing = AuraRingApi.getAuraRing( AuraRingDirectory.all(), name, 'name', ); + + auraRing = foundry.utils.deepClone(auraRing); + auraRing.id = null; + + return auraRing; } /** diff --git a/AuraRingFlags.js b/AuraRingFlags.js index dc3e411..b59672f 100644 --- a/AuraRingFlags.js +++ b/AuraRingFlags.js @@ -4,6 +4,8 @@ export class AuraRingFlags { static auraRingsKey = 'aura-rings'; + static hook = 'flags-updated'; + static namespace = 'token-aura-ring'; // Flags @@ -26,9 +28,19 @@ export class AuraRingFlags return tokenDocument.flags[AuraRingFlags.namespace].hasOwnProperty(AuraRingFlags.auraRingsKey) === true; } - static setAuraRings(tokenDocument, auraRings) + /** + * Set the TokenDocument's Aura Ring Flag + * @param {TokenDocument} tokenDocument + * @param {AuraRing} auraRings + * @param {boolean} directly Whether to set the flag directly, to avoid re-rendering + */ + static setAuraRings(tokenDocument, auraRings, directly = false) { - tokenDocument.setFlag(AuraRingFlags.namespace, AuraRingFlags.auraRingsKey, auraRings); + directly === true + ? tokenDocument.flags[AuraRingFlags.namespace][AuraRingFlags.auraRingsKey] = auraRings + : tokenDocument.setFlag(AuraRingFlags.namespace, AuraRingFlags.auraRingsKey, auraRings); + + Hooks.call(AuraRingFlags.hook); } // Auras diff --git a/AuraRingSettings.js b/AuraRingSettings.js index b17aa1e..e7b73d0 100644 --- a/AuraRingSettings.js +++ b/AuraRingSettings.js @@ -78,12 +78,33 @@ export class AuraRingSettings extends HandlebarsApplicationMixin(ApplicationV2) } // Setup - constructor(simpleTokenDocument, options={}) { + constructor(simpleTokenDocument, options = {}) { super(options); + this.registerHooks(); this.preview = simpleTokenDocument; this.auraRings = AuraRingFlags.getAuraRings(this.preview); } + async close(options = {}) + { + this.deregisterHooks(); + return super.close(options); + } + + registerHooks() + { + Hooks.on(AuraRingFlags.hook, this.renderDirectory); + } + + renderDirectory = () => { + this.render(); + } + + deregisterHooks() + { + Hooks.off(AuraRingFlags.hook, this.renderDirectory); + } + _onChangeForm(context, event) { if (event.target.form !== null) { diff --git a/README.md b/README.md index 32294ef..973d601 100644 --- a/README.md +++ b/README.md @@ -119,23 +119,33 @@ For example, a standard medium creature (1 square = 5 foot) can have a minimum r ## Directory -A global Aura Ring Directory is provided to allow for defining and reusing common Aura Rings which you may want to use across many tokens. +A global Aura Ring Directory is provided to allow for defining Aura Rings for use across many tokens. ![An example of the Aura Ring Directory](images/directory.jpg) -You can pick which token to add Aura Rings to from the dropdown, which lists all Tokens in the current scene. +### Opening the Directory -If the Directory was opened from an Aura Ring Configuration screen, the current Token will be automatically selected. +A button to open the Aura Ring Directory is provided in the main "Configure Settings" and on Aura Ring Configuration screens. -You can then add any number of Aura Rings to that token. +You can also open the Directory using a macro, which is provided in the `API` section. + +### Applying Aura Rings + +You can pick which token to add Aura Rings to from the dropdown, which lists all tokens and token previews in the current scene. + +If the Directory was opened from an Aura Ring Configuration screen, the current token preview will be automatically selected. + +Pressing the "Add" button will copy the Aura Ring from the directory onto the selected token. You can also rename and remove any Aura Rings from the directory. -To overwrite an existing Aura Ring, simply save an Aura Ring with the same name. +### Library Management + +To overwrite an existing Aura Ring, save an Aura Ring with the same name. You will be prompted to change the name, in case you did not intend to overwrite an existing Aura Ring. -You can open the Directory without going through a Token using a macro, which is provided in the `API` section. +Pressing the "Remove" button will immediately delete that Aura Ring from the Directory. ## API diff --git a/directory.html b/directory.html index 949a44c..c1865e3 100644 --- a/directory.html +++ b/directory.html @@ -21,8 +21,8 @@

Selected Tok

Select the token to add Aura Rings to.

{{else}} -

There are no Tokens in the current scene.

-

Add a Token to the scene and reload the Directory.

+

You do not control any Tokens in the current scene.

+

Add an owned Token to the scene to add Aura Rings.

{{/if}}

Saved Aura Rings

diff --git a/images/directory.jpg b/images/directory.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4e27cf89a48ea6a36ca9f2c6007c3234a36cff2b GIT binary patch literal 27240 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 z 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 U@VDMWCx`~Ow@2KMYFZ!q39d-@`2YX_ literal 0 HcmV?d00001