namespace Views { export abstract class DataBoundList < T , C extends HTMLElement , E extends HTMLElement > extends Views . View < C > { private _initialised : boolean ; private _keys : string [ ] ; constructor ( container ) { super ( container ) ; this . _initialised = false ; this . _keys = [ ] ; } private initialise ( ) { if ( ( ! this . _initialised ) && ( this . root . childElementCount > 0 ) ) { Utils . log ( Utils . LogSeverity . Warning , "Data Bound List: " + this . root . childElementCount . toString ( ) + " alien element(s) removed" ) ; } $ ( this . root ) . empty ( ) ; this . _initialised = true ; } private beginBind ( dataCount ) { if ( ( ! this . _initialised ) || ( dataCount == 0 ) ) this . initialise ( ) ; return ( dataCount > 0 ) ; } protected bind ( source , keys , moveKeys ? ) { let oldKeys = this . _keys ; let dataMap = { } ; let dataCount = 0 ; if ( source != null ) { this . _keys = < any > keys ; if ( ! moveKeys ) this . _keys = this . _keys . slice ( ) ; for ( let i = 0 ; i < this . _keys . length ; ++ i ) { let k = this . _keys [ i ] ; if ( source ( k ) ) { if ( dataCount != i ) this . _keys [ dataCount ] = k ; dataMap [ k ] = true ; ++ dataCount ; } } this . _keys . length = dataCount ; } if ( ! this . beginBind ( dataCount ) ) return ; let oldIndex = { } ; let oldCount = 0 ; for ( let j = 0 ; j < oldKeys . length ; ++ j ) { let k = oldKeys [ j ] ; if ( dataMap [ k ] ) { oldIndex [ k ] = oldCount ; if ( oldCount != j ) { oldKeys [ oldCount ] = k ; } ++ oldCount ; } else $ ( this . root . children [ oldCount ] ) . remove ( ) ; } oldKeys . length = oldCount ; let created = 0 ; for ( let i = 0 ; i < dataCount ; ++ i ) { let k = this . _keys [ i ] ; let datum = source ( k ) ; let idx = oldIndex [ k ] ; if ( null == idx ) { this . root . insertBefore ( this . createChild ( k , datum ) , this . root . children [ i ] ) ; ++ created ; } else { let child = this . root . children [ idx + created ] ; if ( ( idx + created ) > i ) { let right = child . nextSibling ; let left = this . root . children [ i ] ; let leftKey = oldKeys [ i - created ] ; this . root . insertBefore ( child , left ) ; if ( ( idx + created ) > ( i + 1 ) ) { this . root . insertBefore ( left , right ) ; } oldKeys [ idx ] = leftKey ; oldIndex [ leftKey ] = idx ; } this . updateChild ( k , datum , child as E ) ; } } } protected bindDictionary ( data , keys ? ) { if ( data != null ) { let moveKeys = false ; if ( keys == null ) { keys = Object . keys ( data ) ; moveKeys = true ; } return this . bind ( ( k ) => data [ k ] , keys , moveKeys ) ; } } protected bindArray ( data ) { let dataCount = ( data == null ) ? 0 : data . length ; if ( data ) data ; if ( ! this . beginBind ( dataCount ) ) return ; let oldCount = Math . min ( this . _keys . length , this . root . childElementCount ) ; for ( let i = 0 ; i < dataCount ; ++ i ) { let k = i . toString ( ) ; let datum = data [ i ] ; if ( i < oldCount ) { let child = this . root . children [ i ] ; this . updateChild ( k , datum , child as E ) ; } else { let child = this . createChild ( k , datum ) ; this . root . appendChild ( child ) ; this . _keys [ i ] = k ; } } for ( let j = ( oldCount - 1 ) ; j >= dataCount ; -- j ) { $ ( this . root . children [ j ] ) . remove ( ) ; } this . _keys . length = dataCount ; } protected abstract createChild ( key , datum ) ; protected abstract updateChild ( key , datum , element ) ; } }