Files
fvtt-oath-hammer/module/applications/sheets/base-item-sheet.mjs

162 lines
4.9 KiB
JavaScript

const { HandlebarsApplicationMixin } = foundry.applications.api
import { ARMOR_TYPE_CHOICES, WEAPON_PROFICIENCY_GROUPS } from "../../config/system.mjs"
import { rollRarityCheck } from "../../rolls.mjs"
export default class OathHammerItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["oathhammer", "item"],
position: {
width: 600,
height: "auto",
},
form: {
submitOnChange: true,
},
window: {
resizable: true,
},
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
actions: {
toggleSheet: OathHammerItemSheet.#onToggleSheet,
editImage: OathHammerItemSheet.#onEditImage,
rollRarity: OathHammerItemSheet.#onRollRarity,
},
}
_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
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.fields = this.document.schema.fields
context.systemFields = this.document.system.schema.fields
context.item = this.document
context.system = this.document.system
context.source = this.document.toObject()
context.isEditMode = this.isEditMode
context.isPlayMode = this.isPlayMode
context.isEditable = this.isEditable
if (this.document.system.description !== undefined) {
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description ?? "", { async: true })
}
// Armor-specific numeric selects
context.armorValueChoices = Object.fromEntries(
Array.from({ length: 13 }, (_, i) => [i, String(i)])
)
context.penaltyChoices = Object.fromEntries(
Array.from({ length: 6 }, (_, i) => [-i, String(-i)])
)
// Weapon-specific numeric selects
context.damageModChoices = Object.fromEntries(
Array.from({ length: 10 }, (_, i) => [i - 4, i - 4 >= 0 ? `+${i - 4}` : String(i - 4)])
)
context.apChoices = Object.fromEntries(
Array.from({ length: 7 }, (_, i) => [i, String(i)])
)
// Class proficiency choices (for class-sheet checkboxes)
context.armorTypeChoices = ARMOR_TYPE_CHOICES
context.weaponGroupChoices = WEAPON_PROFICIENCY_GROUPS
return context
}
/** @override */
_onRender(context, options) {
super._onRender(context, options)
this.#dragDrop.forEach((d) => d.bind(this.element))
for (const pm of this.element.querySelectorAll("prose-mirror[name]")) {
pm.addEventListener("change", async (event) => {
event.stopPropagation()
await this.document.update({ [pm.name]: pm.value ?? "" })
})
}
}
#createDragDropHandlers() {
return this.options.dragDrop.map((d) => {
d.permissions = {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
}
d.callbacks = {
dragstart: this._onDragStart.bind(this),
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this),
}
return new foundry.applications.ux.DragDrop.implementation(d)
})
}
_canDragStart(selector) {
return this.isEditable
}
_canDragDrop(selector) {
return this.isEditable && this.document.isOwner
}
_onDragStart(event) {
if ("link" in event.target.dataset) return
}
_onDragOver(event) {}
async _onDrop(event) {}
static #onToggleSheet(event, target) {
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
const current = foundry.utils.getProperty(this.document, attr)
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
const fp = new FilePicker({
current,
type: "image",
redirectToRoot: img ? [img] : [],
callback: (path) => {
this.document.update({ [attr]: path })
},
top: this.position.top + 40,
left: this.position.left + 10,
})
return fp.browse()
}
static async #onRollRarity(event, target) {
const rarity = this.document.system.rarity
if (!rarity) return
// Find the owning actor (embedded item) or prompt user to select a character
let actor = this.document.parent
if (!actor || actor.documentName !== "Actor") {
// Item not embedded — use the user's selected character
actor = game.user.character
if (!actor) {
ui.notifications.warn(game.i18n.localize("OATHHAMMER.Roll.NoActor"))
return
}
}
await rollRarityCheck(actor, rarity, this.document.name)
}
}