const { HandlebarsApplicationMixin } = foundry.applications.api /** * Fiche de base pour tous les items Vermine 2047 (ApplicationV2). */ export class VermineBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) { // ── Mode édition ──────────────────────────────────────────────────── static SHEET_MODES = { EDIT: 0, PLAY: 1 } _sheetMode = this.constructor.SHEET_MODES.PLAY get isPlayMode() { return this._sheetMode === this.constructor.SHEET_MODES.PLAY } get isEditMode() { return this._sheetMode === this.constructor.SHEET_MODES.EDIT } // ── Options par défaut ────────────────────────────────────────────── static DEFAULT_OPTIONS = { classes: ["vermine2047", "item"], position: { width: 560, height: "auto" }, form: { submitOnChange: true }, window: { resizable: true }, actions: { editImage: VermineBaseItemSheet.#onEditImage, toggleSheet: VermineBaseItemSheet.#onToggleSheet, clickDamage: VermineBaseItemSheet.#onClickDamage, openTraits: VermineBaseItemSheet.#onOpenTraits } } // ── Drag & Drop ───────────────────────────────────────────────────── #dragDrop constructor(options = {}) { super(options) this.#dragDrop = this.#createDragDropHandlers() } #createDragDropHandlers() { if (!this.options.dragDrop) return [] return this.options.dragDrop.map(d => { d.permissions = { dragstart: this._canDragStart.bind(this), drop: this._canDragDrop.bind(this) } d.callbacks = { dragover: this._onDragOver.bind(this), drop: this._onDrop.bind(this) } return new foundry.applications.ux.DragDrop.implementation(d) }) } _canDragStart() { return this.isEditable } _canDragDrop() { return this.isEditable } // ── Contexte commun ───────────────────────────────────────────────── async _prepareContext() { return { fields: this.document.schema.fields, systemFields: this.document.system.schema.fields, item: this.document, system: this.document.system, source: this.document.toObject(), config: CONFIG.VERMINE, isEditMode: this.isEditMode, isPlayMode: this.isPlayMode, isEditable: this.isEditable } } // ── Rendu ─────────────────────────────────────────────────────────── _onRender(context, options) { this.#dragDrop.forEach(d => d.bind(this.element)) } // ── Sauvegarde ─────────────────────────────────────────────────────── /** @override */ _prepareSubmitData(event, form, formData, updateData) { return super._prepareSubmitData(event, form, formData, updateData) } // ── Actions ───────────────────────────────────────────────────────── static #onToggleSheet() { const modes = this.constructor.SHEET_MODES this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT this.render() } static async #onEditImage(event, target) { const attr = target.dataset.edit ?? "img" const current = foundry.utils.getProperty(this.document, attr) const fp = new FilePicker({ current, type: "image", callback: (path) => this.document.update({ [attr]: path }), top: this.position.top + 40, left: this.position.left + 10 }) return fp.browse() } static #onClickDamage(event, target) { // Les radios de dégâts sont 1-based dans le template (value="{{@index}}" avec index 1..max) // mais le stockage est 0-based. On soustrait 1 avant de sauvegarder. const prop = target.name const value = parseInt(target.value) - 1 this.document.update({ [prop]: value }) } static async #onOpenTraits(event, target) { const { TraitSelector } = await import("../../system/applications.mjs") new TraitSelector(this.document).render(true) } }