Files
fvtt-mournblade/modules/applications/sheets/base-item-sheet.mjs
T
2026-05-02 23:16:10 +02:00

200 lines
6.5 KiB
JavaScript

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 })
}
}