2018-08-06 10:29:12 +00:00
import React from 'react' ;
2018-10-16 10:19:51 +00:00
import PropTypes from 'prop-types' ;
2018-08-06 10:29:12 +00:00
import TreeNodeView from './tree-node-view' ;
2019-03-23 06:16:48 +00:00
import TreeViewContextMenu from './tree-view-contextmenu'
2018-10-16 10:19:51 +00:00
const propTypes = {
2019-02-20 03:54:25 +00:00
repoPermission : PropTypes . bool ,
2019-01-28 08:48:03 +00:00
isNodeMenuShow : PropTypes . bool . isRequired ,
2018-10-16 10:19:51 +00:00
treeData : PropTypes . object . isRequired ,
2019-01-28 08:48:03 +00:00
currentPath : PropTypes . string . isRequired ,
onMenuItemClick : PropTypes . func ,
2018-10-16 10:19:51 +00:00
onNodeClick : PropTypes . func . isRequired ,
2019-01-28 08:48:03 +00:00
onNodeExpanded : PropTypes . func . isRequired ,
onNodeCollapse : PropTypes . func . isRequired ,
2019-03-27 03:25:27 +00:00
onItemMove : PropTypes . func ,
currentRepoInfo : PropTypes . object ,
2019-04-08 03:35:46 +00:00
switchAnotherMenuToShow : PropTypes . func ,
appMenuType : PropTypes . oneOf ( [ 'list_view_contextmenu' , 'item_contextmenu' , 'tree_contextmenu' , 'item_op_menu' ] ) ,
2018-10-16 10:19:51 +00:00
} ;
2019-03-04 09:45:28 +00:00
const PADDING _LEFT = 20 ;
2019-01-28 08:48:03 +00:00
class TreeView extends React . Component {
2018-08-06 10:29:12 +00:00
2019-01-28 08:48:03 +00:00
constructor ( props ) {
super ( props ) ;
this . state = {
isItemFreezed : false ,
2019-03-23 06:16:48 +00:00
isRightMenuShow : false ,
nodeData : null ,
fileData : null ,
mousePosition : { clientX : '' , clientY : '' } ,
2019-04-09 06:58:40 +00:00
isTreeViewDropTipShow : false ,
2019-01-28 08:48:03 +00:00
} ;
2018-08-06 10:29:12 +00:00
}
2019-03-23 06:16:48 +00:00
componentDidMount ( ) {
this . registerHandlers ( ) ;
}
2019-04-08 03:35:46 +00:00
componentDidUpdate ( ) {
this . registerHandlers ( ) ;
}
2019-03-23 06:16:48 +00:00
componentWillUnmount ( ) {
this . unregisterHandlers ( ) ;
}
2019-03-27 03:25:27 +00:00
onItemMove = ( repo , dirent , selectedPath , currentPath ) => {
this . props . onItemMove ( repo , dirent , selectedPath , currentPath ) ;
}
2019-01-28 08:48:03 +00:00
onNodeDragStart = ( e , node ) => {
2019-03-27 03:25:27 +00:00
let dragStartNodeData = { nodeDirent : node . object , nodeParentPath : node . parentNode . path , nodeRootPath : node . path } ;
dragStartNodeData = JSON . stringify ( dragStartNodeData ) ;
e . dataTransfer . effectAllowed = "move" ;
e . dataTransfer . setData ( 'applicaiton/drag-item-info' , dragStartNodeData ) ;
}
onNodeDragEnter = ( e , node ) => {
2019-04-09 06:58:40 +00:00
e . persist ( )
if ( e . target . className === 'tree-view tree ' ) {
this . setState ( {
isTreeViewDropTipShow : true ,
} )
}
2019-03-27 03:25:27 +00:00
}
onNodeDragMove = ( e ) => {
e . preventDefault ( ) ;
e . dataTransfer . dropEffect = 'move' ;
}
onNodeDragLeave = ( e , node ) => {
2019-04-09 06:58:40 +00:00
if ( e . target . className === 'tree-view tree tree-view-drop' ) {
this . setState ( {
isTreeViewDropTipShow : false ,
} )
}
2019-03-27 03:25:27 +00:00
}
onNodeDrop = ( e , node ) => {
if ( e . dataTransfer . files . length ) { // uploaded files
return ;
}
let dragStartNodeData = e . dataTransfer . getData ( 'applicaiton/drag-item-info' ) ;
dragStartNodeData = JSON . parse ( dragStartNodeData ) ;
let { nodeDirent , nodeParentPath , nodeRootPath } = dragStartNodeData ;
let dropNodeData = node ;
2019-04-09 06:58:40 +00:00
if ( ! dropNodeData ) {
2019-04-09 08:07:57 +00:00
if ( nodeParentPath === '/' ) {
this . setState ( { isTreeViewDropTipShow : false } ) ;
return ;
}
2019-04-09 06:58:40 +00:00
this . onItemMove ( this . props . currentRepoInfo , nodeDirent , '/' , nodeParentPath ) ;
2019-04-09 08:07:57 +00:00
this . setState ( { isTreeViewDropTipShow : false } ) ;
2019-04-09 06:58:40 +00:00
return ;
}
2019-03-27 03:25:27 +00:00
if ( dropNodeData . object . type !== 'dir' ) {
return ;
}
2019-04-09 08:07:57 +00:00
if ( nodeParentPath === dropNodeData . path ) {
return ;
}
2019-03-27 03:25:27 +00:00
// copy the dirent to itself. eg: A/B -> A/B
if ( nodeParentPath === dropNodeData . parentNode . path ) {
if ( dropNodeData . object . name === nodeDirent . name ) {
return ;
}
}
// copy the dirent to it's child. eg: A/B -> A/B/C
if ( dropNodeData . object . type === 'dir' && nodeDirent . type === 'dir' ) {
if ( dropNodeData . parentNode . path !== nodeParentPath ) {
if ( dropNodeData . path . indexOf ( nodeRootPath ) !== - 1 ) {
return ;
}
}
}
this . onItemMove ( this . props . currentRepoInfo , nodeDirent , dropNodeData . path , nodeParentPath ) ;
2018-08-06 10:29:12 +00:00
}
2019-01-28 08:48:03 +00:00
onFreezedItem = ( ) => {
this . setState ( { isItemFreezed : true } ) ;
2019-04-08 03:35:46 +00:00
this . props . switchAnotherMenuToShow ( 'item_op_menu' ) ;
2018-08-22 08:39:42 +00:00
}
2019-01-28 08:48:03 +00:00
onUnFreezedItem = ( ) => {
this . setState ( { isItemFreezed : false } ) ;
2018-08-22 08:39:42 +00:00
}
2019-03-23 06:16:48 +00:00
contextMenu = ( e ) => {
e . preventDefault ( ) ;
2019-04-08 03:35:46 +00:00
this . props . switchAnotherMenuToShow ( 'tree_contextmenu' ) ;
2019-03-23 06:16:48 +00:00
this . setState ( {
isRightMenuShow : false ,
2019-04-08 03:35:46 +00:00
} , ( ) => {
2019-03-23 06:16:48 +00:00
this . setState ( {
2019-04-08 03:35:46 +00:00
isRightMenuShow : true ,
fileData : this . state . nodeData ,
2019-03-23 06:16:48 +00:00
mousePosition : { clientX : e . clientX , clientY : e . clientY }
} )
2019-04-08 03:35:46 +00:00
} )
2019-03-23 06:16:48 +00:00
}
unregisterHandlers = ( ) => {
let treeView = document . querySelector ( '.tree-view' ) ;
treeView . removeEventListener ( 'contextmenu' , this . contextMenu ) ;
}
registerHandlers = ( ) => {
let treeView = document . querySelector ( '.tree-view' ) ;
treeView . addEventListener ( 'contextmenu' , this . contextMenu ) ;
}
onNodeChanged = ( node ) => {
this . setState ( {
nodeData : node
} )
}
closeRightMenu = ( ) => {
this . setState ( {
isRightMenuShow : false ,
} )
2019-04-08 03:35:46 +00:00
this . onUnFreezedItem ( ) ;
2019-03-23 06:16:48 +00:00
}
onMenuItemClick = ( operation , node ) => {
this . props . onMenuItemClick ( operation , node )
}
2018-08-22 08:39:42 +00:00
render ( ) {
return (
2019-04-09 06:58:40 +00:00
< div className = { ` tree-view tree ${ this . state . isTreeViewDropTipShow ? 'tree-view-drop' : '' } ` } onDrop = { this . onNodeDrop } onDragEnter = { this . onNodeDragEnter } onDragLeave = { this . onNodeDragLeave } >
2019-01-28 08:48:03 +00:00
< TreeNodeView
2019-02-20 03:54:25 +00:00
repoPermission = { this . props . repoPermission }
2018-08-22 08:39:42 +00:00
node = { this . props . treeData . root }
2018-11-22 03:26:00 +00:00
currentPath = { this . props . currentPath }
2019-01-28 08:48:03 +00:00
paddingLeft = { PADDING _LEFT }
isNodeMenuShow = { this . props . isNodeMenuShow }
isItemFreezed = { this . state . isItemFreezed }
onNodeClick = { this . props . onNodeClick }
onMenuItemClick = { this . props . onMenuItemClick }
onNodeExpanded = { this . props . onNodeExpanded }
onNodeCollapse = { this . props . onNodeCollapse }
onNodeDragStart = { this . onNodeDragStart }
onFreezedItem = { this . onFreezedItem }
onUnFreezedItem = { this . onUnFreezedItem }
2019-03-23 06:16:48 +00:00
onNodeChanged = { this . onNodeChanged }
registerHandlers = { this . registerHandlers }
unregisterHandlers = { this . unregisterHandlers }
2019-03-27 03:25:27 +00:00
onNodeDragMove = { this . onNodeDragMove }
onNodeDrop = { this . onNodeDrop }
onNodeDragEnter = { this . onNodeDragEnter }
onNodeDragLeave = { this . onNodeDragLeave }
2019-04-08 03:35:46 +00:00
appMenuType = { this . props . appMenuType }
2018-08-22 08:39:42 +00:00
/ >
2019-04-08 03:35:46 +00:00
{ this . state . isRightMenuShow && this . props . appMenuType === 'tree_contextmenu' && (
2019-03-23 06:16:48 +00:00
< TreeViewContextMenu
node = { this . state . fileData }
onMenuItemClick = { this . onMenuItemClick }
mousePosition = { this . state . mousePosition }
closeRightMenu = { this . closeRightMenu }
registerHandlers = { this . registerHandlers }
unregisterHandlers = { this . unregisterHandlers }
/ >
) }
2018-08-22 08:39:42 +00:00
< / d i v >
) ;
2018-08-06 10:29:12 +00:00
}
}
2018-10-16 10:19:51 +00:00
TreeView . propTypes = propTypes ;
2018-08-06 10:29:12 +00:00
export default TreeView ;