@@ -54,7 +54,7 @@ export class GridStackEngine {
5454 this . onChange = opts . onChange ;
5555 }
5656
57- public batchUpdate ( flag = true ) : GridStackEngine {
57+ public batchUpdate ( flag = true , doPack = true ) : GridStackEngine {
5858 if ( ! ! this . batchMode === flag ) return this ;
5959 this . batchMode = flag ;
6060 if ( flag ) {
@@ -64,7 +64,8 @@ export class GridStackEngine {
6464 } else {
6565 this . _float = this . _prevFloat ;
6666 delete this . _prevFloat ;
67- this . _packNodes ( ) . _notify ( ) ;
67+ if ( doPack ) this . _packNodes ( ) ;
68+ this . _notify ( ) ;
6869 }
6970 return this ;
7071 }
@@ -258,12 +259,14 @@ export class GridStackEngine {
258259 return ! this . collide ( nn ) ;
259260 }
260261
261- /** re-layout grid items to reclaim any empty space - optionally keeping the sort order exactly the same (list mode) vs truly finding an empty spaces */
262- public compact ( layout : CompactOptions = 'compact' , sortBefore = true ) : GridStackEngine {
262+ /** re-layout grid items to reclaim any empty space - optionally keeping the sort order exactly the same (' list' mode) vs truly finding an empty spaces */
263+ public compact ( layout : CompactOptions = 'compact' , doSort = true ) : GridStackEngine {
263264 if ( this . nodes . length === 0 ) return this ;
264- this . batchUpdate ( )
265- if ( sortBefore ) this . sortNodes ( ) ;
266- this . _inColumnResize = true ; // faster addNode()
265+ if ( doSort ) this . sortNodes ( ) ;
266+ const wasBatch = this . batchMode ;
267+ if ( ! wasBatch ) this . batchUpdate ( ) ;
268+ const wasColumnResize = this . _inColumnResize ;
269+ if ( ! wasColumnResize ) this . _inColumnResize = true ; // faster addNode()
267270 let copyNodes = this . nodes ;
268271 this . nodes = [ ] ; // pretend we have no nodes to conflict layout to start with...
269272 copyNodes . forEach ( ( n , index , list ) => {
@@ -274,8 +277,9 @@ export class GridStackEngine {
274277 }
275278 this . addNode ( n , false , after ) ; // 'false' for add event trigger
276279 } ) ;
277- delete this . _inColumnResize ;
278- return this . batchUpdate ( false ) ;
280+ if ( ! wasColumnResize ) delete this . _inColumnResize ;
281+ if ( ! wasBatch ) this . batchUpdate ( false ) ;
282+ return this ;
279283 }
280284
281285 /** enable/disable floating widgets (default: `false`) See [example](http://gridstackjs.com/demo/float.html) */
@@ -518,14 +522,16 @@ export class GridStackEngine {
518522 delete node . _temporaryRemoved ;
519523 delete node . _removeDOM ;
520524
525+ let skipCollision : boolean ;
521526 if ( node . autoPosition && this . findEmptyPosition ( node , this . nodes , this . column , after ) ) {
522527 delete node . autoPosition ; // found our slot
528+ skipCollision = true ;
523529 }
524530
525531 this . nodes . push ( node ) ;
526532 if ( triggerAddEvent ) { this . addedNodes . push ( node ) ; }
527533
528- this . _fixCollisions ( node ) ;
534+ if ( ! skipCollision ) this . _fixCollisions ( node ) ;
529535 if ( ! this . batchMode ) { this . _packNodes ( ) . _notify ( ) ; }
530536 return node ;
531537 }
@@ -792,23 +798,21 @@ export class GridStackEngine {
792798 * @param layout specify the type of re-layout that will happen (position, size, etc...).
793799 * Note: items will never be outside of the current column boundaries. default (moveScale). Ignored for 1 column
794800 */
795- public updateNodeWidths ( prevColumn : number , column : number , nodes : GridStackNode [ ] , layout : ColumnOptions = 'moveScale' ) : GridStackEngine {
801+ public columnChanged ( prevColumn : number , column : number , nodes : GridStackNode [ ] , layout : ColumnOptions = 'moveScale' ) : GridStackEngine {
796802 if ( ! this . nodes . length || ! column || prevColumn === column ) return this ;
797803
798804 // simpler shortcuts layouts
799805 const doCompact = layout === 'compact' || layout === 'list' ;
800806 if ( doCompact ) {
801807 this . sortNodes ( 1 , prevColumn ) ; // sort with original layout once and only once (new column will affect order otherwise)
802- return this . compact ( layout , false ) ;
803808 }
804-
805- // cache the current layout in case they want to go back (like 12 -> 1 -> 12) as it requires original data
806- this . cacheLayout ( this . nodes , prevColumn ) ;
809+
810+ // cache the current layout in case they want to go back (like 12 -> 1 -> 12) as it requires original data IFF we're sizing down (see below)
811+ if ( column < prevColumn ) this . cacheLayout ( this . nodes , prevColumn ) ;
807812 this . batchUpdate ( ) ; // do this EARLY as it will call saveInitial() so we can detect where we started for _dirty and collision
808813 let newNodes : GridStackNode [ ] = [ ] ;
809-
810-
811- // if we're going to 1 column and using DOM order rather than default sorting, then generate that layout
814+
815+ // if we're going to 1 column and using DOM order (item passed in) rather than default sorting, then generate that layout
812816 let domOrder = false ;
813817 if ( column === 1 && nodes ?. length ) {
814818 domOrder = true ;
@@ -822,14 +826,13 @@ export class GridStackEngine {
822826 newNodes = nodes ;
823827 nodes = [ ] ;
824828 } else {
825- nodes = Utils . sort ( this . nodes , - 1 , prevColumn ) ; // current column reverse sorting so we can insert last to front (limit collision)
829+ nodes = doCompact ? this . nodes : Utils . sort ( this . nodes , - 1 , prevColumn ) ; // current column reverse sorting so we can insert last to front (limit collision)
826830 }
827831
828832 // see if we have cached previous layout IFF we are going up in size (restore) otherwise always
829833 // generate next size down from where we are (looks more natural as you gradually size down).
830- let cacheNodes : GridStackNode [ ] = [ ] ;
831- if ( column > prevColumn ) {
832- cacheNodes = this . _layouts [ column ] || [ ] ;
834+ if ( column > prevColumn && this . _layouts ) {
835+ const cacheNodes = this . _layouts [ column ] || [ ] ;
833836 // ...if not, start with the largest layout (if not already there) as down-scaling is more accurate
834837 // by pretending we came from that larger column by assigning those values as starting point
835838 let lastIndex = this . _layouts . length - 1 ;
@@ -839,59 +842,72 @@ export class GridStackEngine {
839842 let n = nodes . find ( n => n . _id === cacheNode . _id ) ;
840843 if ( n ) {
841844 // still current, use cache info positions
842- n . x = cacheNode . x ;
843- n . y = cacheNode . y ;
845+ if ( ! doCompact ) {
846+ n . x = cacheNode . x ;
847+ n . y = cacheNode . y ;
848+ }
844849 n . w = cacheNode . w ;
845850 }
846851 } ) ;
847852 }
848- }
849853
850- // if we found cache re-use those nodes that are still current
851- cacheNodes . forEach ( cacheNode => {
852- let j = nodes . findIndex ( n => n . _id === cacheNode . _id ) ;
853- if ( j !== - 1 ) {
854- // still current, use cache info positions
855- if ( cacheNode . autoPosition || isNaN ( cacheNode . x ) || isNaN ( cacheNode . y ) ) {
856- this . findEmptyPosition ( cacheNode , newNodes ) ;
854+ // if we found cache re-use those nodes that are still current
855+ cacheNodes . forEach ( cacheNode => {
856+ let j = nodes . findIndex ( n => n . _id === cacheNode . _id ) ;
857+ if ( j !== - 1 ) {
858+ // still current, use cache info positions
859+ if ( doCompact ) {
860+ nodes [ j ] . w = cacheNode . w ; // only w is used, and don't trim the list
861+ return ;
862+ }
863+ if ( cacheNode . autoPosition || isNaN ( cacheNode . x ) || isNaN ( cacheNode . y ) ) {
864+ this . findEmptyPosition ( cacheNode , newNodes ) ;
865+ }
866+ if ( ! cacheNode . autoPosition ) {
867+ nodes [ j ] . x = cacheNode . x ;
868+ nodes [ j ] . y = cacheNode . y ;
869+ nodes [ j ] . w = cacheNode . w ;
870+ newNodes . push ( nodes [ j ] ) ;
871+ }
872+ nodes . splice ( j , 1 ) ;
857873 }
858- if ( ! cacheNode . autoPosition ) {
859- nodes [ j ] . x = cacheNode . x ;
860- nodes [ j ] . y = cacheNode . y ;
861- nodes [ j ] . w = cacheNode . w ;
862- newNodes . push ( nodes [ j ] ) ;
874+ } ) ;
875+ }
876+
877+ // much simpler layout that just compacts
878+ if ( doCompact ) {
879+ this . compact ( layout , false ) ;
880+ } else {
881+ // ...and add any extra non-cached ones
882+ if ( nodes . length ) {
883+ if ( typeof layout === 'function' ) {
884+ layout ( column , prevColumn , newNodes , nodes ) ;
885+ } else if ( ! domOrder ) {
886+ let ratio = ( doCompact || layout === 'none' ) ? 1 : column / prevColumn ;
887+ let move = ( layout === 'move' || layout === 'moveScale' ) ;
888+ let scale = ( layout === 'scale' || layout === 'moveScale' ) ;
889+ nodes . forEach ( node => {
890+ // NOTE: x + w could be outside of the grid, but addNode() below will handle that
891+ node . x = ( column === 1 ? 0 : ( move ? Math . round ( node . x * ratio ) : Math . min ( node . x , column - 1 ) ) ) ;
892+ node . w = ( ( column === 1 || prevColumn === 1 ) ? 1 : scale ? ( Math . round ( node . w * ratio ) || 1 ) : ( Math . min ( node . w , column ) ) ) ;
893+ newNodes . push ( node ) ;
894+ } ) ;
895+ nodes = [ ] ;
863896 }
864- nodes . splice ( j , 1 ) ;
865897 }
866- } ) ;
867- // ...and add any extra non-cached ones
868- if ( nodes . length ) {
869- if ( typeof layout === 'function' ) {
870- layout ( column , prevColumn , newNodes , nodes ) ;
871- } else if ( ! domOrder ) {
872- let ratio = column / prevColumn ;
873- let move = ( layout === 'move' || layout === 'moveScale' ) ;
874- let scale = ( layout === 'scale' || layout === 'moveScale' ) ;
875- nodes . forEach ( node => {
876- // NOTE: x + w could be outside of the grid, but addNode() below will handle that
877- node . x = ( column === 1 ? 0 : ( move ? Math . round ( node . x * ratio ) : Math . min ( node . x , column - 1 ) ) ) ;
878- node . w = ( ( column === 1 || prevColumn === 1 ) ? 1 :
879- scale ? ( Math . round ( node . w * ratio ) || 1 ) : ( Math . min ( node . w , column ) ) ) ;
880- newNodes . push ( node ) ;
881- } ) ;
882- nodes = [ ] ;
883- }
884- }
885898
886- // finally re-layout them in reverse order (to get correct placement)
887- if ( ! domOrder ) newNodes = Utils . sort ( newNodes , - 1 , column ) ;
888- this . _inColumnResize = true ; // prevent cache update
889- this . nodes = [ ] ; // pretend we have no nodes to start with (add() will use same structures) to simplify layout
890- newNodes . forEach ( node => {
891- this . addNode ( node , false ) ; // 'false' for add event trigger
892- delete node . _orig ; // make sure the commit doesn't try to restore things back to original
893- } ) ;
894- this . batchUpdate ( false ) ;
899+ // finally re-layout them in reverse order (to get correct placement)
900+ if ( ! domOrder ) newNodes = Utils . sort ( newNodes , - 1 , column ) ;
901+ this . _inColumnResize = true ; // prevent cache update
902+ this . nodes = [ ] ; // pretend we have no nodes to start with (add() will use same structures) to simplify layout
903+ newNodes . forEach ( node => {
904+ this . addNode ( node , false ) ; // 'false' for add event trigger
905+ delete node . _orig ; // make sure the commit doesn't try to restore things back to original
906+ } ) ;
907+ }
908+
909+ this . nodes . forEach ( n => delete n . _orig ) ; // clear _orig before batch=false so it doesn't handle float=true restore
910+ this . batchUpdate ( false , ! doCompact ) ;
895911 delete this . _inColumnResize ;
896912 return this ;
897913 }
0 commit comments