@@ -34,10 +34,10 @@ export class GridStackEngine {
34
34
private _float : boolean ;
35
35
/** @internal */
36
36
private _prevFloat : boolean ;
37
- /** @internal */
37
+ /** @internal cached layouts of difference column count so we can restore ack (eg 12 -> 1 -> 12) */
38
38
private _layouts ?: Layout [ ] [ ] ; // maps column # to array of values nodes
39
- /** @internal */
40
- private _ignoreLayoutsNodeChange : boolean ;
39
+ /** @internal true while we are resizing widgets during column resize to skip certain parts */
40
+ private _inColumnResize : boolean ;
41
41
/** @internal true if we have some items locked */
42
42
private _hasLocked : boolean ;
43
43
/** @internal unique global internal _id counter NOT starting at 0 */
@@ -273,6 +273,7 @@ export class GridStackEngine {
273
273
274
274
/** @internal called to top gravity pack the items back OR revert back to original Y positions when floating */
275
275
private _packNodes ( ) : GridStackEngine {
276
+ if ( this . batchMode ) { return ; }
276
277
this . _sortNodes ( ) ; // first to last
277
278
278
279
if ( this . float ) {
@@ -346,6 +347,8 @@ export class GridStackEngine {
346
347
/** part2 of preparing a node to fit inside our grid - checks for x,y from grid dimensions */
347
348
public nodeBoundFix ( node : GridStackNode , resizing ?: boolean ) : GridStackNode {
348
349
350
+ let before = node . _orig || Utils . copyPos ( { } , node ) ;
351
+
349
352
if ( node . maxW ) { node . w = Math . min ( node . w , node . maxW ) ; }
350
353
if ( node . maxH ) { node . h = Math . min ( node . h , node . maxH ) ; }
351
354
if ( node . minW && node . minW <= this . column ) { node . w = Math . max ( node . w , node . minW ) ; }
@@ -354,7 +357,8 @@ export class GridStackEngine {
354
357
if ( node . w > this . column ) {
355
358
// if user loaded a larger than allowed widget for current # of columns,
356
359
// remember it's full width so we can restore back (1 -> 12 column) #1655
357
- if ( this . column < 12 ) {
360
+ // IFF we're not in the middle of column resizing!
361
+ if ( this . column < 12 && ! this . _inColumnResize ) {
358
362
node . w = Math . min ( 12 , node . w ) ;
359
363
this . cacheOneLayout ( node , 12 ) ;
360
364
}
@@ -391,6 +395,10 @@ export class GridStackEngine {
391
395
}
392
396
}
393
397
398
+ if ( ! Utils . samePos ( node , before ) ) {
399
+ node . _dirty = true ;
400
+ }
401
+
394
402
return node ;
395
403
}
396
404
@@ -446,10 +454,11 @@ export class GridStackEngine {
446
454
447
455
/** call to add the given node to our list, fixing collision and re-packing */
448
456
public addNode ( node : GridStackNode , triggerAddEvent = false ) : GridStackNode {
449
- let dup : GridStackNode ;
450
- if ( dup = this . nodes . find ( n => n . _id === node . _id ) ) return dup ; // prevent inserting twice! return it instead.
457
+ let dup = this . nodes . find ( n => n . _id === node . _id ) ;
458
+ if ( dup ) return dup ; // prevent inserting twice! return it instead.
451
459
452
- node = this . prepareNode ( node ) ;
460
+ // skip prepareNode if we're in middle of column resize (not new) but do check for bounds!
461
+ node = this . _inColumnResize ? this . nodeBoundFix ( node ) : this . prepareNode ( node ) ;
453
462
delete node . _temporaryRemoved ;
454
463
delete node . _removeDOM ;
455
464
@@ -473,11 +482,10 @@ export class GridStackEngine {
473
482
}
474
483
475
484
this . nodes . push ( node ) ;
476
- triggerAddEvent && this . addedNodes . push ( node ) ;
485
+ if ( triggerAddEvent ) { this . addedNodes . push ( node ) ; }
477
486
478
487
this . _fixCollisions ( node ) ;
479
- this . _packNodes ( )
480
- . _notify ( ) ;
488
+ if ( ! this . batchMode ) { this . _packNodes ( ) . _notify ( ) ; }
481
489
return node ;
482
490
}
483
491
@@ -696,7 +704,7 @@ export class GridStackEngine {
696
704
697
705
/** @internal called whenever a node is added or moved - updates the cached layouts */
698
706
public layoutsNodesChange ( nodes : GridStackNode [ ] ) : GridStackEngine {
699
- if ( ! this . _layouts || this . _ignoreLayoutsNodeChange ) return this ;
707
+ if ( ! this . _layouts || this . _inColumnResize ) return this ;
700
708
// remove smaller layouts - we will re-generate those on the fly... larger ones need to update
701
709
this . _layouts . forEach ( ( layout , column ) => {
702
710
if ( ! layout || column === this . column ) return this ;
@@ -705,12 +713,12 @@ export class GridStackEngine {
705
713
}
706
714
else {
707
715
// we save the original x,y,w (h isn't cached) to see what actually changed to propagate better.
708
- // Note: we don't need to check against out of bound scaling/moving as that will be done when using those cache values.
716
+ // NOTE: we don't need to check against out of bound scaling/moving as that will be done when using those cache values. #1785
717
+ let ratio = column / this . column ;
709
718
nodes . forEach ( node => {
710
719
if ( ! node . _orig ) return ; // didn't change (newly added ?)
711
720
let n = layout . find ( l => l . _id === node . _id ) ;
712
721
if ( ! n ) return ; // no cache for new nodes. Will use those values.
713
- let ratio = column / this . column ;
714
722
// Y changed, push down same amount
715
723
// TODO: detect doing item 'swaps' will help instead of move (especially in 1 column mode)
716
724
if ( node . y !== node . _orig . y ) {
@@ -736,55 +744,60 @@ export class GridStackEngine {
736
744
* Note we store previous layouts (especially original ones) to make it possible to go
737
745
* from say 12 -> 1 -> 12 and get back to where we were.
738
746
*
739
- * @param oldColumn previous number of columns
747
+ * @param prevColumn previous number of columns
740
748
* @param column new column number
741
749
* @param nodes different sorted list (ex: DOM order) instead of current list
742
750
* @param layout specify the type of re-layout that will happen (position, size, etc...).
743
751
* Note: items will never be outside of the current column boundaries. default (moveScale). Ignored for 1 column
744
752
*/
745
- public updateNodeWidths ( oldColumn : number , column : number , nodes : GridStackNode [ ] , layout : ColumnOptions = 'moveScale' ) : GridStackEngine {
746
- if ( ! this . nodes . length || oldColumn === column ) return this ;
753
+ public updateNodeWidths ( prevColumn : number , column : number , nodes : GridStackNode [ ] , layout : ColumnOptions = 'moveScale' ) : GridStackEngine {
754
+ if ( ! this . nodes . length || ! column || prevColumn === column ) return this ;
747
755
748
756
// cache the current layout in case they want to go back (like 12 -> 1 -> 12) as it requires original data
749
- this . cacheLayout ( this . nodes , oldColumn ) ;
757
+ this . cacheLayout ( this . nodes , prevColumn ) ;
758
+ this . batchUpdate ( ) ; // do this EARLY as it will call saveInitial() so we can detect where we started for _dirty and collision
759
+ let newNodes : GridStackNode [ ] = [ ] ;
750
760
751
761
// if we're going to 1 column and using DOM order rather than default sorting, then generate that layout
752
- if ( column === 1 && nodes && nodes . length ) {
762
+ let domOrder = false ;
763
+ if ( column === 1 && nodes ?. length ) {
764
+ domOrder = true ;
753
765
let top = 0 ;
754
766
nodes . forEach ( n => {
755
767
n . x = 0 ;
756
768
n . w = 1 ;
757
769
n . y = Math . max ( n . y , top ) ;
758
770
top = n . y + n . h ;
759
771
} ) ;
772
+ newNodes = nodes ;
773
+ nodes = [ ] ;
760
774
} else {
761
- nodes = Utils . sort ( this . nodes , - 1 , oldColumn ) ; // current column reverse sorting so we can insert last to front (limit collision)
762
- }
763
-
764
- // see if we have cached previous layout.
765
- let cacheNodes = this . _layouts [ column ] || [ ] ;
766
- // if not AND we are going up in size start with the largest layout as down-scaling is more accurate
767
- let lastIndex = this . _layouts . length - 1 ;
768
- if ( cacheNodes . length === 0 && column > oldColumn && column < lastIndex ) {
769
- cacheNodes = this . _layouts [ lastIndex ] || [ ] ;
770
- if ( cacheNodes . length ) {
771
- // pretend we came from that larger column by assigning those values as starting point
772
- oldColumn = lastIndex ;
773
- cacheNodes . forEach ( cacheNode => {
774
- let j = nodes . findIndex ( n => n . _id === cacheNode . _id ) ;
775
- if ( j !== - 1 ) {
775
+ nodes = Utils . sort ( this . nodes , - 1 , prevColumn ) ; // current column reverse sorting so we can insert last to front (limit collision)
776
+ }
777
+
778
+ // see if we have cached previous layout IFF we are going up in size (restore) otherwise always
779
+ // generate next size down from where we are (looks more natural as you gradually size down).
780
+ let cacheNodes : Layout [ ] = [ ] ;
781
+ if ( column > prevColumn ) {
782
+ cacheNodes = this . _layouts [ column ] || [ ] ;
783
+ // ...if not, start with the largest layout (if not already there) as down-scaling is more accurate
784
+ // by pretending we came from that larger column by assigning those values as starting point
785
+ let lastIndex = this . _layouts . length - 1 ;
786
+ if ( ! cacheNodes . length && prevColumn !== lastIndex && this . _layouts [ lastIndex ] ?. length ) {
787
+ prevColumn = lastIndex ;
788
+ this . _layouts [ lastIndex ] . forEach ( cacheNode => {
789
+ let n = nodes . find ( n => n . _id === cacheNode . _id ) ;
790
+ if ( n ) {
776
791
// still current, use cache info positions
777
- nodes [ j ] . x = cacheNode . x ;
778
- nodes [ j ] . y = cacheNode . y ;
779
- nodes [ j ] . w = cacheNode . w ;
792
+ n . x = cacheNode . x ;
793
+ n . y = cacheNode . y ;
794
+ n . w = cacheNode . w ;
780
795
}
781
796
} ) ;
782
- cacheNodes = [ ] ; // we still don't have new column cached data... will generate from larger one.
783
797
}
784
798
}
785
799
786
800
// if we found cache re-use those nodes that are still current
787
- let newNodes : GridStackNode [ ] = [ ] ;
788
801
cacheNodes . forEach ( cacheNode => {
789
802
let j = nodes . findIndex ( n => n . _id === cacheNode . _id ) ;
790
803
if ( j !== - 1 ) {
@@ -799,14 +812,15 @@ export class GridStackEngine {
799
812
// ...and add any extra non-cached ones
800
813
if ( nodes . length ) {
801
814
if ( typeof layout === 'function' ) {
802
- layout ( column , oldColumn , newNodes , nodes ) ;
803
- } else {
804
- let ratio = column / oldColumn ;
815
+ layout ( column , prevColumn , newNodes , nodes ) ;
816
+ } else if ( ! domOrder ) {
817
+ let ratio = column / prevColumn ;
805
818
let move = ( layout === 'move' || layout === 'moveScale' ) ;
806
819
let scale = ( layout === 'scale' || layout === 'moveScale' ) ;
807
820
nodes . forEach ( node => {
821
+ // NOTE: x + w could be outside of the grid, but addNode() below will handle that
808
822
node . x = ( column === 1 ? 0 : ( move ? Math . round ( node . x * ratio ) : Math . min ( node . x , column - 1 ) ) ) ;
809
- node . w = ( ( column === 1 || oldColumn === 1 ) ? 1 :
823
+ node . w = ( ( column === 1 || prevColumn === 1 ) ? 1 :
810
824
scale ? ( Math . round ( node . w * ratio ) || 1 ) : ( Math . min ( node . w , column ) ) ) ;
811
825
newNodes . push ( node ) ;
812
826
} ) ;
@@ -816,15 +830,14 @@ export class GridStackEngine {
816
830
817
831
// finally re-layout them in reverse order (to get correct placement)
818
832
newNodes = Utils . sort ( newNodes , - 1 , column ) ;
819
- this . _ignoreLayoutsNodeChange = true ;
820
- this . batchUpdate ( ) ;
821
- this . nodes = [ ] ; // pretend we have no nodes to start with (we use same structures) to simplify layout
833
+ this . _inColumnResize = true ; // prevent cache update
834
+ this . nodes = [ ] ; // pretend we have no nodes to start with (add() will use same structures) to simplify layout
822
835
newNodes . forEach ( node => {
823
836
this . addNode ( node , false ) ; // 'false' for add event trigger
824
- node . _dirty = true ; // force attr update
825
- } , this ) ;
837
+ delete node . _orig ; // make sure the commit doesn't try to restore things back to original
838
+ } ) ;
826
839
this . commit ( ) ;
827
- delete this . _ignoreLayoutsNodeChange ;
840
+ delete this . _inColumnResize ;
828
841
return this ;
829
842
}
830
843
0 commit comments