From 4d5ea97d332463a61e47476a1a573c82fc325a8c Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 10:43:22 -0600 Subject: [PATCH 01/29] Removed references to Tidy 5e Sheet from the magicitemtab script. --- src/scripts/magicItemtab.js | 41 +++++++++++++------------------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 9131857..1faaa83 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -29,31 +29,20 @@ export class MagicItemTab { } init(html, data) { - - if (this.app.constructor.name !== "Tidy5eKgarItemSheet") { - if (html[0].localName !== "div") { - html = $(html[0].parentElement.parentElement); - } - let tabs = html.find(`form nav.sheet-navigation.tabs`); - if (tabs.find("a[data-tab=magicitems]").length > 0) { - return; // already initialized, duplication bug! - } - - tabs.append($('Magic Item')); - - $(html.find(`.sheet-body`)).append( - $('
') - ); + if (html[0].localName !== "div") { + html = $(html[0].parentElement.parentElement); } - else { - html = $(html[0]); - Logger.logObject(html); - let tabs = html.find(`form nav.tidy-tabs`); - if (tabs.find("a[data-tab-id=magic-items]").length > 0) { - return; - } + let tabs = html.find(`form nav.sheet-navigation.tabs`); + if (tabs.find("a[data-tab=magicitems]").length > 0) { + return; // already initialized, duplication bug! } + tabs.append($('Magic Item')); + + $(html.find(`.sheet-body`)).append( + $('
') + ); + this.html = html; this.editable = data.editable; @@ -82,7 +71,7 @@ export class MagicItemTab { hack(app) { let tab = this; - app.setPosition = function(position = {}) { + app.setPosition = function (position = {}) { position.height = tab.isActive() && !position.height ? "auto" : position.height; let that = this; for (let i = 0; i < 100; i++) { @@ -154,7 +143,7 @@ export class MagicItemTab { this.app.setPosition(); - if (this.app.constructor.name !== "Tidy5eKgarItemSheet" && this.activate && !this.isActive()) { + if (this.activate && !this.isActive()) { this.app._tabs[0].activate("magicitems"); this.activate = false; } else { @@ -317,9 +306,7 @@ export class MagicItemTab { } isActive() { - return this.app.constructor.name !== "Tidy5eKgarItemSheet" ? - $(this.html).find('a.item[data-tab="magicitems"]').hasClass("active") : - $(this.html).find('a.item[data-tab-id="magic-items"]').hasClass("active") + $(this.html).find('a.item[data-tab="magicitems"]').hasClass("active"); } _canDragDrop() { From 95fcddcd3c7ea8ba65ddc86f904cd6ef50684923 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 11:51:39 -0600 Subject: [PATCH 02/29] Moved show/hide and enable/disable logic to the template. --- src/scripts/magicItemtab.js | 42 +-- src/templates/magic-item-tab.hbs | 433 +++++++++++++++++-------------- 2 files changed, 240 insertions(+), 235 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 1faaa83..7cf92d0 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -85,7 +85,9 @@ export class MagicItemTab { } async render() { + // TODO: Sort as part of the magic item adapter when enumerating items this.magicItem.sort(); + let template = await renderTemplate(`modules/${CONSTANTS.MODULE_ID}/templates/magic-item-tab.hbs`, this.magicItem); let el = this.html.find(`.magic-items-content`); if (el.length) { @@ -94,46 +96,6 @@ export class MagicItemTab { this.html.find(".tab.magic-items").append(template); } - let magicItemEnabled = this.html.find(".magic-item-enabled"); - if (this.magicItem.enabled) { - magicItemEnabled.show(); - } else { - magicItemEnabled.hide(); - } - - let magicItemDestroyType = this.html.find('select[name="flags.magicitems.destroyType"]'); - if (this.magicItem.chargeType === "c1") { - magicItemDestroyType.show(); - } else { - magicItemDestroyType.hide(); - } - - let magicItemDestroyCheck = this.html.find('select[name="flags.magicitems.destroyCheck"]'); - let magicItemFlavorText = this.html.find(".magic-item-destroy-flavor-text"); - if (this.magicItem.destroy) { - magicItemDestroyCheck.prop("disabled", false); - magicItemDestroyType.prop("disabled", false); - magicItemFlavorText.show(); - } else { - magicItemDestroyCheck.prop("disabled", true); - magicItemDestroyType.prop("disabled", true); - magicItemFlavorText.hide(); - } - - let magicItemRecharge = this.html.find(".form-group.magic-item-recharge"); - if (this.magicItem.rechargeable) { - magicItemRecharge.show(); - } else { - magicItemRecharge.hide(); - } - - let rechargeField = this.html.find('input[name="flags.magicitems.recharge"]'); - if (this.magicItem.rechargeType === MAGICITEMS.FORMULA_FULL) { - rechargeField.prop("disabled", true); - } else { - rechargeField.prop("disabled", false); - } - if (this.editable) { this.handleEvents(); } else { diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index df14f91..fe320c4 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -1,241 +1,284 @@
+
+ + +
+
- - + + {{localize "MAGICITEMS.SheetActivationEquipped"}} + + {{localize "MAGICITEMS.SheetActivationAttuned"}} +
-
- - {{localize "MAGICITEMS.SheetActivationEquipped"}} - - {{localize "MAGICITEMS.SheetActivationAttuned"}} - -
-
- -
- - -
+ +
+ + +
- - - + - +
-
- - +
+ +
+
- - + +
-
- -
- - - -
+
+ +
+ + + +
{{!--
- -
- {{radioBoxes "flags.magicitems.sorting" sortingModes checked=sorting localize=true}} -
-
--}} + +
+ {{radioBoxes "flags.magicitems.sorting" sortingModes checked=sorting localize=true}} +
+
--}} {{#if spells.length}} -
    -
  1. -
    -

    {{localize "MAGICITEMS.SheetSpell"}}

    -
    -
    {{localize "MAGICITEMS.SheetLevel"}}
    -
    {{localize "MAGICITEMS.SheetConsumption"}}
    -
    {{localize "MAGICITEMS.SheetUpcast"}}
    -
    {{localize "MAGICITEMS.SheetCost"}}
    -
    Save DC
    -
     
    -
  2. +
      +
    1. +
      +

      {{localize "MAGICITEMS.SheetSpell"}}

      +
      +
      {{localize "MAGICITEMS.SheetLevel"}}
      +
      {{localize "MAGICITEMS.SheetConsumption"}}
      +
      {{localize "MAGICITEMS.SheetUpcast"}}
      +
      {{localize "MAGICITEMS.SheetCost"}}
      +
      Save DC
      +
       
      +
    2. -
        - {{#each spells as |item i|}} -
      1. -
        -
        -

        {{item.displayName}}

        - - - - - - -
        - - - - +
          + {{#each spells as |item i|}} +
        1. +
          +
          +

          {{item.displayName}}

          + + + + + + +
          + + + + - - + + -
          - - - -
          -
        2. - {{/each}} -
        +
        + + + +
        +
      2. + {{/each}}
      +
    {{/if}} {{#if feats.length}} -
      -
    1. -
      -

      {{localize "MAGICITEMS.SheetFeat"}}

      -
      -
      {{localize "MAGICITEMS.SheetEffect"}}
      -
      {{localize "MAGICITEMS.SheetConsumption"}}
      -
       
      -
    2. +
        +
      1. +
        +

        {{localize "MAGICITEMS.SheetFeat"}}

        +
        +
        {{localize "MAGICITEMS.SheetEffect"}}
        +
        {{localize "MAGICITEMS.SheetConsumption"}}
        +
         
        +
      2. -
          - {{#each feats as |item i|}} -
        1. -
          -
          -

          {{item.displayName}}

          - - - - - -
          - - -
          - - - -
          -
        2. - {{/each}} -
        +
          + {{#each feats as |item i|}} +
        1. +
          +
          +

          {{item.displayName}}

          + + + + + +
          + + +
          + + + +
          +
        2. + {{/each}}
        +
      {{/if}} {{#if tables.length}} -
        -
      1. -
        -

        {{localize "MAGICITEMS.SheetTable"}}

        -
        -
        {{localize "MAGICITEMS.SheetUsage"}}
        -
        {{localize "MAGICITEMS.SheetConsumption"}}
        -
         
        -
      2. +
          +
        1. +
          +

          {{localize "MAGICITEMS.SheetTable"}}

          +
          +
          {{localize "MAGICITEMS.SheetUsage"}}
          +
          {{localize "MAGICITEMS.SheetConsumption"}}
          +
           
          +
        2. -
            - {{#each tables as |item i|}} -
          1. -
            -
            -

            {{item.displayName}}

            - - - - - -
            - - -
            - - - -
            -
          2. - {{/each}} -
          +
            + {{#each tables as |item i|}} +
          1. +
            +
            +

            {{item.displayName}}

            + + + + + +
            + + +
            + + + +
            +
          2. + {{/each}}
          +
        {{/if}} {{#each spellsGarbage as |index i|}} - + {{/each}} {{#each featsGarbage as |index i|}} - + {{/each}} {{#each tablesGarbage as |index i|}} - + {{/each}} {{#if empty}} -
      3. -
        {{localize "MAGICITEMS.SheetDragContent"}}
        -
      4. +
      5. +
        {{localize "MAGICITEMS.SheetDragContent"}}
        +
      6. {{/if}} -
-
+
+
\ No newline at end of file From 155c7b628b64125858b566382509adbe9a816566 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 12:07:31 -0600 Subject: [PATCH 03/29] Swapped out block logic in attribute values with inline `ifThen` operator to allow prettier to format without error. --- src/templates/magic-item-tab.hbs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index fe320c4..9c81a38 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -3,7 +3,7 @@ -
+
{{localize "MAGICITEMS.SheetActivationEquipped"}} @@ -36,27 +36,28 @@ {{/each}} {{/select}} - +
-
+
- +
-
+
Date: Wed, 24 Jan 2024 14:14:07 -0600 Subject: [PATCH 04/29] Separated tab content event handling and tab management event handling. Made content event handling a static/shareable function to allow for alternate sheet integration. Removed all unnecessary event handling for the MI tab. Added manual item updating to spell/feat/table delete icon click events. Ensured the MI tab stays selected between renders when interacting with delete icons. Added manual item updating when dropping a relevant entity onto the MI tab. Began to extract `onDrop` for more public shareability. --- src/scripts/magicItemtab.js | 220 ++++++++++++++---------------------- 1 file changed, 84 insertions(+), 136 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 7cf92d0..7736924 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -56,7 +56,10 @@ export class MagicItemTab { callbacks: { dragstart: this.app._onDragStart.bind(this.app), dragover: this.app._onDragOver.bind(this.app), - drop: this._onDrop.bind(this), + drop: (event) => { + this.activate = true; + this.onDrop.call(this, event); + }, }, }); @@ -97,7 +100,15 @@ export class MagicItemTab { } if (this.editable) { - this.handleEvents(); + this.activateTabManagementListeners(); + MagicItemTab.activateTabContentsListeners({ + html: this.html, + item: this.item, + magicItem: this.magicItem, + onItemUpdatingCallback: () => { + this.activate = true; + }, + }); } else { this.html.find("input").prop("disabled", true); this.html.find("select").prop("disabled", true); @@ -113,139 +124,7 @@ export class MagicItemTab { } } - handleEvents() { - this.html.find('.magic-items-content input[type="text"]').change((evt) => { - this.activate = true; - this.render(); - }); - this.html.find(".magic-items-content select").change((evt) => { - this.activate = true; - this.render(); - }); - - this.html.find('input[name="flags.magicitems.enabled"]').click((evt) => { - this.magicItem.toggleEnabled(evt.target.checked); - this.render(); - }); - this.html.find('input[name="flags.magicitems.equipped"]').click((evt) => { - this.magicItem.equipped = evt.target.checked; - this.render(); - }); - this.html.find('input[name="flags.magicitems.attuned"]').click((evt) => { - this.magicItem.attuned = evt.target.checked; - this.render(); - }); - this.html.find('input[name="flags.magicitems.charges"]').change((evt) => { - this.magicItem.charges = MagicItemHelpers.numeric(evt.target.value, this.magicItem.charges); - this.render(); - }); - this.html.find('select[name="flags.magicitems.chargeType"]').change((evt) => { - this.magicItem.chargeType = evt.target.value; - this.magicItem.updateDestroyTarget(); - this.render(); - }); - this.html.find('input[name="flags.magicitems.rechargeable"]').change((evt) => { - this.magicItem.toggleRechargeable(evt.target.checked); - this.render(); - }); - this.html.find('input[name="flags.magicitems.recharge"]').change((evt) => { - this.magicItem.recharge = evt.target.value; - this.render(); - }); - this.html.find('select[name="flags.magicitems.rechargeType"]').change((evt) => { - this.magicItem.rechargeType = evt.target.value; - this.render(); - }); - this.html.find('select[name="flags.magicitems.rechargeUnit"]').change((evt) => { - this.magicItem.rechargeUnit = evt.target.value; - this.render(); - }); - this.html.find('input[name="flags.magicitems.destroy"]').change((evt) => { - this.magicItem.destroy = evt.target.checked; - this.render(); - }); - this.html.find('select[name="flags.magicitems.destroyCheck"]').change((evt) => { - this.magicItem.destroyCheck = evt.target.value; - this.render(); - }); - this.html.find('select[name="flags.magicitems.destroyType"]').change((evt) => { - this.magicItem.destroyType = evt.target.value; - this.render(); - }); - this.html.find('input[name="flags.magicitems.destroyFlavorText"]').change((evt) => { - this.magicItem.destroyFlavorText = evt.target.value; - this.render(); - }); - this.html.find('input[name="flags.magicitems.sorting"]').change((evt) => { - this.magicItem.sorting = evt.target.value; - this.magicItem.sort(); - this.render(); - }); - this.html.find(".item-delete.item-spell").click((evt) => { - this.magicItem.removeSpell(evt.target.getAttribute("data-spell-idx")); - this.render(); - }); - this.html.find(".item-delete.item-feat").click((evt) => { - this.magicItem.removeFeat(evt.target.getAttribute("data-feat-idx")); - this.render(); - }); - this.html.find(".item-delete.item-table").click((evt) => { - this.magicItem.removeTable(evt.target.getAttribute("data-table-idx")); - this.render(); - }); - this.magicItem.spells.forEach((spell, idx) => { - this.html.find(`select[name="flags.magicitems.spells.${idx}.level"]`).change((evt) => { - spell.level = parseInt(evt.target.value); - this.render(); - }); - this.html.find(`input[name="flags.magicitems.spells.${idx}.consumption"]`).change((evt) => { - spell.consumption = MagicItemHelpers.numeric(evt.target.value, spell.consumption); - this.render(); - }); - this.html.find(`select[name="flags.magicitems.spells.${idx}.upcast"]`).change((evt) => { - spell.upcast = parseInt(evt.target.value); - this.render(); - }); - this.html.find(`input[name="flags.magicitems.spells.${idx}.upcastCost"]`).change((evt) => { - spell.upcastCost = MagicItemHelpers.numeric(evt.target.value, spell.cost); - this.render(); - }); - this.html.find(`input[name="flags.magicitems.spells.${idx}.flatDc"]`).click((evt) => { - spell.flatDc = evt.target.checked; - this.render(); - }); - this.html.find(`input[name="flags.magicitems.spells.${idx}.dc"]`).change((evt) => { - spell.dc = evt.target.value; - this.render(); - }); - this.html.find(`a[data-spell-idx="${idx}"]`).click((evt) => { - spell.renderSheet(); - }); - }); - this.magicItem.feats.forEach((feat, idx) => { - this.html.find(`select[name="flags.magicitems.feats.${idx}.effect"]`).change((evt) => { - feat.effect = evt.target.value; - this.render(); - }); - this.html.find(`input[name="flags.magicitems.feats.${idx}.consumption"]`).change((evt) => { - feat.consumption = MagicItemHelpers.numeric(evt.target.value, feat.consumption); - this.render(); - }); - this.html.find(`a[data-feat-idx="${idx}"]`).click((evt) => { - feat.renderSheet(); - }); - }); - this.magicItem.tables.forEach((table, idx) => { - this.html.find(`input[name="flags.magicitems.tables.${idx}.consumption"]`).change((evt) => { - table.consumption = MagicItemHelpers.numeric(evt.target.value, table.consumption); - }); - this.html.find(`a[data-table-idx="${idx}"]`).click((evt) => { - table.renderSheet(); - }); - }); - } - - async _onDrop(evt) { + async onDrop(evt) { evt.preventDefault(); let data; @@ -263,7 +142,11 @@ export class MagicItemTab { if (entity && this.magicItem.compatible(entity)) { this.magicItem.addEntity(entity, pack); - this.render(); + this.item.update({ + flags: { + magicitems: this.magicItem.serializeData(), + }, + }); } } @@ -278,4 +161,69 @@ export class MagicItemTab { _canDragStart() { return true; } + + activateTabManagementListeners() { + this.html.find(".magic-items-content").on("change", ":input, :focus", (evt) => { + this.activate = true; + }); + } + + /** + * Activates listeners related to tab contents. + * + * @param {object} params The parameters for wiring up tab content event handling. + * @param {jQuery} params.html The sheet HTML jQuery element + * @param {Item5e} params.item The item which is to be changed. + * @param {MagicItem} params.magicItem A Magic Item instance + * @param {Function} params.onItemUpdatingCallback A callback for handling when item updates are about to be applied. This is useful for current tab management. + */ + static activateTabContentsListeners({ + html, + item, + magicItem, + onItemUpdatingCallback: onMagicItemUpdatingCallback = null, + }) { + html.find(".item-delete.item-spell").click((evt) => { + magicItem.removeSpell(evt.target.getAttribute("data-spell-idx")); + onMagicItemUpdatingCallback?.(); + item.update({ + flags: { + magicitems: magicItem.serializeData(), + }, + }); + }); + html.find(".item-delete.item-feat").click((evt) => { + magicItem.removeFeat(evt.target.getAttribute("data-feat-idx")); + onMagicItemUpdatingCallback?.(); + item.update({ + flags: { + magicitems: magicItem.serializeData(), + }, + }); + }); + html.find(".item-delete.item-table").click((evt) => { + magicItem.removeTable(evt.target.getAttribute("data-table-idx")); + onMagicItemUpdatingCallback?.(); + item.update({ + flags: { + magicitems: magicItem.serializeData(), + }, + }); + }); + magicItem.spells.forEach((spell, idx) => { + html.find(`a[data-spell-idx="${idx}"]`).click((evt) => { + spell.renderSheet(); + }); + }); + magicItem.feats.forEach((feat, idx) => { + html.find(`a[data-feat-idx="${idx}"]`).click((evt) => { + feat.renderSheet(); + }); + }); + magicItem.tables.forEach((table, idx) => { + html.find(`a[data-table-idx="${idx}"]`).click((evt) => { + table.renderSheet(); + }); + }); + } } From 56b510bfb2119ce635a5998288913443a1bc9118 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 14:41:57 -0600 Subject: [PATCH 05/29] Added `enable` check on construction, to ensure that the Magic Item clears all data on construction if it is disabled. --- src/scripts/magic-item/MagicItem.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/scripts/magic-item/MagicItem.js b/src/scripts/magic-item/MagicItem.js index 6888b43..98682a1 100644 --- a/src/scripts/magic-item/MagicItem.js +++ b/src/scripts/magic-item/MagicItem.js @@ -23,7 +23,6 @@ export class MagicItem { this.destroyFlavorText = data.destroyFlavorText; this.sorting = data.sorting; this.sortingModes = { l: "MAGICITEMS.SheetSortByLevel", a: "MAGICITEMS.SheetSortAlphabetically" }; - this.updateDestroyTarget(); this.spells = Object.values(data.spells ? data.spells : {}) .filter((spell) => spell !== "null") @@ -44,6 +43,10 @@ export class MagicItem { this.savedSpells = this.spells.length; this.savedFeats = this.feats.length; this.savedTables = this.tables.length; + + if (!this.enabled) { + this.clear(); + } } sort() { @@ -55,11 +58,10 @@ export class MagicItem { } } - updateDestroyTarget() { - this.destroyTarget = - this.chargeType === "c1" - ? game.i18n.localize("MAGICITEMS.SheetObjectTarget") - : game.i18n.localize("MAGICITEMS.SheetSpellTarget"); + get destroyTarget() { + return this.chargeType === "c1" + ? game.i18n.localize("MAGICITEMS.SheetObjectTarget") + : game.i18n.localize("MAGICITEMS.SheetSpellTarget"); } defaultData() { From f10e19c7d33e0d4387a1b80afa06f75b774fdbec Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 15:58:21 -0600 Subject: [PATCH 06/29] Made onDrop static so that it can be shared with other sheet modules without the MagicItemTab class. Made disableMagicItemTabInputs static so that it can be shared with other sheet modules without the MagicItemTab class. Revamped tidy registration to leverage tab contents event listeners, on-drop handling, and tab contents input disabling during onRender callback. Added getData prop for the Handlebars template. Formalized the isAcceptedItemType and isAllowedToShow static functions in MagicItemTab to be shared between Tidy and regular tab handling. Replaced Tidy5eKgarItemSheet constructor detection with API call that checks whether MI2 is dealing with a Tidy sheet. --- src/module.js | 56 ++++++++++++++-------- src/scripts/magicItemtab.js | 93 ++++++++++++++++++++++++------------- 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/module.js b/src/module.js index 73bfd05..c8bb9f2 100644 --- a/src/module.js +++ b/src/module.js @@ -4,6 +4,7 @@ import Logger from "./scripts/lib/Logger.js"; import { MagicItemActor } from "./scripts/magicitemactor.js"; import { MagicItemSheet } from "./scripts/magicitemsheet.js"; import { MagicItemTab } from "./scripts/magicItemtab.js"; +import { MagicItem } from "./scripts/magic-item/MagicItem.js"; //CONFIG.debug.hooks = true; @@ -66,33 +67,50 @@ Hooks.once("createToken", (token) => { } }); -Hooks.once('tidy5e-sheet.ready', (api) => { - const myTab = new api.models.HandlebarsTab({ - title: 'Magic Items', - tabId: 'magic-items', - path: '/modules/magic-items-2/templates/magic-item-tab.hbs', - enabled: (data) => { return ["weapon", "equipment", "consumable", "tool", "backpack", "feat"].includes(data.item.type) }, +let tidyApi; +Hooks.once("tidy5e-sheet.ready", (api) => { + tidyApi = api; + const magicItemsTab = new api.models.HandlebarsTab({ + title: "Magic Items", + tabId: "magic-items", + path: "/modules/magic-items-2/templates/magic-item-tab.hbs", + enabled: (data) => { + return MagicItemTab.isAcceptedItemType(data.item) && MagicItemTab.isAllowedToShow(); + }, + getData(data) { + return new MagicItem(data.item.flags.magicitems); + }, onRender(params) { - if (!game.user.isGM && game.settings.get(CONSTANTS.MODULE_ID, "hideFromPlayers")) { - return; + const html = $(params.element); + + if (params.data.editable) { + const magicItem = new MagicItem(params.data.item.flags.magicitems); + MagicItemTab.activateTabContentsListeners({ + html: html, + item: params.data.item, + magicItem: magicItem, + }); + params.element.querySelector(`.magic-items-content`).addEventListener("drop", (event) => { + MagicItemTab.onDrop({ event, item: params.data.item, magicItem: magicItem }); + }); + } else { + MagicItemTab.disableMagicItemTabInputs(html); } - var htmlArr = []; - htmlArr.push($(params.element)); - MagicItemTab.bind(params.app, htmlArr, params.data); }, }); - Logger.logObject(myTab); - api.registerItemTab(myTab); + api.registerItemTab(magicItemsTab); }); - Hooks.on(`renderItemSheet5e`, (app, html, data) => { - if (app.constructor.name !== "Tidy5eKgarItemSheet") { - if (!game.user.isGM && game.settings.get(CONSTANTS.MODULE_ID, "hideFromPlayers")) { - return; - } - MagicItemTab.bind(app, html, data); + if (tidyApi?.isTidy5eItemSheet(app)) { + return; } + + if (!MagicItemTab.isAllowedToShow()) { + return; + } + + MagicItemTab.bind(app, html, data); }); Hooks.on(`renderActorSheet5eCharacter`, (app, html, data) => { diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 7736924..f4cc6d1 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -8,8 +8,7 @@ const magicItemTabs = []; export class MagicItemTab { static bind(app, html, item) { - let acceptedTypes = ["weapon", "equipment", "consumable", "tool", "backpack", "feat"]; - if (acceptedTypes.includes(item.document.type)) { + if (MagicItemTab.isAcceptedItemType(item.document)) { let tab = magicItemTabs[app.id]; if (!tab) { tab = new MagicItemTab(app); @@ -58,7 +57,11 @@ export class MagicItemTab { dragover: this.app._onDragOver.bind(this.app), drop: (event) => { this.activate = true; - this.onDrop.call(this, event); + MagicItemTab.onDrop({ + event: event, + item: this.item, + magicItem: this.magicItem, + }); }, }, }); @@ -110,8 +113,7 @@ export class MagicItemTab { }, }); } else { - this.html.find("input").prop("disabled", true); - this.html.find("select").prop("disabled", true); + MagicItemTab.disableMagicItemTabInputs(this.html); } this.app.setPosition(); @@ -124,32 +126,6 @@ export class MagicItemTab { } } - async onDrop(evt) { - evt.preventDefault(); - - let data; - try { - data = JSON.parse(evt.dataTransfer.getData("text/plain")); - if (!this.magicItem.support(data.type)) { - return; - } - } catch (err) { - return false; - } - - const entity = await fromUuid(data.uuid); - const pack = entity.pack ? entity.pack : "world"; - - if (entity && this.magicItem.compatible(entity)) { - this.magicItem.addEntity(entity, pack); - this.item.update({ - flags: { - magicitems: this.magicItem.serializeData(), - }, - }); - } - } - isActive() { $(this.html).find('a.item[data-tab="magicitems"]').hasClass("active"); } @@ -168,6 +144,49 @@ export class MagicItemTab { }); } + /** + * Disable all relevant inputs in the magic items tab. + */ + static disableMagicItemTabInputs(html) { + html.find(".magic-items-content input").prop("disabled", true); + html.find(".magic-items-content select").prop("disabled", true); + } + + /** + * Handles drop event for compatible magic item source (for example, a spell). + * + * @param {object} params Parameters needed to handle item drops to the magic item tab. + * @param {DragEvent} params.event The drop event. + * @param {Item5e} params.item The target item. + * @param {MagicItem} params.magicItem The relevant magic item associated with the target item. + * @returns + */ + static async onDrop({ event, item, magicItem }) { + event.preventDefault(); + + let data; + try { + data = JSON.parse(event.dataTransfer.getData("text/plain")); + if (!magicItem.support(data.type)) { + return; + } + } catch (err) { + return false; + } + + const entity = await fromUuid(data.uuid); + const pack = entity.pack ? entity.pack : "world"; + + if (entity && magicItem.compatible(entity)) { + magicItem.addEntity(entity, pack); + item.update({ + flags: { + magicitems: magicItem.serializeData(), + }, + }); + } + } + /** * Activates listeners related to tab contents. * @@ -226,4 +245,16 @@ export class MagicItemTab { }); }); } + + static get acceptedItemTypes() { + return ["weapon", "equipment", "consumable", "tool", "backpack", "feat"]; + } + + static isAcceptedItemType(document) { + return MagicItemTab.acceptedItemTypes.includes(document?.type); + } + + static isAllowedToShow() { + return game.user.isGM || !game.settings.get(CONSTANTS.MODULE_ID, "hideFromPlayers"); + } } From a9fdcc7a8e5945a1b157d7372d99791b08f53a93 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 16:14:28 -0600 Subject: [PATCH 07/29] Re-enabled sort radio boxes. Made sorting universally applied upon MagicItem construciton, so it is no longer necessary to call on render in MagicItemTab. --- src/scripts/magic-item/MagicItem.js | 2 ++ src/scripts/magicItemtab.js | 3 --- src/templates/magic-item-tab.hbs | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/scripts/magic-item/MagicItem.js b/src/scripts/magic-item/MagicItem.js index 98682a1..3bd20f4 100644 --- a/src/scripts/magic-item/MagicItem.js +++ b/src/scripts/magic-item/MagicItem.js @@ -44,6 +44,8 @@ export class MagicItem { this.savedFeats = this.feats.length; this.savedTables = this.tables.length; + this.sort(); + if (!this.enabled) { this.clear(); } diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index f4cc6d1..6476427 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -91,9 +91,6 @@ export class MagicItemTab { } async render() { - // TODO: Sort as part of the magic item adapter when enumerating items - this.magicItem.sort(); - let template = await renderTemplate(`modules/${CONSTANTS.MODULE_ID}/templates/magic-item-tab.hbs`, this.magicItem); let el = this.html.find(`.magic-items-content`); if (el.length) { diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index 9c81a38..4df984f 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -83,12 +83,12 @@
- {{!--
+
- {{radioBoxes "flags.magicitems.sorting" sortingModes checked=sorting localize=true}} + {{radioBoxes "flags.magicitems.sorting" sortingModes checked=sorting localize=true}}
-
--}} +
{{#if spells.length}}
    From 8036595d25d55e1683e334441df25b006d1aab3f Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 16:21:49 -0600 Subject: [PATCH 08/29] --- src/scripts/magicItemtab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 6476427..cd365f7 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -136,7 +136,7 @@ export class MagicItemTab { } activateTabManagementListeners() { - this.html.find(".magic-items-content").on("change", ":input, :focus", (evt) => { + this.html.find(".magic-items-content").on("change", ":input", (evt) => { this.activate = true; }); } From 84482f2b5c74758d9ab77dbb01a078a2f2cf7276 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 17:04:27 -0600 Subject: [PATCH 09/29] Eliminated bug where swapping sheets for an item would break the logic that maintains focus on the Magic Item tab. The fix was to use a fresh copy of `app` each time something is being done. Otherwise, a previous version of app will be cached in the tab, and all tab activations will be called on a sheet that is no longer being used. --- src/scripts/magicItemtab.js | 42 ++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index cd365f7..2ae0781 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -1,7 +1,4 @@ -import { MAGICITEMS } from "./config.js"; import CONSTANTS from "./constants/constants.js"; -import Logger from "./lib/Logger.js"; -import { MagicItemHelpers } from "./magic-item-helpers.js"; import { MagicItem } from "./magic-item/MagicItem.js"; const magicItemTabs = []; @@ -14,20 +11,20 @@ export class MagicItemTab { tab = new MagicItemTab(app); magicItemTabs[app.id] = tab; } - tab.init(html, item); + tab.init(html, item, app); } } constructor(app) { - this.app = app; - this.item = app.item; - - this.hack(this.app); - + this.hack(app); this.activate = false; } - init(html, data) { + init(html, data, app) { + this.item = app.item; + this.html = html; + this.editable = data.editable; + if (html[0].localName !== "div") { html = $(html[0].parentElement.parentElement); } @@ -42,19 +39,16 @@ export class MagicItemTab { $('
    ') ); - this.html = html; - this.editable = data.editable; - if (this.editable) { const dragDrop = new DragDrop({ dropSelector: ".tab.magic-items", permissions: { - dragstart: this._canDragStart.bind(this.app), - drop: this._canDragDrop.bind(this.app), + dragstart: this._canDragStart.bind(app), + drop: this._canDragDrop.bind(app), }, callbacks: { - dragstart: this.app._onDragStart.bind(this.app), - dragover: this.app._onDragOver.bind(this.app), + dragstart: app._onDragStart.bind(app), + dragover: app._onDragOver.bind(app), drop: (event) => { this.activate = true; MagicItemTab.onDrop({ @@ -66,13 +60,13 @@ export class MagicItemTab { }, }); - this.app._dragDrop.push(dragDrop); - dragDrop.bind(this.app.form); + app._dragDrop.push(dragDrop); + dragDrop.bind(app.form); } - this.magicItem = new MagicItem(this.item.flags.magicitems); + this.magicItem = new MagicItem(app.item.flags.magicitems); - this.render(); + this.render(app); } hack(app) { @@ -90,7 +84,7 @@ export class MagicItemTab { }; } - async render() { + async render(app) { let template = await renderTemplate(`modules/${CONSTANTS.MODULE_ID}/templates/magic-item-tab.hbs`, this.magicItem); let el = this.html.find(`.magic-items-content`); if (el.length) { @@ -113,10 +107,10 @@ export class MagicItemTab { MagicItemTab.disableMagicItemTabInputs(this.html); } - this.app.setPosition(); + app.setPosition(); if (this.activate && !this.isActive()) { - this.app._tabs[0].activate("magicitems"); + app._tabs[0].activate("magicitems"); this.activate = false; } else { this.activate = false; From 4fbfea9e53a4caefa5069fae1f14f774cd2229f0 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Wed, 24 Jan 2024 17:14:14 -0600 Subject: [PATCH 10/29] Restored tab resize behavior. --- src/scripts/magicItemtab.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index 2ae0781..aba856c 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -107,10 +107,9 @@ export class MagicItemTab { MagicItemTab.disableMagicItemTabInputs(this.html); } - app.setPosition(); - if (this.activate && !this.isActive()) { app._tabs[0].activate("magicitems"); + app.setPosition(); this.activate = false; } else { this.activate = false; @@ -118,7 +117,7 @@ export class MagicItemTab { } isActive() { - $(this.html).find('a.item[data-tab="magicitems"]').hasClass("active"); + return $(this.html).find('a.item[data-tab="magicitems"]').hasClass("active"); } _canDragDrop() { From 915c7550a7d9dde919697f5060ac77de659f95f1 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 10:58:30 -0600 Subject: [PATCH 11/29] Corrected tidy tab name. Converted the item lists for Magic Item tab to use the standard/default sheet HTML structure/classes. This eliminated the need for a number of CSS styles. Added some minimal layout styles for the item lists. Removed unneeded template content for magic item tab, based on refactors. --- src/module.js | 2 +- src/styles/magicitems.css | 132 ++---------------- src/templates/magic-item-tab.hbs | 223 +++++++++++++++---------------- 3 files changed, 120 insertions(+), 237 deletions(-) diff --git a/src/module.js b/src/module.js index c8bb9f2..9097ba7 100644 --- a/src/module.js +++ b/src/module.js @@ -71,7 +71,7 @@ let tidyApi; Hooks.once("tidy5e-sheet.ready", (api) => { tidyApi = api; const magicItemsTab = new api.models.HandlebarsTab({ - title: "Magic Items", + title: "Magic Item", tabId: "magic-items", path: "/modules/magic-items-2/templates/magic-item-tab.hbs", enabled: (data) => { diff --git a/src/styles/magicitems.css b/src/styles/magicitems.css index 3ead743..9db43e2 100644 --- a/src/styles/magicitems.css +++ b/src/styles/magicitems.css @@ -11,22 +11,6 @@ border-bottom: 1px solid #c9c7b8; } -.dnd5e.sheet.item .magic-item-list .inventory-header { - margin: 2px 0; - padding: 0; - background: rgba(0, 0, 0, 0.05); - border: 2px groove #eeede0; - font-weight: bold; - line-height: 24px; -} - -.dnd5e.sheet.item .magic-item-list .inventory-header h3 { - margin: 0 -5px 0 0; - padding-left: 5px; - font-size: 13px; - font-weight: bold; -} - .dnd5e.sheet.item .magic-item-list .item .item-name { cursor: pointer; } @@ -35,12 +19,6 @@ border-bottom: none; } -.dnd5e.sheet.item .magic-item-list .item-list { - list-style: none; - margin: 0; - padding: 0; -} - .dnd5e.sheet.item .spell-slots, .dnd5e.sheet.item .spell-comps { flex: 0 0 60px; @@ -50,106 +28,6 @@ border-right: 1px solid #c9c7b8; } -.dnd5e.sheet.item .spell-level-head, -.dnd5e.sheet.item .spell-upcast-head, -.dnd5e.sheet.item .spell-consumption-head, -.dnd5e.sheet.item .spell-cost-head, -.dnd5e.sheet.item .spell-dc-head { - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item .spell-upcast-head { - flex: 0 0 80px; -} - -.dnd5e.sheet.item .spell-level-head, -.dnd5e.sheet.item .spell-consumption-head, -.dnd5e.sheet.item .spell-cost-head { - flex: 0 0 50px; -} - -.dnd5e.sheet.item .spell-dc-head { - flex: 0 0 64px; -} - -.dnd5e.sheet.item .spell-controls-head { - flex: 0 0 20px; -} - -.dnd5e.sheet.item .table-usage-head, -.dnd5e.sheet.item .table-consumption-head { - flex: 0 0 80px; - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item .feat-effect-head, -.dnd5e.sheet.item .feat-consumption-head { - flex: 0 0 80px; - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item .magic-item-list .item .item-name .item-image { - flex: 0 0 30px; - background-size: 30px; - margin-right: 5px; -} - -.dnd5e.sheet.item .magic-item-list .item .item-name h4 { - margin: 0; -} - -.dnd5e.sheet.item .magic-item-list .item-controls { - text-align: right; - flex: 0 0 20px; -} - -.dnd5e.sheet.item .magic-item-list .item-controls a { - flex: 0 0 22px; - font-size: 10px; - text-align: center; - color: #666; - margin-right: 5px; -} - -.dnd5e.sheet.item .magic-item-list .item .spell-upcast { - flex: 0 0 80px; - margin-right: 4px; -} - -.dnd5e.sheet.item .magic-item-list .item .spell-level, -.dnd5e.sheet.item .magic-item-list .item .spell-consumption, -.dnd5e.sheet.item .magic-item-list .item .spell-cost { - flex: 0 0 50px; - margin-right: 4px; -} - -.dnd5e.sheet.item .magic-item-list .item .spell-flat-dc { - flex: 0 0 20px; -} - -.dnd5e.sheet.item .magic-item-list .item .spell-dc { - flex: 0 0 38px; - margin-right: 2px; -} - -.dnd5e.sheet.item .magic-item-list .item .table-usage, -.dnd5e.sheet.item .magic-item-list .item .table-consumption { - flex: 0 0 80px; - margin-right: 4px; -} - .dnd5e.sheet.item .magic-item-list .item .spell-dc:disabled { color: #9a9a9a; border-color: #dad9d9; @@ -180,6 +58,16 @@ border: 2px #828180 dashed; } +.sheet.item .magic-items-content .item-controls { + flex-basis: 2rem; + display: flex; + justify-content: center; +} + +.sheet.item .magic-items-content .item-detail select { + width: 100%; +} + .dnd5e.sheet.actor .magic-items-head { margin-top: 10px; } diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index 4df984f..18d7abe 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -91,24 +91,21 @@
{{#if spells.length}} -
    -
  1. -
    -

    {{localize "MAGICITEMS.SheetSpell"}}

    -
    -
    {{localize "MAGICITEMS.SheetLevel"}}
    -
    {{localize "MAGICITEMS.SheetConsumption"}}
    -
    {{localize "MAGICITEMS.SheetUpcast"}}
    -
    {{localize "MAGICITEMS.SheetCost"}}
    -
    Save DC
    -
     
    +
      +
    1. +

      {{localize "MAGICITEMS.SheetSpell"}}

      +
      {{localize "MAGICITEMS.SheetLevel"}}
      +
      {{localize "MAGICITEMS.SheetConsumption"}}
      +
      {{localize "MAGICITEMS.SheetUpcast"}}
      +
      {{localize "MAGICITEMS.SheetCost"}}
      +
      Save DC
      +
       
    2. -
        {{#each spells as |item i|}} -
      1. +
      2. -
        +
        {{{@root/rollIcon}}}

        {{item.displayName}}

        @@ -117,47 +114,55 @@
        - - - - - - - - +
        + +
        +
        + +
        +
        + +
        +
        + +
        +
        + + +
        @@ -170,19 +175,16 @@ {{/if}} {{#if feats.length}} -
          -
        1. -
          -

          {{localize "MAGICITEMS.SheetFeat"}}

          -
          -
          {{localize "MAGICITEMS.SheetEffect"}}
          -
          {{localize "MAGICITEMS.SheetConsumption"}}
          -
           
          +
            +
          1. +

            {{localize "MAGICITEMS.SheetFeat"}}

            +
            {{localize "MAGICITEMS.SheetEffect"}}
            +
            {{localize "MAGICITEMS.SheetConsumption"}}
            +
             
          2. -
              {{#each feats as |item i|}} -
            1. +
            2. {{item.displayName}}

              @@ -192,19 +194,23 @@
              - - +
              + +
              +
              + +
              @@ -217,21 +223,18 @@ {{/if}} {{#if tables.length}} -
                -
              1. -
                -

                {{localize "MAGICITEMS.SheetTable"}}

                -
                -
                {{localize "MAGICITEMS.SheetUsage"}}
                -
                {{localize "MAGICITEMS.SheetConsumption"}}
                -
                 
                +
                  +
                1. +

                  {{localize "MAGICITEMS.SheetTable"}}

                  +
                  {{localize "MAGICITEMS.SheetUsage"}}
                  +
                  {{localize "MAGICITEMS.SheetConsumption"}}
                  +
                   
                2. -
                    {{#each tables as |item i|}} -
                  1. +
                  2. - - +
                    + +
                    +
                    + +
                  {{/if}} - {{#each spellsGarbage as |index i|}} - - {{/each}} - - {{#each featsGarbage as |index i|}} - - {{/each}} - - {{#each tablesGarbage as |index i|}} - - {{/each}} - {{#if empty}}
                3. {{localize "MAGICITEMS.SheetDragContent"}}
                  From 54d7f4e884fea35dbe1da412e88fcab56f5382b6 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 16:28:01 -0600 Subject: [PATCH 12/29] Added Tidy NPC and Character registration of magic item list templates. Added scaffolding for placing the Wand icon and wiring events for the MI2 content. --- package.json | 1 + src/module.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/package.json b/package.json index 18af797..bb4c229 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ ], "scripts": { "build": "vite build", + "build:watch": "vite build --watch", "dev": "vite", "eslint": "eslint .", "prepare": "husky install", diff --git a/src/module.js b/src/module.js index 9097ba7..ef98a82 100644 --- a/src/module.js +++ b/src/module.js @@ -99,6 +99,45 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, }); api.registerItemTab(magicItemsTab); + + api.registerCharacterContent( + new api.models.HandlebarsContent({ + path: `modules/${CONSTANTS.MODULE_ID}/templates/magic-item-spell-sheet.html`, + injectParams: { + position: "beforeend", + selector: `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_SPELLBOOK}"] .scroll-container`, + }, + enabled(data) { + const actor = MagicItemActor.get(data.actor.id); + return actor?.hasItemsSpells(); + }, + getData(data) { + return MagicItemActor.get(data.actor.id); + }, + }) + ); + + api.registerCharacterContent( + new api.models.HandlebarsContent({ + path: `modules/${CONSTANTS.MODULE_ID}/templates/magic-item-feat-sheet.html`, + injectParams: { + position: "beforeend", + selector: `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_FEATURES}"] .scroll-container`, + }, + enabled(data) { + const actor = MagicItemActor.get(data.actor.id); + return actor?.hasItemsFeats(); + }, + getData(data) { + return MagicItemActor.get(data.actor.id); + }, + }) + ); +}); + +Hooks.on("tidy5e-sheet.renderActorSheet", (app, element, data) => { + // Place wand for visible magic items + // Wire events for custom tidy content }); Hooks.on(`renderItemSheet5e`, (app, html, data) => { @@ -114,10 +153,16 @@ Hooks.on(`renderItemSheet5e`, (app, html, data) => { }); Hooks.on(`renderActorSheet5eCharacter`, (app, html, data) => { + if (tidyApi?.isTidy5eCharacterSheet(app)) { + return; + } MagicItemSheet.bind(app, html, data); }); Hooks.on(`renderActorSheet5eNPC`, (app, html, data) => { + if (tidyApi?.isTidy5eNpcSheet(app)) { + return; + } MagicItemSheet.bind(app, html, data); }); From 442070f2402dfcfb7c6322be0b8e1682781f1b8e Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 17:05:56 -0600 Subject: [PATCH 13/29] Added constant for the magic item icon. Added magic wand for visible magic items logic for New Tidy. --- src/module.js | 14 ++++++++++++++ src/scripts/constants/constants.js | 4 ++++ src/scripts/magicitemsheet.js | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/module.js b/src/module.js index ef98a82..7d3e24a 100644 --- a/src/module.js +++ b/src/module.js @@ -137,7 +137,21 @@ Hooks.once("tidy5e-sheet.ready", (api) => { Hooks.on("tidy5e-sheet.renderActorSheet", (app, element, data) => { // Place wand for visible magic items + const actor = MagicItemActor.get(data.actor.id); + const html = $(element); + actor?.items + .filter((item) => item.visible) + .forEach((item) => { + let itemEl = html.find( + `[data-tidy-sheet-part="${tidyApi.constants.SHEET_PARTS.ITEM_TABLE_ROW}"][data-item-id="${item.id}"]` + ); + let itemNameContainer = itemEl.find(`[data-tidy-sheet-part=${tidyApi.constants.SHEET_PARTS.ITEM_NAME}]`); + let iconHtml = tidyApi.useHandlebarsRendering(CONSTANTS.HTML.MAGIC_ITEM_ICON); + itemNameContainer.append(iconHtml); + }); + // Wire events for custom tidy content + // TODO }); Hooks.on(`renderItemSheet5e`, (app, html, data) => { diff --git a/src/scripts/constants/constants.js b/src/scripts/constants/constants.js index 2c12e2b..5204013 100644 --- a/src/scripts/constants/constants.js +++ b/src/scripts/constants/constants.js @@ -4,6 +4,10 @@ const CONSTANTS = { PREFIX_LABEL: "MAGICITEMS", PREFIX_FLAG: "magicitems", FLAGS: {}, + HTML: { + MAGIC_ITEM_ICON: '', + }, }; CONSTANTS.PATH = `modules/${CONSTANTS.MODULE_NAME}/`; + export default CONSTANTS; diff --git a/src/scripts/magicitemsheet.js b/src/scripts/magicitemsheet.js index e713cfb..ecea8b0 100644 --- a/src/scripts/magicitemsheet.js +++ b/src/scripts/magicitemsheet.js @@ -68,7 +68,7 @@ export class MagicItemSheet { let itemEl = this.html.find(`.inventory-list .item-list .item[data-item-id="${item.id}"]`); let h4 = itemEl.find("h4"); if (!h4.find("i.fa-magic").length) { - h4.append(''); + h4.append(CONSTANTS.HTML.MAGIC_ITEM_ICON); } }); From af2214a5fadbd8b6729ebf7fcf84764aba923852 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 19:44:39 -0600 Subject: [PATCH 14/29] Removed double-rendering. Removed some commented code. Some light refactor/renaming for clarity. --- src/scripts/magic-item/MagicItem.js | 23 +++++------------------ src/scripts/magicitemactor.js | 18 ++---------------- src/scripts/magicitemsheet.js | 2 -- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/src/scripts/magic-item/MagicItem.js b/src/scripts/magic-item/MagicItem.js index 3bd20f4..35831de 100644 --- a/src/scripts/magic-item/MagicItem.js +++ b/src/scripts/magic-item/MagicItem.js @@ -317,26 +317,13 @@ export class MagicItem { return this.items.filter((item) => item.id === itemId)[0]; } - async renderSheet(spellId) { - let spellFounded = this.findByUuid(spellId); - if (!byUuid) { - spellFounded = this.findById(spellId); + async renderSheet(itemId) { + let item = this.findByUuid(itemId); + if (!item) { + item = this.findById(itemId); } - // let uuid = null; - // if (spellFounded.uuid) { - // uuid = spellFounded.uuid; - // } else { - // uuid = MagiItemHelpers.retrieveUuid({ - // documentName: spellFounded.name, - // documentId: spellFounded.id, - // documentCollectionType: "Item", - // documentPack: spellFounded.pack, - // }); - // } - // const itemTmp = await fromUuid(uuid); - // itemTmp.sheet.render(true); - await spellFounded.renderSheet(); + await item.renderSheet(); } cleanup() { diff --git a/src/scripts/magicitemactor.js b/src/scripts/magicitemactor.js index 43662a2..b1b4316 100644 --- a/src/scripts/magicitemactor.js +++ b/src/scripts/magicitemactor.js @@ -268,25 +268,11 @@ export class MagicItemActor { * @param ownedItemId */ async renderSheet(itemId, ownedItemId) { - let found = this.items.filter((item) => { + let item = this.items.find((item) => { return item.id === itemId || item.uuid === itemId; }); - if (found.length) { - let item = found[0]; + if (item) { item.renderSheet(ownedItemId); - // let uuid = null; - // if (item.uuid) { - // uuid = item.uuid; - // } else { - // uuid = MagiItemHelpers.retrieveUuid({ - // documentName: item.name, - // documentId: item.id, - // documentCollectionType: "Item", - // documentPack: item.pack, - // }); - // } - // const itemTmp = await fromUuid(uuid); - // itemTmp.sheet.render(true); } } diff --git a/src/scripts/magicitemsheet.js b/src/scripts/magicitemsheet.js index ecea8b0..f28aeee 100644 --- a/src/scripts/magicitemsheet.js +++ b/src/scripts/magicitemsheet.js @@ -155,8 +155,6 @@ export class MagicItemSheet { } const itemTmp = await fromUuid(uuid); itemTmp.sheet.render(true); - // TODO TO REMOVE ??? OR UPDATE SOMEHOW ? - await this.actor.renderSheet(magicItemId, itemId); } /** From 6a17adabd43c61630737ccbaddb82d2e54631378 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 19:44:58 -0600 Subject: [PATCH 15/29] TODOs --- src/module.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/module.js b/src/module.js index 7d3e24a..6824bcb 100644 --- a/src/module.js +++ b/src/module.js @@ -151,7 +151,10 @@ Hooks.on("tidy5e-sheet.renderActorSheet", (app, element, data) => { }); // Wire events for custom tidy content - // TODO + // 1. item rolls + // 2. show item on name click + // 3. Handle item uses change + // 4. Handle individual item uses/max change }); Hooks.on(`renderItemSheet5e`, (app, html, data) => { From 87d197d06e5465ad48a407c755c0a127a6448b6b Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Thu, 25 Jan 2024 21:46:00 -0600 Subject: [PATCH 16/29] Wrapped item list tables in ol.items-list. While this is not needed for default-like sheets, because they are slotting into an existing ordered list, for a non-default-like sheet, there may not be a parent ordered list to drop into. Removed d20 from feat and spell sheet templates, as it is not needed. Also removed the CSS style for showing/hiding the d20 icon, because dnd5e sheets are already doing this. --- src/styles/magicitems.css | 8 -- src/templates/magic-item-feat-sheet.html | 105 ++++++++------- src/templates/magic-item-spell-sheet.html | 155 ++++++++++++---------- 3 files changed, 138 insertions(+), 130 deletions(-) diff --git a/src/styles/magicitems.css b/src/styles/magicitems.css index 9db43e2..1e7fc0d 100644 --- a/src/styles/magicitems.css +++ b/src/styles/magicitems.css @@ -104,10 +104,6 @@ margin-right: 5px; } -.dnd5e.sheet.actor .inventory-list .item .magic-item-image:hover { - background-image: url(/icons/svg/d20-black.svg) !important; -} - .dnd5e.sheet.item .magic-items-content select.magic-item-charges-type { flex: 0.5; } @@ -136,10 +132,6 @@ border-color: #dad9d9; } -.dnd5e.sheet .items-list .item .item-name .item-image .fa-dice-d20 { - display: none; -} - .tidy5e.sheet.actor .magic-items-head { display: none; } diff --git a/src/templates/magic-item-feat-sheet.html b/src/templates/magic-item-feat-sheet.html index dfb62e9..0422639 100644 --- a/src/templates/magic-item-feat-sheet.html +++ b/src/templates/magic-item-feat-sheet.html @@ -1,53 +1,60 @@ {{#if hasVisibleItems}}
                  -
                  - -
                  - {{#each items as |item i|}} - {{#if (and visible active hasFeats)}} -
                4. -

                  {{name}}

                  -
                  - - / - -
                  -
                  {{rechargeableLabel}}
                  -
                  {{localize "MAGICITEMS.SheetFeatOnUsage"}}
                  -
                5. -
                    - - {{#each feats as |feat|}} -
                  1. -
                    -
                    - -
                    -

                    {{feat.displayName}}

                    -
                    -
                    {{feat.consumptionLabel}}
                    -
                  2. - {{/each}} - - {{#if hasTableAsFeats}} - {{#each tableAsFeats as |table|}} -
                  3. -
                    -
                    -
                    -

                    {{table.displayName}}

                    -
                    -
                    {{table.consumption}}
                    -
                  4. - {{/each}} - {{/if}} -
                  - {{/if}} - {{/each}} +
                  + +
                  + {{#each items as |item i|}} {{#if (and visible active hasFeats)}} +
                    +
                  1. +

                    {{name}}

                    +
                    + + / + +
                    +
                    {{rechargeableLabel}}
                    +
                    {{localize "MAGICITEMS.SheetFeatOnUsage"}}
                    +
                  2. +
                      + + {{#each feats as |feat|}} +
                    1. +
                      +
                      +

                      {{feat.displayName}}

                      +
                      +
                      {{feat.consumptionLabel}}
                      +
                    2. + {{/each}} + + {{#if hasTableAsFeats}} {{#each tableAsFeats as |table|}} +
                    3. +
                      +
                      +

                      {{table.displayName}}

                      +
                      +
                      {{table.consumption}}
                      +
                    4. + {{/each}} {{/if}} +
                    +
                  + {{/if}} {{/each}}
              {{/if}} diff --git a/src/templates/magic-item-spell-sheet.html b/src/templates/magic-item-spell-sheet.html index 5a51661..70cc736 100644 --- a/src/templates/magic-item-spell-sheet.html +++ b/src/templates/magic-item-spell-sheet.html @@ -1,76 +1,85 @@ {{#if hasVisibleItems}}
              -
              - -
              - {{#each items as |item i|}} - {{#if (and visible active hasSpells)}} -
            3. -

              {{name}}

              - {{#if chargesOnWholeItem}} -
              - - / - -
              -
              {{rechargeableLabel}}
              - {{/if}} -
              {{localize "MAGICITEMS.SheetLevel"}}
              -
              {{localize "MAGICITEMS.SheetConsumption"}}
              -
              {{localize "MAGICITEMS.SheetCanUpcast"}}
              -
            4. -
                - {{#each spells as |spell|}} -
              1. -
                -
                - -
                -

                {{spell.displayName}}

                -
                - {{#if ../chargesPerSpell}} -
                - - / - -
                -
                {{../rechargeableLabel}}
                - {{/if}} -
                {{spell.level}}
                -
                {{spell.consumption}}
                -
                {{spell.canUpcastLabel}}
                -
              2. - {{/each}} - - {{#if hasTableAsSpells}} - {{#each tableAsSpells as |table|}} -
              3. -
                -
                -
                -

                {{table.displayName}}

                -
                - {{#if ../chargesPerSpell}} -
                - - / - -
                -
                {{../rechargeableLabel}}
                - {{/if}} -
                -
                -
                {{table.consumption}}
                -
                -
                -
              4. - {{/each}} - {{/if}} - -
              - {{/if}} - {{/each}} +
              + +
              + {{#each items as |item i|}} {{#if (and visible active hasSpells)}} +
                +
              1. +

                {{name}}

                + {{#if chargesOnWholeItem}} +
                + + / + +
                +
                {{rechargeableLabel}}
                + {{/if}} +
                {{localize "MAGICITEMS.SheetLevel"}}
                +
                {{localize "MAGICITEMS.SheetConsumption"}}
                +
                {{localize "MAGICITEMS.SheetCanUpcast"}}
                +
              2. +
                  + {{#each spells as |spell|}} +
                1. +
                  +
                  +

                  {{spell.displayName}}

                  +
                  + {{#if ../chargesPerSpell}} +
                  + + / + +
                  +
                  {{../rechargeableLabel}}
                  + {{/if}} +
                  {{spell.level}}
                  +
                  {{spell.consumption}}
                  +
                  {{spell.canUpcastLabel}}
                  +
                2. + {{/each}} {{#if hasTableAsSpells}} {{#each tableAsSpells as |table|}} +
                3. +
                  +
                  +

                  {{table.displayName}}

                  +
                  + {{#if ../chargesPerSpell}} +
                  + + / + +
                  +
                  {{../rechargeableLabel}}
                  + {{/if}} +
                  -
                  +
                  {{table.consumption}}
                  +
                  -
                  +
                4. + {{/each}} {{/if}} +
                +
              + {{/if}} {{/each}}
        -{{/if}} \ No newline at end of file +{{/if}} From 5618529d27fb2d7195d1ed4dcdf8e35756f1bb14 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 11:29:16 -0600 Subject: [PATCH 17/29] Established Tidy NPC sheet compatibility for feature content. Added some explanatory comments. --- src/module.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/module.js b/src/module.js index 6824bcb..2b73444 100644 --- a/src/module.js +++ b/src/module.js @@ -70,6 +70,8 @@ Hooks.once("createToken", (token) => { let tidyApi; Hooks.once("tidy5e-sheet.ready", (api) => { tidyApi = api; + + // Register Tidy Item Sheet Tab const magicItemsTab = new api.models.HandlebarsTab({ title: "Magic Item", tabId: "magic-items", @@ -100,7 +102,8 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }); api.registerItemTab(magicItemsTab); - api.registerCharacterContent( + // Register character and NPC spell tab custom content + api.registerActorContent( new api.models.HandlebarsContent({ path: `modules/${CONSTANTS.MODULE_ID}/templates/magic-item-spell-sheet.html`, injectParams: { @@ -109,7 +112,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); - return actor?.hasItemsSpells(); + return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsSpells(); }, getData(data) { return MagicItemActor.get(data.actor.id); @@ -117,16 +120,22 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }) ); - api.registerCharacterContent( + // Register character and NPC feature tab custom content + const npcAbilitiesTabContainerSelector = `[data-tidy-sheet-part="${api.constants.SHEET_PARTS.NPC_ABILITIES_CONTAINER}"]`; + const characterFeaturesContainerSelector = `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_FEATURES}"] [data-tidy-sheet-part="${api.constants.SHEET_PARTS.NPC_ABILITIES_CONTAINER}"]`; + const magicItemFeatureTargetSelector = [npcAbilitiesTabContainerSelector, characterFeaturesContainerSelector].join( + ", " + ); + api.registerActorContent( new api.models.HandlebarsContent({ path: `modules/${CONSTANTS.MODULE_ID}/templates/magic-item-feat-sheet.html`, injectParams: { position: "beforeend", - selector: `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_FEATURES}"] .scroll-container`, + selector: magicItemFeatureTargetSelector, }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); - return actor?.hasItemsFeats(); + return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsFeats(); }, getData(data) { return MagicItemActor.get(data.actor.id); @@ -135,6 +144,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { ); }); +// Wire Tidy events and register iterated, data-dependent content Hooks.on("tidy5e-sheet.renderActorSheet", (app, element, data) => { // Place wand for visible magic items const actor = MagicItemActor.get(data.actor.id); From 41d5992c272f441827a114057b9fb2c5e5535821 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 13:02:29 -0600 Subject: [PATCH 18/29] Made sheet event functions static so they can be shared. Wired up Tidy sheet events with the new statically available version of the sheet event handlers. --- src/module.js | 9 +++----- src/scripts/magicitemsheet.js | 42 ++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/module.js b/src/module.js index 2b73444..3c7b3ec 100644 --- a/src/module.js +++ b/src/module.js @@ -122,7 +122,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { // Register character and NPC feature tab custom content const npcAbilitiesTabContainerSelector = `[data-tidy-sheet-part="${api.constants.SHEET_PARTS.NPC_ABILITIES_CONTAINER}"]`; - const characterFeaturesContainerSelector = `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_FEATURES}"] [data-tidy-sheet-part="${api.constants.SHEET_PARTS.NPC_ABILITIES_CONTAINER}"]`; + const characterFeaturesContainerSelector = `[data-tab-contents-for="${api.constants.TAB_ID_CHARACTER_FEATURES}"] [data-tidy-sheet-part="${api.constants.SHEET_PARTS.ITEMS_CONTAINER}"]`; const magicItemFeatureTargetSelector = [npcAbilitiesTabContainerSelector, characterFeaturesContainerSelector].join( ", " ); @@ -160,11 +160,8 @@ Hooks.on("tidy5e-sheet.renderActorSheet", (app, element, data) => { itemNameContainer.append(iconHtml); }); - // Wire events for custom tidy content - // 1. item rolls - // 2. show item on name click - // 3. Handle item uses change - // 4. Handle individual item uses/max change + // Wire events for custom tidy actor sheet content + MagicItemSheet.handleEvents(html, actor); }); Hooks.on(`renderItemSheet5e`, (app, html, data) => { diff --git a/src/scripts/magicitemsheet.js b/src/scripts/magicitemsheet.js index f28aeee..ac27e5d 100644 --- a/src/scripts/magicitemsheet.js +++ b/src/scripts/magicitemsheet.js @@ -72,7 +72,7 @@ export class MagicItemSheet { } }); - this.handleEvents(); + MagicItemSheet.handleEvents(this.html, this.actor); } /** @@ -96,48 +96,54 @@ export class MagicItemSheet { /** * */ - handleEvents() { - this.html.find(".item div.magic-item-image").click((evt) => this.onItemRoll(evt)); - this.html.find(".item h4.spell-name").click((evt) => this.onItemShow(evt)); - this.actor.items.forEach((item) => { - this.html.find(`input[data-item-id="magicitems.${item.id}.uses"]`).change((evt) => { + static handleEvents(html, actor) { + html.find(".item div.magic-item-image").click((evt) => MagicItemSheet.onItemRoll(evt, actor)); + html.find(".item h4.spell-name").click((evt) => MagicItemSheet.onItemShow(evt)); + MagicItemSheet.handleActorItemUsesChangeEvents(html, actor); + MagicItemSheet.handleMagicItemDragStart(html, actor); + } + + static handleMagicItemDragStart(html, actor) { + html.find(`li.item.magic-item`).each((i, li) => { + li.addEventListener("dragstart", (evt) => MagicItemSheet.onDragItemStart(evt, actor)); + }); + } + + static handleActorItemUsesChangeEvents(html, actor) { + actor.items.forEach((item) => { + html.find(`input[data-item-id="magicitems.${item.id}.uses"]`).change((evt) => { item.setUses(MagicItemHelpers.numeric(evt.currentTarget.value, item.uses)); item.update(); }); item.ownedEntries.forEach((entry) => { - this.html.find(`input[data-item-id="magicitems.${item.id}.${entry.id}.uses"]`).change((evt) => { + html.find(`input[data-item-id="magicitems.${item.id}.${entry.id}.uses"]`).change((evt) => { entry.uses = MagicItemHelpers.numeric(evt.currentTarget.value, entry.uses); item.update(); }); }); }); - this.html.find(`li.item.magic-item`).each((i, li) => { - li.addEventListener("dragstart", this.onDragItemStart.bind(this), false); - }); } /** * * @param evt */ - onItemRoll(evt) { + static async onItemRoll(evt, actor) { evt.preventDefault(); let dataset = evt.currentTarget.closest(".item").dataset; let magicItemId = dataset.magicItemId; let itemId = dataset.itemId; - this.actor.roll(magicItemId, itemId).then(() => { - this.render(); - }); + await actor.roll(magicItemId, itemId); + // this.render(); } /** * * @param evt */ - async onItemShow(evt) { + static async onItemShow(evt) { evt.preventDefault(); let dataset = evt.currentTarget.closest(".item").dataset; - let magicItemId = dataset.magicItemId; let itemId = dataset.itemId; let itemUuid = dataset.itemUuid; let itemPack = dataset.itemPack; @@ -161,11 +167,11 @@ export class MagicItemSheet { * * @param evt */ - onDragItemStart(evt) { + static onDragItemStart(evt, actor) { const li = evt.currentTarget; let magicItemId = li.dataset.magicItemId; let itemId = li.dataset.itemId; - let magicItem = this.actor.magicItem(magicItemId); + let magicItem = actor.magicItem(magicItemId); let item = magicItem.entryBy(itemId); const dragData = { From dbaf04ae6f09e7cb455f92e5c6fec6284f02e262 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 13:55:22 -0600 Subject: [PATCH 19/29] Restored MI tab classes and began restoring the CSS for the table contents. --- src/styles/magicitems.css | 88 +++++++++++++++++++++++++++++--- src/templates/magic-item-tab.hbs | 54 ++++++++++---------- 2 files changed, 109 insertions(+), 33 deletions(-) diff --git a/src/styles/magicitems.css b/src/styles/magicitems.css index 1e7fc0d..fd00313 100644 --- a/src/styles/magicitems.css +++ b/src/styles/magicitems.css @@ -28,16 +28,88 @@ border-right: 1px solid #c9c7b8; } -.dnd5e.sheet.item .magic-item-list .item .spell-dc:disabled { +.dnd5e.sheet.item .spell-level-head, +.dnd5e.sheet.item .spell-upcast-head, +.dnd5e.sheet.item .spell-consumption-head, +.dnd5e.sheet.item .spell-cost-head, +.dnd5e.sheet.item .spell-dc-head { + font-size: 12px; + color: #7a7971; + margin-right: 4px; + text-align: center; + border-right: 1px solid #c9c7b8; +} + +.dnd5e.sheet.item :is(.spell-upcast-head, .item-detail.spell-upcast) { + flex: 0 0 80px; +} + +.dnd5e.sheet.item + :is( + .spell-level-head, + .spell-level, + .spell-consumption-head, + .spell-consumption, + .spell-cost-head, + .spell-cost + ).item-detail { + flex: 0 0 50px; +} + +.dnd5e.sheet.item :is(.spell-dc-head, .spell-dc).item-detail { + flex: 0 0 64px; +} + +.dnd5e.sheet.item :is(.spell-controls-head, .spell-controls).item-detail { + flex: 0 0 20px; +} + +.dnd5e.sheet.item :is(.table-usage-head, .table-usage, .table-consumption-head, .table-consumption).item-detail { + flex: 0 0 80px; + font-size: 12px; + color: #7a7971; + margin-right: 4px; + text-align: center; + border-right: 1px solid #c9c7b8; +} + +.dnd5e.sheet.item :is(.feat-effect-head, .feat-effect, .feat-consumption-head, .feat-consumption).item-details { + flex: 0 0 80px; + font-size: 12px; + color: #7a7971; + margin-right: 4px; + text-align: center; + border-right: 1px solid #c9c7b8; +} + +.dnd5e.sheet.item .magic-item-list .item .item-name .item-image { + flex: 0 0 30px; + background-size: 30px; + margin-right: 5px; +} + +/* .dnd5e.sheet.item .magic-item-list .item-controls a { + flex: 0 0 22px; + font-size: 10px; + text-align: center; + color: #666; + margin-right: 5px; +} */ + +/* .dnd5e.sheet.item .magic-item-list .item .spell-upcast { + flex: 0 0 80px; +} */ + +/* .dnd5e.sheet.item .magic-item-list .item .spell-dc:disabled { color: #9a9a9a; border-color: #dad9d9; -} +} */ -.dnd5e.sheet.item .magic-item-list .item .feat-effect, +/* .dnd5e.sheet.item .magic-item-list .item .feat-effect, .dnd5e.sheet.item .magic-item-list .item .feat-consumption { flex: 0 0 80px; margin-right: 4px; -} +} */ .dnd5e.sheet.item .magic-items-content input[type="text"], .dnd5e.sheet.item .magic-items-content select { @@ -64,9 +136,9 @@ justify-content: center; } -.sheet.item .magic-items-content .item-detail select { +/* .sheet.item .magic-items-content .item-detail select { width: 100%; -} +} */ .dnd5e.sheet.actor .magic-items-head { margin-top: 10px; @@ -132,6 +204,10 @@ border-color: #dad9d9; } +:not(.tidy5e).sheet .items-list .item .item-name .item-image .fa-dice-d20 { + display: none; +} + .tidy5e.sheet.actor .magic-items-head { display: none; } diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index 18d7abe..3b7f966 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -91,21 +91,21 @@
{{#if spells.length}} -
    +
    1. {{localize "MAGICITEMS.SheetSpell"}}

      -
      {{localize "MAGICITEMS.SheetLevel"}}
      -
      {{localize "MAGICITEMS.SheetConsumption"}}
      -
      {{localize "MAGICITEMS.SheetUpcast"}}
      -
      {{localize "MAGICITEMS.SheetCost"}}
      -
      Save DC
      -
       
      +
      {{localize "MAGICITEMS.SheetLevel"}}
      +
      {{localize "MAGICITEMS.SheetConsumption"}}
      +
      {{localize "MAGICITEMS.SheetUpcast"}}
      +
      {{localize "MAGICITEMS.SheetCost"}}
      +
      Save DC
      +
       
      1. {{#each spells as |item i|}} -
      2. +
      3. -
        +
        -
        +
        -
        +
        -
        +
        +
        1. {{localize "MAGICITEMS.SheetFeat"}}

          -
          {{localize "MAGICITEMS.SheetEffect"}}
          -
          {{localize "MAGICITEMS.SheetConsumption"}}
          -
           
          +
          {{localize "MAGICITEMS.SheetEffect"}}
          +
          {{localize "MAGICITEMS.SheetConsumption"}}
          +
           
          1. {{#each feats as |item i|}} -
          2. +
          3. {{item.displayName}}

            @@ -194,7 +194,7 @@
            -
            +
            -
            +
            +
            1. {{localize "MAGICITEMS.SheetTable"}}

              -
              {{localize "MAGICITEMS.SheetUsage"}}
              -
              {{localize "MAGICITEMS.SheetConsumption"}}
              -
               
              +
              {{localize "MAGICITEMS.SheetUsage"}}
              +
              {{localize "MAGICITEMS.SheetConsumption"}}
              +
               
              1. {{#each tables as |item i|}} -
              2. +
              3. {{{@root/rollIcon}}}

                {{item.displayName}}

                @@ -242,7 +242,7 @@
                -
                +
                -
                +
                Date: Fri, 26 Jan 2024 14:09:02 -0600 Subject: [PATCH 20/29] Reverted restore of custom widths for magic item tab list columns. --- src/styles/magicitems.css | 80 ++------------------------------ src/templates/magic-item-tab.hbs | 2 +- 2 files changed, 5 insertions(+), 77 deletions(-) diff --git a/src/styles/magicitems.css b/src/styles/magicitems.css index fd00313..66e066d 100644 --- a/src/styles/magicitems.css +++ b/src/styles/magicitems.css @@ -28,88 +28,16 @@ border-right: 1px solid #c9c7b8; } -.dnd5e.sheet.item .spell-level-head, -.dnd5e.sheet.item .spell-upcast-head, -.dnd5e.sheet.item .spell-consumption-head, -.dnd5e.sheet.item .spell-cost-head, -.dnd5e.sheet.item .spell-dc-head { - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item :is(.spell-upcast-head, .item-detail.spell-upcast) { - flex: 0 0 80px; -} - -.dnd5e.sheet.item - :is( - .spell-level-head, - .spell-level, - .spell-consumption-head, - .spell-consumption, - .spell-cost-head, - .spell-cost - ).item-detail { - flex: 0 0 50px; -} - -.dnd5e.sheet.item :is(.spell-dc-head, .spell-dc).item-detail { - flex: 0 0 64px; -} - -.dnd5e.sheet.item :is(.spell-controls-head, .spell-controls).item-detail { - flex: 0 0 20px; -} - -.dnd5e.sheet.item :is(.table-usage-head, .table-usage, .table-consumption-head, .table-consumption).item-detail { - flex: 0 0 80px; - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item :is(.feat-effect-head, .feat-effect, .feat-consumption-head, .feat-consumption).item-details { - flex: 0 0 80px; - font-size: 12px; - color: #7a7971; - margin-right: 4px; - text-align: center; - border-right: 1px solid #c9c7b8; -} - -.dnd5e.sheet.item .magic-item-list .item .item-name .item-image { - flex: 0 0 30px; - background-size: 30px; - margin-right: 5px; -} - -/* .dnd5e.sheet.item .magic-item-list .item-controls a { - flex: 0 0 22px; - font-size: 10px; - text-align: center; - color: #666; - margin-right: 5px; -} */ - -/* .dnd5e.sheet.item .magic-item-list .item .spell-upcast { - flex: 0 0 80px; -} */ - -/* .dnd5e.sheet.item .magic-item-list .item .spell-dc:disabled { +.dnd5e.sheet.item .magic-item-list .item .spell-dc:disabled { color: #9a9a9a; border-color: #dad9d9; -} */ +} -/* .dnd5e.sheet.item .magic-item-list .item .feat-effect, +.dnd5e.sheet.item .magic-item-list .item .feat-effect, .dnd5e.sheet.item .magic-item-list .item .feat-consumption { flex: 0 0 80px; margin-right: 4px; -} */ +} .dnd5e.sheet.item .magic-items-content input[type="text"], .dnd5e.sheet.item .magic-items-content select { diff --git a/src/templates/magic-item-tab.hbs b/src/templates/magic-item-tab.hbs index 3b7f966..2016d35 100644 --- a/src/templates/magic-item-tab.hbs +++ b/src/templates/magic-item-tab.hbs @@ -131,7 +131,7 @@ value="{{item.consumption}}" />
                -
                +
                Date: Fri, 26 Jan 2024 16:06:59 -0600 Subject: [PATCH 25/29] Added drop zone styles for New Tidy. --- src/styles/magicitems.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/styles/magicitems.css b/src/styles/magicitems.css index 5474fea..73d6e95 100644 --- a/src/styles/magicitems.css +++ b/src/styles/magicitems.css @@ -252,3 +252,15 @@ display: flex; justify-content: center; } + +[data-sheet-module="tidy5e-sheet"][data-document-name="Item"] .magic-items-content .spell-drag-content { + margin: 0.25rem; + height: 4.375rem; + text-align: center; + color: var(--t5e-primary-font-color); + color: var(--t5ek-primary-font-color); + line-height: 5; + border: 0.125rem dashed; + border-color: var(--t5e-primary-font-color); + border-color: var(--t5ek-primary-font-color); +} From 41361746731b2cb72404bd71307212aa360e1e43 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 16:23:16 -0600 Subject: [PATCH 26/29] Fixed New Tidy's "One Step Behind" render issue. The `updateItem` hook handler is doing a half-second `setTimeout()` to build items. New Tidy needs thos built items synchronously during render. --- src/module.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/module.js b/src/module.js index a086e2c..cca8920 100644 --- a/src/module.js +++ b/src/module.js @@ -112,6 +112,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); + actor.buildItems(); return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsSpells(); }, getData(data) { @@ -135,6 +136,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); + actor.buildItems(); return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsFeats(); }, getData(data) { From f09aedfc5a1bf09b3fae60c7bd0e26ce7ce35381 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 16:34:22 -0600 Subject: [PATCH 27/29] Corrected NaN bug when the following conditions are met: - Magic Item requires Equipped and Attuned - Item Attunement is set to "Attunement Not Required" - Item is equipped by Actor --- src/scripts/magic-item/OwnedMagicItem.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scripts/magic-item/OwnedMagicItem.js b/src/scripts/magic-item/OwnedMagicItem.js index 35f7912..f8eb8d6 100644 --- a/src/scripts/magic-item/OwnedMagicItem.js +++ b/src/scripts/magic-item/OwnedMagicItem.js @@ -58,7 +58,9 @@ export class OwnedMagicItem extends MagicItem { active = active && this.item.system.equipped; } if (this.attuned) { - let isAttuned = this.item.system.attunement ? this.item.system.attunement === 2 : this.item.system.attuned; + let isAttuned = + this.item.system.attunement === 2 || + this.item.system.attuned === true; /* this.item.system.attuned is a legacy property; can be undefined */ active = active && isAttuned; } return active; From 1f53ecf957e994d87c6b6bd6b58d1f6d7b18e604 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 16:41:54 -0600 Subject: [PATCH 28/29] Added some more explanatory comments --- src/module.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/module.js b/src/module.js index cca8920..9ac5a61 100644 --- a/src/module.js +++ b/src/module.js @@ -112,6 +112,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); + // Required for Tidy to have accurate item data actor.buildItems(); return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsSpells(); }, @@ -136,6 +137,7 @@ Hooks.once("tidy5e-sheet.ready", (api) => { }, enabled(data) { const actor = MagicItemActor.get(data.actor.id); + // Required for Tidy to have accurate item data actor.buildItems(); return ["character", "npc"].includes(data.actor.type) && actor?.hasItemsFeats(); }, From 407673604bbc6617317ef8e64031217179025f38 Mon Sep 17 00:00:00 2001 From: Kevin Garner Date: Fri, 26 Jan 2024 16:50:40 -0600 Subject: [PATCH 29/29] Simplified expression. --- src/scripts/magicItemtab.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scripts/magicItemtab.js b/src/scripts/magicItemtab.js index aba856c..22c40d3 100644 --- a/src/scripts/magicItemtab.js +++ b/src/scripts/magicItemtab.js @@ -110,10 +110,9 @@ export class MagicItemTab { if (this.activate && !this.isActive()) { app._tabs[0].activate("magicitems"); app.setPosition(); - this.activate = false; - } else { - this.activate = false; } + + this.activate = false; } isActive() {