@@ -67,13 +67,56 @@ export default class ABFActorSheet extends ActorSheet {
6767 }
6868
6969 async close ( options = { } ) {
70- // Cancel any pending debounced update
71- this . _flushPendingUpdate ?. cancel ?. ( ) ;
72- this . _pendingUpdate = { } ;
70+ this . _isClosing = true ;
7371
74- await super . close ( { ...options , submit : false } ) ;
72+ try {
73+ await this . _flushPendingSheetUpdatesImmediately ( ) ;
7574
76- this . position . width = this . getWidthDependingFromContent ( ) ;
75+ // Capture image before close; persist it after close to avoid re-render race.
76+ const nextImg = this . _getEditedActorImage ( ) ;
77+
78+ await super . close ( {
79+ ...options ,
80+ // Avoid submitting the whole form on close: it can persist derived/AE-applied values.
81+ submit : options . submit ?? false
82+ } ) ;
83+
84+ await this . _persistActorImageIfChanged ( nextImg ) ;
85+
86+ this . position . width = this . getWidthDependingFromContent ( ) ;
87+ } finally {
88+ this . _isClosing = false ;
89+ }
90+ }
91+
92+ _getEditedActorImage ( ) {
93+ const imgEl = this . element ?. find ?. ( "[data-edit='img']" ) ?. [ 0 ] ;
94+ return imgEl ?. getAttribute ?. ( 'src' ) ?. trim ?. ( ) ?? '' ;
95+ }
96+
97+ async _persistActorImageIfChanged ( nextImg = '' ) {
98+ if ( ! this . options . editable ) return false ;
99+
100+ if ( ! nextImg || nextImg === this . actor . img ) return false ;
101+
102+ await this . actor . update ( { img : nextImg } ) ;
103+ await this . _refreshActorDirectoryImage ( nextImg ) ;
104+ return true ;
105+ }
106+
107+ async _refreshActorDirectoryImage ( nextImg ) {
108+ const actorDirectory = ui . actors ?? ui . sidebar ?. tabs ?. actors ?? null ;
109+
110+ actorDirectory ?. render ?. ( true ) ;
111+
112+ const selectors = [
113+ `[data-entry-id="${ this . actor . id } "] img` ,
114+ `[data-document-id="${ this . actor . id } "] img`
115+ ] ;
116+
117+ for ( const selector of selectors ) {
118+ actorDirectory ?. element ?. find ?. ( selector ) ?. attr ?. ( 'src' , nextImg ) ;
119+ }
77120 }
78121
79122 getWidthDependingFromContent ( ) {
@@ -85,6 +128,8 @@ export default class ABFActorSheet extends ActorSheet {
85128 }
86129
87130 async _render ( force , options = { } ) {
131+ if ( this . _isClosing ) return ;
132+
88133 // If user permission is exactly LIMITED, then display image popout and quit; else do normal render
89134 if ( force && this . actor . testUserPermission ( game . user , 'LIMITED' , { exact : true } ) ) {
90135 this . displayActorImagePopout ( ) ;
@@ -154,6 +199,27 @@ export default class ABFActorSheet extends ActorSheet {
154199 ] ) ;
155200 }
156201
202+ async _flushPendingSheetUpdatesImmediately ( ) {
203+ const flat = this . _pendingUpdate ;
204+
205+ this . _flushPendingUpdate ?. cancel ?. ( ) ;
206+ this . _pendingUpdate = { } ;
207+
208+ await this . _applyFlatChanges ( flat ) ;
209+ }
210+
211+ async _applyFlatChanges ( flat ) {
212+ if ( ! flat || Object . keys ( flat ) . length === 0 ) return ;
213+
214+ const [ actorChanges , itemChanges ] = splitAsActorAndItemChanges ( flat ) ;
215+
216+ await this . updateItems ( itemChanges ) ;
217+
218+ if ( actorChanges && Object . keys ( actorChanges ) . length > 0 ) {
219+ await this . actor . update ( actorChanges ) ;
220+ }
221+ }
222+
157223 _setupDebouncedSheetUpdates ( html ) {
158224 this . _pendingUpdate = { } ;
159225
@@ -164,15 +230,7 @@ export default class ABFActorSheet extends ActorSheet {
164230 const flat = this . _pendingUpdate ;
165231 this . _pendingUpdate = { } ;
166232
167- if ( ! flat || Object . keys ( flat ) . length === 0 ) return ;
168-
169- const [ actorChanges , itemChanges ] = splitAsActorAndItemChanges ( flat ) ;
170-
171- await this . updateItems ( itemChanges ) ;
172-
173- if ( actorChanges && Object . keys ( actorChanges ) . length > 0 ) {
174- await this . actor . update ( actorChanges ) ;
175- }
233+ await this . _applyFlatChanges ( flat ) ;
176234 } , 150 ) ;
177235
178236 // IMPORTANT: remove previous handlers for this sheet instance
0 commit comments