@@ -2946,4 +2946,119 @@ suite('Blocks', function () {
29462946 ) ;
29472947 } ) ;
29482948 } ) ;
2949+
2950+ suite ( 'Disposal focus management' , function ( ) {
2951+ setup ( function ( ) {
2952+ this . workspace = Blockly . inject ( 'blocklyDiv' ) ;
2953+ const firstBlock = this . workspace . newBlock ( 'stack_block' ) ;
2954+ firstBlock . moveBy ( - 500 , - 500 ) ;
2955+ } ) ;
2956+
2957+ test ( 'Deleting the sole block on the workspace focuses the workspace' , function ( ) {
2958+ const block = this . workspace . getTopBlocks ( false ) [ 0 ] ;
2959+ Blockly . getFocusManager ( ) . focusNode ( block ) ;
2960+ block . dispose ( ) ;
2961+ this . clock . runAll ( ) ;
2962+
2963+ assert . strictEqual (
2964+ Blockly . getFocusManager ( ) . getFocusedNode ( ) ,
2965+ this . workspace ,
2966+ 'Focus should move to the workspace when the focused block is deleted' ,
2967+ ) ;
2968+ } ) ;
2969+
2970+ test ( 'Deleting a block with several adjacent blocks focuses the closest one' , function ( ) {
2971+ this . workspace . newBlock ( 'stack_block' ) ;
2972+ const blockMiddle = this . workspace . newBlock ( 'stack_block' ) ;
2973+ const blockRight = this . workspace . newBlock ( 'stack_block' ) ;
2974+ blockMiddle . moveBy ( 60 , 0 ) ;
2975+ blockRight . moveBy ( 100 , 0 ) ;
2976+
2977+ Blockly . getFocusManager ( ) . focusNode ( blockMiddle ) ;
2978+ blockMiddle . dispose ( ) ;
2979+ this . clock . runAll ( ) ;
2980+
2981+ const focused = Blockly . getFocusManager ( ) . getFocusedNode ( ) ;
2982+ assert . strictEqual (
2983+ focused ,
2984+ blockRight ,
2985+ 'Focus should move to the closest remaining block (blockRight at (100, 0))' ,
2986+ ) ;
2987+ } ) ;
2988+
2989+ test ( 'Bulk deleting blocks does not focus another dying block' , function ( ) {
2990+ const blocks = this . workspace . getTopBlocks ( false ) ;
2991+ for ( let i = 0 ; i < 5 ; i ++ ) {
2992+ blocks . push ( this . workspace . newBlock ( 'stack_block' ) ) ;
2993+ }
2994+
2995+ // Focus the last block we added; clearing the workspace proceeds in block
2996+ // creation order, so if we focused an earlier block, it would (correctly)
2997+ // assign focus to a later-added block which is not yet dying, on down the
2998+ // chain. If we focus the last block, by the time deletion gets to it, all
2999+ // the other blocks will have already been marked as disposing, and should
3000+ // thus be ineligible to be focused.
3001+ Blockly . getFocusManager ( ) . focusNode (
3002+ this . workspace . getTopBlocks ( false ) [ 5 ] ,
3003+ ) ;
3004+
3005+ const spy = sinon . spy ( Blockly . getFocusManager ( ) , 'focusNode' ) ;
3006+
3007+ this . workspace . clear ( ) ;
3008+ this . clock . runAll ( ) ;
3009+
3010+ for ( const block of blocks ) {
3011+ assert . isFalse ( spy . calledWith ( block ) ) ;
3012+ }
3013+ assert . strictEqual (
3014+ Blockly . getFocusManager ( ) . getFocusedNode ( ) ,
3015+ this . workspace ,
3016+ 'Focus should move to the workspace, not a dying peer block' ,
3017+ ) ;
3018+
3019+ spy . restore ( ) ;
3020+ } ) ;
3021+
3022+ test ( 'Deleting a block focuses its parent block' , function ( ) {
3023+ const parent = this . workspace . newBlock ( 'stack_block' ) ;
3024+ const child = this . workspace . newBlock ( 'stack_block' ) ;
3025+ parent . nextConnection . connect ( child . previousConnection ) ;
3026+
3027+ Blockly . getFocusManager ( ) . focusNode ( child ) ;
3028+ child . dispose ( ) ;
3029+ this . clock . runAll ( ) ;
3030+
3031+ assert . strictEqual (
3032+ Blockly . getFocusManager ( ) . getFocusedNode ( ) ,
3033+ parent ,
3034+ 'Focus should move to the parent block when a connected child is deleted' ,
3035+ ) ;
3036+ } ) ;
3037+
3038+ test ( 'Deleting an unfocused block does not change focus' , function ( ) {
3039+ const a = this . workspace . getTopBlocks ( false ) [ 0 ] ;
3040+ const b = this . workspace . newBlock ( 'stack_block' ) ;
3041+ this . workspace . newBlock ( 'stack_block' ) ;
3042+
3043+ Blockly . getFocusManager ( ) . focusNode ( a ) ;
3044+ b . dispose ( ) ;
3045+ this . clock . runAll ( ) ;
3046+
3047+ assert . strictEqual (
3048+ Blockly . getFocusManager ( ) . getFocusedNode ( ) ,
3049+ a ,
3050+ 'Focus should not change when an unfocused block is deleted' ,
3051+ ) ;
3052+ } ) ;
3053+
3054+ test ( 'Disposing a workspace with a focused block succeeds' , function ( ) {
3055+ Blockly . getFocusManager ( ) . focusNode (
3056+ this . workspace . getTopBlocks ( false ) [ 0 ] ,
3057+ ) ;
3058+ this . workspace . dispose ( ) ;
3059+ this . clock . runAll ( ) ;
3060+
3061+ // No assert, this just shouldn't throw.
3062+ } ) ;
3063+ } ) ;
29493064} ) ;
0 commit comments