@@ -23,6 +23,17 @@ export class CombatHUD extends Application {
23
23
this . _emptyImage = document . createElement ( 'img' ) ;
24
24
this . _emptyImage . src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ;
25
25
26
+ // Drag trackers
27
+ this . dragInitialX = 0 ;
28
+ this . dragInitialY = 0 ;
29
+ this . dragInitialTop = 0 ;
30
+ this . dragInitialLeft = 0 ;
31
+ this . firefoxDragX = 0 ;
32
+ this . firefoxDragY = 0 ;
33
+
34
+ // TODO: Move such browser checks to a higher scope
35
+ this . isFirefox = navigator . userAgent . toLowerCase ( ) . includes ( 'firefox' ) ;
36
+
26
37
console . debug ( `Combat HUD: Constructing` ) ;
27
38
Hooks . callAll ( 'combatHudInit' , this ) ;
28
39
this . #hooks. push ( { hook : 'createCombatant' , func : this . _onUpdateHUD . bind ( this ) } ) ;
@@ -193,10 +204,8 @@ export class CombatHUD extends Application {
193
204
actor : combatant . actor ,
194
205
token : combatant . token ,
195
206
effects : activeEffects ,
196
- img : game . settings . get ( SYSTEM , SETTINGS . optionCombatHudPortrait ) === 'token' ?
197
- // token._source should contain the most current version of the token's texture.
198
- combatant . token . _source . texture . src :
199
- combatant . actor . img ,
207
+ // token._source should contain the most current version of the token's texture.
208
+ img : game . settings . get ( SYSTEM , SETTINGS . optionCombatHudPortrait ) === 'token' ? combatant . token . _source . texture . src : combatant . actor . img ,
200
209
trackedResourcePart1 : trackedResourcePart1 ,
201
210
trackedResourcePart2 : trackedResourcePart2 ,
202
211
trackedResourcePart3 : trackedResourcePart3 ,
@@ -332,7 +341,7 @@ export class CombatHUD extends Application {
332
341
dragButton . on ( 'drag' , this . _doHudDrag . bind ( this ) ) ;
333
342
dragButton . on ( 'dragend' , this . _doHudDrop . bind ( this ) ) ;
334
343
335
- if ( navigator . userAgent . toLowerCase ( ) . includes ( 'firefox' ) ) {
344
+ if ( this . isFirefox ) {
336
345
$ ( window . document ) . on ( 'dragover' , this . _fireFoxDragWorkaround . bind ( this ) ) ;
337
346
}
338
347
@@ -356,32 +365,66 @@ export class CombatHUD extends Application {
356
365
357
366
_doHudDragStart ( event ) {
358
367
event . originalEvent . dataTransfer . setDragImage ( this . _emptyImage , 0 , 0 ) ;
368
+
369
+ // Set drag tracking vars
370
+ const nativeEvent = event . originalEvent ;
371
+ const elementPos = this . element . position ( ) ;
372
+ this . dragInitialLeft = elementPos . left ;
373
+ this . dragInitialTop = elementPos . top ;
374
+ this . dragInitialX = nativeEvent . clientX ;
375
+ this . dragInitialY = nativeEvent . clientY ;
376
+ this . firefoxDragX = 0 ;
377
+ this . firefoxDragY = 0 ;
359
378
}
360
379
380
+ // FireFox does not populate event.clientX or event.clientY
381
+ // during drag events. A workaround is to bind a seperate handler
382
+ // to the dragover event instead, which gets processed directly
383
+ // before any drag event and allows us to record the current drag position.
361
384
_fireFoxDragWorkaround ( event ) {
362
- // FireFox does not populate event.clientX or event.clientY
363
- // during drag events. A workaround is to bind a seperate handler
364
- // to the dragover event instead, which gets processed directly
365
- // before any drag event and allows us to record the current drag position.
366
- this . _dragX = event . clientX ;
367
- this . _dragY = event . clientY ;
385
+ // Keep this check; drag events can trigger with (0,0) when outside the window or target
386
+ // and they should be treated as invalid
387
+ if ( event . clientX <= 0 || event . clientY <= 0 ) return ;
388
+
389
+ // These need to be tracked separately
390
+ // The listener is listening to *any* drag on window, and may not be relevant to the combatHUD
391
+ // So the actual update should be deferred to _doHudDrag which is bound specifically to combatHUD
392
+ this . firefoxDragX = event . clientX ;
393
+ this . firefoxDragY = event . clientY ;
368
394
}
369
395
370
396
_doHudDrag ( event ) {
371
- let dragPosition ;
397
+ event . originalEvent . dataTransfer . dropEffect = 'move' ;
372
398
373
- if ( navigator . userAgent . toLowerCase ( ) . includes ( 'firefox' ) ) {
374
- // Workaround: FireFox doesn't populate event.<clientX/clientY> during drag events
375
- dragPosition = { x : this . _dragX , y : this . _dragY } ;
399
+ // Firefox doesn't handle drag events the same as other browsers
400
+ // We use the 'dragOver' event for that
401
+ let dragPosition ;
402
+ if ( this . isFirefox ) {
403
+ dragPosition = { x : this . firefoxDragX , y : this . firefoxDragY } ;
376
404
} else {
377
405
dragPosition = { x : event . clientX , y : event . clientY } ;
378
406
}
379
- event . originalEvent . dataTransfer . dropEffect = 'move' ;
380
407
381
- if ( this . _dragAnimationFrame ) cancelAnimationFrame ( this . _dragAnimationFrame ) ;
408
+ // Keep this check; drag events can trigger with (0,0) when outside the window or target
409
+ // and they should be treated as invalid
410
+ if ( dragPosition . x <= 0 || dragPosition . y <= 0 ) return ;
411
+
412
+ // Update
413
+ if ( this . _dragAnimationFrame ) {
414
+ cancelAnimationFrame ( this . _dragAnimationFrame ) ;
415
+ }
382
416
this . _dragAnimationFrame = requestAnimationFrame ( ( ) => {
383
- this . element . css ( 'left' , this . _dragOffsetX + dragPosition . x ) ;
384
- this . element . css ( 'top' , this . _dragOffsetY + dragPosition . y ) ;
417
+ // Calculate deltas
418
+ const deltaX = dragPosition . x - this . dragInitialX ;
419
+ const deltaY = dragPosition . y - this . dragInitialY ;
420
+
421
+ // Calculate final values
422
+ const newLeft = this . dragInitialLeft + deltaX ;
423
+ const newTop = this . dragInitialTop + deltaY ;
424
+
425
+ // Apply
426
+ this . element . css ( 'left' , newLeft ) ;
427
+ this . element . css ( 'top' , newTop ) ;
385
428
if ( this . element . css ( 'bottom' ) !== 'initial' ) {
386
429
this . element . css ( 'bottom' , 'initial' ) ;
387
430
}
@@ -395,7 +438,7 @@ export class CombatHUD extends Application {
395
438
396
439
const draggedPosition = {
397
440
x : offset . left ,
398
- y : positionFromTop ? offset . top : $ ( window ) . height ( ) - offset . top - height
441
+ y : positionFromTop ? offset . top : $ ( window ) . height ( ) - offset . top - height ,
399
442
} ;
400
443
game . settings . set ( SYSTEM , SETTINGS . optionCombatHudDraggedPosition , draggedPosition ) ;
401
444
}
@@ -739,33 +782,28 @@ export class CombatHUD extends Application {
739
782
740
783
_onUpdateToken ( token , changes ) {
741
784
// Is the updated token in the current combat?
742
- if ( ! game . combat ?. combatants . some ( c => c . token . uuid === token . uuid ) ) {
785
+ if ( ! game . combat ?. combatants . some ( ( c ) => c . token . uuid === token . uuid ) ) {
743
786
return ;
744
787
}
745
788
746
789
// Are any of the changes relevant to the Combat HUD?
747
790
if (
748
791
foundry . utils . hasProperty ( changes , 'name' ) ||
749
- foundry . utils . hasProperty ( changes , 'actorId' ) ||
750
- foundry . utils . hasProperty ( changes , 'disposition' ) ||
751
- (
752
- game . settings . get ( SYSTEM , 'optionCombatHudPortrait' ) === 'token' &&
753
- foundry . utils . hasProperty ( changes , 'texture.src' )
754
- )
792
+ foundry . utils . hasProperty ( changes , 'actorId' ) ||
793
+ foundry . utils . hasProperty ( changes , 'disposition' ) ||
794
+ ( game . settings . get ( SYSTEM , 'optionCombatHudPortrait' ) === 'token' && foundry . utils . hasProperty ( changes , 'texture.src' ) )
755
795
) {
756
796
this . _onUpdateHUD ( ) ;
757
797
}
758
798
}
759
799
760
800
_onUpdateActor ( actor , changes ) {
761
801
// Is the updated actor in the current combat?
762
- if ( ! game . combat ?. combatants . some ( c => c . actor . uuid === actor . uuid ) ) {
802
+ if ( ! game . combat ?. combatants . some ( ( c ) => c . actor . uuid === actor . uuid ) ) {
763
803
return ;
764
804
}
765
805
766
- const systemResources = [
767
- 'hp' , 'mp' , 'ip' , 'fp' , 'exp' , 'zenit'
768
- ] ;
806
+ const systemResources = [ 'hp' , 'mp' , 'ip' , 'fp' , 'exp' , 'zenit' ] ;
769
807
770
808
const trackedResources = [
771
809
game . settings . get ( SYSTEM , SETTINGS . optionCombatHudTrackedResource1 ) ,
@@ -775,10 +813,7 @@ export class CombatHUD extends Application {
775
813
] ;
776
814
777
815
// Are any of the changes relevant to the Combat HUD?
778
- if (
779
- trackedResources . filter ( r => systemResources . includes ( r ) )
780
- . some ( r => foundry . utils . hasProperty ( changes , `system.resources.${ r } ` ) )
781
- ) {
816
+ if ( trackedResources . filter ( ( r ) => systemResources . includes ( r ) ) . some ( ( r ) => foundry . utils . hasProperty ( changes , `system.resources.${ r } ` ) ) ) {
782
817
this . _onUpdateHUD ( ) ;
783
818
}
784
819
}
@@ -793,10 +828,7 @@ export class CombatHUD extends Application {
793
828
794
829
_onModifyItem ( item , changes ) {
795
830
// Is the item owned by an actor in the current combat?
796
- if (
797
- item . parent ?. documentName !== 'Actor' ||
798
- ! game . combat ?. combatants . some ( c => c . actor . uuid === item . parent . uuid )
799
- ) {
831
+ if ( item . parent ?. documentName !== 'Actor' || ! game . combat ?. combatants . some ( ( c ) => c . actor . uuid === item . parent . uuid ) ) {
800
832
return ;
801
833
}
802
834
@@ -809,20 +841,11 @@ export class CombatHUD extends Application {
809
841
810
842
// Are any of the changes relevant to the combat HUD?
811
843
if (
812
- trackedResources . includes ( 'zeropower' ) &&
813
- item . type === 'optionalFeature' &&
814
- (
815
- item . system . optionalType === 'projectfu.zeroPower' ) ||
816
- // The optionalType can theoretically change, so make sure to check for it.
817
- foundry . utils . hasProperty ( changes , 'system.optionalType'
818
- )
819
- &&
820
- (
844
+ ( trackedResources . includes ( 'zeropower' ) && item . type === 'optionalFeature' && item . system . optionalType === 'projectfu.zeroPower' ) ||
845
+ // The optionalType can theoretically change, so make sure to check for it.
846
+ ( foundry . utils . hasProperty ( changes , 'system.optionalType' ) &&
821
847
// Progress changes aren't relevant during create/delete hooks.
822
- ! changes ||
823
- foundry . utils . hasProperty ( changes , 'system.data.progress.current' ) ||
824
- foundry . utils . hasProperty ( changes , 'system.data.progress.max' )
825
- )
848
+ ( ! changes || foundry . utils . hasProperty ( changes , 'system.data.progress.current' ) || foundry . utils . hasProperty ( changes , 'system.data.progress.max' ) ) )
826
849
) {
827
850
this . _onUpdateHUD ( ) ;
828
851
}
@@ -831,17 +854,13 @@ export class CombatHUD extends Application {
831
854
_onModifyActiveEffect ( activeEffect , changes ) {
832
855
if (
833
856
// Is the active effect targeting an actor in the current combat?
834
- ! (
835
- activeEffect . target &&
836
- game . combat ?. combatants . some ( c => c . actor . uuid === activeEffect . target . uuid )
837
- )
838
- &&
857
+ ! ( activeEffect . target && game . combat ?. combatants . some ( ( c ) => c . actor . uuid === activeEffect . target . uuid ) ) &&
839
858
// Did the transfer property change on an effect on an item owned by an actor in the current combat?
840
859
! (
841
860
activeEffect . parent ?. documentName === 'Item' &&
842
861
activeEffect . parent . parent ?. documentName === 'Actor' &&
843
862
foundry . utils . hasProperty ( changes , 'transfer' ) &&
844
- game . combat ?. combatants . some ( c => c . actor . uuid === activeEffect . parent . parent . uuid )
863
+ game . combat ?. combatants . some ( ( c ) => c . actor . uuid === activeEffect . parent . parent . uuid )
845
864
)
846
865
) {
847
866
return ;
0 commit comments