From 20f42e8a0d0bf45cd998396fb0366dd5941cbf92 Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Fri, 1 May 2026 22:09:21 -0400 Subject: [PATCH] Continue work on updating identifier --- lang/en.json | 3 ++ module/applications/sheets/items/class.mjs | 24 +++++----- module/applications/sheets/items/subclass.mjs | 23 ++++++++++ module/data/item/class.mjs | 27 +++++------- module/data/item/subclass.mjs | 6 ++- module/helpers/utils.mjs | 8 ++++ styles/less/global/feature-section.less | 44 +++++++++---------- .../less/sheets/items/item-sheet-shared.less | 4 ++ templates/sheets/items/class/features.hbs | 25 +++++------ templates/sheets/items/class/header.hbs | 4 -- templates/sheets/items/class/settings.hbs | 9 ++++ templates/sheets/items/subclass/features.hbs | 14 ++++++ 12 files changed, 122 insertions(+), 69 deletions(-) diff --git a/lang/en.json b/lang/en.json index b91d426e..09cbef70 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2532,6 +2532,9 @@ "recovery": { "label": "Recovery" }, "type": { "label": "Type" }, "value": { "label": "Value" } + }, + "identifier": { + "label": "Identifier" } }, "Ancestry": { diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 154f9ad9..0e253ddd 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -9,7 +9,8 @@ export default class ClassSheet extends DHBaseItemSheet { position: { width: 700 }, actions: { removeItemFromCollection: ClassSheet.#removeItemFromCollection, - removeSuggestedItem: ClassSheet.#removeSuggestedItem + removeSuggestedItem: ClassSheet.#removeSuggestedItem, + resetIdentifier: ClassSheet.#resetIdentifier }, tagifyConfigs: [ { @@ -107,6 +108,7 @@ export default class ClassSheet extends DHBaseItemSheet { async _prepareContext(_options) { const context = await super._prepareContext(_options); context.domains = this.document.system.domains; + context.subclasses = await this.document.system.getSubclasses(); return context; } @@ -129,19 +131,7 @@ export default class ClassSheet extends DHBaseItemSheet { const itemType = data.type === 'ActiveEffect' ? data.type : item.type; const target = event.target.closest('fieldset.drop-section'); - if (itemType === 'subclass') { - if (!this.document.system.identifier) { - return ui.notifications.error( - game.i18n.localize('DAGGERHEART.UI.Notifications.classMissingIdentifier') - ); - } - - if (item.system.classIdentifiers.includes(this.document.system.identifier)) return; - - await item.update({ - 'system.classIdentifiers': [...item.system.classIdentifiers, this.document.system.identifier] - }); - } else if (['feature', 'ActiveEffect'].includes(itemType)) { + if (['feature', 'ActiveEffect'].includes(itemType)) { super._onDrop(event); } else if (this.document.parent?.type !== 'character') { if (itemType === 'weapon') { @@ -218,4 +208,10 @@ export default class ClassSheet extends DHBaseItemSheet { const { target } = element.dataset; await this.document.update({ [`system.characterGuide.${target}`]: null }); } + + static async #resetIdentifier() { + const document = this.document; + const initial = document.system.schema.fields.identifier.getInitialValue(document._source); + document.update({ 'system.identifier': initial }); + } } diff --git a/module/applications/sheets/items/subclass.mjs b/module/applications/sheets/items/subclass.mjs index 5c731777..db01bfae 100644 --- a/module/applications/sheets/items/subclass.mjs +++ b/module/applications/sheets/items/subclass.mjs @@ -40,4 +40,27 @@ export default class SubclassSheet extends DHBaseItemSheet { get relatedDocs() { return this.document.system.features.map(x => x.item); } + + async _onDrop(event) { + event.stopPropagation(); + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + const itemType = data.type === 'ActiveEffect' ? data.type : item.type; + if (itemType === 'class') { + const identifier = item.system.identifier; + if (!identifier) { + return ui.notifications.error( + game.i18n.localize('DAGGERHEART.UI.Notifications.classMissingIdentifier') + ); + } + + if (this.document.system.classLink.identifier !== identifier) { + const { img, name } = item; + await this.document.update({ 'system.classLink': { identifier, img, name } }); + } + return; + } + + return super._onDrop(event); + } } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index e53b0b70..49195b5a 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -2,7 +2,7 @@ import BaseDataItem from './base.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs'; -import { addLinkedItemsDiff, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs'; +import { addLinkedItemsDiff, camelize, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs'; export default class DHClass extends BaseDataItem { /** @inheritDoc */ @@ -51,7 +51,7 @@ export default class DHClass extends BaseDataItem { backgroundQuestions: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), connections: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), isMulticlass: new fields.BooleanField({ initial: false }), - identifier: new fields.StringField(), + identifier: new fields.StringField({ blank: false, initial: obj => camelize(obj?.name ?? '') }), /* Subclasses is legacy. If we can safetely migrate it away at some point we could remove it*/ subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }) }; @@ -73,24 +73,21 @@ export default class DHClass extends BaseDataItem { } async getSubclasses() { - const oldLinkedSubclasses = this.subclasses.filter(x => x); - if (!this.identifier) return oldLinkedSubclasses; + const oldLinkedSubclasses = this.subclasses; + if (oldLinkedSubclasses.length) return oldLinkedSubclasses; const subclasses = game.items.filter( - x => x.type === 'subclass' && x.system.classIdentifiers.includes(this.identifier) + x => x.type === 'subclass' && x.system.classLink.identifier === this.identifier ); for (const pack of game.packs) { - const indexes = await pack.getIndex({ fields: ['system.classIdentifiers'] }); + const indexes = await pack.getIndex({ fields: ['system.classLink.identifier'] }); for (const index of indexes) { - if ( - index.type === 'subclass' && - (index.system.classIdentifiers ?? []).includes( - this.identifier && !subclasses.find(x => x.uuid === index.uuid) - ) - ) { - const subclass = await foundry.utils.fromUuid(index.uuid); - subclasses.push(subclass); - } + if (index.type !== 'subclass') continue; + if (index.system?.classLink?.identifier !== this.identifier) continue; + if (subclasses.find(x => x.uuid === index.uuid)) continue; + + const subclass = await foundry.utils.fromUuid(index.uuid); + subclasses.push(subclass); } } diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index f166d01b..96c9f5de 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -28,7 +28,11 @@ export default class DHSubclass extends BaseDataItem { features: new ItemLinkFields(), featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }), isMulticlass: new fields.BooleanField({ initial: false }), - classIdentifiers: new fields.ArrayField(new fields.StringField({ nullable: false })), + classLink: new fields.SchemaField({ + identifier: new fields.StringField({ nullable: true, initial: null }), + name: new fields.StringField(), + img: new fields.StringField() + }), /* Linked class is legacy. If we can safetely migrate it away at some point we could remove it */ linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null }) }; diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index faa046ff..c993dce3 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -841,3 +841,11 @@ export function createShallowProxy(obj) { } }); } + +export function camelize(str) { + return str + .replace(/(?:^\w|[A-Z]|\b\w)/g, (part, index) => { + return index === 0 ? part.toLowerCase() : part.toUpperCase(); + }) + .replace(/\s+/g, ''); +} diff --git a/styles/less/global/feature-section.less b/styles/less/global/feature-section.less index 13feb92c..937f0cde 100644 --- a/styles/less/global/feature-section.less +++ b/styles/less/global/feature-section.less @@ -19,28 +19,28 @@ &:last-child { margin-bottom: 0px; } - .feature-line { - display: grid; - align-items: center; - grid-template-columns: 1fr 4fr 1fr; - h4 { - font-weight: lighter; - color: light-dark(@dark, @beige); - } - .image { - height: 40px; - width: 40px; - object-fit: cover; - border-radius: 6px; - border: none; - } - .controls { - display: flex; - justify-content: center; - gap: 10px; - a { - text-shadow: none; - } + } + .feature-line { + display: grid; + align-items: center; + grid-template-columns: 1fr 4fr 1fr; + h4 { + font-weight: lighter; + color: light-dark(@dark, @beige); + } + .image { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 6px; + border: none; + } + .controls { + display: flex; + justify-content: center; + gap: 10px; + a { + text-shadow: none; } } } diff --git a/styles/less/sheets/items/item-sheet-shared.less b/styles/less/sheets/items/item-sheet-shared.less index d0a8cc48..5155ad70 100644 --- a/styles/less/sheets/items/item-sheet-shared.less +++ b/styles/less/sheets/items/item-sheet-shared.less @@ -10,4 +10,8 @@ font-family: @font-body; color: light-dark(@chat-blue-bg, @beige-50); } + + button.plain.inline-control { + flex: 0 0 auto; + } } diff --git a/templates/sheets/items/class/features.hbs b/templates/sheets/items/class/features.hbs index 9d037b65..5da6e368 100644 --- a/templates/sheets/items/class/features.hbs +++ b/templates/sheets/items/class/features.hbs @@ -27,10 +27,7 @@
{{localize "TYPES.Item.subclass"}}
- {{#unless source.system.subclasses}} -
{{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "DAGGERHEART.GENERAL.subclasses")}}
- {{/unless}} - {{#each source.system.subclasses as |subclass index|}} + {{#each subclasses as |subclass index|}}
  • @@ -46,15 +43,17 @@ > - - - + {{#if document.system.subclasses}} + + + + {{/if}}
  • diff --git a/templates/sheets/items/class/header.hbs b/templates/sheets/items/class/header.hbs index 12c08bc3..019825f8 100644 --- a/templates/sheets/items/class/header.hbs +++ b/templates/sheets/items/class/header.hbs @@ -3,10 +3,6 @@

    -

    - {{localize 'TYPES.Item.class'}} - {{formInput systemFields.identifier value=source.system.identifier}} -

    {{localize "DAGGERHEART.GENERAL.Domain.plural"}} diff --git a/templates/sheets/items/class/settings.hbs b/templates/sheets/items/class/settings.hbs index b224ec1f..d44b12dd 100644 --- a/templates/sheets/items/class/settings.hbs +++ b/templates/sheets/items/class/settings.hbs @@ -3,6 +3,15 @@ data-tab='{{tabs.settings.id}}' data-group='{{tabs.settings.group}}' > +
    + {{localize "DAGGERHEART.GENERAL.general"}} + {{localize "DAGGERHEART.ITEMS.FIELDS.identifier.label"}} +
    + {{formInput systemFields.identifier value=source.system.identifier}} + +
    +
    +
    {{localize tabs.settings.label}} {{formGroup systemFields.hitPoints value=source.system.hitPoints localize=true}} diff --git a/templates/sheets/items/subclass/features.hbs b/templates/sheets/items/subclass/features.hbs index 1a75974e..5221c8ae 100644 --- a/templates/sheets/items/subclass/features.hbs +++ b/templates/sheets/items/subclass/features.hbs @@ -3,6 +3,20 @@ data-tab='{{tabs.features.id}}' data-group='{{tabs.features.group}}' > +
    + {{localize "TYPES.Item.class"}} + {{#if document.system.classLink.identifier}} +
    +
  • + + {{document.system.classLink.name}} +
  • +
    + {{else}} +
    {{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "TYPES.Item.class")}}
    + {{/if}} +
    +
    {{localize "DAGGERHEART.GENERAL.Tabs.foundation"}}