import { TreeNode } from './tree-node' ; import { TreeDataSource , FilterState , ITree } from './types' ; import { isBlank } from '../common/utils' ; export class Tree implements ITree { service : TreeDataSource ; selectedNode : TreeNode ; filterLoading : boolean ; serverSideFiltering : boolean ; filterLoadingFunc : ( state : boolean ) => void ; get nodes ( ) : TreeNode [ ] { return this . _nodes ; } set nodes ( val ) { this . _nodes = [ ] ; for ( const node of val ) { this . _nodes . push ( new TreeNode ( node , null , this ) ) ; } } private _nodes : TreeNode [ ] ; private uidNode = 0 ; constructor ( ) { } generateId ( ) { return this . uidNode ++ ; } initLoadNodes ( ) { if ( this . service && ! ( this . nodes && this . nodes . length ) ) { return this . service . getNodes ( ) . then ( data => { this . nodes = data ; } ) ; } else { return Promise . resolve ( ) ; } } loadNode ( node ) { if ( ( ! node . children || node . children . length === 0 ) && node . leaf === false && this . service ) { return this . service . getNodes ( node ) . then ( data => { this . addNode ( node . $$id , data ) ; } ) ; } else { return Promise . resolve ( ) ; } } addNode ( nodeId , children ) { this . nodes . forEach ( ( node ) => { this . _addNode ( node , nodeId , children ) ; } ) ; } private _addNode ( node , nodeId , children ) { if ( node . $$id === nodeId ) { node . children = children ; return true ; } else if ( node . children ) { node . children . forEach ( ( child ) => { this . _addNode ( child , nodeId , children ) ; } ) ; } return false ; } doForAll ( fn ) { return this . doForEach ( this . nodes , fn ) ; } filterTree ( filterValue ) { if ( this . serverSideFiltering ) { return this . filterServerSide ( filterValue ) ; } else { this . filterClientSide ( filterValue ) ; return Promise . resolve ( ) ; } } filterClientSide ( filterValue ) { if ( ! filterValue . trim ( ) ) { this . clearSearchState ( ) ; return ; } const searchNode = ( node ) : boolean => { let expandUp = false ; const index = node . name . toLowerCase ( ) . indexOf ( filterValue . toLowerCase ( ) ) ; if ( index >= 0 ) { node . $$filterState = FilterState . FOUND ; expandUp = true ; } else { node . $$filterState = FilterState . NOT_FOUND ; node . expanded = false ; expandUp = false ; } if ( node . children ) { const childState = node . children . map ( searchNode ) . find ( ( state ) => state ) ; if ( childState ) { if ( node . $$filterState !== FilterState . FOUND ) { node . $$filterState = FilterState . ON_FOUND_PATH ; } node . expanded = true ; expandUp = true ; } } return expandUp ; } ; if ( this . nodes ) { this . nodes . forEach ( searchNode ) ; } } clearSearchState ( ) { return this . doForAll ( ( node ) => { node . $$filterState = null ; node . expanded = false ; } ) ; } getNodeById ( nodeId ) { return this . getNodeBy ( node => node . id && node . id . toString ( ) === nodeId . toString ( ) ) ; } getNodeBy ( predicate , startNode = null ) { startNode = startNode || { children : this . nodes } ; if ( ! startNode . children ) { return null ; } const found = startNode . children . find ( predicate ) ; if ( found ) { return found ; } else { for ( const child of startNode . children ) { const foundInChildren = this . getNodeBy ( predicate , child ) ; if ( foundInChildren ) { return foundInChildren ; } } return null ; } } getChildren ( node ) { if ( ( ! node . children || node . children . length === 0 ) && node . leaf === false ) { return this . service . getNodes ( node ) . then ( data => { node . children = data ; } ) ; } else { return Promise . resolve ( ) ; } } doForEach ( nodes , fn ) { return Promise . all ( nodes . map ( ( node ) => { return Promise . resolve ( fn ( node ) ) . then ( ( ) => { return ( node . children ) ? this . doForEach ( node . children , fn ) : null ; } ) ; } , this ) ) ; } expandAll ( ) { this . doForEach ( this . nodes , ( node ) => { node . expanded = true ; return this . getChildren ( node ) ; } ) . then ( ) ; } collapseAll ( ) { this . doForEach ( this . nodes , ( node ) => { node . expanded = false ; } ) . then ( ) ; } loadPath ( path ) { if ( path && path . length ) { return Promise . all ( path . map ( ( p ) => { return this . doForEach ( this . nodes , ( node ) => ( node . id === p ) ? this . getChildren ( node ) : null ) ; } , this ) ) . then ( ( ) => { path . shift ( ) ; return this . loadPath ( path ) ; } ) ; } else { return Promise . resolve ( ) ; } } filterServerSide ( filterValue ) { if ( isBlank ( filterValue ) ) { return this . clearSearchState ( ) ; } if ( this . service ) { this . filterLoading = true ; if ( this . filterLoadingFunc ) { this . filterLoadingFunc ( true ) ; } return this . service . searchNodes ( filterValue ) . then ( items => { return this . loadPath ( items ) . then ( ( ) => { this . filterClientSide ( filterValue ) ; this . filterLoading = false ; if ( this . filterLoadingFunc ) { this . filterLoadingFunc ( false ) ; } } ) ; } ) ; } return null ; } }