Add saving and editing of default attributes and their values (closes #29)

This commit is contained in:
Oliver 2026-03-02 21:48:59 -07:00
parent 5159db3d33
commit d540cc72f6
6 changed files with 178 additions and 34 deletions

View file

@ -1,5 +1,6 @@
import { __ID__, filePath } from "../consts.mjs";
import { attributeSorter } from "../utils/attributeSort.mjs";
import { ask } from "../utils/DialogManager.mjs";
import { localizer } from "../utils/localizer.mjs";
import { toID } from "../utils/toID.mjs";
@ -22,6 +23,14 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
},
window: {
resizable: true,
controls: [
{
icon: `fa-solid fa-globe`,
label: `Save As Defaults`,
visible: () => game.user.isGM,
action: `saveAsDefault`,
}
],
},
form: {
submitOnChange: false,
@ -31,6 +40,7 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
actions: {
addNew: this.#addNew,
removeAttribute: this.#remove,
saveAsDefault: this.#saveAsDefaults,
},
};
@ -73,16 +83,39 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
new DragDrop.implementation({
dragSelector: `.attribute-drag-handle`,
dropSelector: `.attributes`,
permissions: {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
},
callbacks: {
dragstart: this._onDragStart.bind(this),
drop: this._onDrop.bind(this),
},
}).bind(this.element);
};
/** @this {AttributeManager} */
static async #onSubmit() {
const entries = Object.entries(this.#attributes)
.map(([id, attr]) => {
if (attr == null) {
return [ id, attr ];
};
if (attr.isNew) {
delete attr.isNew;
return [ toID(attr.name), attr ];
};
return [ id, attr ];
});
const data = Object.fromEntries(entries);
this.#attributes = data;
const diff = diffObject(
this.#doc.system.attr,
data,
{ inner: false, deletionKeys: true },
);
await this.#doc.update({ "system.attr": diff });
};
// #endregion Lifecycle
// #region Data Prep
@ -152,48 +185,87 @@ export class AttributeManager extends HandlebarsApplicationMixin(ApplicationV2)
static async #remove($e, element) {
const attribute = element.closest(`[data-attribute]`)?.dataset.attribute;
if (!attribute) { return };
delete this.#attributes[attribute];
this.#attributes[`-=${attribute}`] = null;
if (game.release.generation < 14) {
delete this.#attributes[attribute];
this.#attributes[`-=${attribute}`] = null;
}
else {
this.#attributes[attribute] = _del;
}
await this.render({ parts: [ `attributes` ] });
};
/** @this {AttributeManager} */
static async #onSubmit() {
const entries = Object.entries(this.#attributes)
.map(([id, attr]) => {
if (attr == null) {
return [ id, attr ];
};
static async #saveAsDefaults() {
const attrs = deepClone(this.#attributes);
if (attr.isNew) {
delete attr.isNew;
return [ toID(attr.name), attr ];
};
// Prompt the user for what values they want to save the attributes with
const inputs = [];
for (const attr of Object.values(attrs)) {
const id = toID(attr.name);
return [ id, attr ];
if (attr.isRange) {
inputs.push(
{
type: `collapse`,
summary: attr.name,
inputs: [
{
key: `${id}.value`,
type: `input`,
inputType: `number`,
label: `Value`,
defaultValue: attr.value,
},
{
key: `${id}.max`,
type: `input`,
inputType: `number`,
label: `Maximum`,
defaultValue: attr.max,
},
],
},
{ type: `divider` }
);
continue;
};
inputs.push({
key: `${id}.value`,
type: `input`,
inputType: `number`,
label: `${attr.name}`,
defaultValue: attr.value,
});
const data = Object.fromEntries(entries);
this.#attributes = data;
const diff = diffObject(
this.#doc.system.attr,
data,
{ inner: false, deletionKeys: true },
);
inputs.push({ type: `divider` });
};
await this.#doc.update({ "system.attr": diff });
const prompt = {
id: `${this.#doc.id}-global-attr-saving`,
inputs: inputs.slice(0, -1),
alwaysUseAnswerObject: true,
window: { title: `taf.Apps.AttributeManager.default-attribute-values` },
};
const response = await ask(prompt);
switch (response.state) {
case `errored`:
ui.notifications.error(response.error);
case `fronted`:
return;
};
if (!response.answers) { return };
const fullAttrs = mergeObject(attrs, response.answers);
game.settings.set(__ID__, `actorDefaultAttributes`, fullAttrs);
ui.notifications.success(`taf.notifs.success.saved-default-attributes`);
};
// #endregion Actions
// #region Drag & Drop
_canDragStart() {
return this.#doc.isOwner;
};
_canDragDrop() {
return this.#doc.isOwner;
};
_onDragStart(event) {
const target = event.currentTarget.closest(`[data-attribute]`);
if (`link` in event.target.dataset) { return };