@@ -4217,7 +4217,7 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
42174217 throw new Error ( 'SlickGrid Selection model is not set' ) ;
42184218 }
42194219 if ( this && this . getEditorLock && ! this . getEditorLock ( ) ?. isActive ( ) ) {
4220- this . selectionModel . setSelectedRanges ( this . rowsToRanges ( rows ) , caller || 'SlickGrid.setSelectedRows' ) ;
4220+ this . selectionModel . setSelectedRanges ( this . rowsToRanges ( rows , caller === 'click.selectAll' ) , caller || 'SlickGrid.setSelectedRows' ) ;
42214221 }
42224222 }
42234223
@@ -4288,7 +4288,10 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
42884288 protected handleSelectedRangesChanged ( e : SlickEventData_ , ranges : SlickRange_ [ ] ) {
42894289 const ne = e . getNativeEvent < CustomEvent > ( ) ;
42904290 const selectionMode = ne ?. detail ?. selectionMode ?? '' ;
4291+ const caller = ne ?. detail ?. caller ?? 'click' ;
4292+ const isBulkSelection = caller === 'click.selectAll' || caller === 'click.unselectAll' ;
42914293 let addDragHandle = ! ! ne ?. detail ?. addDragHandle ;
4294+ const selectedCellCssClass = this . _options . selectedCellCssClass || '' ;
42924295 const selectionType = this . getSelectionModel ( ) ?. getOptions ( ) ?. selectionType ;
42934296 const showDragHandle = this . getDragHandleVisibility ( ) ;
42944297 addDragHandle = selectionType === 'cell' || selectionType === 'mixed' ;
@@ -4336,15 +4339,21 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
43364339
43374340 this . selectedRows = [ ] ;
43384341 const hash : CssStyleHash = Object . create ( null ) ;
4342+ const selectedRowsSet = ranges . length > 1 ? new Set < number > ( ) : undefined ;
4343+ let rangesAreOrdered = true ;
43394344 for ( let i = 0 ; i < ranges . length ; i ++ ) {
4345+ if ( i > 0 && ranges [ i - 1 ] . toRow >= ranges [ i ] . fromRow ) {
4346+ rangesAreOrdered = false ;
4347+ }
43404348 for ( let j = ranges [ i ] . fromRow ; j <= ranges [ i ] . toRow ; j ++ ) {
4341- if ( ! hash [ j ] ) { // prevent duplicates
4349+ if ( ! selectedRowsSet || ! selectedRowsSet . has ( j ) ) {
4350+ selectedRowsSet ?. add ( j ) ;
43424351 this . selectedRows . push ( j ) ;
4343- hash [ j ] = Object . create ( null ) ;
43444352 }
4353+ const rowHash = this . rowsCache [ j ] ? ( hash [ j ] ??= Object . create ( null ) ) : undefined ;
43454354 for ( let k = ranges [ i ] . fromCell ; k <= ranges [ i ] . toCell ; k ++ ) {
4346- if ( this . canCellBeSelected ( j , k ) ) {
4347- hash [ j ] [ this . columns [ k ] . id ] = this . _options . selectedCellCssClass ;
4355+ if ( rowHash && this . canCellBeSelected ( j , k ) ) {
4356+ rowHash [ this . columns [ k ] . id ] = selectedCellCssClass ;
43484357 }
43494358 }
43504359 }
@@ -4356,25 +4365,32 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
43564365 this . selectionRightCell = activeRange . toCell ;
43574366 }
43584367
4359- this . setCellCssStyles ( this . _options . selectedCellCssClass || '' , hash ) ;
4368+ if ( ! isBulkSelection || ! rangesAreOrdered ) {
4369+ // Preserve the legacy default sort order (numeric values are compared as strings).
4370+ this . selectedRows . sort ( ) ;
4371+ }
4372+
4373+ this . setCellCssStyles ( selectedCellCssClass , hash ) ;
43604374
43614375 if ( this . selectionBottomRow >= 0 && this . selectionRightCell >= 0 && addDragHandle && showDragHandle !== false ) {
43624376 const lowerRightCell = this . getCellNode ( this . selectionBottomRow , this . selectionRightCell )
43634377 this . dragReplaceEl . createEl ( lowerRightCell , showDragHandle ) ;
43644378 }
43654379
4366- // check if the selected rows have changed (index order isn't important, so we'll sort them both before comparing them)
4367- if ( ! this . arrayEquals ( previousSelectedRows . sort ( ) , this . selectedRows . sort ( ) ) ) {
4368- const caller = ne ?. detail ?. caller ?? 'click' ;
4369- // Use Set for faster performance
4370- const selectedRowsSet = new Set ( this . getSelectedRows ( ) ) ;
4380+ let selectedRowsChanged = previousSelectedRows . length !== this . selectedRows . length ;
4381+ if ( ! selectedRowsChanged ) {
43714382 const previousSelectedRowsSet = new Set ( previousSelectedRows ) ;
4372-
4373- const newSelectedAdditions = Array . from ( selectedRowsSet ) . filter ( i => ! previousSelectedRowsSet . has ( i ) ) ;
4374- const newSelectedDeletions = Array . from ( previousSelectedRowsSet ) . filter ( i => ! selectedRowsSet . has ( i ) ) ;
4383+ selectedRowsChanged = this . selectedRows . some ( ( row ) => ! previousSelectedRowsSet . has ( row ) ) ;
4384+ }
4385+ if ( selectedRowsChanged ) {
4386+ const selectedRows = this . getSelectedRows ( ) ;
4387+ const selectedRowsSet = selectedRows . length ? new Set ( selectedRows ) : undefined ;
4388+ const previousSelectedRowsSet = previousSelectedRows . length ? new Set ( previousSelectedRows ) : undefined ;
4389+ const newSelectedAdditions = previousSelectedRowsSet ? selectedRows . filter ( ( i ) => ! previousSelectedRowsSet . has ( i ) ) : selectedRows ;
4390+ const newSelectedDeletions = selectedRowsSet ? previousSelectedRows . filter ( ( i ) => ! selectedRowsSet . has ( i ) ) : previousSelectedRows ;
43754391
43764392 this . trigger ( this . onSelectedRowsChanged , {
4377- rows : this . getSelectedRows ( ) ,
4393+ rows : selectedRows ,
43784394 previousSelectedRows,
43794395 caller,
43804396 changedSelectedRows : newSelectedAdditions ,
@@ -5821,6 +5837,9 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
58215837 if ( cellCssClasses ) {
58225838 cellCss += ` ${ cellCssClasses } ` ;
58235839 }
5840+ if ( this . isCellSelected ( row , cell ) && ! cellCssClasses ?. includes ( this . _options . selectedCellCssClass || '' ) ) {
5841+ cellCss += ` ${ this . _options . selectedCellCssClass } ` ;
5842+ }
58245843
58255844 let value : any = null ;
58265845 let formatterResult : FormatterResultWithHtml | FormatterResultWithText | HTMLElement | DocumentFragment | string = '' ;
@@ -8103,6 +8122,14 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
81038122 return this . cellCssClasses [ key ] ;
81048123 }
81058124
8125+ protected isCellSelected ( row : number , cell : number ) : boolean {
8126+ return (
8127+ ! ! this . _options . selectedCellCssClass &&
8128+ this . selectedRanges . some ( ( range ) => range . contains ( row , cell ) ) &&
8129+ this . canCellBeSelected ( row , cell )
8130+ ) ;
8131+ }
8132+
81068133 /**
81078134 * Flashes the cell twice by toggling the CSS class 4 times.
81088135 * @param {Number } row A row index.
@@ -8848,11 +8875,29 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
88488875 * @param {number[] } rows - The row indices.
88498876 * @returns {SlickRange_[] } An array of ranges covering the specified rows.
88508877 */
8851- protected rowsToRanges ( rows : number [ ] ) {
8852- const ranges : SlickRange_ [ ] = [ ] ;
8878+ protected rowsToRanges ( rows : number [ ] , compactRows = false ) {
88538879 const lastCell = this . columns . length - 1 ;
8854- for ( let i = 0 ; i < rows . length ; i ++ ) {
8855- ranges . push ( new SlickRange ( rows [ i ] , 0 , rows [ i ] , lastCell ) ) ;
8880+ const ranges : SlickRange_ [ ] = [ ] ;
8881+ if ( ! compactRows ) {
8882+ rows . forEach ( ( row ) => ranges . push ( new SlickRange ( row , 0 , row , lastCell ) ) ) ;
8883+ return ranges ;
8884+ }
8885+
8886+ let rangeStart = rows [ 0 ] ;
8887+ let previousRow = rangeStart ;
8888+ for ( let i = 1 ; i < rows . length ; i ++ ) {
8889+ const row = rows [ i ] ;
8890+ if ( row <= previousRow ) {
8891+ return rows . map ( ( row ) => new SlickRange ( row , 0 , row , lastCell ) ) ;
8892+ }
8893+ if ( row !== previousRow + 1 ) {
8894+ ranges . push ( new SlickRange ( rangeStart , 0 , previousRow , lastCell ) ) ;
8895+ rangeStart = row ;
8896+ }
8897+ previousRow = row ;
8898+ }
8899+ if ( rangeStart !== undefined ) {
8900+ ranges . push ( new SlickRange ( rangeStart , 0 , previousRow , lastCell ) ) ;
88568901 }
88578902 return ranges ;
88588903 }
0 commit comments