const { HandlebarsApplicationMixin } = foundry.applications.api export default class MournbladeItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) { constructor(options = {}) { super(options) this.#dragDrop = this.#createDragDropHandlers() } #dragDrop /** @override */ static DEFAULT_OPTIONS = { classes: ["fvtt-mournblade", "item"], position: { width: 620, height: 600, }, form: { submitOnChange: true, }, window: { resizable: true, }, tabs: [ { navSelector: 'nav[data-group="primary"]', contentSelector: "section.sheet-body", initial: "description", }, ], dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }], actions: { editImage: MournbladeItemSheet.#onEditImage, postItem: MournbladeItemSheet.#onPostItem, enchanter: MournbladeItemSheet.#onEnchanter, }, } /** * Tab groups state * @type {object} */ tabGroups = { primary: "description" } /** @override */ async _prepareContext() { const item = this.document const enchantableTypes = ["arme", "equipement", "protection", "bouclier"] const actorIsLoyal = item.actor?.getAlignement?.() === "loyal" const alreadyEnchanted = enchantableTypes.includes(item.type) && (item.system.enchantementLoi?.actif ?? false) const canEnchant = enchantableTypes.includes(item.type) && !!item.actor && actorIsLoyal && !alreadyEnchanted const context = { fields: item.schema.fields, systemFields: item.system.schema.fields, item, system: item.system, source: item.toObject(), enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.system.description, { async: true }), isEditMode: true, isEditable: this.isEditable, isGM: game.user.isGM, config: game.system.mournblade.config, canEnchant, enchantementActif: alreadyEnchanted, } return context } /** @override */ _onRender(context, options) { super._onRender(context, options) this.#dragDrop.forEach((d) => d.bind(this.element)) // Activate tab navigation manually const nav = this.element.querySelector('nav.tabs[data-group]') if (nav) { const group = nav.dataset.group // Activate the current tab const activeTab = this.tabGroups[group] || "description" nav.querySelectorAll('[data-tab]').forEach(link => { const tab = link.dataset.tab link.classList.toggle('active', tab === activeTab) link.addEventListener('click', (event) => { event.preventDefault() this.tabGroups[group] = tab this.render() }) }) // Show/hide tab content this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => { content.classList.toggle('active', content.dataset.tab === activeTab) }) } } // #region Drag-and-Drop Workflow /** * Create drag-and-drop workflow handlers for this Application */ #createDragDropHandlers() { return [] } // #region Actions /** * Handle enchanting this item with Loi power */ static async #onEnchanter(event) { event.preventDefault() const item = this.document if (!item.actor) { ui.notifications.warn("Cet objet doit être sur un personnage pour être enchanté.") return } await item.actor.enchanter(item.id) } /** * Handle editing the item image * @param {Event} event - The triggering event */ static async #onEditImage(event) { event.preventDefault() const filePicker = new FilePicker({ type: "image", current: this.document.img, callback: (path) => { this.document.update({ img: path }) }, }) filePicker.browse() } /** * Handle posting the item to chat * @param {Event} event - The triggering event */ static async #onPostItem(event) { event.preventDefault() let chatData = foundry.utils.duplicate(this.document) if (this.document.actor) { chatData.actor = { id: this.document.actor.id } } if (chatData.img?.includes("/blank.png")) { chatData.img = null } chatData.jsondata = JSON.stringify({ compendium: "postedItem", payload: chatData, }) // Localized type label const typeLabels = { arme: "Arme", bouclier: "Bouclier", competence: "Compétence", rune: "Rune", runeeffect: "Rune Active", don: "Don", pacte: "Pacte", protection: "Protection", equipement: "Équipement", heritage: "Héritage", metier: "Métier", capacite: "Capacité", tendance: "Tendance", traitchaotique: "Trait Chaotique", traitespece: "Trait d'Espèce", origine: "Origine", modifier: "Modificateur", monnaie: "Monnaie", potion: "Potion" } chatData.typeLabel = typeLabels[chatData.type] ?? chatData.type // Type icon for the badge const typeIcons = { arme: "fa-sword", bouclier: "fa-shield-halved", competence: "fa-graduation-cap", rune: "fa-star-of-david", runeeffect: "fa-star-of-david", don: "fa-hand-sparkles", pacte: "fa-scroll", protection: "fa-shield", equipement: "fa-box", heritage: "fa-dna", metier: "fa-hammer", capacite: "fa-bolt", tendance: "fa-yin-yang", traitchaotique: "fa-skull", traitespece: "fa-paw", origine: "fa-compass", modifier: "fa-sliders", monnaie: "fa-coins", potion: "fa-flask" } chatData.typeIcon = typeIcons[chatData.type] ?? "fa-cube" // Potion: add localized labels for statut and forme if (chatData.type === "potion") { const statutLabels = { inconnue: game.i18n.localize("MNBL.potionInconnue"), efficace: game.i18n.localize("MNBL.potionEfficace"), heroique: game.i18n.localize("MNBL.potionHeroique"), inefficace: game.i18n.localize("MNBL.potionInefficace"), poison: game.i18n.localize("MNBL.potionPoison"), } const formeLabels = { liquide: game.i18n.localize("MNBL.potionLiquide"), onguent: game.i18n.localize("MNBL.potionOnguent"), cachets: game.i18n.localize("MNBL.potionCachets"), pilules: game.i18n.localize("MNBL.potionPilules"), } chatData.system.statutLabel = statutLabels[chatData.system.statut] ?? chatData.system.statut chatData.system.formeLabel = formeLabels[chatData.system.forme] ?? chatData.system.forme } const html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-mournblade/templates/post-item.hbs', chatData) ChatMessage.create({ user: game.user.id, content: html }) } }