@@ -54,6 +54,23 @@ function mapBlockOrder( blocks, rootClientId = '' ) {
54
54
return result ;
55
55
}
56
56
57
+ /**
58
+ * Given an array of blocks, returns an object where each key contains
59
+ * the clientId of the block and the value is the parent of the block.
60
+ *
61
+ * @param {Array } blocks Blocks to map.
62
+ * @param {?string } rootClientId Assumed root client ID.
63
+ *
64
+ * @return {Object } Block order map object.
65
+ */
66
+ function mapBlockParents ( blocks , rootClientId = '' ) {
67
+ return blocks . reduce ( ( result , block ) => Object . assign (
68
+ result ,
69
+ { [ block . clientId ] : rootClientId } ,
70
+ mapBlockParents ( block . innerBlocks , block . clientId )
71
+ ) , { } ) ;
72
+ }
73
+
57
74
/**
58
75
* Helper method to iterate through all blocks, recursing into inner blocks,
59
76
* applying a transformation function to each one.
@@ -264,16 +281,40 @@ function withIgnoredBlockChange( reducer ) {
264
281
* @return {Function } Enhanced reducer function.
265
282
*/
266
283
const withInnerBlocksRemoveCascade = ( reducer ) => ( state , action ) => {
267
- if ( state && action . type === 'REMOVE_BLOCKS' ) {
268
- const clientIds = [ ...action . clientIds ] ;
284
+ const getAllChildren = ( clientIds ) => {
285
+ let result = clientIds ;
286
+ for ( let i = 0 ; i < result . length ; i ++ ) {
287
+ if ( ! state . order [ result [ i ] ] ) {
288
+ continue ;
289
+ }
269
290
270
- // For each removed client ID, include its inner blocks to remove,
271
- // recursing into those so long as inner blocks exist.
272
- for ( let i = 0 ; i < clientIds . length ; i ++ ) {
273
- clientIds . push ( ...state . order [ clientIds [ i ] ] ) ;
291
+ if ( result === clientIds ) {
292
+ result = [ ...result ] ;
293
+ }
294
+
295
+ result . push ( ...state . order [ result [ i ] ] ) ;
274
296
}
275
297
276
- action = { ...action , clientIds } ;
298
+ return result ;
299
+ } ;
300
+
301
+ if ( state ) {
302
+ switch ( action . type ) {
303
+ case 'REMOVE_BLOCKS' :
304
+ action = {
305
+ ...action ,
306
+ type : 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN' ,
307
+ removedClientIds : getAllChildren ( action . clientIds ) ,
308
+ } ;
309
+ break ;
310
+ case 'REPLACE_BLOCKS' :
311
+ action = {
312
+ ...action ,
313
+ type : 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN' ,
314
+ replacedClientIds : getAllChildren ( action . clientIds ) ,
315
+ } ;
316
+ break ;
317
+ }
277
318
}
278
319
279
320
return reducer ( state , action ) ;
@@ -306,6 +347,10 @@ const withBlockReset = ( reducer ) => ( state, action ) => {
306
347
...omit ( state . order , visibleClientIds ) ,
307
348
...mapBlockOrder ( action . blocks ) ,
308
349
} ,
350
+ parents : {
351
+ ...omit ( state . parents , visibleClientIds ) ,
352
+ ...mapBlockParents ( action . blocks ) ,
353
+ } ,
309
354
} ;
310
355
}
311
356
@@ -435,18 +480,18 @@ export const blocks = flow(
435
480
...getFlattenedBlocksWithoutAttributes ( action . blocks ) ,
436
481
} ;
437
482
438
- case 'REPLACE_BLOCKS ' :
483
+ case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN ' :
439
484
if ( ! action . blocks ) {
440
485
return state ;
441
486
}
442
487
443
488
return {
444
- ...omit ( state , action . clientIds ) ,
489
+ ...omit ( state , action . replacedClientIds ) ,
445
490
...getFlattenedBlocksWithoutAttributes ( action . blocks ) ,
446
491
} ;
447
492
448
- case 'REMOVE_BLOCKS ' :
449
- return omit ( state , action . clientIds ) ;
493
+ case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN ' :
494
+ return omit ( state , action . removedClientIds ) ;
450
495
}
451
496
452
497
return state ;
@@ -511,18 +556,18 @@ export const blocks = flow(
511
556
...getFlattenedBlockAttributes ( action . blocks ) ,
512
557
} ;
513
558
514
- case 'REPLACE_BLOCKS ' :
559
+ case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN ' :
515
560
if ( ! action . blocks ) {
516
561
return state ;
517
562
}
518
563
519
564
return {
520
- ...omit ( state , action . clientIds ) ,
565
+ ...omit ( state , action . replacedClientIds ) ,
521
566
...getFlattenedBlockAttributes ( action . blocks ) ,
522
567
} ;
523
568
524
- case 'REMOVE_BLOCKS ' :
525
- return omit ( state , action . clientIds ) ;
569
+ case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN ' :
570
+ return omit ( state , action . removedClientIds ) ;
526
571
}
527
572
528
573
return state ;
@@ -609,7 +654,7 @@ export const blocks = flow(
609
654
} ;
610
655
}
611
656
612
- case 'REPLACE_BLOCKS ' : {
657
+ case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN ' : {
613
658
const { clientIds } = action ;
614
659
if ( ! action . blocks ) {
615
660
return state ;
@@ -618,7 +663,7 @@ export const blocks = flow(
618
663
const mappedBlocks = mapBlockOrder ( action . blocks ) ;
619
664
620
665
return flow ( [
621
- ( nextState ) => omit ( nextState , clientIds ) ,
666
+ ( nextState ) => omit ( nextState , action . replacedClientIds ) ,
622
667
( nextState ) => ( {
623
668
...nextState ,
624
669
...omit ( mappedBlocks , '' ) ,
@@ -642,20 +687,59 @@ export const blocks = flow(
642
687
] ) ( state ) ;
643
688
}
644
689
645
- case 'REMOVE_BLOCKS ' :
690
+ case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN ' :
646
691
return flow ( [
647
692
// Remove inner block ordering for removed blocks
648
- ( nextState ) => omit ( nextState , action . clientIds ) ,
693
+ ( nextState ) => omit ( nextState , action . removedClientIds ) ,
649
694
650
695
// Remove deleted blocks from other blocks' orderings
651
696
( nextState ) => mapValues ( nextState , ( subState ) => (
652
- without ( subState , ...action . clientIds )
697
+ without ( subState , ...action . removedClientIds )
653
698
) ) ,
654
699
] ) ( state ) ;
655
700
}
656
701
657
702
return state ;
658
703
} ,
704
+
705
+ // While technically redundant data as the inverse of `order`, it serves as
706
+ // an optimization for the selectors which derive the ancestry of a block.
707
+ parents ( state = { } , action ) {
708
+ switch ( action . type ) {
709
+ case 'RESET_BLOCKS' :
710
+ return mapBlockParents ( action . blocks ) ;
711
+
712
+ case 'RECEIVE_BLOCKS' :
713
+ return {
714
+ ...state ,
715
+ ...mapBlockParents ( action . blocks ) ,
716
+ } ;
717
+
718
+ case 'INSERT_BLOCKS' :
719
+ return {
720
+ ...state ,
721
+ ...mapBlockParents ( action . blocks , action . rootClientId || '' ) ,
722
+ } ;
723
+
724
+ case 'MOVE_BLOCK_TO_POSITION' : {
725
+ return {
726
+ ...state ,
727
+ [ action . clientId ] : action . toRootClientId || '' ,
728
+ } ;
729
+ }
730
+
731
+ case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN' :
732
+ return {
733
+ ...omit ( state , action . replacedClientIds ) ,
734
+ ...mapBlockParents ( action . blocks , state [ action . clientIds [ 0 ] ] ) ,
735
+ } ;
736
+
737
+ case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN' :
738
+ return omit ( state , action . removedClientIds ) ;
739
+ }
740
+
741
+ return state ;
742
+ } ,
659
743
} ) ;
660
744
661
745
/**
0 commit comments