diff --git a/module/applications/sheets/api/_modules.mjs b/module/applications/sheets/api/_modules.mjs index d5ef290d..4316da2a 100644 --- a/module/applications/sheets/api/_modules.mjs +++ b/module/applications/sheets/api/_modules.mjs @@ -1,2 +1,3 @@ -export {default as DHApplicationMixin} from "./application-mixin.mjs"; -export {default as DHBaseItemSheet} from "./base-item.mjs"; +export { default as DHApplicationMixin } from './application-mixin.mjs'; +export { default as DHBaseItemSheet } from './base-item.mjs'; +export { default as DHHeritageSheet } from './heritage-sheet.mjs'; diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index d45cafe6..12b55bd6 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -17,86 +17,128 @@ const { HandlebarsApplicationMixin } = foundry.applications.api; * @returns {BaseDocumentSheet} */ export default function DHApplicationMixin(Base) { - class DHSheetV2 extends HandlebarsApplicationMixin(Base) { - /** - * @param {DHSheetV2Configuration} [options={}] - */ - constructor(options = {}) { - super(options); - /** - * @type {foundry.applications.ux.DragDrop[]} - * @private - */ - this._dragDrop = this._createDragDropHandlers(); - } + class DHSheetV2 extends HandlebarsApplicationMixin(Base) { + /** + * @param {DHSheetV2Configuration} [options={}] + */ + constructor(options = {}) { + super(options); + /** + * @type {foundry.applications.ux.DragDrop[]} + * @private + */ + this._dragDrop = this._createDragDropHandlers(); + } - /** - * The default options for the sheet. - * @type {DHSheetV2Configuration} - */ - static DEFAULT_OPTIONS = { - classes: ['daggerheart', 'sheet', 'dh-style'], - position: { - width: 480, - height: 'auto' - }, - - dragDrop: [] - }; - - /* -------------------------------------------- */ - - /**@inheritdoc */ - _attachPartListeners(partId, htmlElement, options) { - super._attachPartListeners(partId, htmlElement, options); - this._dragDrop.forEach(d => d.bind(htmlElement)); - } - - /* -------------------------------------------- */ - /* Drag and Drop */ - /* -------------------------------------------- */ - - /** - * Creates drag-drop handlers from the configured options. - * @returns {foundry.applications.ux.DragDrop[]} - * @private - */ - _createDragDropHandlers() { - return this.options.dragDrop.map(d => { - d.callbacks = { - drop: this._onDrop.bind(this) + /** + * The default options for the sheet. + * @type {DHSheetV2Configuration} + */ + static DEFAULT_OPTIONS = { + classes: ['daggerheart', 'sheet', 'dh-style'], + position: { + width: 480, + height: 'auto' + }, + actions: { + addEffect: DHSheetV2.#addEffect, + editEffect: DHSheetV2.#editEffect, + removeEffect: DHSheetV2.#removeEffect + }, + dragDrop: [] }; - return new foundry.applications.ux.DragDrop.implementation(d); - }); + + /* -------------------------------------------- */ + + /**@inheritdoc */ + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + this._dragDrop.forEach(d => d.bind(htmlElement)); + } + + /* -------------------------------------------- */ + /* Drag and Drop */ + /* -------------------------------------------- */ + + /** + * Creates drag-drop handlers from the configured options. + * @returns {foundry.applications.ux.DragDrop[]} + * @private + */ + _createDragDropHandlers() { + return this.options.dragDrop.map(d => { + d.callbacks = { + drop: this._onDrop.bind(this) + }; + return new foundry.applications.ux.DragDrop.implementation(d); + }); + } + + /** + * Handle drop event. + * @param {DragEvent} event + * @protected + */ + _onDrop(event) {} + + /* -------------------------------------------- */ + /* Prepare Context */ + /* -------------------------------------------- */ + + /** + * Prepare the template context. + * @param {object} options + * @param {string} [objectPath='document'] + * @returns {Promise} + * @inheritdoc + */ + async _prepareContext(options, objectPath = 'document') { + const context = await super._prepareContext(options); + context.config = CONFIG.daggerheart; + context.source = this[objectPath]; + context.fields = this[objectPath].schema.fields; + context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {}; + return context; + } + + /* -------------------------------------------- */ + /* Application Clicks Actions */ + /* -------------------------------------------- */ + + /** + * Renders an ActiveEffect's sheet sheet. + * @param {PointerEvent} event - The originating click event + * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"] + */ + static async #addEffect() { + const cls = foundry.documents.ActiveEffect; + await cls.create( + { + name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize(cls.metadata.label) }) + }, + { parent: this.document } + ); + } + + /** + * Renders an ActiveEffect's sheet sheet. + * @param {PointerEvent} event - The originating click event + * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"] + */ + static async #editEffect(_event, button) { + const effect = this.document.effects.get(button.dataset.effect); + effect.sheet.render({ force: true }); + } + + /** + * Delete an ActiveEffect from the item. + * @param {PointerEvent} _event - The originating click event + * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"] + */ + static async #removeEffect(_event, button) { + await this.document.effects.get(button.dataset.effect).delete(); + } } - /** - * Handle drop event. - * @param {DragEvent} event - * @protected - */ - _onDrop(event) { } - - /* -------------------------------------------- */ - /* Prepare Context */ - /* -------------------------------------------- */ - - /** - * Prepare the template context. - * @param {object} options - * @param {string} [objectPath='document'] - * @returns {Promise} - * @inheritdoc - */ - async _prepareContext(options, objectPath = 'document') { - const context = await super._prepareContext(options); - context.config = CONFIG.daggerheart; - context.source = this[objectPath]; - context.fields = this[objectPath].schema.fields; - context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {}; - return context; - } - } - - return DHSheetV2; + return DHSheetV2; } diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index b85f9696..020b482d 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -1,6 +1,6 @@ -import DHApplicationMixin from "./application-mixin.mjs"; -import { actionsTypes } from "../../../data/_module.mjs"; -import DHActionConfig from "../../config/Action.mjs"; +import DHApplicationMixin from './application-mixin.mjs'; +import { actionsTypes } from '../../../data/_module.mjs'; +import DHActionConfig from '../../config/Action.mjs'; const { ItemSheetV2 } = foundry.applications.sheets; @@ -10,118 +10,115 @@ const { ItemSheetV2 } = foundry.applications.sheets; * @mixes DHSheetV2 */ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { - /** @inheritDoc */ - static DEFAULT_OPTIONS = { - classes: ['item'], - position: { width: 600 }, - form: { - submitOnChange: true - }, - actions: { - addAction: DHBaseItemSheet.#addAction, - editAction: DHBaseItemSheet.#editAction, - removeAction: DHBaseItemSheet.#removeAction + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + classes: ['item'], + position: { width: 600 }, + form: { + submitOnChange: true + }, + actions: { + addAction: DHBaseItemSheet.#addAction, + editAction: DHBaseItemSheet.#editAction, + removeAction: DHBaseItemSheet.#removeAction + } + }; + + /* -------------------------------------------- */ + + /** @inheritdoc */ + static TABS = { + primary: { + tabs: [{ id: 'description' }, { id: 'actions' }, { id: 'settings' }], + initial: 'description', + labelPrefix: 'DAGGERHEART.Sheets.TABS' + } + }; + + /* -------------------------------------------- */ + /* Application Clicks Actions */ + /* -------------------------------------------- */ + + /** + * Render a dialog prompting the user to select an action type. + * + * @returns {Promise} An object containing the selected action type. + */ + static async selectActionType() { + const content = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/views/actionType.hbs', + { types: SYSTEM.ACTIONS.actionTypes } + ), + title = 'Select Action Type', //useless var + type = 'form', + data = {}; //useless var + //TODO: use DialogV2 + return Dialog.prompt({ + title, + label: title, + content, + type, //this prop is useless + callback: html => { + const form = html[0].querySelector('form'), + fd = new foundry.applications.ux.FormDataExtended(form); + foundry.utils.mergeObject(data, fd.object, { inplace: true }); + // if (!data.name?.trim()) data.name = game.i18n.localize(SYSTEM.ACTIONS.actionTypes[data.type].name); + return data; + }, + rejectClose: false + }); } - }; - /* -------------------------------------------- */ - - /** @inheritdoc */ - static TABS = { - primary: { - tabs: [ - { id: 'description' }, - { id: 'actions' }, - { id: 'settings' } - ], - initial: "description", - labelPrefix: "DAGGERHEART.Sheets.TABS" + /** + * Add a new action to the item, prompting the user for its type. + * @param {PointerEvent} _event - The originating click event + * @param {HTMLElement} _button - The capturing HTML element which defines the [data-action="addAction"] + */ + static async #addAction(_event, _button) { + const actionType = await DHBaseItemSheet.selectActionType(); + try { + const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack, + action = new cls( + { + _id: foundry.utils.randomID(), + type: actionType.type, + name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name), + ...cls.getSourceConfig(this.document) + }, + { + parent: this.document + } + ); + await this.document.update({ 'system.actions': [...this.document.system.actions, action] }); + await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render({ + force: true + }); + } catch (error) { + console.log(error); + } } - } - /* -------------------------------------------- */ - /* Application Clicks Actions */ - /* -------------------------------------------- */ - - /** - * Render a dialog prompting the user to select an action type. - * - * @returns {Promise} An object containing the selected action type. - */ - static async selectActionType() { - const content = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/views/actionType.hbs', - { types: SYSTEM.ACTIONS.actionTypes } - ), - title = 'Select Action Type', //useless var - type = 'form', - data = {}; //useless var - //TODO: use DialogV2 - return Dialog.prompt({ - title, - label: title, - content, - type, //this prop is useless - callback: html => { - const form = html[0].querySelector('form'), - fd = new foundry.applications.ux.FormDataExtended(form); - foundry.utils.mergeObject(data, fd.object, { inplace: true }); - // if (!data.name?.trim()) data.name = game.i18n.localize(SYSTEM.ACTIONS.actionTypes[data.type].name); - return data; - }, - rejectClose: false - }); - } - - /** - * Add a new action to the item, prompting the user for its type. - * @param {PointerEvent} _event - The originating click event - * @param {HTMLElement} _button - The capturing HTML element which defines the [data-action="addAction"] - */ - static async #addAction(_event, _button) { - const actionType = await DHBaseItemSheet.selectActionType() - try { - const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack, - action = new cls( - { - _id: foundry.utils.randomID(), - type: actionType.type, - name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name), - ...cls.getSourceConfig(this.document) - }, - { - parent: this.document - } - ); - await this.document.update({ 'system.actions': [...this.document.system.actions, action] }); - await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render({force: true}); - } catch (error) { - console.log(error); + /** + * Edit an existing action on the item + * @param {PointerEvent} _event - The originating click event + * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="editAction"] + */ + static async #editAction(_event, button) { + const action = this.document.system.actions[button.dataset.index]; + await new DHActionConfig(action).render({ force: true }); } - } - /** - * Edit an existing action on the item - * @param {PointerEvent} event - The originating click event - * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="editAction"] - */ - static async #editAction(_event, button) { - const action = this.document.system.actions[button.dataset.index]; - await new DHActionConfig(action).render(true); - } - - /** - * Remove an action from the item. - * @param {PointerEvent} event - The originating click event - * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"] - */ - static async #removeAction(event, button) { - event.stopPropagation(); - await this.document.update({ - 'system.actions': this.document.system.actions.filter( - (_, index) => index !== Number.parseInt(button.dataset.index) - ) - }); - } - -} \ No newline at end of file + /** + * Remove an action from the item. + * @param {PointerEvent} event - The originating click event + * @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"] + */ + static async #removeAction(event, button) { + event.stopPropagation(); + await this.document.update({ + 'system.actions': this.document.system.actions.filter( + (_, index) => index !== Number.parseInt(button.dataset.index) + ) + }); + } +} diff --git a/module/applications/sheets/api/heritage-sheet.mjs b/module/applications/sheets/api/heritage-sheet.mjs new file mode 100644 index 00000000..4938f5b0 --- /dev/null +++ b/module/applications/sheets/api/heritage-sheet.mjs @@ -0,0 +1,31 @@ +import DHBaseItemSheet from './base-item.mjs'; + +export default class DHHeritageSheet extends DHBaseItemSheet { + /**@inheritdoc */ + static DEFAULT_OPTIONS = { + position: { width: 450, height: 700 } + }; + + /**@override */ + static PARTS = { + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + description: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-description.hbs' }, + actions: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-actions.hbs', + scrollable: ['.actions'] + }, + effects: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-effects.hbs', + scrollable: ['.effects'] + } + }; + + /** @override*/ + static TABS = { + primary: { + tabs: [{ id: 'description' }, { id: 'actions' }, { id: 'effects' }], + initial: 'description', + labelPrefix: 'DAGGERHEART.Sheets.TABS' + } + }; +} diff --git a/module/applications/sheets/items/ancestry.mjs b/module/applications/sheets/items/ancestry.mjs index 3d20df7a..eb03de99 100644 --- a/module/applications/sheets/items/ancestry.mjs +++ b/module/applications/sheets/items/ancestry.mjs @@ -1,7 +1,6 @@ -import DHHeritageSheetV2 from './heritage.mjs'; +import DHHeritageSheet from '../api/heritage-sheet.mjs'; -const { ItemSheetV2 } = foundry.applications.sheets; -export default class AncestrySheet extends DHHeritageSheetV2(ItemSheetV2) { +export default class AncestrySheet extends DHHeritageSheet { static DEFAULT_OPTIONS = { classes: ['ancestry'] }; diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index f55c2b5f..f91f70fa 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -50,14 +50,11 @@ export default class ClassSheet extends DHBaseItemSheet { /** @inheritdoc */ static TABS = { primary: { - tabs: [ - { id: 'description' }, - { id: 'settings' }, - ], - initial: "description", - labelPrefix: "DAGGERHEART.Sheets.Feature.Tabs" + tabs: [{ id: 'description' }, { id: 'settings' }], + initial: 'description', + labelPrefix: 'DAGGERHEART.Sheets.Feature.Tabs' } - } + }; _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); @@ -72,7 +69,6 @@ export default class ClassSheet extends DHBaseItemSheet { return context; } - onAddTag(e) { if (e.detail.index === 2) { ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains')); @@ -137,9 +133,9 @@ export default class ClassSheet extends DHBaseItemSheet { async selectActionType() { const content = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/views/actionType.hbs', - { types: SYSTEM.ACTIONS.actionTypes } - ), + 'systems/daggerheart/templates/views/actionType.hbs', + { types: SYSTEM.ACTIONS.actionTypes } + ), title = 'Select Action Type', type = 'form', data = {}; diff --git a/module/applications/sheets/items/community.mjs b/module/applications/sheets/items/community.mjs index 890ff605..92c3731e 100644 --- a/module/applications/sheets/items/community.mjs +++ b/module/applications/sheets/items/community.mjs @@ -1,11 +1,12 @@ -import DHHeritageSheetV2 from './heritage.mjs'; +import DHHeritageSheet from '../api/heritage-sheet.mjs'; -const { ItemSheetV2 } = foundry.applications.sheets; -export default class CommunitySheet extends DHHeritageSheetV2(ItemSheetV2) { +export default class CommunitySheet extends DHHeritageSheet { + /**@inheritdoc */ static DEFAULT_OPTIONS = { classes: ['community'] }; + /**@inheritdoc */ static PARTS = { header: { template: 'systems/daggerheart/templates/sheets/items/community/header.hbs' }, ...super.PARTS