@@ -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