244 lines
6.3 KiB
JavaScript
244 lines
6.3 KiB
JavaScript
const { HandlebarsApplicationMixin } = foundry.applications.api
|
|
|
|
/**
|
|
* Base Item Sheet for BoL system using AppV2
|
|
* @extends {ItemSheetV2}
|
|
*/
|
|
export default class BoLBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
|
constructor(options = {}) {
|
|
super(options)
|
|
this.#dragDrop = this.#createDragDropHandlers()
|
|
}
|
|
|
|
#dragDrop
|
|
|
|
/** @override */
|
|
static DEFAULT_OPTIONS = {
|
|
classes: ["bol", "sheet", "item"],
|
|
position: {
|
|
width: 650,
|
|
height: 780,
|
|
},
|
|
form: {
|
|
submitOnChange: true,
|
|
},
|
|
window: {
|
|
resizable: true,
|
|
},
|
|
actions: {
|
|
editImage: BoLBaseItemSheet.#onEditImage,
|
|
postItem: BoLBaseItemSheet.#onPostItem,
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Tab groups state
|
|
* @type {object}
|
|
*/
|
|
tabGroups = { primary: "description" }
|
|
|
|
/** @override */
|
|
async _prepareContext() {
|
|
const context = {
|
|
// Document & system
|
|
fields: this.document.schema.fields,
|
|
systemFields: this.document.system.schema.fields,
|
|
item: this.document,
|
|
system: this.document.system,
|
|
source: this.document.toObject(),
|
|
|
|
// Enriched content
|
|
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
|
this.document.system.description,
|
|
{ async: true }
|
|
),
|
|
|
|
// Properties
|
|
category: this.document.system.category,
|
|
itemProperties: this.document.itemProperties,
|
|
|
|
// Config & permissions
|
|
config: game.bol.config,
|
|
isGM: game.user.isGM,
|
|
isEditable: this.isEditable,
|
|
|
|
// CSS classes for template
|
|
cssClass: this.options.classes.join(" "),
|
|
|
|
// Tab state
|
|
tabs: this._getTabs(),
|
|
activeTab: this.tabGroups.primary || "description"
|
|
}
|
|
|
|
// Add careers if item is on an actor
|
|
if (this.document.actor) {
|
|
context.careers = this.document.actor.careers
|
|
}
|
|
|
|
// Apply dynamic defaults based on item type
|
|
this._applyDynamicDefaults(context)
|
|
|
|
return context
|
|
}
|
|
|
|
/**
|
|
* Get tabs configuration
|
|
* @returns {object[]}
|
|
* @private
|
|
*/
|
|
_getTabs() {
|
|
return [
|
|
{ id: "description", label: "BOL.ui.tab.description", icon: "fa-solid fa-book" },
|
|
{ id: "properties", label: "BOL.ui.tab.details", icon: "fa-solid fa-cog" }
|
|
]
|
|
}
|
|
|
|
/**
|
|
* Apply dynamic defaults to context based on item type and category
|
|
* @param {object} context
|
|
* @private
|
|
*/
|
|
_applyDynamicDefaults(context) {
|
|
const itemData = context.item
|
|
|
|
if (itemData.type === "item") {
|
|
// Set default category
|
|
if (!itemData.system.category) {
|
|
itemData.system.category = "equipment"
|
|
}
|
|
|
|
// Handle equipment slot
|
|
if (itemData.system.category === "equipment" && itemData.system.properties.equipable) {
|
|
if (!itemData.system.properties.slot) {
|
|
itemData.system.properties.slot = "-"
|
|
}
|
|
}
|
|
|
|
// Handle spell conditions
|
|
if (itemData.system.category === 'spell') {
|
|
if (!itemData.system.properties.mandatoryconditions) {
|
|
itemData.system.properties.mandatoryconditions = []
|
|
}
|
|
if (!itemData.system.properties.optionnalconditions) {
|
|
itemData.system.properties.optionnalconditions = []
|
|
}
|
|
for (let i = 0; i < 4; i++) {
|
|
itemData.system.properties.mandatoryconditions[i] = itemData.system.properties.mandatoryconditions[i] ?? ""
|
|
}
|
|
for (let i = 0; i < 8; i++) {
|
|
itemData.system.properties.optionnalconditions[i] = itemData.system.properties.optionnalconditions[i] ?? ""
|
|
}
|
|
}
|
|
} else if (itemData.type === "feature") {
|
|
// Set default subtype/category
|
|
if (!itemData.system.subtype) {
|
|
itemData.system.category = "origin"
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @override */
|
|
_onRender(context, options) {
|
|
super._onRender(context, options)
|
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
|
this._activateTabs()
|
|
this._activateListeners()
|
|
}
|
|
|
|
/**
|
|
* Activate tab navigation
|
|
* @private
|
|
*/
|
|
_activateTabs() {
|
|
const nav = this.element.querySelector('nav.tabs[data-group="primary"]')
|
|
if (!nav) return
|
|
|
|
const activeTab = this.tabGroups.primary || "description"
|
|
|
|
// Activate tab links
|
|
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.primary = tab
|
|
this.render()
|
|
})
|
|
})
|
|
|
|
// Show/hide tab content
|
|
this.element.querySelectorAll('.tab[data-tab]').forEach(content => {
|
|
content.classList.toggle('active', content.dataset.tab === activeTab)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Activate custom listeners
|
|
* @private
|
|
*/
|
|
_activateListeners() {
|
|
if (!this.isEditable) return
|
|
|
|
// Armor quality change handler
|
|
const armorQuality = this.element.querySelector('.armorQuality')
|
|
if (armorQuality) {
|
|
armorQuality.addEventListener('change', (ev) => {
|
|
const value = ev.currentTarget.value
|
|
const soakFormula = this.element.querySelector('.soakFormula')
|
|
if (soakFormula && game.bol.config.soakFormulas[value]) {
|
|
soakFormula.value = game.bol.config.soakFormulas[value]
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// #region Drag-and-Drop Workflow
|
|
|
|
/**
|
|
* Create drag-and-drop workflow handlers for this Application
|
|
* @returns {DragDrop[]}
|
|
* @private
|
|
*/
|
|
#createDragDropHandlers() {
|
|
return []
|
|
}
|
|
|
|
// #endregion
|
|
|
|
// #region Actions
|
|
|
|
/**
|
|
* Handle editing the item image
|
|
* @param {PointerEvent} event
|
|
* @param {HTMLElement} target
|
|
* @private
|
|
*/
|
|
static async #onEditImage(event, target) {
|
|
const fp = new FilePicker({
|
|
current: this.document.img,
|
|
type: "image",
|
|
callback: (path) => {
|
|
this.document.update({ img: path })
|
|
},
|
|
})
|
|
return fp.browse()
|
|
}
|
|
|
|
/**
|
|
* Handle posting the item to chat
|
|
* @param {PointerEvent} event
|
|
* @param {HTMLElement} target
|
|
* @private
|
|
*/
|
|
static async #onPostItem(event, target) {
|
|
const BoLUtility = (await import("../../system/bol-utility.js")).BoLUtility
|
|
let chatData = foundry.utils.duplicate(this.document)
|
|
if (this.document.actor) {
|
|
chatData.actor = { id: this.document.actor.id }
|
|
}
|
|
BoLUtility.postItem(chatData)
|
|
}
|
|
|
|
// #endregion
|
|
}
|