From 07d596f620479bb9c078500c820a587aa6e3c917 Mon Sep 17 00:00:00 2001 From: zxj96 <35951769+zxj96@users.noreply.github.com> Date: Mon, 8 Apr 2019 11:35:46 +0800 Subject: [PATCH] Item right menu (#3203) * Add item right menu * Add item right menu * Pass value bug * Add item right menu * modify style problem * Add some style * Modifying naming issues * Modify Priority * Add showShare jurisdiction and modify priority * Modify subscript to itemIndex * Communication between sibling components * Improve interaction * modify style problem * Promotion isItemFreezed and onUnfreezedItem level * modify bugs * have tree-node bug * Solve tree-node item-click bug * Complete right click menu * modify style * modify style * item-right-menu finash * modify style to dirent-=list-item * modify some style problem * modify styles * stop thead contextmenu --- .../dir-view-mode/dir-column-nav.js | 4 + .../dir-view-mode/dir-column-view.js | 7 + .../components/dir-view-mode/dir-list-view.js | 172 +++++++++-- .../dirent-list-view/dirent-list-item.js | 100 +++++- .../dirent-list-view/dirent-list-view.js | 26 +- .../dirent-list-view/dirent-menu.js | 7 + .../dirent-list-view/dirent-right-menu.js | 291 ++++++++++++++++++ .../components/tree-view/tree-node-menu.js | 10 +- .../components/tree-view/tree-node-view.js | 12 + .../src/components/tree-view/tree-view.js | 23 +- frontend/src/css/layout.css | 6 + frontend/src/css/tree-view-contextmenu.css | 4 +- .../lib-content-view/lib-content-container.js | 26 ++ 13 files changed, 648 insertions(+), 40 deletions(-) create mode 100644 frontend/src/components/dirent-list-view/dirent-right-menu.js diff --git a/frontend/src/components/dir-view-mode/dir-column-nav.js b/frontend/src/components/dir-view-mode/dir-column-nav.js index c86196a45a..a22e1203b0 100644 --- a/frontend/src/components/dir-view-mode/dir-column-nav.js +++ b/frontend/src/components/dir-view-mode/dir-column-nav.js @@ -32,6 +32,8 @@ const propTypes = { navRate: PropTypes.number, inResizing: PropTypes.bool.isRequired, currentRepoInfo: PropTypes.object.isRequired, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class DirColumnNav extends React.Component { @@ -282,6 +284,8 @@ class DirColumnNav extends React.Component { onUnFreezedItem={this.onUnFreezedItem} onItemMove={this.props.onItemMove} currentRepoInfo={this.props.currentRepoInfo} + switchAnotherMenuToShow={this.props.switchAnotherMenuToShow} + appMenuType={this.props.appMenuType} />) } diff --git a/frontend/src/components/dir-view-mode/dir-column-view.js b/frontend/src/components/dir-view-mode/dir-column-view.js index 41ab1b3a50..884a2cd68a 100644 --- a/frontend/src/components/dir-view-mode/dir-column-view.js +++ b/frontend/src/components/dir-view-mode/dir-column-view.js @@ -63,6 +63,8 @@ const propTypes = { onDirentClick: PropTypes.func.isRequired, isAllItemSelected: PropTypes.bool.isRequired, onAllItemSelected: PropTypes.func.isRequired, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class DirColumnView extends React.Component { @@ -165,6 +167,8 @@ class DirColumnView extends React.Component { currentRepoInfo={this.props.currentRepoInfo} onItemMove={this.props.onItemMove} onItemCopy={this.props.onItemCopy} + switchAnotherMenuToShow={this.props.switchAnotherMenuToShow} + appMenuType={this.props.appMenuType} />
@@ -213,6 +217,9 @@ class DirColumnView extends React.Component { updateDirent={this.props.updateDirent} isAllItemSelected={this.props.isAllItemSelected} onAllItemSelected={this.props.onAllItemSelected} + switchAnotherMenuToShow={this.props.switchAnotherMenuToShow} + appMenuType={this.props.appMenuType} + onAddFolder={this.props.onAddFolder} /> )}
diff --git a/frontend/src/components/dir-view-mode/dir-list-view.js b/frontend/src/components/dir-view-mode/dir-list-view.js index 60de02eb87..ced53459b4 100644 --- a/frontend/src/components/dir-view-mode/dir-list-view.js +++ b/frontend/src/components/dir-view-mode/dir-list-view.js @@ -1,7 +1,11 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import RepoInfoBar from '../../components/repo-info-bar'; +import ModalPortal from '../modal-portal'; import DirentListView from '../../components/dirent-list-view/dirent-list-view'; +import CreateFile from '../../components/dialog/create-file-dialog'; +import CreateFolder from '../../components/dialog/create-folder-dialog'; +import DirentListMenu from '../dirent-list-view/dirent-right-menu'; const propTypes = { path: PropTypes.string.isRequired, @@ -31,9 +35,94 @@ const propTypes = { updateDirent: PropTypes.func.isRequired, isAllItemSelected: PropTypes.bool.isRequired, onAllItemSelected: PropTypes.func.isRequired, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), + onAddFolder: PropTypes.func, }; class DirListView extends React.Component { + + constructor(props) { + super(props); + this.state = { + isCreateFileDialogShow: false, + fileType: '', + isContainerContextmenuShow: false, + isCreateFolderDialogShow: false, + itemMousePosition: {clientX: '', clientY: ''}, + } + } + + componentDidUpdate() { + this.registerTableContainerContextmenuHandler(); + } + + componentWillUnmount() { + this.unregisterTableContainerContextmenuHandler(); + } + + registerTableContainerContextmenuHandler = () => { + let tableContainer = document.querySelector('.table-container'); + if (tableContainer) { + tableContainer.addEventListener('contextmenu', this.tableContainerContextmenuHandler); + } + } + + unregisterTableContainerContextmenuHandler = () => { + let tableContainer = document.querySelector('.table-container'); + tableContainer.removeEventListener('contextmenu', this.tableContainerContextmenuHandler); + } + + tableContainerContextmenuHandler = (e) => { + e.preventDefault(); + + this.props.switchAnotherMenuToShow('list_view_contextmenu'); + + this.setState({isContainerContextmenuShow: false}, () => { + this.setState({ + isContainerContextmenuShow: true, + itemMousePosition: {clientX: e.clientX, clientY: e.clientY} + }) + }); + } + + closeTableContainerRightMenu = () => { + this.setState({ + isContainerContextmenuShow: false, + }); + this.props.switchAnotherMenuToShow('item_op_menu'); + } + + onCreateFolderToggle = () => { + this.setState({ + isCreateFolderDialogShow: !this.state.isCreateFolderDialogShow, + }); + } + + onCreateFileToggle = () => { + this.setState({ + isCreateFileDialogShow: !this.state.isCreateFileDialogShow, + fileType: '' + }); + } + + onAddFile = (filePath, isDraft) => { + this.setState({isCreateFileDialogShow: false}); + this.props.onAddFile(filePath, isDraft); + } + + onAddFolder = (dirPath) => { + this.setState({isCreateFolderDialogShow: false}); + this.props.onAddFolder(dirPath); + } + + checkDuplicatedName = (newName) => { + let direntList = this.props.direntList; + let isDuplicated = direntList.some(object => { + return object.name === newName; + }); + return isDuplicated; + } render() { return ( @@ -48,30 +137,65 @@ class DirListView extends React.Component { updateUsedRepoTags={this.props.updateUsedRepoTags} /> )} - +
+ +
+ {this.state.isContainerContextmenuShow && this.props.appMenuType === 'list_view_contextmenu' && ( + + )} + {this.state.isCreateFolderDialogShow && ( + + + + )} + {this.state.isCreateFileDialogShow && ( + + + + )} ); } diff --git a/frontend/src/components/dirent-list-view/dirent-list-item.js b/frontend/src/components/dirent-list-view/dirent-list-item.js index 13e538bad2..32265ae802 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-item.js +++ b/frontend/src/components/dirent-list-view/dirent-list-item.js @@ -13,6 +13,7 @@ import ZipDownloadDialog from '../dialog/zip-download-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import ShareDialog from '../dialog/share-dialog'; +import DirentRightMenu from './dirent-right-menu'; import '../../css/dirent-list-item.css'; @@ -39,6 +40,8 @@ const propTypes = { isAdmin: PropTypes.bool.isRequired, repoEncrypted: PropTypes.bool.isRequired, isGroupOwnedRepo: PropTypes.bool.isRequired, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class DirentListItem extends React.Component { @@ -57,10 +60,70 @@ class DirentListItem extends React.Component { isShowTagTooltip: false, isDragTipShow: false, isDropTipshow: false, + enterItemData: '', + enterItemIndex: -1, + contextmenuItemData: {}, + contextmenuItemIndex: -1, + isItemContextMenuShow: false, }; this.zipToken = null; } + componentWillReceiveProps(nextProp) { + if (nextProp.appMenuType === 'list_view_contextmenu' || nextProp.appMenuType === 'item_contextmenu') { + this.setState({ + highlight: false, + isOperationShow: false, + }) + } + } + + componentDidUpdate() { + this.itemRegisterHandlers(); + } + + componentWillUnmount() { + this.itemUnregisterHandlers(); + } + + itemUnregisterHandlers = () => { + let itemTbody = document.querySelector('tbody'); + itemTbody.removeEventListener('contextmenu', this.itemRightContextMenu); + } + + itemRegisterHandlers = () => { + let itemTbody = document.querySelector('tbody'); + if (itemTbody) { + itemTbody.addEventListener('contextmenu', this.itemRightContextMenu); + } + } + + itemRightContextMenu = (e) =>{ + e.preventDefault(); + e.stopPropagation(); + + this.props.switchAnotherMenuToShow('item_contextmenu'); + this.setState({ + isItemContextMenuShow: false, + itemMousePosition: {clientX: e.clientX, clientY: e.clientY}, + contextmenuItemData: this.state.enterItemData, + contextmenuItemIndex: this.state.enterItemIndex, + }) + setTimeout(() => { + this.setState({ + isItemContextMenuShow: true, + }) + },40) + } + + closeRightMenu = () => { + this.setState({ + isItemContextMenuShow: false, + }); + this.onUnfreezedItem(); + this.props.switchAnotherMenuToShow('item_op_menu'); + } + //UI Interactive onMouseEnter = () => { if (!this.props.isItemFreezed) { @@ -69,7 +132,11 @@ class DirentListItem extends React.Component { isOperationShow: true, }); } - this.setState({isDragTipShow: true}); + this.setState({ + isDragTipShow: true, + enterItemData: this.props.dirent, + enterItemIndex: this.props.itemIndex, + }); } onMouseOver = () => { @@ -79,7 +146,10 @@ class DirentListItem extends React.Component { isOperationShow: true, }); } - this.setState({isDragTipShow: true}); + this.setState({ + isDragTipShow: true, + enterItemData: this.props.dirent, + enterItemIndex: this.props.itemIndex}); } onMouseLeave = () => { @@ -89,7 +159,11 @@ class DirentListItem extends React.Component { isOperationShow: false, }); } - this.setState({isDragTipShow: false}); + this.setState({ + isDragTipShow: false, + enterItemData: '', + enterItemIndex: -1, + }); } onUnfreezedItem = () => { @@ -209,7 +283,7 @@ class DirentListItem extends React.Component { onRenameCancel = () => { this.setState({isRenameing: false}); - this.props.onUnfreezedItem(); + this.onUnfreezedItem(); } onItemMoveToggle = () => { @@ -484,11 +558,29 @@ class DirentListItem extends React.Component { isRepoOwner={this.props.isRepoOwner} onFreezedItem={this.props.onFreezedItem} onUnfreezedItem={this.onUnfreezedItem} + appMenuType={this.props.appMenuType} /> } + {this.state.isItemContextMenuShow && this.state.contextmenuItemIndex === this.props.itemIndex && this.props.appMenuType === 'item_contextmenu' && + + } {dirent.size && dirent.size} {dirent.mtime_relative} diff --git a/frontend/src/components/dirent-list-view/dirent-list-view.js b/frontend/src/components/dirent-list-view/dirent-list-view.js index 31dc7be7cf..1cc815f8e2 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-view.js +++ b/frontend/src/components/dirent-list-view/dirent-list-view.js @@ -34,6 +34,8 @@ const propTypes = { onDirentClick: PropTypes.func.isRequired, onItemDetails: PropTypes.func.isRequired, updateDirent: PropTypes.func.isRequired, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class DirentListView extends React.Component { @@ -48,7 +50,7 @@ class DirentListView extends React.Component { imageIndex: 0, isCreateFileDialogShow: false, - fileType: '' + fileType: '', }; this.isRepoOwner = props.currentRepoInfo.owner_email === username; @@ -56,6 +58,23 @@ class DirentListView extends React.Component { this.repoEncrypted = props.currentRepoInfo.encrypted; } + componentWillReceiveProps(nextProps) { + if (nextProps.appMenuType === 'item_op_menu' || nextProps.appMenuType === 'tree_contextmenu') { + this.setState({isItemFreezed: false}); + } else { + this.setState({isItemFreezed: true}); + } + } + + componentDidUpdate() { + let thead = document.querySelector('thead'); + if (thead) { + thead.addEventListener('contextmenu', (e) => { + e.stopPropagation(); + }) + } + } + onFreezedItem = () => { this.setState({isItemFreezed: true}); } @@ -254,7 +273,7 @@ class DirentListView extends React.Component { - @@ -296,6 +315,9 @@ class DirentListView extends React.Component { onDirentClick={this.props.onDirentClick} onItemDetails={this.onItemDetails} showImagePopup={this.showImagePopup} + switchAnotherMenuToShow={this.props.switchAnotherMenuToShow} + appMenuType={this.props.appMenuType} + itemIndex={index} /> ); }) diff --git a/frontend/src/components/dirent-list-view/dirent-menu.js b/frontend/src/components/dirent-list-view/dirent-menu.js index 3c2f06e7ae..8296cdfcb4 100644 --- a/frontend/src/components/dirent-list-view/dirent-menu.js +++ b/frontend/src/components/dirent-list-view/dirent-menu.js @@ -10,6 +10,7 @@ const propTypes = { onMenuItemClick: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired, onUnfreezedItem: PropTypes.func.isRequired, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class DirentMenu extends React.Component { @@ -26,6 +27,12 @@ class DirentMenu extends React.Component { this.menuList = this.calculateMenuList(); } + componentWillReceiveProps(nextProp) { + if (nextProp.appMenuType === 'list_view_contextmenu' || nextProp.appMenuType === 'item_contextmenu') { + this.setState({isItemMenuShow: false}); + } + } + calculateMenuList() { let { currentRepoInfo, dirent, isRepoOwner } = this.props; diff --git a/frontend/src/components/dirent-list-view/dirent-right-menu.js b/frontend/src/components/dirent-list-view/dirent-right-menu.js new file mode 100644 index 0000000000..1afeaadd08 --- /dev/null +++ b/frontend/src/components/dirent-list-view/dirent-right-menu.js @@ -0,0 +1,291 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { gettext, isPro, enableFileComment, fileAuditEnabled, folderPermEnabled } from '../../utils/constants'; + +import '../../css/tree-view-contextmenu.css' + +const propTypes = { + dirent: PropTypes.object, + mousePosition: PropTypes.object, + isRepoOwner: PropTypes.bool, + currentRepoInfo: PropTypes.object, + onMenuItemClick: PropTypes.func, + onItemDownload: PropTypes.func, + onItemShare: PropTypes.func, + onItemDelete: PropTypes.func, + itemRegisterHandlers: PropTypes.func, + itemUnregisterHandlers: PropTypes.func, + closeRightMenu: PropTypes.func, + onCreateFolderToggle: PropTypes.func, + onCreateFileToggle: PropTypes.func, +}; + +class DirentRightMenu extends React.Component { + + constructor(props) { + super(props); + this.state = { + isItemMenuShow: false, + menuList: [], + }; + } + + componentDidMount() { + let menuList = this.caculateMenuList(); + this.setState({menuList: menuList}); + } + + componentDidUpdate() { + this.calculateMenuDistance(); + } + + componentWillUnmount() { + document.removeEventListener('click', this.listenClick); + document.removeEventListener('mousemove', this.handleContextMenu); + } + + caculateMenuList() { + if (!this.props.dirent) { + let menuList = ['New Folder', 'New File']; + return menuList; + } + + let { currentRepoInfo, dirent, isRepoOwner, showShare } = this.props; + + let type = dirent.type ? dirent.type : ''; + let permission = dirent.permission ? dirent.permission : ''; + let can_set_folder_perm = folderPermEnabled && ((isRepoOwner && currentRepoInfo.has_been_shared_out) || currentRepoInfo.is_admin); + if (type === 'dir' && permission === 'rw') { + let subscriptList = showShare ? ['Share', 'Download', 'Delete'] : ['Download', 'Delete']; + let menuList = []; + if (can_set_folder_perm) { + menuList = [...subscriptList, 'Rename', 'Move', 'Copy', 'Permission', 'Details', 'Open via Client']; + } else { + menuList = [...subscriptList, 'Rename', 'Move', 'Copy', 'Details', 'Open via Client']; + } + return menuList; + } + + if (type === 'dir' && permission === 'r') { + let menuList = showShare ? ['Share', 'Download', 'Delete', 'Copy', 'Details'] : ['Download', 'Delete', 'Details']; + return menuList; + } + + if (type === 'file' && permission === 'rw') { + let menuList = showShare ? ['Share', 'Download', 'Delete'] : ['Download', 'Delete']; + + if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) { + menuList.push('Rename'); + menuList.push('Move'); + } + menuList.push('Copy'); + if (isPro) { + if (dirent.is_locked) { + if (dirent.locked_by_me || (dirent.lock_owner === 'OnlineOffice' && permission === 'rw')) { + menuList.push('Unlock'); + } + } else { + menuList.push('Lock'); + } + } + if (enableFileComment) { + menuList.push('Comment'); + } + menuList.push('History'); + if (fileAuditEnabled) { + menuList.push('Access Log'); + } + menuList.push('Details'); + menuList.push('Open via Client'); + return menuList; + } + + if (type === 'file' && permission === 'r') { + let menuList = showShare ? ['Share', 'Download', 'Delete'] : ['Download', 'Delete']; + if (!currentRepoInfo.encrypted) { + menuList.push('Copy'); + } + if (enableFileComment) { + menuList.push('Comment'); + } + menuList.push('History'); + menuList.push('Details'); + return menuList; + } + } + + calculateMenuDistance = () => { + let { mousePosition } = this.props; + let rightTreeMenu = document.querySelector('.right-tree-menu'); + let rightTreeMenuHeight = rightTreeMenu.offsetHeight; + let rightTreeMenuWidth = rightTreeMenu.offsetWidth; + + if (mousePosition.clientY + rightTreeMenuHeight > document.body.clientHeight) { + rightTreeMenu.style.top = mousePosition.clientY - rightTreeMenuHeight + 'px'; + } else { + rightTreeMenu.style.top = mousePosition.clientY + 'px'; + } + + if (mousePosition.clientX + rightTreeMenuWidth > document.body.clientWidth) { + rightTreeMenu.style.left = mousePosition.clientX - rightTreeMenuWidth + 'px'; + } else { + rightTreeMenu.style.left = mousePosition.clientX + 'px'; + } + + document.addEventListener('click', this.listenClick); + document.addEventListener('mousemove', this.handleContextMenu); + } + + translateMenuItem = (menuItem) => { + let translateResult = ''; + switch(menuItem) { + case 'New Folder': + translateResult = gettext('New Folder'); + break; + case 'Share': + translateResult = gettext('Share'); + break; + case 'Download': + translateResult = gettext('Download'); + break; + case 'New File': + translateResult = gettext('New File'); + break; + case 'Rename': + translateResult = gettext('Rename'); + break; + case 'Copy': + translateResult = gettext('Copy'); + break; + case 'Move': + translateResult = gettext('Move'); + break; + case 'Delete': + translateResult = gettext('Delete'); + break; + case 'Details': + translateResult = gettext('Details'); + break; + case 'Unlock': + translateResult = gettext('Unlock'); + break; + case 'Lock': + translateResult = gettext('Lock'); + break; + case 'History': + translateResult = gettext('History'); + break; + case 'Open via Client': + translateResult = gettext('Open via Client'); + break; + default: + break; + } + return translateResult; + } + + handleContextMenu = (e) => { + let { mousePosition } = this.props; + let rightTreeMenu = document.querySelector('.right-tree-menu'); + let rightTreeMenuHeight = rightTreeMenu.offsetHeight; + let rightTreeMenuWidth = rightTreeMenu.offsetWidth; + + rightTreeMenu.addEventListener('contextmenu', (e) => { + e.stopPropagation(); + }) + + if (mousePosition.clientY + rightTreeMenuHeight > document.body.clientHeight) { + if (mousePosition.clientX + rightTreeMenuWidth > document.body.clientWidth) { + if ((e.clientX >= (mousePosition.clientX - rightTreeMenuWidth)) && (e.clientX <= mousePosition.clientX) && (e.clientY <= mousePosition.clientY) && (e.clientY >= (mousePosition.clientY - rightTreeMenuHeight))) { + this.props.itemUnregisterHandlers(); + } else { + this.props.itemRegisterHandlers(); + } + } else { + if ((e.clientX >= mousePosition.clientX) && (e.clientX <= (mousePosition.clientX + rightTreeMenuWidth)) && (e.clientY <= mousePosition.clientY) && (e.clientY >= (mousePosition.clientY - rightTreeMenuHeight))) { + this.props.itemUnregisterHandlers(); + } else { + this.props.itemRegisterHandlers(); + } + } + } else { + if (mousePosition.clientX + rightTreeMenuWidth > document.body.clientWidth) { + if ((e.clientX >= (mousePosition.clientX - rightTreeMenuWidth)) && (e.clientX <= mousePosition.clientX) && (e.clientY >= mousePosition.clientY) && (e.clientY <= (mousePosition.clientY + rightTreeMenuHeight))) { + this.props.itemUnregisterHandlers(); + } else { + this.props.itemRegisterHandlers(); + } + } else { + if ((e.clientX >= mousePosition.clientX) && (e.clientX <= (mousePosition.clientX + rightTreeMenuWidth)) && (e.clientY >= mousePosition.clientY) && (e.clientY <= (mousePosition.clientY + rightTreeMenuHeight))) { + this.props.itemUnregisterHandlers(); + } else { + this.props.itemRegisterHandlers(); + } + } + } + } + + listenClick = (e) => { + let { mousePosition } = this.props; + let rightTreeMenu = document.querySelector('.right-tree-menu'); + let rightTreeMenuHeight = rightTreeMenu.offsetHeight; + let rightTreeMenuWidth = rightTreeMenu.offsetWidth; + + if (mousePosition.clientX + rightTreeMenuWidth > document.body.clientWidth) { + if (e.clientX <= (mousePosition.clientX - rightTreeMenuWidth) || e.clientX >= mousePosition.clientX) { + this.props.closeRightMenu(); + } + } else { + if (e.clientX <= mousePosition.clientX || e.clientX >= (mousePosition.clientX + rightTreeMenuWidth)) { + this.props.closeRightMenu(); + } + } + + if (mousePosition.clientY + rightTreeMenuHeight > document.body.clientHeight) { + if ((e.clientY <= (mousePosition.clientY - rightTreeMenuHeight)) || e.clientY >= mousePosition.clientY) { + this.props.closeRightMenu(); + } + } else { + if ((e.clientY <= mousePosition.clientY) || (e.clientY >= (mousePosition.clientY + rightTreeMenuHeight))) { + this.props.closeRightMenu(); + } + } + } + + onMenuItemClick = (event) => { + let operation = event.target.dataset.toggle; + if (operation === 'Share') { + this.props.onItemShare(event); + } else if (operation === 'Delete') { + this.props.onItemDelete(event); + } else if (operation === 'Download') { + this.props.onItemDownload(event); + } else if (operation === 'New Folder') { + this.props.onCreateFolderToggle() + } else if (operation === 'New File') { + this.props.onCreateFileToggle(); + } else { + this.props.onMenuItemClick(operation); + } + this.props.closeRightMenu(); + if(this.props.onUnfreezedItem){ + this.props.onUnfreezedItem(); + } + } + + render() { + return ( +
+ {this.state.menuList.map((menuItem, index) => { + return ( + + ); + })} +
+ ); + } +} + +DirentRightMenu.propTypes = propTypes; + +export default DirentRightMenu; diff --git a/frontend/src/components/tree-view/tree-node-menu.js b/frontend/src/components/tree-view/tree-node-menu.js index d165bdfd01..337b7810c6 100644 --- a/frontend/src/components/tree-view/tree-node-menu.js +++ b/frontend/src/components/tree-view/tree-node-menu.js @@ -10,6 +10,7 @@ const propTypes = { onUnFreezedItem: PropTypes.func.isRequired, registerHandlers: PropTypes.func, unregisterHandlers: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; class TreeNodeMenu extends React.Component { @@ -27,6 +28,13 @@ class TreeNodeMenu extends React.Component { this.setState({menuList: menuList}); } + componentWillReceiveProps(nextProps) { + if (nextProps.appMenuType !== 'item_op_menu') { + this.setState({isItemMenuShow: false}); + this.props.onUnFreezedItem(); + } + } + caculateMenuList() { let { node } = this.props; let menuList = []; @@ -93,8 +101,6 @@ class TreeNodeMenu extends React.Component { } render() { - this.state.isItemMenuShow ? this.props.unregisterHandlers() : this.props.registerHandlers() - return ( { if (!this.props.isItemFreezed) { this.setState({ @@ -163,6 +173,7 @@ class TreeNodeView extends React.Component { onNodeDrop={this.props.onNodeDrop} onNodeDragEnter={this.props.onNodeDragEnter} onNodeDragLeave={this.props.onNodeDragLeave} + appMenuType={this.props.appMenuType} /> ); })} @@ -203,6 +214,7 @@ class TreeNodeView extends React.Component { onFreezedItem={this.props.onFreezedItem} registerHandlers={this.props.registerHandlers} unregisterHandlers={this.props.unregisterHandlers} + appMenuType={this.props.appMenuType} /> )} diff --git a/frontend/src/components/tree-view/tree-view.js b/frontend/src/components/tree-view/tree-view.js index 687905e8ae..316cbdc877 100644 --- a/frontend/src/components/tree-view/tree-view.js +++ b/frontend/src/components/tree-view/tree-view.js @@ -15,6 +15,8 @@ const propTypes = { onNodeCollapse: PropTypes.func.isRequired, onItemMove: PropTypes.func, currentRepoInfo: PropTypes.object, + switchAnotherMenuToShow: PropTypes.func, + appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']), }; const PADDING_LEFT = 20; @@ -36,6 +38,10 @@ class TreeView extends React.Component { this.registerHandlers(); } + componentDidUpdate() { + this.registerHandlers(); + } + componentWillUnmount() { this.unregisterHandlers(); } @@ -100,6 +106,7 @@ class TreeView extends React.Component { onFreezedItem = () => { this.setState({isItemFreezed: true}); + this.props.switchAnotherMenuToShow('item_op_menu'); } onUnFreezedItem = () => { @@ -108,16 +115,18 @@ class TreeView extends React.Component { contextMenu = (e) => { e.preventDefault(); + + this.props.switchAnotherMenuToShow('tree_contextmenu'); + this.setState({ isRightMenuShow:false, - }); - setTimeout(() => { + }, () => { this.setState({ - isRightMenuShow:true, - fileData:this.state.nodeData, + isRightMenuShow: true, + fileData: this.state.nodeData, mousePosition: {clientX: e.clientX, clientY: e.clientY} }) - },40) + }) } unregisterHandlers = () => { @@ -140,6 +149,7 @@ class TreeView extends React.Component { this.setState({ isRightMenuShow:false, }) + this.onUnFreezedItem(); } onMenuItemClick = (operation, node) => { @@ -170,8 +180,9 @@ class TreeView extends React.Component { onNodeDrop={this.onNodeDrop} onNodeDragEnter={this.onNodeDragEnter} onNodeDragLeave={this.onNodeDragLeave} + appMenuType={this.props.appMenuType} /> - {this.state.isRightMenuShow && ( + {this.state.isRightMenuShow && this.props.appMenuType === 'tree_contextmenu' && ( {gettext('Folder does not exist.')}); @@ -117,6 +118,25 @@ class LibContentContainer extends React.Component { this.props.closeDirentDetail(); } + switchAnotherMenuToShow = (type) => { + switch(type) { + case 'list_view_contextmenu': + this.setState({appMenuType: 'list_view_contextmenu'}); + break; + case 'item_contextmenu': + this.setState({appMenuType: 'item_contextmenu'}); + break; + case 'tree_contextmenu': + this.setState({appMenuType: 'tree_contextmenu'}); + break; + case 'item_op_menu': + this.setState({appMenuType: 'item_op_menu'}); + break; + default: + break; + } + } + componentWillReceiveProps (nextProps) { if (nextProps.isDirentDetailShow) { this.setState({ @@ -190,6 +210,9 @@ class LibContentContainer extends React.Component { updateDirent={this.props.updateDirent} isAllItemSelected={this.props.isAllDirentSelected} onAllItemSelected={this.props.onAllDirentSelected} + appMenuType={this.state.appMenuType} + switchAnotherMenuToShow={this.switchAnotherMenuToShow} + onAddFolder={this.props.onAddFolder} /> )} {this.props.currentMode === 'grid' && ( @@ -248,6 +271,9 @@ class LibContentContainer extends React.Component { updateDirent={this.props.updateDirent} isAllItemSelected={this.props.isAllDirentSelected} onAllItemSelected={this.props.onAllDirentSelected} + appMenuType={this.state.appMenuType} + switchAnotherMenuToShow={this.switchAnotherMenuToShow} + onAddFolder={this.props.onAddFolder} /> )}
+ {/*icon */}