import * as React from 'react' ; import * as common from 'tree-component' ; export * from 'tree-component' ; public export class Node < T = any > extends React . PureComponent < { data : common . TreeData < T > ; last : boolean ; checkbox ? : boolean ; path : number [ ] ; draggable ? : boolean ; root : common . TreeData < T > [ ] ; zindex ? : number ; preid ? : string ; parent : any ; toggle : ( eventData : common . EventData < T > ) => void ; change : ( eventData : common . EventData < T > ) => void ; onDragStart ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; onDragEnd ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; onDragOver ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; onDragEnter ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; onDragLeave ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; onDrop ? : ( eventData : React . DragEvent < HTMLElement > ) => void ; } , { hovered : boolean ; contextmenuVisible : boolean ; contextmenuStyle : React . CSSProperties ; } > { private hovered = false ; private doubleClick = new common . DoubleClick ( ) ; private contextmenuVisible = false ; private contextmenuStyle : React . CSSProperties = { position : 'absolute' , left : '0px' , top : '0px' , zIndex : typeof this . props . zindex === 'number' ? this . props . zindex : 1 } ; render ( ) { let childrenElement ; if ( this . props . children ) { childrenElement = this . props . children ; } else if ( this . props . data . children ) { const nodesElement = this . props . data . children . map ( ( child , i ) => ( < Node data = { child } key = { i } last = { i === this . props . data . children . length - 1 } checkbox = { this . props . checkbox } path = { this . geChildPath ( i ) } draggable = { this . props . draggable } root = { this . props . root } parent = { this } zindex = { this . props . zindex } preid = { this . props . preid } toggle = { ( eventData ) => this . ontoggle ( eventData ) } change = { ( eventData ) => this . onchange ( eventData ) } > < /Node>)); childrenElement = ( < ul role = 'group' className = 'tree-children' > { nodesElement } < /ul>); } else { childrenElement = null ; } const checkboxElement = this . props . checkbox ? < i className = { this . checkboxClassName } role = 'presentation' > < /i> : null; const iconElement = this . props . data . icon !== false ? < i className = { this . iconClassName } role = 'presentation' > < /i> : null; const markerElement = this . hasMarker ? < span className = { this . markerClassName } > & # 160 ; < /span> : null; const contextmenu = this . props . data . contextmenu && this . contextmenuVisible ? React . createElement ( this . props . data . contextmenu as React . ComponentClass < { data : common . ContextMenuData < T > ; } > , { data : this . contextmenuData } ) : null ; const text = this . props . data . component ? React . createElement ( this . props . data . component as React . ComponentClass < { data : common . TreeData < T > ; } > , { data : this . props . data } ) : this . props . data . text ; return ( < li role = 'treeitem' className = { this . nodeClassName } id = { this . id } onDragStart = { eventData => { if ( this . props . onDragStart ) { this . props . onDragStart ( eventData ) ; } } } onDragEnd = { eventData => { if ( this . props . onDragEnd ) { this . props . onDragEnd ( eventData ) ; } } } onDragOver = { eventData => { if ( this . props . onDragOver ) { this . props . onDragOver ( eventData ) ; } } } onDragEnter = { ( eventData ) => { if ( this . props . onDragEnter ) { this . props . onDragEnter ( eventData ) ; } } } onDragLeave = { eventData => { if ( this . props . onDragLeave ) { this . props . onDragLeave ( eventData ) ; } } } onDrop = { eventData => { if ( this . props . onDrop ) { this . props . onDrop ( eventData ) ; } } } > < i className = { this . oclClassName } role = 'presentation' onClick = { ( ) => this . ontoggle ( ) } > < /i> < a className = { this . anchorClassName } href = 'javascript:void(0)' draggable = { this . props . draggable } onClick = { ( ) => this . onchange ( ) } onDoubleClick = { ( ) => this . ontoggle ( ) } onMouseEnter = { ( ) => this . hover ( true ) } onMouseLeave = { ( ) => this . hover ( false ) } onContextMenu = { e => this . oncontextmenu ( e ) } data - path = { this . pathString } > { checkboxElement } { iconElement } { text } { markerElement } < div style = { this . contextmenuStyle } > { contextmenu } < /div> < /a> { childrenElement } < /li>); } private get nodeClassName ( ) { return common . getNodeClassName ( this . props . data , this . props . last , ! ! this . props . children ) ; } private get anchorClassName ( ) { return common . getAnchorClassName ( this . props . data , this . hovered , this . props . path ) ; } private get checkboxClassName ( ) { return common . getCheckboxClassName ( this . props . data , this . props . path ) ; } private get iconClassName ( ) { return common . getIconClassName ( this . props . data . icon ) ; } private get oclClassName ( ) { return common . getOclClassName ( this . props . path ) ; } private get pathString ( ) { return this . props . path . toString ( ) ; } private get hasMarker ( ) { return this . props . draggable && this . props . data . state . dropPosition !== common . DropPosition . empty ; } private get markerClassName ( ) { return common . getMarkerClassName ( this . props . data ) ; } private get eventData ( ) : common . EventData < T > { return { data : this . props . data , path : this . props . path } ; } private get contextmenuData ( ) : common . ContextMenuData < T > { return { data : this . props . data , path : this . props . path , root : this . props . root , parent : this . props . parent } ; } private get id ( ) { return common . getId ( this . props . path , this . props . preid ) ; } private geChildPath ( index ) { return this . props . path . concat ( index ) ; } private hover ( hovered ) { this . hovered = hovered ; this . setState ( { hovered : this . hovered } ) ; if ( ! hovered ) { this . contextmenuVisible = false ; this . setState ( { contextmenuVisible : this . contextmenuVisible } ) ; } } private ontoggle ( eventData ? ) { if ( eventData ) { this . props . toggle ( eventData ) ; } else { if ( this . props . data . state . openable || this . props . data . children . length > 0 || this . props . children ) { this . props . toggle ( this . eventData ) ; } } } private onchange ( eventData ? ) { if ( eventData ) { this . props . change ( eventData ) ; } else { if ( this . props . data . state . disabled ) { return ; } this . doubleClick . onclick ( ( ) => { this . props . change ( this . eventData ) ; } ) ; } } private oncontextmenu ( e ) { this . contextmenuVisible = true ; this . setState ( { contextmenuVisible : this . contextmenuVisible } ) ; e . preventDefault ( ) ; return false ; } } public export class Tree < T = any > extends React . PureComponent < { data : common . TreeData < T > [ ] ; checkbox ? : boolean ; draggable ? : boolean ; nodots ? : boolean ; size ? : string ; theme ? : string ; dropAllowed ? : ( dropData : common . DropData < T > ) => boolean ; zindex ? : number ; preid ? : string ; toggle ? : ( eventData : common . EventData < T > ) => void ; change ? : ( eventData : common . EventData < T > ) => void ; drop ? : ( dropData : common . DropData < T > ) => void ; dragTarget ? : common . DragTargetData | null ; changeDragTarget ? : ( dragTarget : common . DragTargetData | null ) => void ; } , { dragTarget : HTMLElement | null ; dropTarget : HTMLElement | null ; } > { private dragTarget : HTMLElement | null = null ; private dropTarget : HTMLElement | null = null ; render ( ) { const childrenElement = this . props . children || this . props . data . map ( ( child , i ) => ( < Node data = { child } key = { i } last = { i === this . props . data . length - 1 } checkbox = { this . props . checkbox } path = { [ i ] } draggable = { this . props . draggable } root = { this . props . data } parent = { this } zindex = { this . props . zindex } preid = { this . props . preid } toggle = { ( data ) => this . ontoggle ( data ) } change = { ( data ) => this . onchange ( data ) } > < /Node>)); return ( < div className = { this . rootClassName } role = 'tree' > < ul className = { this . containerClassName } role = 'group' onDragStart = { eventData => this . ondragstart ( eventData ) } onDragEnd = { eventData => this . ondragend ( eventData ) } onDragOver = { eventData => this . ondragover ( eventData ) } onDragEnter = { ( eventData ) => this . ondragenter ( eventData ) } onDragLeave = { eventData => this . ondragleave ( eventData ) } onDrop = { eventData => this . ondrop ( eventData ) } > { childrenElement } < /ul> < /div>); } private get rootClassName ( ) { return common . getRootClassName ( this . props . checkbox , this . props . size , this . props . theme ) ; } private get containerClassName ( ) { return common . getContainerClassName ( this . props . nodots ) ; } private canDrop ( event ) { return this . props . draggable && event . target && ( event . target as HTMLElement ) . dataset && ( event . target as HTMLElement ) . dataset . path ; } private ontoggle ( eventData ) { if ( this . props . toggle ) { this . props . toggle ( eventData ) ; } } private onchange ( eventData ) { if ( this . props . change ) { this . props . change ( eventData ) ; } } private ondragstart ( event ) { if ( ! this . props . draggable ) { return ; } this . dragTarget = event . target as HTMLElement ; this . dropTarget = event . target as HTMLElement ; this . setState ( { dragTarget : this . dragTarget , dropTarget : this . dropTarget } ) ; if ( this . props . changeDragTarget ) { this . props . changeDragTarget ( { target : event . target as HTMLElement , root : this . props . data } ) ; } } private ondragend ( event ) { if ( ! this . props . draggable ) { return ; } this . dragTarget = null ; for ( const tree of this . props . data ) { common . clearMarkerOfTree ( tree ) ; } this . setState ( { dragTarget : this . dragTarget } ) ; if ( this . props . changeDragTarget ) { this . props . changeDragTarget ( null ) ; } } private ondragover ( event ) { if ( ! this . canDrop ( event ) ) { return ; } if ( this . props . dragTarget ) { common . ondrag ( event . pageY , this . props . dragTarget . target , this . dropTarget , this . props . dragTarget . root , this . props . data , this . props . dropAllowed , ( ) => this . forceUpdate ( ) ) ; } else { common . ondrag ( event . pageY , this . dragTarget , this . dropTarget , this . props . data , this . props . data , this . props . dropAllowed , ( ) => this . forceUpdate ( ) ) ; } event . preventDefault ( ) ; } private ondragenter ( event ) { if ( ! this . canDrop ( event ) ) { return ; } this . dropTarget = event . target as HTMLElement ; this . setState ( { dropTarget : this . dropTarget } ) ; if ( this . props . dragTarget ) { common . ondrag ( event . pageY , this . props . dragTarget . target , this . dropTarget , this . props . dragTarget . root , this . props . data , this . props . dropAllowed , ( ) => this . forceUpdate ( ) ) ; } else { common . ondrag ( event . pageY , this . dragTarget , this . dropTarget , this . props . data , this . props . data , this . props . dropAllowed , ( ) => this . forceUpdate ( ) ) ; } } private ondragleave ( event ) { if ( ! this . canDrop ( event ) ) { return ; } if ( event . target === this . dropTarget ) { this . dropTarget = null ; } this . setState ( { dropTarget : this . dropTarget } ) ; common . ondragleave ( event . target as HTMLElement , this . props . data ) ; } private ondrop ( event ) { if ( ! this . canDrop ( event ) ) { return ; } if ( this . props . dragTarget ) { common . ondrop ( event . target as HTMLElement , this . props . dragTarget . target , this . props . dragTarget . root , this . props . data , dropData => { if ( this . props . drop ) { this . props . drop ( dropData ) ; } } ) ; } else { common . ondrop ( event . target as HTMLElement , this . dragTarget , this . props . data , this . props . data , dropData => { if ( this . props . drop ) { this . props . drop ( dropData ) ; } } ) ; } } }