1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-01 23:20:51 +00:00

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
This commit is contained in:
zxj96
2019-04-08 11:35:46 +08:00
committed by Daniel Pan
parent 85195d70a9
commit 07d596f620
13 changed files with 648 additions and 40 deletions

View File

@@ -32,6 +32,8 @@ const propTypes = {
navRate: PropTypes.number, navRate: PropTypes.number,
inResizing: PropTypes.bool.isRequired, inResizing: PropTypes.bool.isRequired,
currentRepoInfo: PropTypes.object.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 { class DirColumnNav extends React.Component {
@@ -282,6 +284,8 @@ class DirColumnNav extends React.Component {
onUnFreezedItem={this.onUnFreezedItem} onUnFreezedItem={this.onUnFreezedItem}
onItemMove={this.props.onItemMove} onItemMove={this.props.onItemMove}
currentRepoInfo={this.props.currentRepoInfo} currentRepoInfo={this.props.currentRepoInfo}
switchAnotherMenuToShow={this.props.switchAnotherMenuToShow}
appMenuType={this.props.appMenuType}
/>) />)
} }
</div> </div>

View File

@@ -63,6 +63,8 @@ const propTypes = {
onDirentClick: PropTypes.func.isRequired, onDirentClick: PropTypes.func.isRequired,
isAllItemSelected: PropTypes.bool.isRequired, isAllItemSelected: PropTypes.bool.isRequired,
onAllItemSelected: PropTypes.func.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 { class DirColumnView extends React.Component {
@@ -165,6 +167,8 @@ class DirColumnView extends React.Component {
currentRepoInfo={this.props.currentRepoInfo} currentRepoInfo={this.props.currentRepoInfo}
onItemMove={this.props.onItemMove} onItemMove={this.props.onItemMove}
onItemCopy={this.props.onItemCopy} onItemCopy={this.props.onItemCopy}
switchAnotherMenuToShow={this.props.switchAnotherMenuToShow}
appMenuType={this.props.appMenuType}
/> />
<div className="dir-content-resize" onMouseDown={this.onResizeMouseDown}></div> <div className="dir-content-resize" onMouseDown={this.onResizeMouseDown}></div>
<div className="dir-content-main" style={{userSelect: select, flex: mainFlex}}> <div className="dir-content-main" style={{userSelect: select, flex: mainFlex}}>
@@ -213,6 +217,9 @@ class DirColumnView extends React.Component {
updateDirent={this.props.updateDirent} updateDirent={this.props.updateDirent}
isAllItemSelected={this.props.isAllItemSelected} isAllItemSelected={this.props.isAllItemSelected}
onAllItemSelected={this.props.onAllItemSelected} onAllItemSelected={this.props.onAllItemSelected}
switchAnotherMenuToShow={this.props.switchAnotherMenuToShow}
appMenuType={this.props.appMenuType}
onAddFolder={this.props.onAddFolder}
/> />
)} )}
</div> </div>

View File

@@ -1,7 +1,11 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import RepoInfoBar from '../../components/repo-info-bar'; import RepoInfoBar from '../../components/repo-info-bar';
import ModalPortal from '../modal-portal';
import DirentListView from '../../components/dirent-list-view/dirent-list-view'; 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 = { const propTypes = {
path: PropTypes.string.isRequired, path: PropTypes.string.isRequired,
@@ -31,9 +35,94 @@ const propTypes = {
updateDirent: PropTypes.func.isRequired, updateDirent: PropTypes.func.isRequired,
isAllItemSelected: PropTypes.bool.isRequired, isAllItemSelected: PropTypes.bool.isRequired,
onAllItemSelected: PropTypes.func.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 { 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() { render() {
return ( return (
@@ -48,30 +137,65 @@ class DirListView extends React.Component {
updateUsedRepoTags={this.props.updateUsedRepoTags} updateUsedRepoTags={this.props.updateUsedRepoTags}
/> />
)} )}
<DirentListView <div className="table-container">
path={this.props.path} <DirentListView
currentRepoInfo={this.props.currentRepoInfo} path={this.props.path}
repoID={this.props.repoID} currentRepoInfo={this.props.currentRepoInfo}
isGroupOwnedRepo={this.props.isGroupOwnedRepo} repoID={this.props.repoID}
enableDirPrivateShare={this.props.enableDirPrivateShare} isGroupOwnedRepo={this.props.isGroupOwnedRepo}
direntList={this.props.direntList} enableDirPrivateShare={this.props.enableDirPrivateShare}
sortBy={this.props.sortBy} direntList={this.props.direntList}
sortOrder={this.props.sortOrder} sortBy={this.props.sortBy}
sortItems={this.props.sortItems} sortOrder={this.props.sortOrder}
onAddFile={this.props.onAddFile} sortItems={this.props.sortItems}
onItemClick={this.props.onItemClick} onAddFile={this.props.onAddFile}
onItemSelected={this.props.onItemSelected} onItemClick={this.props.onItemClick}
onItemDelete={this.props.onItemDelete} onItemSelected={this.props.onItemSelected}
onItemRename={this.props.onItemRename} onItemDelete={this.props.onItemDelete}
onItemMove={this.props.onItemMove} onItemRename={this.props.onItemRename}
onItemCopy={this.props.onItemCopy} onItemMove={this.props.onItemMove}
onDirentClick={this.props.onDirentClick} onItemCopy={this.props.onItemCopy}
onItemDetails={this.props.onItemDetails} onDirentClick={this.props.onDirentClick}
isDirentListLoading={this.props.isDirentListLoading} onItemDetails={this.props.onItemDetails}
updateDirent={this.props.updateDirent} isDirentListLoading={this.props.isDirentListLoading}
isAllItemSelected={this.props.isAllItemSelected} updateDirent={this.props.updateDirent}
onAllItemSelected={this.props.onAllItemSelected} isAllItemSelected={this.props.isAllItemSelected}
/> onAllItemSelected={this.props.onAllItemSelected}
switchAnotherMenuToShow={this.props.switchAnotherMenuToShow}
appMenuType={this.props.appMenuType}
/>
</div>
{this.state.isContainerContextmenuShow && this.props.appMenuType === 'list_view_contextmenu' && (
<DirentListMenu
mousePosition={this.state.itemMousePosition}
itemUnregisterHandlers={this.unregisterTableContainerContextmenuHandler}
itemRegisterHandlers={this.registerTableContainerContextmenuHandler}
closeRightMenu={this.closeTableContainerRightMenu}
onCreateFolderToggle={this.onCreateFolderToggle}
onCreateFileToggle={this.onCreateFileToggle}
/>
)}
{this.state.isCreateFolderDialogShow && (
<ModalPortal>
<CreateFolder
parentPath={this.props.path}
onAddFolder={this.onAddFolder}
checkDuplicatedName={this.checkDuplicatedName}
addFolderCancel={this.onCreateFolderToggle}
/>
</ModalPortal>
)}
{this.state.isCreateFileDialogShow && (
<ModalPortal>
<CreateFile
parentPath={this.props.path}
fileType={this.state.fileType}
onAddFile={this.onAddFile}
checkDuplicatedName={this.checkDuplicatedName}
addFileCancel={this.onCreateFileToggle}
/>
</ModalPortal>
)}
</Fragment> </Fragment>
); );
} }

View File

@@ -13,6 +13,7 @@ import ZipDownloadDialog from '../dialog/zip-download-dialog';
import MoveDirentDialog from '../dialog/move-dirent-dialog'; import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog'; import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ShareDialog from '../dialog/share-dialog'; import ShareDialog from '../dialog/share-dialog';
import DirentRightMenu from './dirent-right-menu';
import '../../css/dirent-list-item.css'; import '../../css/dirent-list-item.css';
@@ -39,6 +40,8 @@ const propTypes = {
isAdmin: PropTypes.bool.isRequired, isAdmin: PropTypes.bool.isRequired,
repoEncrypted: PropTypes.bool.isRequired, repoEncrypted: PropTypes.bool.isRequired,
isGroupOwnedRepo: 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 { class DirentListItem extends React.Component {
@@ -57,10 +60,70 @@ class DirentListItem extends React.Component {
isShowTagTooltip: false, isShowTagTooltip: false,
isDragTipShow: false, isDragTipShow: false,
isDropTipshow: false, isDropTipshow: false,
enterItemData: '',
enterItemIndex: -1,
contextmenuItemData: {},
contextmenuItemIndex: -1,
isItemContextMenuShow: false,
}; };
this.zipToken = null; 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 //UI Interactive
onMouseEnter = () => { onMouseEnter = () => {
if (!this.props.isItemFreezed) { if (!this.props.isItemFreezed) {
@@ -69,7 +132,11 @@ class DirentListItem extends React.Component {
isOperationShow: true, isOperationShow: true,
}); });
} }
this.setState({isDragTipShow: true}); this.setState({
isDragTipShow: true,
enterItemData: this.props.dirent,
enterItemIndex: this.props.itemIndex,
});
} }
onMouseOver = () => { onMouseOver = () => {
@@ -79,7 +146,10 @@ class DirentListItem extends React.Component {
isOperationShow: true, isOperationShow: true,
}); });
} }
this.setState({isDragTipShow: true}); this.setState({
isDragTipShow: true,
enterItemData: this.props.dirent,
enterItemIndex: this.props.itemIndex});
} }
onMouseLeave = () => { onMouseLeave = () => {
@@ -89,7 +159,11 @@ class DirentListItem extends React.Component {
isOperationShow: false, isOperationShow: false,
}); });
} }
this.setState({isDragTipShow: false}); this.setState({
isDragTipShow: false,
enterItemData: '',
enterItemIndex: -1,
});
} }
onUnfreezedItem = () => { onUnfreezedItem = () => {
@@ -209,7 +283,7 @@ class DirentListItem extends React.Component {
onRenameCancel = () => { onRenameCancel = () => {
this.setState({isRenameing: false}); this.setState({isRenameing: false});
this.props.onUnfreezedItem(); this.onUnfreezedItem();
} }
onItemMoveToggle = () => { onItemMoveToggle = () => {
@@ -484,11 +558,29 @@ class DirentListItem extends React.Component {
isRepoOwner={this.props.isRepoOwner} isRepoOwner={this.props.isRepoOwner}
onFreezedItem={this.props.onFreezedItem} onFreezedItem={this.props.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
appMenuType={this.props.appMenuType}
/> />
</li> </li>
</ul> </ul>
</div> </div>
} }
{this.state.isItemContextMenuShow && this.state.contextmenuItemIndex === this.props.itemIndex && this.props.appMenuType === 'item_contextmenu' &&
<DirentRightMenu
dirent={this.state.contextmenuItemData}
mousePosition={this.state.itemMousePosition}
isRepoOwner={this.props.isRepoOwner}
currentRepoInfo={this.props.currentRepoInfo}
onMenuItemClick={this.onMenuItemClick}
onItemDownload={this.onItemDownload}
onItemShare={this.onItemShare}
onItemDelete={this.onItemDelete}
itemRegisterHandlers={this.itemRegisterHandlers}
itemUnregisterHandlers={this.itemUnregisterHandlers}
closeRightMenu={this.closeRightMenu}
onUnfreezedItem={this.onUnfreezedItem}
showShare={showShare}
/>
}
</td> </td>
<td className="file-size">{dirent.size && dirent.size}</td> <td className="file-size">{dirent.size && dirent.size}</td>
<td className="last-update">{dirent.mtime_relative}</td> <td className="last-update">{dirent.mtime_relative}</td>

View File

@@ -34,6 +34,8 @@ const propTypes = {
onDirentClick: PropTypes.func.isRequired, onDirentClick: PropTypes.func.isRequired,
onItemDetails: PropTypes.func.isRequired, onItemDetails: PropTypes.func.isRequired,
updateDirent: 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 { class DirentListView extends React.Component {
@@ -48,7 +50,7 @@ class DirentListView extends React.Component {
imageIndex: 0, imageIndex: 0,
isCreateFileDialogShow: false, isCreateFileDialogShow: false,
fileType: '' fileType: '',
}; };
this.isRepoOwner = props.currentRepoInfo.owner_email === username; this.isRepoOwner = props.currentRepoInfo.owner_email === username;
@@ -56,6 +58,23 @@ class DirentListView extends React.Component {
this.repoEncrypted = props.currentRepoInfo.encrypted; 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 = () => { onFreezedItem = () => {
this.setState({isItemFreezed: true}); this.setState({isItemFreezed: true});
} }
@@ -254,7 +273,7 @@ class DirentListView extends React.Component {
<table> <table>
<thead> <thead>
<tr> <tr>
<th width="3%" className="pl10"> <th width="3%" className="pl10">
<input type="checkbox" className="vam" onChange={this.props.onAllItemSelected} checked={this.props.isAllItemSelected}/> <input type="checkbox" className="vam" onChange={this.props.onAllItemSelected} checked={this.props.isAllItemSelected}/>
</th> </th>
<th width="3%" className="pl10">{/*icon */}</th> <th width="3%" className="pl10">{/*icon */}</th>
@@ -296,6 +315,9 @@ class DirentListView extends React.Component {
onDirentClick={this.props.onDirentClick} onDirentClick={this.props.onDirentClick}
onItemDetails={this.onItemDetails} onItemDetails={this.onItemDetails}
showImagePopup={this.showImagePopup} showImagePopup={this.showImagePopup}
switchAnotherMenuToShow={this.props.switchAnotherMenuToShow}
appMenuType={this.props.appMenuType}
itemIndex={index}
/> />
); );
}) })

View File

@@ -10,6 +10,7 @@ const propTypes = {
onMenuItemClick: PropTypes.func.isRequired, onMenuItemClick: PropTypes.func.isRequired,
onFreezedItem: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired,
onUnfreezedItem: 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 { class DirentMenu extends React.Component {
@@ -26,6 +27,12 @@ class DirentMenu extends React.Component {
this.menuList = this.calculateMenuList(); this.menuList = this.calculateMenuList();
} }
componentWillReceiveProps(nextProp) {
if (nextProp.appMenuType === 'list_view_contextmenu' || nextProp.appMenuType === 'item_contextmenu') {
this.setState({isItemMenuShow: false});
}
}
calculateMenuList() { calculateMenuList() {
let { currentRepoInfo, dirent, isRepoOwner } = this.props; let { currentRepoInfo, dirent, isRepoOwner } = this.props;

View File

@@ -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 (
<div className='right-tree-menu'>
{this.state.menuList.map((menuItem, index) => {
return (
<button className='right-tree-item' key={index} data-toggle={menuItem} onClick={this.onMenuItemClick}>{this.translateMenuItem(menuItem)}</button>
);
})}
</div>
);
}
}
DirentRightMenu.propTypes = propTypes;
export default DirentRightMenu;

View File

@@ -10,6 +10,7 @@ const propTypes = {
onUnFreezedItem: PropTypes.func.isRequired, onUnFreezedItem: PropTypes.func.isRequired,
registerHandlers: PropTypes.func, registerHandlers: PropTypes.func,
unregisterHandlers: PropTypes.func, unregisterHandlers: PropTypes.func,
appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']),
}; };
class TreeNodeMenu extends React.Component { class TreeNodeMenu extends React.Component {
@@ -27,6 +28,13 @@ class TreeNodeMenu extends React.Component {
this.setState({menuList: menuList}); this.setState({menuList: menuList});
} }
componentWillReceiveProps(nextProps) {
if (nextProps.appMenuType !== 'item_op_menu') {
this.setState({isItemMenuShow: false});
this.props.onUnFreezedItem();
}
}
caculateMenuList() { caculateMenuList() {
let { node } = this.props; let { node } = this.props;
let menuList = []; let menuList = [];
@@ -93,8 +101,6 @@ class TreeNodeMenu extends React.Component {
} }
render() { render() {
this.state.isItemMenuShow ? this.props.unregisterHandlers() : this.props.registerHandlers()
return ( return (
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}> <Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
<DropdownToggle <DropdownToggle

View File

@@ -21,6 +21,7 @@ const propTypes = {
unregisterHandlers: PropTypes.func, unregisterHandlers: PropTypes.func,
onNodeDragMove: PropTypes.func, onNodeDragMove: PropTypes.func,
onNodeDrop: PropTypes.func, onNodeDrop: PropTypes.func,
appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']),
}; };
class TreeNodeView extends React.Component { class TreeNodeView extends React.Component {
@@ -34,6 +35,15 @@ class TreeNodeView extends React.Component {
}; };
} }
componentWillReceiveProps(nextProp) {
if (nextProp.appMenuType === 'list_view_contextmenu' && nextProp.appMenuType === 'item_contextmenu') {
this.setState({
isShowOperationMenu: false,
isHighlight: false,
})
}
}
onMouseEnter = () => { onMouseEnter = () => {
if (!this.props.isItemFreezed) { if (!this.props.isItemFreezed) {
this.setState({ this.setState({
@@ -163,6 +173,7 @@ class TreeNodeView extends React.Component {
onNodeDrop={this.props.onNodeDrop} onNodeDrop={this.props.onNodeDrop}
onNodeDragEnter={this.props.onNodeDragEnter} onNodeDragEnter={this.props.onNodeDragEnter}
onNodeDragLeave={this.props.onNodeDragLeave} onNodeDragLeave={this.props.onNodeDragLeave}
appMenuType={this.props.appMenuType}
/> />
); );
})} })}
@@ -203,6 +214,7 @@ class TreeNodeView extends React.Component {
onFreezedItem={this.props.onFreezedItem} onFreezedItem={this.props.onFreezedItem}
registerHandlers={this.props.registerHandlers} registerHandlers={this.props.registerHandlers}
unregisterHandlers={this.props.unregisterHandlers} unregisterHandlers={this.props.unregisterHandlers}
appMenuType={this.props.appMenuType}
/> />
)} )}
</div> </div>

View File

@@ -15,6 +15,8 @@ const propTypes = {
onNodeCollapse: PropTypes.func.isRequired, onNodeCollapse: PropTypes.func.isRequired,
onItemMove: PropTypes.func, onItemMove: PropTypes.func,
currentRepoInfo: PropTypes.object, currentRepoInfo: PropTypes.object,
switchAnotherMenuToShow: PropTypes.func,
appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']),
}; };
const PADDING_LEFT = 20; const PADDING_LEFT = 20;
@@ -36,6 +38,10 @@ class TreeView extends React.Component {
this.registerHandlers(); this.registerHandlers();
} }
componentDidUpdate() {
this.registerHandlers();
}
componentWillUnmount() { componentWillUnmount() {
this.unregisterHandlers(); this.unregisterHandlers();
} }
@@ -100,6 +106,7 @@ class TreeView extends React.Component {
onFreezedItem = () => { onFreezedItem = () => {
this.setState({isItemFreezed: true}); this.setState({isItemFreezed: true});
this.props.switchAnotherMenuToShow('item_op_menu');
} }
onUnFreezedItem = () => { onUnFreezedItem = () => {
@@ -108,16 +115,18 @@ class TreeView extends React.Component {
contextMenu = (e) => { contextMenu = (e) => {
e.preventDefault(); e.preventDefault();
this.props.switchAnotherMenuToShow('tree_contextmenu');
this.setState({ this.setState({
isRightMenuShow:false, isRightMenuShow:false,
}); }, () => {
setTimeout(() => {
this.setState({ this.setState({
isRightMenuShow:true, isRightMenuShow: true,
fileData:this.state.nodeData, fileData: this.state.nodeData,
mousePosition: {clientX: e.clientX, clientY: e.clientY} mousePosition: {clientX: e.clientX, clientY: e.clientY}
}) })
},40) })
} }
unregisterHandlers = () => { unregisterHandlers = () => {
@@ -140,6 +149,7 @@ class TreeView extends React.Component {
this.setState({ this.setState({
isRightMenuShow:false, isRightMenuShow:false,
}) })
this.onUnFreezedItem();
} }
onMenuItemClick = (operation, node) => { onMenuItemClick = (operation, node) => {
@@ -170,8 +180,9 @@ class TreeView extends React.Component {
onNodeDrop={this.onNodeDrop} onNodeDrop={this.onNodeDrop}
onNodeDragEnter={this.onNodeDragEnter} onNodeDragEnter={this.onNodeDragEnter}
onNodeDragLeave={this.onNodeDragLeave} onNodeDragLeave={this.onNodeDragLeave}
appMenuType={this.props.appMenuType}
/> />
{this.state.isRightMenuShow && ( {this.state.isRightMenuShow && this.props.appMenuType === 'tree_contextmenu' && (
<TreeViewContextMenu <TreeViewContextMenu
node={this.state.fileData} node={this.state.fileData}
onMenuItemClick={this.onMenuItemClick} onMenuItemClick={this.onMenuItemClick}

View File

@@ -110,6 +110,12 @@
flex: 1; flex: 1;
min-height: 0; min-height: 0;
overflow: auto; overflow: auto;
display: flex;
flex-direction: column;
}
.table-container {
flex: 1;
} }
.cur-view-content .article { .cur-view-content .article {

View File

@@ -1,7 +1,7 @@
.right-tree-menu { .right-tree-menu {
position: absolute; position: absolute;
left: 15rem; left: -1000rem;
top: 20rem; top: -1000rem;
z-index: 1000; z-index: 1000;
float: left; float: left;
min-width: 10rem; min-width: 10rem;

View File

@@ -84,6 +84,7 @@ class LibContentContainer extends React.Component {
super(props); super(props);
this.state = { this.state = {
currentDirent: null, currentDirent: null,
appMenuType: 'item_op_menu',
}; };
this.errMessage = (<div className="message err-tip">{gettext('Folder does not exist.')}</div>); this.errMessage = (<div className="message err-tip">{gettext('Folder does not exist.')}</div>);
@@ -117,6 +118,25 @@ class LibContentContainer extends React.Component {
this.props.closeDirentDetail(); 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) { componentWillReceiveProps (nextProps) {
if (nextProps.isDirentDetailShow) { if (nextProps.isDirentDetailShow) {
this.setState({ this.setState({
@@ -190,6 +210,9 @@ class LibContentContainer extends React.Component {
updateDirent={this.props.updateDirent} updateDirent={this.props.updateDirent}
isAllItemSelected={this.props.isAllDirentSelected} isAllItemSelected={this.props.isAllDirentSelected}
onAllItemSelected={this.props.onAllDirentSelected} onAllItemSelected={this.props.onAllDirentSelected}
appMenuType={this.state.appMenuType}
switchAnotherMenuToShow={this.switchAnotherMenuToShow}
onAddFolder={this.props.onAddFolder}
/> />
)} )}
{this.props.currentMode === 'grid' && ( {this.props.currentMode === 'grid' && (
@@ -248,6 +271,9 @@ class LibContentContainer extends React.Component {
updateDirent={this.props.updateDirent} updateDirent={this.props.updateDirent}
isAllItemSelected={this.props.isAllDirentSelected} isAllItemSelected={this.props.isAllDirentSelected}
onAllItemSelected={this.props.onAllDirentSelected} onAllItemSelected={this.props.onAllDirentSelected}
appMenuType={this.state.appMenuType}
switchAnotherMenuToShow={this.switchAnotherMenuToShow}
onAddFolder={this.props.onAddFolder}
/> />
)} )}
</Fragment> </Fragment>