import { isNullOrUndefined , remove } from '@syncfusion/ej2-base' ; import { formatUnit } from '@syncfusion/ej2-base' ; import { IRenderer , IGrid } from '../base/interface' ; import { Browser } from '@syncfusion/ej2-base' ; import { colGroupRefresh , columnWidthChanged , scroll , columnVisibilityChanged , refreshFooterRenderer } from '../base/constant' ; import { Column } from '../models/column' ; import { AggregateRowModel , AggregateColumnModel } from '../models/models' ; import { Row } from '../models/row' ; import { ContentRender } from './content-renderer' ; import { RowRenderer } from './row-renderer' ; import { ServiceLocator } from '../services/service-locator' ; import { SummaryModelGenerator } from '../services/summary-model-generator' ; import { renderMovable , calculateAggregate } from '../base/util' ; import { DataUtil } from '@syncfusion/ej2-data' ; import { AggregateColumn , AggregateRow } from '../models/aggregate' ; hidden export class FooterRenderer extends ContentRender implements IRenderer { private locator : ServiceLocator ; protected modelGenerator : SummaryModelGenerator ; private aggregates : Object = { } ; private freezeTable : HTMLTableElement ; private frozenContent : Element ; private movableContent : Element ; constructor ( gridModule ? , serviceLocator ? ) { super ( gridModule , serviceLocator ) ; this . parent = gridModule ; this . locator = serviceLocator ; this . modelGenerator = new SummaryModelGenerator ( this . parent ) ; this . addEventListener ( ) ; } /**
     * The function is used to render grid footer div
     */ public renderPanel ( ) { let div = this . parent . createElement ( 'div' , { className : 'e-gridfooter' } ) ; let innerDiv = this . parent . createElement ( 'div' , { className : 'e-summarycontent' } ) ; let movableContent = innerDiv ; if ( this . parent . getFrozenColumns ( ) ) { let fDiv = this . parent . createElement ( 'div' , { className : 'e-frozenfootercontent' } ) ; let mDiv = this . parent . createElement ( 'div' , { className : 'e-movablefootercontent' } ) ; innerDiv . appendChild ( fDiv ) ; innerDiv . appendChild ( mDiv ) ; this . frozenContent = fDiv ; this . movableContent = mDiv ; movableContent = mDiv ; } if ( Browser . isDevice ) { ( < HTMLElement > movableContent ) . style . overflowX = 'scroll' ; } div . appendChild ( innerDiv ) ; this . setPanel ( div ) ; if ( this . parent . getPager ( ) != null ) { this . parent . element . insertBefore ( div , this . parent . getPager ( ) ) ; } else { this . parent . element . appendChild ( div ) ; } } /**
     * The function is used to render grid footer table
     */ public renderTable ( ) { let contentDiv = this . getPanel ( ) ; let innerDiv = this . createContentTable ( '_footer_table' ) ; let table = < HTMLTableElement > innerDiv . querySelector ( '.e-table' ) ; let tFoot = < HTMLTableSectionElement > this . parent . createElement ( 'tfoot' ) ; table . appendChild ( tFoot ) ; if ( this . parent . getFrozenColumns ( ) ) { let freezeTable = table . cloneNode ( true ) as HTMLTableElement ; this . frozenContent . appendChild ( freezeTable ) ; this . freezeTable = freezeTable ; this . movableContent . appendChild ( table ) ; remove ( table . querySelector ( 'colgroup' ) ) ; let colGroup = ( ( this . parent . getHeaderContent ( ) . querySelector ( '.e-movableheader' ) . querySelector ( 'colgroup' ) ) . cloneNode ( true ) ) as Element ; table . insertBefore ( colGroup , table . querySelector ( 'tbody' ) ) ; this . setColGroup ( colGroup ) ; } this . setTable ( table ) ; } private renderSummaryContent ( e ? , table ? , cStart ? , cEnd ? ) { let input = this . parent . dataSource instanceof Array ? this . parent . dataSource : this . parent . currentViewData ; let summaries = < AggregateRowModel [ ] > this . modelGenerator . getData ( ) ; let dummies = isNullOrUndefined ( cStart ) ? this . modelGenerator . getColumns ( ) : this . modelGenerator . getColumns ( cStart , cEnd ) ; let rows = isNullOrUndefined ( cStart ) ? this . modelGenerator . generateRows ( input , e || this . aggregates ) : this . modelGenerator . generateRows ( input , e || this . aggregates , cStart , cEnd ) ; let fragment = < DocumentFragment > document . createDocumentFragment ( ) ; let rowrenderer = new RowRenderer < AggregateColumnModel > ( this . locator , null , this . parent ) ; rowrenderer . element = this . parent . createElement ( 'TR' , { className : 'e-summaryrow' } ) ; for ( let srow = 0 , len = summaries . length ; srow < len ; srow ++ ) { let row = rows [ srow ] ; if ( ! row ) { continue ; } let tr = rowrenderer . render ( row , dummies ) ; fragment . appendChild ( tr ) ; } table . tFoot . appendChild ( fragment ) ; this . aggregates = e ; } public refresh ( e ? ) { if ( this . parent . getFrozenColumns ( ) ) { remove ( this . getPanel ( ) ) ; this . renderPanel ( ) ; this . renderTable ( ) ; this . freezeTable . tFoot . innerHTML = '' ; this . renderSummaryContent ( e , this . freezeTable , 0 , this . parent . getFrozenColumns ( ) ) ; } ( < HTMLTableElement > this . getTable ( ) ) . tFoot . innerHTML = '' ; this . renderSummaryContent ( e , < HTMLTableElement > this . getTable ( ) , this . parent . getFrozenColumns ( ) ) ; if ( this . parent . getFrozenColumns ( ) ) { let frozenDiv = < HTMLElement > this . frozenContent ; if ( ! frozenDiv . offsetHeight ) { frozenDiv . style . height = ( < HTMLElement > this . getTable ( ) ) . offsetHeight + 'px' ; } } this . onScroll ( ) ; } public refreshCol ( ) { let mheaderCol ; let fheaderCol = mheaderCol = this . parent . element . querySelector ( '.e-gridheader' ) . querySelector ( 'colgroup' ) . cloneNode ( true ) ; if ( this . parent . getFrozenColumns ( ) ) { mheaderCol = renderMovable ( < Element > fheaderCol , this . parent . getFrozenColumns ( ) ) ; this . freezeTable . replaceChild ( fheaderCol , this . freezeTable . querySelector ( 'colGroup' ) ) ; } this . getTable ( ) . replaceChild ( mheaderCol , this . getColGroup ( ) ) ; this . setColGroup ( < Element > mheaderCol ) ; } private onWidthChange ( args ) { this . getColFromIndex ( args . index ) . style . width = formatUnit ( args . width ) ; if ( this . parent . allowResizing && args . module === 'resize' ) { this . updateFooterTableWidth ( this . getTable ( ) as HTMLElement ) ; } } private onScroll ( e = { left : ( < HTMLElement > this . parent . getContent ( ) . firstChild ) . scrollLeft } ) { ( < HTMLElement > this . getTable ( ) . parentElement ) . scrollLeft = e . left ; } public getColFromIndex ( index ? ) { let fCol = this . parent . getFrozenColumns ( ) ; if ( fCol && fCol > index ) { return this . freezeTable . querySelector ( 'colGroup' ) . children [ index ] as HTMLElement ; } return this . getColGroup ( ) . children [ index - fCol ] as HTMLElement ; } private columnVisibilityChanged ( ) { this . refresh ( ) ; } public addEventListener ( ) { this . parent . on ( colGroupRefresh , this . refreshCol , this ) ; this . parent . on ( columnWidthChanged , this . onWidthChange , this ) ; this . parent . on ( scroll , this . onScroll , this ) ; this . parent . on ( columnVisibilityChanged , this . columnVisibilityChanged , this ) ; this . parent . on ( refreshFooterRenderer , this . refreshFooterRenderer , this ) ; } public removeEventListener ( ) { this . parent . off ( colGroupRefresh , this . refreshCol ) ; this . parent . off ( columnWidthChanged , this . onWidthChange ) ; this . parent . off ( scroll , this . onScroll ) ; this . parent . off ( columnVisibilityChanged , this . columnVisibilityChanged ) ; this . parent . off ( refreshFooterRenderer , this . refreshFooterRenderer ) ; } private updateFooterTableWidth ( tFoot ) { let tHead = this . parent . getHeaderTable ( ) as HTMLTableElement ; if ( tHead && tFoot ) { tFoot . style . width = tHead . style . width ; } } public refreshFooterRenderer ( editedData ) { let aggregates = this . onAggregates ( editedData ) ; this . refresh ( aggregates ) ; } public onAggregates ( editedData ) { editedData = editedData instanceof Array ? editedData : [ ] ; let field = this . parent . getPrimaryKeyFieldNames ( ) [ 0 ] ; let deletedCols = [ ] ; let mergeds ; let rows = this . parent . frozenColumns > 0 ? this . parent . getMovableRowsObject ( ) : this . parent . getRowsObject ( ) ; let initds = this . parent . dataSource instanceof Array ? this . parent . dataSource : this . parent . getCurrentViewRecords ( ) ; let addrow = [ ] ; let changeds = rows . map ( ( row ) => { if ( row . changes && row . edit === 'add' ) { addrow . push ( row . changes ) ; } if ( row . edit === 'delete' ) { deletedCols . push ( row . data ) ; } return row . isDirty && row . changes ? row . changes : row . data ; } ) ; changeds = editedData . length === 0 ? changeds : editedData ; mergeds = initds . map ( ( item ) => { let idVal = DataUtil . getObject ( field , item ) ; let value ; let hasVal = changeds . some ( ( cItem ) => { value = cItem ; return idVal === DataUtil . getObject ( field , cItem ) ; } ) ; return hasVal ? value : item ; } ) ; let currentData = this . parent . groupSettings . columns . length > 0 && 'records' in this . parent . currentViewData ? this . parent . getCurrentViewRecords ( ) : this . parent . currentViewData ; let currentds ; currentds = currentData . map ( ( item ) => { let idVal = DataUtil . getObject ( field , item ) ; let value ; let hasVal = mergeds . some ( ( cItem ) => { value = cItem ; return idVal === DataUtil . getObject ( field , cItem ) ; } ) ; return hasVal ? value : item ; } ) ; if ( addrow . length > 0 ) { addrow . forEach ( ( row ) => { mergeds . push ( row ) ; currentds . push ( row ) ; } ) ; } let eData = editedData ; if ( ! ( ( < { type : string ; } > eData ) . type && ( < { type : string ; } > eData ) . type === 'cancel' ) && deletedCols . length > 0 ) { deletedCols . forEach ( ( row ) => { let index = mergeds . indexOf ( row ) ; let curIndx = currentData . indexOf ( row ) ; mergeds . splice ( index , 1 ) ; if ( currentds && currentds . length ) { currentds . splice ( curIndx , 1 ) ; } } ) ; } let aggregate = { } ; let agrVal ; let aggregateRows = this . parent . aggregates ; aggregateRows . forEach ( ( row ) => { row . columns . forEach ( ( col ) => { let data = [ ] ; let type = col . type . toString ( ) ; data = type . toLowerCase ( ) === 'custom' && ! isNullOrUndefined ( currentds ) ? currentds : mergeds ; agrVal = calculateAggregate ( type , data , col , this . parent ) ; aggregate [ col . field + ' - ' + type . toLowerCase ( ) ] = agrVal ; } ) ; } ) ; let result = { result : this . parent . groupSettings . columns . length > 0 ? mergeds : currentds , count : mergeds . length , aggregates : aggregate } ; return result ; } }