Skip to content

Commit 085e0c8

Browse files
committed
cleanup-persistent-damage-editor-lifecycle
1 parent 2366486 commit 085e0c8

1 file changed

Lines changed: 50 additions & 34 deletions

File tree

src/module/item/condition/persistent-damage-editor.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
import type { ActorPF2e } from "@actor";
2-
import type { ApplicationConfiguration } from "@client/applications/_module.d.mts";
32
import { DamageRoll } from "@system/damage/roll.ts";
43
import type { DamageType } from "@system/damage/types.ts";
54
import { htmlClosest, htmlQuery } from "@util";
65
import * as R from "remeda";
76
import type { PersistentDamagePF2e } from "./document.ts";
87

9-
class PersistentDamageEditor extends fa.api.HandlebarsApplicationMixin(fa.api.ApplicationV2) {
10-
static override DEFAULT_OPTIONS: DeepPartial<fa.ApplicationConfiguration> = {
8+
interface PersistentDamageEditorConfiguration extends fa.ApplicationConfiguration {
9+
actor: ActorPF2e;
10+
selectedItemId: string | null;
11+
}
12+
13+
class PersistentDamageEditor extends fa.api.HandlebarsApplicationMixin<
14+
AbstractConstructorOf<fa.api.ApplicationV2> & {
15+
DEFAULT_OPTIONS: DeepPartial<PersistentDamageEditorConfiguration>;
16+
}
17+
>(fa.api.ApplicationV2) {
18+
static override DEFAULT_OPTIONS: DeepPartial<PersistentDamageEditorConfiguration> = {
1119
classes: ["persistent-damage-editor"],
1220
tag: "form",
1321
window: { icon: "fa-solid fa-droplet", contentClasses: ["standard-form"] },
1422
position: { width: 420 },
23+
selectedItemId: null,
1524
actions: {
1625
add: PersistentDamageEditor.#onClickAdd,
1726
delete: PersistentDamageEditor.#onClickDelete,
@@ -26,50 +35,62 @@ class PersistentDamageEditor extends fa.api.HandlebarsApplicationMixin(fa.api.Ap
2635
},
2736
};
2837

29-
actor: ActorPF2e;
38+
declare options: PersistentDamageEditorConfiguration;
3039

31-
selectedItemId: string | null;
40+
get #actor(): ActorPF2e {
41+
return this.options.actor;
42+
}
43+
44+
get #selectedItemId(): string | null {
45+
return this.options.selectedItemId;
46+
}
3247

33-
constructor(options: DeepPartial<ApplicationConfiguration> & PersistentDamageDialogOptions) {
34-
options.uniqueId = `persistent-damage-editor-${options.actor.uuid.replaceAll(".", "-")}`;
35-
super(options);
36-
this.actor = options.actor;
37-
this.selectedItemId = options.selectedItemId ?? null;
38-
this.actor.apps[this.id] = this;
48+
protected override _initializeApplicationOptions(
49+
options: Partial<PersistentDamageEditorConfiguration>,
50+
): PersistentDamageEditorConfiguration {
51+
const initialized = super._initializeApplicationOptions(options) as PersistentDamageEditorConfiguration;
52+
initialized.uniqueId = `persistent-damage-editor-${initialized.actor.uuid}`;
53+
return initialized;
3954
}
4055

41-
/** Override to guarantee one persistent damage dialog per actor */
42-
override get id(): string {
43-
return `persistent-damage-${this.actor.id}`;
56+
protected override async _onFirstRender(
57+
context: PersistentDialogContext,
58+
options: fa.ApplicationRenderOptions,
59+
): Promise<void> {
60+
await super._onFirstRender(context, options);
61+
this.#actor.apps[this.id] = this;
62+
}
63+
64+
protected override _tearDown(options: fa.ApplicationClosingOptions): void {
65+
delete this.#actor.apps[this.id];
66+
super._tearDown(options);
4467
}
4568

4669
override get title(): string {
47-
return _loc("PF2E.Item.Condition.PersistentDamage.Dialog.Title", { actor: this.actor.name });
70+
return _loc("PF2E.Item.Condition.PersistentDamage.Dialog.Title", { actor: this.#actor.name });
4871
}
4972

5073
protected override async _prepareContext(): Promise<PersistentDialogContext> {
51-
const existing = this.actor.itemTypes.condition
74+
const existing = this.#actor.itemTypes.condition
5275
.filter((c): c is PersistentDamagePF2e<ActorPF2e> => c.slug === "persistent-damage")
5376
.map((c) => ({
5477
id: c.id,
5578
active: c.active,
5679
...R.pick(c.system.persistent, ["formula", "damageType", "dc"]),
5780
}));
5881

82+
const damageTypeLabels = CONFIG.PF2E.damageTypes;
83+
const damageTypes = R.keys(damageTypeLabels)
84+
.map((type) => ({ type, label: _loc(damageTypeLabels[type] ?? type) }))
85+
.sort((a, b) => a.label.localeCompare(b.label));
86+
5987
return {
60-
selectedItemId: this.selectedItemId,
88+
selectedItemId: this.#selectedItemId,
6189
existing,
62-
damageTypes: this.#prepareDamageTypes(),
90+
damageTypes,
6391
};
6492
}
6593

66-
#prepareDamageTypes(): DamageTypeData[] {
67-
const labels = CONFIG.PF2E.damageTypes;
68-
return R.keys(labels)
69-
.map((type) => ({ type, label: _loc(labels[type] ?? type) }))
70-
.sort((a, b) => a.label.localeCompare(b.label));
71-
}
72-
7394
/** Determine whether an inputted formula is valid, reporting to the user if not. */
7495
#reportFormulaValidity(formula: string, input: HTMLInputElement | null): boolean {
7596
if (!input) return false;
@@ -101,7 +122,7 @@ class PersistentDamageEditor extends fa.api.HandlebarsApplicationMixin(fa.api.Ap
101122
const section = htmlClosest(event.target, "[data-id]");
102123
if (!section) return;
103124
const id = section.dataset.id;
104-
const existing = this.actor.items.get(id, { strict: true });
125+
const existing = this.#actor.items.get(id, { strict: true });
105126
const elements = this.#getInputElements(section);
106127
const formula = elements.formula?.value.trim() ?? "";
107128
const damageType = elements.damageType?.value;
@@ -125,27 +146,22 @@ class PersistentDamageEditor extends fa.api.HandlebarsApplicationMixin(fa.api.Ap
125146
const persistentSource = fu.mergeObject(baseConditionSource, {
126147
system: { persistent: { formula, damageType, dc } },
127148
});
128-
await this.actor.createEmbeddedDocuments("Item", [persistentSource]);
149+
await this.#actor.createEmbeddedDocuments("Item", [persistentSource]);
129150
}
130151
}
131152

132153
static async #onClickDelete(this: PersistentDamageEditor, event: PointerEvent): Promise<void> {
133154
const existingId = htmlClosest(event.target, "[data-id]")?.dataset.id;
134-
const existing = this.actor.items.get(existingId, { strict: true });
155+
const existing = this.#actor.items.get(existingId, { strict: true });
135156
await existing.delete();
136157
}
137158

138159
static async #onClickRoll(this: PersistentDamageEditor): Promise<void> {
139-
const existing = this.actor.itemTypes.condition.filter((c) => c.slug === "persistent-damage");
160+
const existing = this.#actor.itemTypes.condition.filter((c) => c.slug === "persistent-damage");
140161
await Promise.all(existing.map((c) => c.onEndTurn()));
141162
}
142163
}
143164

144-
interface PersistentDamageDialogOptions {
145-
actor: ActorPF2e;
146-
selectedItemId?: string;
147-
}
148-
149165
interface PersistentDialogContext extends fa.ApplicationRenderContext {
150166
selectedItemId: string | null;
151167
existing: DamageEntryData[];

0 commit comments

Comments
 (0)