Get items appearing on the sheet, still a lot to do but this is a strong step in the right direction

This commit is contained in:
Oliver 2026-03-15 22:37:55 -06:00
parent 6b03d62234
commit 23a402f11a
9 changed files with 254 additions and 10 deletions

View file

@ -2,10 +2,12 @@ import { __ID__, filePath } from "../consts.mjs";
import { AttributeManager } from "./AttributeManager.mjs";
import { attributeSorter } from "../utils/attributeSort.mjs";
import { TAFDocumentSheetConfig } from "./TAFDocumentSheetConfig.mjs";
import { toPrecision } from "../utils/roundToPrecision.mjs";
const { HandlebarsApplicationMixin } = foundry.applications.api;
const { ActorSheetV2 } = foundry.applications.sheets;
const { getProperty, hasProperty } = foundry.utils;
const { TextEditor } = foundry.applications.ux;
const propertyToParts = {
"name": [`header`],
@ -39,6 +41,7 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
actions: {
manageAttributes: this.#manageAttributes,
configureSheet: this.#configureSheet,
toggleExpand: this.#toggleExpand,
},
};
@ -68,6 +71,15 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
};
// #endregion Options
// #region Instance Data
/**
* This Set is used to keep track of which items have had their full
* details expanded so that it can be persisted across rerenders as
* they occur.
*/
#expandedItems = new Set();
// #endregion Instance Data
// #region Lifecycle
_initializeApplicationOptions(options) {
const sizing = getProperty(options.document, `flags.${__ID__}.PlayerSheet.size`) ?? {};
@ -203,24 +215,73 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
ctx.toggled = true;
ctx.tabActive = this.tabGroups.primary === `content` || this.actor.items.size === 0;
const TextEditor = foundry.applications.ux.TextEditor.implementation;
ctx.enriched = {
system: {
content: await TextEditor.enrichHTML(this.actor.system.content),
content: await TextEditor.implementation.enrichHTML(this.actor.system.content),
},
};
};
async _prepareItems(ctx) {
ctx.tabActive = this.tabGroups.primary === `items`;
const weightUnit = game.settings.get(__ID__, `weightUnit`);
let totalWeight = 0;
ctx.itemGroups = [];
for (const [groupName, items] of Object.entries(this.actor.itemTypes)) {
const preparedItems = [];
let summedWeight = 0;
for (const item of items) {
summedWeight += item.system.quantifiedWeight;
preparedItems.push(await this._prepareItem(item));
};
totalWeight += summedWeight;
ctx.itemGroups.push({
name: groupName.titleCase(),
items: preparedItems,
weight: toPrecision(summedWeight, 2) + weightUnit,
});
};
ctx.totalWeight = toPrecision(totalWeight, 2) + weightUnit;
};
async _prepareItem(item) {};
async _prepareItem(item) {
const weightUnit = game.settings.get(__ID__, `weightUnit`)
const ctx = {
uuid: item.uuid,
img: item.img,
name: item.name,
equipped: item.system.equipped,
quantity: item.system.quantity,
weight: item.system.quantifiedWeight + weightUnit,
isExpanded: this.#expandedItems.has(item.uuid),
canExpand: item.system.description.length > 0,
};
ctx.description = ``;
if (item.system.description.length > 0) {
ctx.description = await TextEditor.implementation.enrichHTML(item.system.description);
};
return ctx;
};
// #endregion Data Prep
// #region Actions
#attributeManager = null;
/** @this {PlayerSheet} */
/**
* This action opens an instance of the AttributeManager application
* so that the user can edit and update all of the attributes for the
* actor. This persists the application instance for the duration of
* the ActorSheet's lifespan.
*
* @this {PlayerSheet}
*/
static async #manageAttributes() {
this.#attributeManager ??= new AttributeManager({ document: this.actor });
if (this.#attributeManager.rendered) {
@ -233,6 +294,13 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
};
};
/**
* This action overrides the default Foundry action in order to tell
* it to open my custom DocumentSheetConfig application instead of
* opening the non-customized sheet config app.
*
* @this {PlayerSheet}
*/
static async #configureSheet(event) {
event.stopPropagation();
if ( event.detail > 1 ) { return }
@ -248,5 +316,27 @@ export class PlayerSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
window: { windowId: this.window.windowId },
});
};
/**
* This action is used by the item lists in order to expand/collapse
* the descriptions while maintaining that state across renders.
*
* @this {PlayerSheet}
*/
static async #toggleExpand(event, target) {
if (event.srcElement instanceof HTMLInputElement) { return };
const { itemUuid } = target.closest(`[data-item-uuid]`)?.dataset ?? {};
if (!itemUuid) { return };
const expanded = this.#expandedItems.has(itemUuid);
if (expanded) {
this.#expandedItems.delete(itemUuid);
target.nextElementSibling.dataset.expanded = false;
} else {
this.#expandedItems.add(itemUuid);
target.nextElementSibling.dataset.expanded = true;
}
};
// #endregion Actions
};

View file

@ -1,3 +1,5 @@
import { toPrecision } from "../../utils/roundToPrecision.mjs";
export class GenericItemData extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
@ -28,4 +30,12 @@ export class GenericItemData extends foundry.abstract.TypeDataModel {
}),
};
};
/**
* Calculates the total weight of the item based on the quantity of it, this
* rounds the number to the nearest 2 decimal places.
*/
get quantifiedWeight() {
return toPrecision(this.weight * this.quantity, 2);
};
};

View file

@ -13,6 +13,15 @@ export function registerWorldSettings() {
scope: `world`,
});
game.settings.register(__ID__, `weightUnit`, {
name: `taf.settings.weightUnit.name`,
hint: `taf.settings.weightUnit.hint`,
config: true,
type: String,
default: ``,
scope: `world`,
});
game.settings.register(__ID__, `canPlayersManageAttributes`, {
name: `taf.settings.canPlayersManageAttributes.name`,
hint: `taf.settings.canPlayersManageAttributes.hint`,

View file

@ -0,0 +1,20 @@
/**
* Takes a possibly-decimal value and rounds after a certain precision, keeping
* only the specified amount of decimals.
*
* @param {number} value The value that is to be rounded.
* @param {number} precision The number of decimal places to round to. Must be a
* positive integer.
* @returns The rounded number
*/
export function toPrecision(value, precision = 1) {
if (!Number.isInteger(precision)) {
throw `Precision must be an integer`;
};
if (precision < 0) {
throw `Precision must be greater than or equal to 0`;
};
const m = 10 ** precision;
return Math.round(value * m) / m;
};