diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index 43faa68a..92038c41 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -6,6 +6,7 @@ export { default as DamageReductionDialog } from './damageReductionDialog.mjs'; export { default as DeathMove } from './deathMove.mjs'; export { default as Downtime } from './downtime.mjs'; export { default as ImageSelectDialog } from './imageSelectDialog.mjs'; +export { default as ItemTransferDialog } from './itemTransfer.mjs'; export { default as MulticlassChoiceDialog } from './multiclassChoiceDialog.mjs'; export { default as OwnershipSelection } from './ownershipSelection.mjs'; export { default as RerollDamageDialog } from './rerollDamageDialog.mjs'; diff --git a/module/applications/dialogs/itemTransfer.mjs b/module/applications/dialogs/itemTransfer.mjs new file mode 100644 index 00000000..76d3c4f3 --- /dev/null +++ b/module/applications/dialogs/itemTransfer.mjs @@ -0,0 +1,69 @@ +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export default class ItemTransferDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(item) { + super({}); + + this.item = item; + this.quantity = item.system.quantity; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'dh-style', 'dialog', 'item-transfer'], + position: { width: 300, height: 'auto' }, + window: { title: 'Transfer Quantity' }, + actions: { + finish: ItemTransferDialog.#finish + }, + form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false } + }; + + static PARTS = { + main: { template: 'systems/daggerheart/templates/dialogs/item-transfer/main.hbs' }, + footer: { template: 'systems/daggerheart/templates/dialogs/item-transfer/footer.hbs' } + }; + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + if (partId === 'main') { + htmlElement.querySelector('.number-display').addEventListener('change', event => { + this.quantity = isNaN(event.target.value) ? this.quantity : Number(event.target.value); + this.render(); + }); + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.item = this.item; + context.quantity = this.quantity; + + return context; + } + + static async updateData(_event, _element, formData) { + const { quantity } = foundry.utils.expandObject(formData.object); + this.quantity = quantity; + this.render(); + } + + static async #finish() { + this.close({ submitted: true }); + } + + close(options = {}) { + if (!options.submitted) this.quantity = null; + + super.close(); + } + + static async configure(item) { + return new Promise(resolve => { + const app = new this(item); + app.addEventListener('close', () => resolve(app.quantity), { once: true }); + app.render({ force: true }); + }); + } +} diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 85267944..a9db2fc4 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -8,7 +8,6 @@ import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ -const { TextEditor } = foundry.applications.ux; export default class CharacterSheet extends DHBaseActorSheet { /**@inheritdoc */ static DEFAULT_OPTIONS = { @@ -881,6 +880,8 @@ export default class CharacterSheet extends DHBaseActorSheet { const item = await getDocFromElement(event.target); const dragData = { + originActor: this.document.uuid, + originId: item.id, type: item.documentName, uuid: item.uuid }; @@ -894,9 +895,12 @@ export default class CharacterSheet extends DHBaseActorSheet { // Prevent event bubbling to avoid duplicate handling event.preventDefault(); event.stopPropagation(); + const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - super._onDrop(event); - this._onDropItem(event, TextEditor.getDragEventData(event)); + const { cancel } = await super._onDrop(event); + if (cancel) return; + + this._onDropItem(event, data); } async _onDropItem(event, data) { diff --git a/module/applications/sheets/actors/party.mjs b/module/applications/sheets/actors/party.mjs index 8572034d..8a0b756d 100644 --- a/module/applications/sheets/actors/party.mjs +++ b/module/applications/sheets/actors/party.mjs @@ -441,6 +441,8 @@ export default class Party extends DHBaseActorSheet { async _onDragStart(event) { const item = await getDocFromElement(event.target); const dragData = { + originActor: this.document.uuid, + originId: item.id, type: item.documentName, uuid: item.uuid }; @@ -453,8 +455,11 @@ export default class Party extends DHBaseActorSheet { // Prevent event bubbling to avoid duplicate handling event.preventDefault(); event.stopPropagation(); - const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); + + const { cancel } = await super._onDrop(event); + if (cancel) return; + const document = await foundry.utils.fromUuid(data.uuid); if (document instanceof DhpActor && Party.ALLOWED_ACTOR_TYPES.includes(document.type)) { diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index e1226416..c61c6b53 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -217,6 +217,72 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { /* Application Drag/Drop */ /* -------------------------------------------- */ + async _onDrop(event) { + const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); + if (data.originActor === this.document.uuid) return { cancel: true }; + + /* Handling transfer of inventoryItems */ + let cancel = false; + const physicalActorTypes = ['character', 'party']; + if (physicalActorTypes.includes(this.document.type)) { + const originActor = data.originActor ? await foundry.utils.fromUuid(data.originActor) : null; + if (data.originId && originActor && physicalActorTypes.includes(originActor.type)) { + const dropDocument = await foundry.utils.fromUuid(data.uuid); + + if (dropDocument.system.metadata.isInventoryItem) { + cancel = true; + if (dropDocument.system.metadata.isQuantifiable) { + const actorItem = originActor.items.get(data.originId); + const quantityTransfered = + actorItem.system.quantity === 1 + ? 1 + : await game.system.api.applications.dialogs.ItemTransferDialog.configure(dropDocument); + + if (quantityTransfered) { + if (quantityTransfered === actorItem.system.quantity) { + await originActor.deleteEmbeddedDocuments('Item', [data.originId]); + } else { + cancel = true; + await actorItem.update({ + 'system.quantity': actorItem.system.quantity - quantityTransfered + }); + } + + const existingItem = this.document.items.find( + x => x._stats.compendiumSource === actorItem._stats.compendiumSource + ); + if (existingItem) { + cancel = true; + await existingItem.update({ + 'system.quantity': existingItem.system.quantity + quantityTransfered + }); + } else { + const createData = dropDocument.toObject(); + await this.document.createEmbeddedDocuments('Item', [ + { + ...createData, + system: { + ...createData.system, + quantity: quantityTransfered + } + } + ]); + } + } else { + cancel = true; + } + } else { + await originActor.deleteEmbeddedDocuments('Item', [data.originId]); + const createData = dropDocument.toObject(); + await this.document.createEmbeddedDocuments('Item', [createData]); + } + } + } + } + + return { cancel }; + } + /** * On dragStart on the item. * @param {DragEvent} event - The drag event diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 0f2b053b..91b2846b 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -35,3 +35,5 @@ @import './tag-team-dialog/sheet.less'; @import './image-select/sheet.less'; + +@import './item-transfer/sheet.less'; diff --git a/styles/less/dialog/item-transfer/sheet.less b/styles/less/dialog/item-transfer/sheet.less new file mode 100644 index 00000000..b18db097 --- /dev/null +++ b/styles/less/dialog/item-transfer/sheet.less @@ -0,0 +1,20 @@ +.daggerheart.dh-style.dialog.item-transfer { + .item-transfer-container { + display: grid; + grid-template-columns: 1fr 40px; + gap: 4px; + + .number-display { + text-align: center; + } + } + + .item-sheet-footer { + padding-top: 8px; + display: flex; + + button { + flex: 1; + } + } +} diff --git a/templates/dialogs/item-transfer/footer.hbs b/templates/dialogs/item-transfer/footer.hbs new file mode 100644 index 00000000..d56a2e76 --- /dev/null +++ b/templates/dialogs/item-transfer/footer.hbs @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/templates/dialogs/item-transfer/main.hbs b/templates/dialogs/item-transfer/main.hbs new file mode 100644 index 00000000..3e6c2433 --- /dev/null +++ b/templates/dialogs/item-transfer/main.hbs @@ -0,0 +1,6 @@ +
+
+ + +
+
\ No newline at end of file