license import { MDCFoundation } from '@material/base/foundation' ; import { MDCDataTableAdapter } from './adapter' ; import { cssClasses , SortValue , strings } from './constants' ; import { RowClickEventData , SortActionEventData } from './types' ; /**
 * The Foundation of data table component containing pure business logic, any
 * logic requiring DOM manipulation are delegated to adapter methods.
 */ export class MDCDataTableFoundation extends MDCFoundation < MDCDataTableAdapter > { static override get defaultAdapter ( ) : MDCDataTableAdapter { return { addClass : ( ) => undefined , addClassAtRowIndex : ( ) => undefined , getAttributeByHeaderCellIndex : ( ) => '' , getHeaderCellCount : ( ) => 0 , getHeaderCellElements : ( ) => [ ] , getRowCount : ( ) => 0 , getRowElements : ( ) => [ ] , getRowIdAtIndex : ( ) => '' , getRowIndexByChildElement : ( ) => 0 , getSelectedRowCount : ( ) => 0 , getTableContainerHeight : ( ) => 0 , getTableHeaderHeight : ( ) => 0 , isCheckboxAtRowIndexChecked : ( ) => false , isHeaderRowCheckboxChecked : ( ) => false , isRowsSelectable : ( ) => false , notifyRowSelectionChanged : ( ) => undefined , notifySelectedAll : ( ) => undefined , notifySortAction : ( ) => undefined , notifyUnselectedAll : ( ) => undefined , notifyRowClick : ( ) => undefined , registerHeaderRowCheckbox : ( ) => undefined , registerRowCheckboxes : ( ) => undefined , removeClass : ( ) => undefined , removeClassAtRowIndex : ( ) => undefined , removeClassNameByHeaderCellIndex : ( ) => undefined , setAttributeAtRowIndex : ( ) => undefined , setAttributeByHeaderCellIndex : ( ) => undefined , setClassNameByHeaderCellIndex : ( ) => undefined , setHeaderRowCheckboxChecked : ( ) => undefined , setHeaderRowCheckboxIndeterminate : ( ) => undefined , setProgressIndicatorStyles : ( ) => undefined , setRowCheckboxCheckedAtIndex : ( ) => undefined , setSortStatusLabelByHeaderCellIndex : ( ) => undefined , } ; } constructor ( adapter ? ) { super ( { ... MDCDataTableFoundation . defaultAdapter , ... adapter } ) ; } /**
     * Re-initializes header row checkbox and row checkboxes when selectable rows
     * are added or removed from table. Use this if registering checkbox is
     * synchronous.
     */ layout ( ) { if ( this . adapter . isRowsSelectable ( ) ) { this . adapter . registerHeaderRowCheckbox ( ) ; this . adapter . registerRowCheckboxes ( ) ; this . setHeaderRowCheckboxState ( ) ; } } /**
     * Re-initializes header row checkbox and row checkboxes when selectable rows
     * are added or removed from table. Use this if registering checkbox is
     * asynchronous.
     */ async layoutAsync ( ) { if ( this . adapter . isRowsSelectable ( ) ) { await this . adapter . registerHeaderRowCheckbox ( ) ; await this . adapter . registerRowCheckboxes ( ) ; this . setHeaderRowCheckboxState ( ) ; } } return getRows ( ) { return this . adapter . getRowElements ( ) ; } return getHeaderCells ( ) { return this . adapter . getHeaderCellElements ( ) ; } param rowIds setSelectedRowIds ( rowIds ) { for ( let rowIndex = 0 ; rowIndex < this . adapter . getRowCount ( ) ; rowIndex ++ ) { const rowId = this . adapter . getRowIdAtIndex ( rowIndex ) ; let isSelected = false ; if ( rowId && rowIds . indexOf ( rowId ) >= 0 ) { isSelected = true ; } this . adapter . setRowCheckboxCheckedAtIndex ( rowIndex , isSelected ) ; this . selectRowAtIndex ( rowIndex , isSelected ) ; } this . setHeaderRowCheckboxState ( ) ; } return getRowIds ( ) { const rowIds = [ ] ; for ( let rowIndex = 0 ; rowIndex < this . adapter . getRowCount ( ) ; rowIndex ++ ) { rowIds . push ( this . adapter . getRowIdAtIndex ( rowIndex ) ) ; } return rowIds ; } return getSelectedRowIds ( ) { const selectedRowIds = [ ] ; for ( let rowIndex = 0 ; rowIndex < this . adapter . getRowCount ( ) ; rowIndex ++ ) { if ( this . adapter . isCheckboxAtRowIndexChecked ( rowIndex ) ) { selectedRowIds . push ( this . adapter . getRowIdAtIndex ( rowIndex ) ) ; } } return selectedRowIds ; } /**
     * Handles header row checkbox change event.
     */ handleHeaderRowCheckboxChange ( ) { const isHeaderChecked = this . adapter . isHeaderRowCheckboxChecked ( ) ; for ( let rowIndex = 0 ; rowIndex < this . adapter . getRowCount ( ) ; rowIndex ++ ) { this . adapter . setRowCheckboxCheckedAtIndex ( rowIndex , isHeaderChecked ) ; this . selectRowAtIndex ( rowIndex , isHeaderChecked ) ; } if ( isHeaderChecked ) { this . adapter . notifySelectedAll ( ) ; } else { this . adapter . notifyUnselectedAll ( ) ; } } /**
     * Handles change event originated from row checkboxes.
     */ handleRowCheckboxChange ( event ) { const rowIndex = this . adapter . getRowIndexByChildElement ( event . target as HTMLInputElement ) ; if ( rowIndex === - 1 ) { return ; } const selected = this . adapter . isCheckboxAtRowIndexChecked ( rowIndex ) ; this . selectRowAtIndex ( rowIndex , selected ) ; this . setHeaderRowCheckboxState ( ) ; const rowId = this . adapter . getRowIdAtIndex ( rowIndex ) ; this . adapter . notifyRowSelectionChanged ( { rowId , rowIndex , selected } ) ; } /**
     * Handles sort action on sortable header cell.
     */ handleSortAction ( eventData ) { const { columnId , columnIndex , headerCell } = eventData ; for ( let index = 0 ; index < this . adapter . getHeaderCellCount ( ) ; index ++ ) { if ( index === columnIndex ) { continue ; } this . adapter . removeClassNameByHeaderCellIndex ( index , cssClasses . HEADER_CELL_SORTED ) ; this . adapter . removeClassNameByHeaderCellIndex ( index , cssClasses . HEADER_CELL_SORTED_DESCENDING ) ; this . adapter . setAttributeByHeaderCellIndex ( index , strings . ARIA_SORT , SortValue . NONE ) ; this . adapter . setSortStatusLabelByHeaderCellIndex ( index , SortValue . NONE ) ; } this . adapter . setClassNameByHeaderCellIndex ( columnIndex , cssClasses . HEADER_CELL_SORTED ) ; const currentSortValue = this . adapter . getAttributeByHeaderCellIndex ( columnIndex , strings . ARIA_SORT ) ; let sortValue = SortValue . NONE ; if ( currentSortValue === SortValue . ASCENDING ) { this . adapter . setClassNameByHeaderCellIndex ( columnIndex , cssClasses . HEADER_CELL_SORTED_DESCENDING ) ; this . adapter . setAttributeByHeaderCellIndex ( columnIndex , strings . ARIA_SORT , SortValue . DESCENDING ) ; sortValue = SortValue . DESCENDING ; } else if ( currentSortValue === SortValue . DESCENDING ) { this . adapter . removeClassNameByHeaderCellIndex ( columnIndex , cssClasses . HEADER_CELL_SORTED_DESCENDING ) ; this . adapter . setAttributeByHeaderCellIndex ( columnIndex , strings . ARIA_SORT , SortValue . ASCENDING ) ; sortValue = SortValue . ASCENDING ; } else { this . adapter . setAttributeByHeaderCellIndex ( columnIndex , strings . ARIA_SORT , SortValue . ASCENDING ) ; sortValue = SortValue . ASCENDING ; } this . adapter . setSortStatusLabelByHeaderCellIndex ( columnIndex , sortValue ) ; this . adapter . notifySortAction ( { columnId , columnIndex , headerCell , sortValue , } ) ; } /**
     * Handles data table row click event.
     */ handleRowClick ( { rowId , row } ) { this . adapter . notifyRowClick ( { rowId , row , } ) ; } /**
     * Shows progress indicator blocking only the table body content when in
     * loading state.
     */ showProgress ( ) { const tableHeaderHeight = this . adapter . getTableHeaderHeight ( ) ; const height = this . adapter . getTableContainerHeight ( ) - tableHeaderHeight ; const top = tableHeaderHeight ; this . adapter . setProgressIndicatorStyles ( { height : `${ height }px` , top : `${ top }px` , } ) ; this . adapter . addClass ( cssClasses . IN_PROGRESS ) ; } /**
     * Hides progress indicator when data table is finished loading.
     */ hideProgress ( ) { this . adapter . removeClass ( cssClasses . IN_PROGRESS ) ; } /**
     * Updates header row checkbox state based on number of rows selected.
     */ private setHeaderRowCheckboxState ( ) { if ( this . adapter . getSelectedRowCount ( ) === 0 ) { this . adapter . setHeaderRowCheckboxChecked ( false ) ; this . adapter . setHeaderRowCheckboxIndeterminate ( false ) ; } else if ( this . adapter . getSelectedRowCount ( ) === this . adapter . getRowCount ( ) ) { this . adapter . setHeaderRowCheckboxChecked ( true ) ; this . adapter . setHeaderRowCheckboxIndeterminate ( false ) ; } else { this . adapter . setHeaderRowCheckboxIndeterminate ( true ) ; this . adapter . setHeaderRowCheckboxChecked ( false ) ; } } /**
     * Sets the attributes of row element based on selection state.
     */ private selectRowAtIndex ( rowIndex , selected ) { if ( selected ) { this . adapter . addClassAtRowIndex ( rowIndex , cssClasses . ROW_SELECTED ) ; this . adapter . setAttributeAtRowIndex ( rowIndex , strings . ARIA_SELECTED , 'true' ) ; } else { this . adapter . removeClassAtRowIndex ( rowIndex , cssClasses . ROW_SELECTED ) ; this . adapter . setAttributeAtRowIndex ( rowIndex , strings . ARIA_SELECTED , 'false' ) ; } } }