const {HandlebarsApplicationMixin} = foundry.applications.api const {DocumentSheetV2, ActorSheetV2} = foundry.applications.sheets export class MerchantSheet extends HandlebarsApplicationMixin(ActorSheetV2) { /** @inheritDoc */ static DEFAULT_OPTIONS = { position: {width: 520, height: 480}, classes: ['dsa41', 'sheet', 'actor', 'merchant'], tag: 'form', dragDrop: [{ dropSelector: '.tab.inventory.active' }], form: { submitOnChange: true, closeOnSubmit: false, handler: MerchantSheet.#onSubmitForm }, window: { resizable: true, }, actions: { editImage: MerchantSheet.editImage, editServiceImage: MerchantSheet.#editServiceImage, editNewServiceImage: MerchantSheet.#editNewServiceImage, addNewService: MerchantSheet.#addNewService, removeService: MerchantSheet.#removeService, } } static TABS = { sheet: { tabs: [ {id: 'goods', group: 'sheet', label: 'Waren'}, {id: 'services', group: 'sheet', label: 'Dienstleistungen'}, // Meta is added via GM permission ], initial: 'goods' } } /** @inheritDoc */ static PARTS = { form: { template: `systems/DSA_4-1/templates/actor/merchant/main-sheet.hbs` }, goods: { template: `systems/DSA_4-1/templates/actor/merchant/tab-goods.hbs` }, services: { template: `systems/DSA_4-1/templates/actor/merchant/tab-services.hbs` }, meta: { template: `systems/DSA_4-1/templates/actor/merchant/tab-meta.hbs` } } constructor(options = {}) { super(options); } /** * Handle form submission * @this {AdvantageSheet} * @param {SubmitEvent} event * @param {HTMLFormElement} form * @param {FormDataExtended} formData */ static async #onSubmitForm(event, form, formData) { event.preventDefault() await this.document.update(formData.object) // Note: formData.object } static async #removeService(event, target) { const {rowId} = target.dataset; const services = this.document.services services.splice(rowId, 1) this.document.update({"system.services": services}) } static async #addNewService(event, target) { event.preventDefault() const fieldset = this.element.querySelector('details') const image = fieldset.querySelector('img').src const name = fieldset.querySelector('input[name="new_name"]').value const price = fieldset.querySelector('input[name="new_price"]').value const availability = fieldset.querySelector('input[name="new_availability"]').value const description = fieldset.querySelector('prose-mirror').value if (name && price) { let services = this.document.system.services services.push({ image, name, price, availability, description }) this.document.update({"system.services": services}).then(e => { this.element.reset() }) } return false } static async #editNewServiceImage(event, target) { const field = target.dataset.field || "img" const current = foundry.utils.getProperty(this.document, field) const fp = new foundry.applications.apps.FilePicker({ type: "image", current: current, callback: (path) => { target.src = path } }) fp.render(true) } static async #editServiceImage(event, target) { const field = target.dataset.field || "img" const current = foundry.utils.getProperty(this.document, field) const fp = new foundry.applications.apps.FilePicker({ type: "image", current: current, callback: (path) => { target.src = path //foundry.utils.setProperty(this.document, field, path) target.parentElement.querySelector(`input[name="${field}"][type="hidden"]`).value = path this.element.submit() } }) fp.render(true) } /** * Handle changing a Document's image. * @param {MouseEvent} event The click event. * @returns {Promise} * @protected */ /* static _onEditImage(event) { const attr = event.currentTarget.dataset.edit; const current = foundry.utils.getProperty(this.object, attr); const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}; const fp = new FilePicker.implementation({ current, type: "image", redirectToRoot: img ? [img] : [], callback: path => { event.target.src = path; event.target.dataset.edit this.document.update({'image': path}) }, top: this.position.top + 40, left: this.position.left + 10 }); return fp.browse(); }*/ _getTabsConfig(group) { const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) // Modify tabs based on document properties if (game.user.isGM) { tabs.tabs.push({id: "meta", group: "sheet", label: "Meta"}) } return tabs } /** @override */ async _prepareContext(options) { const context = await super._prepareContext(options) context.name = this.document.name context.image = this.document.img context.description = this.document.system.description context.goods = this.document.itemTypes["Equipment"] ?? [] context.services = this.document.system.services return context } /** * Actions performed after any render of the Application. * Post-render steps are not awaited by the render process. * @param {ApplicationRenderContext} context Prepared context data * @param {RenderOptions} options Provided render options * @protected */ _onRender(context, options) { new foundry.applications.ux.DragDrop.implementation({ dropSelector: ".window-content", permissions: { drop: this._canDragDrop.bind(this) }, callbacks: { drop: this._onDrop.bind(this) } }).bind(this.element); } _canDragDrop(event, options) { return game.user.isGM } async _onDrop(event) { const data = TextEditor.implementation.getDragEventData(event); const actor = this.actor; const allowed = Hooks.call("dropActorSheetData", actor, this, data); if (allowed === false) return; // Dropped Documents const documentClass = foundry.utils.getDocumentClass(data.type); if (documentClass) { const document = await documentClass.fromDropData(data); if (document.type === "Equipment") { // No duplication by moving items from one actor to another if (document.parent && document.parent !== this.actor) { document.parent.items.get(document._id).delete() } await this._onDropDocument(event, document); } } } }