Skip to content

Commit 497f643

Browse files
committed
FIX - Active effects applying changes multiple times
1 parent eac055c commit 497f643

1 file changed

Lines changed: 80 additions & 28 deletions

File tree

src/module/actor/ABFActorSheet.js

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default class ABFActorSheet extends ActorSheet {
3434
template: 'systems/animabf/templates/actor/actor-sheet.hbs',
3535
width: 1100,
3636
height: 850,
37-
submitOnChange: true,
37+
submitOnChange: false,
3838
viewPermission: CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER,
3939
tabs: [
4040
{
@@ -127,50 +127,110 @@ export default class ABFActorSheet extends ActorSheet {
127127
activateListeners(html) {
128128
super.activateListeners(html);
129129

130-
// Everything below here is only needed if the sheet is editable
131130
if (!this.options.editable) return;
132131

133132
this._activateBaseTypeContextMenu(html);
134133

135-
const handler = ev => this._onDragStart(ev);
134+
this._setupDebouncedSheetUpdates(html);
135+
136+
this._activateRollables(html);
137+
this._activateContractibleButtons(html);
138+
this._activateItemsDragAndContextMenus(html);
139+
this._activateDataOnClickHandlers(html);
140+
this._activateEffectControls(html);
141+
}
142+
143+
_activateBaseTypeContextMenu(html) {
144+
new ContextMenu(html, '.base-type-row', [
145+
{
146+
name: game.i18n.localize('contextualMenu.common.options.edit') ?? 'Edit…',
147+
icon: '<i class="fas fa-edit fa-fw"></i>',
148+
callback: target => this._openBaseTypeEditor(target[0])
149+
}
150+
]);
151+
}
152+
153+
_setupDebouncedSheetUpdates(html) {
154+
// Keep a flat object with pending updates: { "system.foo.bar": 123, ... }
155+
this._pendingUpdate = this._pendingUpdate ?? {};
156+
157+
// Debounced flush (single update per burst)
158+
this._flushPendingUpdate =
159+
this._flushPendingUpdate ??
160+
foundry.utils.debounce(async () => {
161+
const flat = this._pendingUpdate;
162+
this._pendingUpdate = {};
163+
164+
if (!flat || Object.keys(flat).length === 0) return;
165+
166+
const [actorChanges, itemChanges] = splitAsActorAndItemChanges(flat);
167+
168+
// Update items first (if any)
169+
await this.updateItems(itemChanges);
170+
171+
// Then update actor (if any)
172+
if (actorChanges && Object.keys(actorChanges).length > 0) {
173+
await this.actor.update(actorChanges);
174+
}
175+
}, 150);
176+
177+
// Listen to changes on any form control
178+
html.on('change', 'input, select, textarea', ev => {
179+
const el = ev.currentTarget;
180+
if (!el?.name) return;
181+
182+
let value;
183+
if (el.type === 'checkbox') value = el.checked;
184+
else value = el.value;
136185

137-
// Find all items on the character sheet.
186+
// Convert numbers
187+
if (el.type === 'number') value = Number(value);
138188

139-
// Rollable abilities.
140-
html.find('.rollable').click(e => {
141-
this._onRoll(e);
189+
// Accumulate changes using the input name as the update path
190+
// Example: "system.general.presence.base.value"
191+
this._pendingUpdate[el.name] = value;
192+
193+
this._flushPendingUpdate();
142194
});
195+
}
196+
197+
_activateRollables(html) {
198+
html.find('.rollable').click(e => this._onRoll(e));
199+
}
143200

201+
_activateContractibleButtons(html) {
144202
html.find('.contractible-button').click(e => {
145203
const { contractibleItemId } = e.currentTarget.dataset;
204+
if (!contractibleItemId) return;
146205

147-
if (contractibleItemId) {
148-
const ui = this.actor.system.ui;
149-
150-
ui.contractibleItems = {
151-
...ui.contractibleItems,
152-
[contractibleItemId]: !ui.contractibleItems[contractibleItemId]
153-
};
206+
const ui = this.actor.system.ui;
207+
ui.contractibleItems = {
208+
...ui.contractibleItems,
209+
[contractibleItemId]: !ui.contractibleItems[contractibleItemId]
210+
};
154211

155-
this.actor.update({ system: { ui } });
156-
}
212+
this.actor.update({ system: { ui } });
157213
});
214+
}
215+
216+
_activateItemsDragAndContextMenus(html) {
217+
const handler = ev => this._onDragStart(ev);
158218

159219
for (const item of Object.values(ALL_ITEM_CONFIGURATIONS)) {
160220
this.buildCommonContextualMenu(item);
161221

162222
html.find(item.selectors.rowSelector).each((_, row) => {
163-
// Add draggable attribute and dragstart listener.
164223
row.setAttribute('draggable', 'true');
165224
row.addEventListener('dragstart', handler, false);
166225
});
167226

168-
//Buttons cllback from hbs
169227
html.find(`[data-on-click="${item.selectors.addItemButtonSelector}"]`).click(() => {
170228
item.onCreate(this.actor);
171229
});
172230
}
231+
}
173232

233+
_activateDataOnClickHandlers(html) {
174234
const clickHandlers = createClickHandlers(this);
175235

176236
html.find('[data-on-click]').click(e => {
@@ -179,18 +239,10 @@ export default class ABFActorSheet extends ActorSheet {
179239
if (handler) handler(e);
180240
else console.warn(`No handler for data-on-click="${key}"`);
181241
});
182-
183-
html.find('.effect-control').click(this._onEffectControl.bind(this));
184242
}
185243

186-
_activateBaseTypeContextMenu(html) {
187-
new ContextMenu(html, '.base-type-row', [
188-
{
189-
name: game.i18n.localize('contextualMenu.common.options.edit') ?? 'Edit…',
190-
icon: '<i class="fas fa-edit fa-fw"></i>',
191-
callback: target => this._openBaseTypeEditor(target[0])
192-
}
193-
]);
244+
_activateEffectControls(html) {
245+
html.find('.effect-control').click(this._onEffectControl.bind(this));
194246
}
195247

196248
_openBaseTypeEditor(el) {

0 commit comments

Comments
 (0)