mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 15:38:15 +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:
@@ -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}
|
||||
/>)
|
||||
}
|
||||
</div>
|
||||
|
@@ -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}
|
||||
/>
|
||||
<div className="dir-content-resize" onMouseDown={this.onResizeMouseDown}></div>
|
||||
<div className="dir-content-main" style={{userSelect: select, flex: mainFlex}}>
|
||||
@@ -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}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -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,10 +35,95 @@ 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 (
|
||||
<Fragment>
|
||||
@@ -48,6 +137,7 @@ class DirListView extends React.Component {
|
||||
updateUsedRepoTags={this.props.updateUsedRepoTags}
|
||||
/>
|
||||
)}
|
||||
<div className="table-container">
|
||||
<DirentListView
|
||||
path={this.props.path}
|
||||
currentRepoInfo={this.props.currentRepoInfo}
|
||||
@@ -71,7 +161,41 @@ class DirListView extends React.Component {
|
||||
updateDirent={this.props.updateDirent}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
@@ -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}
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</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 className="file-size">{dirent.size && dirent.size}</td>
|
||||
<td className="last-update">{dirent.mtime_relative}</td>
|
||||
|
@@ -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});
|
||||
}
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
})
|
||||
|
@@ -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;
|
||||
|
||||
|
291
frontend/src/components/dirent-list-view/dirent-right-menu.js
Normal file
291
frontend/src/components/dirent-list-view/dirent-right-menu.js
Normal 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;
|
@@ -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 (
|
||||
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
|
||||
<DropdownToggle
|
||||
|
@@ -21,6 +21,7 @@ const propTypes = {
|
||||
unregisterHandlers: PropTypes.func,
|
||||
onNodeDragMove: PropTypes.func,
|
||||
onNodeDrop: PropTypes.func,
|
||||
appMenuType: PropTypes.oneOf(['list_view_contextmenu', 'item_contextmenu', 'tree_contextmenu', 'item_op_menu']),
|
||||
};
|
||||
|
||||
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 = () => {
|
||||
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}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -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,
|
||||
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' && (
|
||||
<TreeViewContextMenu
|
||||
node={this.state.fileData}
|
||||
onMenuItemClick={this.onMenuItemClick}
|
||||
|
@@ -110,6 +110,12 @@
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cur-view-content .article {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.right-tree-menu {
|
||||
position: absolute;
|
||||
left: 15rem;
|
||||
top: 20rem;
|
||||
left: -1000rem;
|
||||
top: -1000rem;
|
||||
z-index: 1000;
|
||||
float: left;
|
||||
min-width: 10rem;
|
||||
|
@@ -84,6 +84,7 @@ class LibContentContainer extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentDirent: null,
|
||||
appMenuType: 'item_op_menu',
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
|
Reference in New Issue
Block a user