1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-14 22:33:17 +00:00

Merge pull request #3338 from haiwen/menu-improve

Menu improve
This commit is contained in:
Daniel Pan
2019-04-22 15:21:01 +08:00
committed by GitHub
10 changed files with 259 additions and 511 deletions

View File

@@ -6,7 +6,7 @@ import { gettext, siteRoot, mediaUrl } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator';
import DirentMenu from './dirent-menu';
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
import Rename from '../rename';
import ModalPortal from '../modal-portal';
import MoveDirentDialog from '../dialog/move-dirent-dialog';
@@ -24,8 +24,8 @@ const propTypes = {
showShareBtn: PropTypes.bool.isRequired,
dirent: PropTypes.object.isRequired,
onItemClick: PropTypes.func.isRequired,
onFreezedItem: PropTypes.func.isRequired,
onUnfreezedItem: PropTypes.func.isRequired,
freezeItem: PropTypes.func.isRequired,
unfreezeItem: PropTypes.func.isRequired,
onItemRenameToggle: PropTypes.func.isRequired,
onItemSelected: PropTypes.func.isRequired,
onItemDelete: PropTypes.func.isRequired,
@@ -44,6 +44,7 @@ const propTypes = {
onItemContextMenu: PropTypes.func.isRequired,
selectedDirentList: PropTypes.array.isRequired,
activeDirent: PropTypes.object,
getDirentItemMenuList: PropTypes.func.isRequired,
};
class DirentListItem extends React.Component {
@@ -109,12 +110,12 @@ class DirentListItem extends React.Component {
this.setState({isDragTipShow: false});
}
onUnfreezedItem = () => {
unfreezeItem = () => {
this.setState({
highlight: false,
isOperationShow: false,
});
this.props.onUnfreezedItem();
this.props.unfreezeItem();
}
//buiness handler
@@ -247,7 +248,7 @@ class DirentListItem extends React.Component {
onRenameCancel = () => {
this.setState({isRenameing: false});
this.onUnfreezedItem();
this.unfreezeItem();
}
onItemMoveToggle = () => {
@@ -428,13 +429,14 @@ class DirentListItem extends React.Component {
<i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i>
</li>
<li className="operation-group-item">
<DirentMenu
dirent={this.props.dirent}
<ItemDropdownMenu
item={this.props.dirent}
toggleClass={'sf2-icon-caret-down'}
isHandleContextMenuEvent={true}
getMenuList={this.props.getDirentItemMenuList}
onMenuItemClick={this.onMenuItemClick}
currentRepoInfo={this.props.currentRepoInfo}
isRepoOwner={this.props.isRepoOwner}
onFreezedItem={this.props.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem}
unfreezeItem={this.unfreezeItem}
freezeItem={this.props.freezeItem}
/>
</li>
</ul>
@@ -457,13 +459,14 @@ class DirentListItem extends React.Component {
<i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i>
</li>
<li className="operation-group-item">
<DirentMenu
dirent={this.props.dirent}
<ItemDropdownMenu
item={this.props.dirent}
toggleClass={'sf2-icon-caret-down'}
isHandleContextMenuEvent={true}
getMenuList={this.props.getDirentItemMenuList}
onMenuItemClick={this.onMenuItemClick}
currentRepoInfo={this.props.currentRepoInfo}
isRepoOwner={this.props.isRepoOwner}
onFreezedItem={this.props.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem}
unfreezeItem={this.unfreezeItem}
freezeItem={this.props.freezeItem}
/>
</li>
</ul>

View File

@@ -78,11 +78,11 @@ class DirentListView extends React.Component {
this.zipToken = null;
}
onFreezedItem = () => {
freezeItem = () => {
this.setState({isItemFreezed: true});
}
onUnfreezedItem = () => {
unfreezeItem = () => {
this.setState({isItemFreezed: false});
}
@@ -100,7 +100,7 @@ class DirentListView extends React.Component {
}
onItemRenameToggle = () => {
this.onFreezedItem();
this.freezeItem();
}
onItemSelected = (dirent) => {
@@ -425,11 +425,11 @@ class DirentListView extends React.Component {
}
onShowMenu = (e) => {
this.onFreezedItem();
this.freezeItem();
}
onHideMenu = (e) => {
this.onUnfreezedItem();
this.unfreezeItem();
}
// contextmenu utils
@@ -575,8 +575,8 @@ class DirentListView extends React.Component {
onItemCopy={this.props.onItemCopy}
updateDirent={this.props.updateDirent}
isItemFreezed={this.state.isItemFreezed}
onFreezedItem={this.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem}
freezeItem={this.freezeItem}
unfreezeItem={this.unfreezeItem}
onDirentClick={this.onDirentClick}
showImagePopup={this.showImagePopup}
onItemMouseDown={this.onItemMouseDown}
@@ -584,6 +584,7 @@ class DirentListView extends React.Component {
selectedDirentList={this.props.selectedDirentList}
activeDirent={this.state.activeDirent}
onFileTagChanged={this.props.onFileTagChanged}
getDirentItemMenuList={this.getDirentItemMenuList}
/>
);
})}

View File

@@ -1,220 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import listener from '../context-menu/globalEventListener';
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
import { gettext, isPro, enableFileComment, fileAuditEnabled, folderPermEnabled } from '../../utils/constants';
const propTypes = {
dirent: PropTypes.object.isRequired,
currentRepoInfo: PropTypes.object.isRequired,
isRepoOwner: PropTypes.bool.isRequired,
onMenuItemClick: PropTypes.func.isRequired,
onFreezedItem: PropTypes.func.isRequired,
onUnfreezedItem: PropTypes.func.isRequired,
};
class DirentMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
isItemMenuShow: false,
menuList: [],
};
}
componentDidMount() {
this.listenerId = listener.register(this.onShowMenu, this.onHideMenu);
let { currentRepoInfo, dirent, isRepoOwner } = this.props;
let menuList = this.calculateMenuList(currentRepoInfo, dirent, isRepoOwner);
this.setState({menuList: menuList});
}
componentWillReceiveProps(nextProps) {
let { currentRepoInfo, dirent, isRepoOwner } = nextProps;
let menuList = this.calculateMenuList(currentRepoInfo, dirent, isRepoOwner);
this.setState({menuList: menuList});
}
componentWillUnmount () {
if (this.listenerId) {
listener.unregister(this.listenerId);
}
}
onShowMenu = () => {
// nothing todo
}
onHideMenu = () => {
if (this.state.isItemMenuShow) {
this.setState({isItemMenuShow: false});
this.props.onUnfreezedItem();
}
}
calculateMenuList(currentRepoInfo, dirent, isRepoOwner) {
let type = dirent.type;
let permission = dirent.permission;
let can_set_folder_perm = folderPermEnabled && ((isRepoOwner && currentRepoInfo.has_been_shared_out) || currentRepoInfo.is_admin);
if (type === 'dir' && permission === 'rw') {
let menuList = [];
if (can_set_folder_perm) {
menuList = ['Rename', 'Move', 'Copy', 'Divider', 'Permission', 'Divider', 'Open via Client'];
} else {
menuList = ['Rename', 'Move', 'Copy', 'Divider', 'Open via Client'];
}
return menuList;
}
if (type === 'dir' && permission === 'r') {
let menuList = currentRepoInfo.encrypted ? ['Copy'] : [];
return menuList;
}
if (type === 'file' && permission === 'rw') {
let menuList = [];
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
menuList.push('Rename');
menuList.push('Move');
}
menuList.push('Copy');
menuList.push('Tags');
if (isPro) {
if (dirent.is_locked) {
if (dirent.locked_by_me || (dirent.lock_owner === 'OnlineOffice' && permission === 'rw')) {
menuList.push('Unlock');
}
} else {
menuList.push('Lock');
}
}
menuList.push('Divider');
if (enableFileComment) {
menuList.push('Comment');
}
menuList.push('History');
if (fileAuditEnabled) {
menuList.push('Access Log');
}
menuList.push('Divider');
menuList.push('Open via Client');
return menuList;
}
if (type === 'file' && permission === 'r') {
let menuList = [];
if (!currentRepoInfo.encrypted) {
menuList.push('Copy');
}
if (enableFileComment) {
menuList.push('Comment');
}
menuList.push('History');
return menuList;
}
return [];
}
translateMenuItem = (menuItem) => {
let translateResult = '';
switch(menuItem) {
case 'Rename':
translateResult = gettext('Rename');
break;
case 'Move':
translateResult = gettext('Move');
break;
case 'Copy':
translateResult = gettext('Copy');
break;
case 'Tags':
translateResult = gettext('Tags');
break;
case 'Permission':
translateResult = gettext('Permission');
break;
case 'Unlock':
translateResult = gettext('Unlock');
break;
case 'Lock':
translateResult = gettext('Lock');
break;
case 'Comment':
translateResult = gettext('Comment');
break;
case 'History':
translateResult = gettext('History');
break;
case 'Access Log':
translateResult = gettext('Access Log');
break;
case 'Open via Client':
translateResult = gettext('Open via Client');
break;
default:
break;
}
return translateResult;
}
onDropdownToggleClick = (e) => {
e.preventDefault();
e.stopPropagation();
this.toggleOperationMenu();
}
toggleOperationMenu = () => {
this.setState(
{isItemMenuShow: !this.state.isItemMenuShow},
() => {
if (this.state.isItemMenuShow) {
this.props.onFreezedItem();
} else {
this.props.onUnfreezedItem();
}
}
);
}
onMenuItemClick = (event) => {
let operation = event.target.dataset.toggle;
this.props.onMenuItemClick(operation);
}
render() {
if (!this.state.menuList.length) {
return '';
}
return (
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle sf2-icon-caret-down"
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isItemMenuShow}
onClick={this.onDropdownToggleClick}
/>
<DropdownMenu>
{this.state.menuList.map((menuItem, index) => {
if (menuItem === 'Divider') {
return <DropdownItem key={index} divider/>;
} else {
return (
<DropdownItem key={index} data-toggle={menuItem} onClick={this.onMenuItemClick}>{this.translateMenuItem(menuItem)}</DropdownItem>
);
}
})}
</DropdownMenu>
</Dropdown>
);
}
}
DirentMenu.propTypes = propTypes;
export default DirentMenu;

View File

@@ -1,101 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { DropdownMenu, DropdownToggle, DropdownItem, ButtonDropdown } from 'reactstrap';
import { Utils } from '../../utils/utils';
import { gettext, isPro } from '../../utils/constants';
import TextTranslation from '../../utils/text-translation';
import '../../css/dirents-menu.css';
const propTypes = {
dirent: PropTypes.object.isRequired,
currentRepoInfo: PropTypes.object.isRequired,
onMenuItemClick: PropTypes.func.isRequired,
};
class DirentMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
isItemMenuShow: false,
menuList: [],
};
}
componentDidMount() {
const { currentRepoInfo, dirent } = this.props;
let menuList = this.calculateMenuList(currentRepoInfo, dirent);
this.setState({menuList: menuList});
}
componentWillReceiveProps(nextProps) {
const { currentRepoInfo, dirent } = nextProps;
let menuList = this.calculateMenuList(currentRepoInfo, dirent);
this.setState({menuList: menuList});
}
calculateMenuList(currentRepoInfo, dirent) {
let menuList = [];
const { SHARE, TAGS, RELATED_FILES, HISTORY, OPEN_VIA_CLIENT, LOCK, UNLOCK } = TextTranslation;
if (dirent.type === 'dir') {
menuList = [SHARE];
return menuList;
}
if (dirent.type === 'file') {
menuList = [SHARE, TAGS, RELATED_FILES, 'Divider', HISTORY, 'Divider', OPEN_VIA_CLIENT];
if (!Utils.isMarkdownFile(dirent.name)) {
menuList.splice(2, 1);
}
if (isPro) {
if (dirent.is_locked) {
if (dirent.locked_by_me || (dirent.lock_owner === 'OnlineOffice' && currentRepoInfo.permission === 'rw')) {
menuList.splice(1, 0, UNLOCK);
}
} else {
menuList.splice(1, 0, LOCK);
}
}
return menuList;
}
}
onDropdownToggleClick = (e) => {
e.preventDefault();
this.setState({
isItemMenuShow: !this.state.isItemMenuShow,
});
}
onMenuItemClick = (event) => {
let operation = event.target.dataset.toggle;
this.props.onMenuItemClick(operation, this.props.dirent);
}
render() {
return (
<ButtonDropdown isOpen={this.state.isItemMenuShow} toggle={this.onDropdownToggleClick} title={gettext('More Operations')}>
<DropdownToggle data-toggle="dropdown" aria-expanded={this.state.isItemMenuShow} onClick={this.onDropdownToggleClick} className="fas fa-ellipsis-v sf-dropdown-toggle dirents-more-menu">
</DropdownToggle>
<DropdownMenu>
{this.state.menuList.map((menuItem, index) => {
if (menuItem === 'Divider') {
return <DropdownItem key={index} divider/>;
} else {
return (
<DropdownItem key={index} data-toggle={menuItem.key} onClick={this.onMenuItemClick}>{menuItem.value}</DropdownItem>
);
}
})}
</DropdownMenu>
</ButtonDropdown>
);
}
}
DirentMenu.propTypes = propTypes;
export default DirentMenu;

View File

@@ -0,0 +1,158 @@
import React from 'react';
import PropTypes from 'prop-types';
import listener from '../context-menu/globalEventListener';
import { Dropdown, ButtonDropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
import { gettext } from '../../utils/constants';
const propTypes = {
tagName: PropTypes.string,
item: PropTypes.object.isRequired,
toggleClass: PropTypes.string,
isHandleContextMenuEvent: PropTypes.bool,
getMenuList: PropTypes.func.isRequired,
onMenuItemClick: PropTypes.func.isRequired,
freezeItem: PropTypes.func,
unfreezeItem: PropTypes.func,
};
class ItemDropdownMenu extends React.Component {
static defaultProps = {
isHandleContextMenuEvent: true,
toggleClass: 'sf2-icon-caret-down'
};
constructor(props) {
super(props);
this.state = {
menuList: [],
isItemMenuShow: false,
};
}
componentDidMount() {
if (this.props.isHandleContextMenuEvent) {
this.listenerId = listener.register(this.onShowMenu, this.onHideMenu);
}
let { item } = this.props;
let menuList = this.props.getMenuList(item);
this.setState({menuList: menuList});
}
componentWillReceiveProps(nextProps) { // for toolbar item operation
let { item } = nextProps;
if (item.name !== this.props.item.name) {
let menuList = this.props.getMenuList(item);
this.setState({menuList: menuList});
}
}
componentWillUnmount() {
if (this.props.isHandleContextMenuEvent && this.listenerId) {
listener.unregister(this.listenerId);
}
}
onShowMenu = () => {
// nothing todo
}
onHideMenu = () => {
if (this.state.isItemMenuShow) {
this.setState({isItemMenuShow: false});
if (typeof(this.props.unfreezeItem) === 'function') {
this.props.unfreezeItem();
}
}
}
onDropdownToggleClick = (e) => {
e.preventDefault();
e.stopPropagation();
this.toggleOperationMenu();
}
toggleOperationMenu = () => {
this.setState(
{isItemMenuShow: !this.state.isItemMenuShow},
() => {
if (this.state.isItemMenuShow && typeof(this.props.freezeItem) === 'function') {
this.props.freezeItem();
} else if (!this.state.isItemMenuShow && typeof(this.props.unfreezeItem) === 'function') {
this.props.unfreezeItem();
}
}
);
}
onMenuItemClick = (event) => {
let operation = event.target.dataset.toggle;
let item = this.props.item;
this.props.onMenuItemClick(operation, event, item);
}
render() {
let menuList = this.state.menuList;
let { toggleClass, tagName } = this.props;
toggleClass = 'sf-dropdown-toggle ' + toggleClass;
if (!menuList.length) {
return '';
}
if (tagName && tagName === 'button') {
return (
<ButtonDropdown isOpen={this.state.isItemMenuShow} toggle={this.onDropdownToggleClick} title={gettext('More Operations')}>
<DropdownToggle
className={toggleClass}
data-toggle="dropdown"
title={gettext('More Operations')}
aria-expanded={this.state.isItemMenuShow}
// onClick={this.onDropdownToggleClick}
>
</DropdownToggle>
<DropdownMenu>
{menuList.map((menuItem, index) => {
if (menuItem === 'Divider') {
return <DropdownItem key={index} divider />;
} else {
return (
<DropdownItem key={index} data-toggle={menuItem.key} onClick={this.onMenuItemClick}>{menuItem.value}</DropdownItem>
);
}
})}
</DropdownMenu>
</ButtonDropdown>
);
}
return (
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.onDropdownToggleClick}>
<DropdownToggle
tag={tagName || 'i'}
className={toggleClass}
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isItemMenuShow}
// onClick={this.onDropdownToggleClick}
/>
<DropdownMenu>
{menuList.map((menuItem, index) => {
if (menuItem === 'Divider') {
return <DropdownItem key={index} divider />;
} else {
return (
<DropdownItem key={index} data-toggle={menuItem.key} onClick={this.onMenuItemClick}>{menuItem.value}</DropdownItem>
);
}
})}
</DropdownMenu>
</Dropdown>
);
}
}
ItemDropdownMenu.propTypes = propTypes;
export default ItemDropdownMenu;

View File

@@ -2,17 +2,20 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Button, ButtonGroup } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import { Utils, isPro } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator';
import TextTranslation from '../../utils/text-translation';
import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import DirentsMenu from '../dirent-list-view/dirents-menu';
import ShareDialog from '../dialog/share-dialog';
import RelatedFileDialogs from '../dialog/related-file-dialogs';
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import ModalPortal from '../modal-portal';
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
import '../../css/dirents-menu.css';
const propTypes = {
path: PropTypes.string.isRequired,
@@ -83,6 +86,35 @@ class MutipleDirOperationToolbar extends React.Component {
});
}
getDirentMenuList = (dirent) => {
let menuList = [];
let currentRepoInfo = this.props.currentRepoInfo;
const { SHARE, TAGS, RELATED_FILES, HISTORY, OPEN_VIA_CLIENT, LOCK, UNLOCK } = TextTranslation;
if (dirent.type === 'dir') {
menuList = [SHARE];
return menuList;
}
if (dirent.type === 'file') {
menuList = [SHARE, TAGS, RELATED_FILES, 'Divider', HISTORY, 'Divider', OPEN_VIA_CLIENT];
if (!Utils.isMarkdownFile(dirent.name)) {
menuList.splice(2, 1);
}
if (isPro) {
if (dirent.is_locked) {
if (dirent.locked_by_me || (dirent.lock_owner === 'OnlineOffice' && currentRepoInfo.permission === 'rw')) {
menuList.splice(1, 0, UNLOCK);
}
} else {
menuList.splice(1, 0, LOCK);
}
}
return menuList;
}
}
onMenuItemClick = (operation) => {
const dirents = this.props.selectedDirentList;
const dirent = dirents[0];
@@ -250,10 +282,12 @@ class MutipleDirOperationToolbar extends React.Component {
<Button className="secondary group-op-item action-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemsDelete}></Button>
<Button className="secondary group-op-item action-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemsDownload}></Button>
{this.props.selectedDirentList.length === 1 &&
<DirentsMenu
dirent={this.props.selectedDirentList[0]}
currentRepoInfo={this.props.currentRepoInfo}
<ItemDropdownMenu
tagName={'button'}
item={this.props.selectedDirentList[0]}
toggleClass={'fas fa-ellipsis-v dirents-more-menu'}
onMenuItemClick={this.onMenuItemClick}
getMenuList={this.getDirentMenuList}
/>
}
</ButtonGroup>

View File

@@ -162,4 +162,4 @@ class ViewFileToolbar extends React.Component {
ViewFileToolbar.propTypes = propTypes;
export default ViewFileToolbar;
export default ViewFileToolbar;

View File

@@ -1,137 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import listener from '../context-menu/globalEventListener';
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
import { gettext } from '../../utils/constants';
const propTypes = {
node: PropTypes.object.isRequired,
onMenuItemClick: PropTypes.func.isRequired,
onFreezedItem: PropTypes.func.isRequired,
onUnFreezedItem: PropTypes.func.isRequired,
};
class TreeNodeMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
isItemMenuShow: false,
menuList: []
};
}
componentDidMount() {
let menuList = this.caculateMenuList();
this.setState({menuList: menuList});
this.listenerId = listener.register(this.onShowMenu, this.onHideMenu);
}
componentWillUnmount () {
if (this.listenerId) {
listener.unregister(this.listenerId);
}
}
onShowMenu = () => {
// nothing todo
}
onHideMenu = () => {
if (this.state.isItemMenuShow) {
this.setState({isItemMenuShow: false});
this.props.onUnFreezedItem();
}
}
caculateMenuList() {
let { node } = this.props;
let menuList = [];
if (node.object.type === 'dir') {
menuList = ['New Folder', 'New File', 'Copy', 'Move', 'Rename', 'Delete'];
} else {
menuList = ['Rename', 'Delete', 'Copy', 'Move', 'Open in New Tab'];
}
return menuList;
}
translateMenuItem = (menuItem) => {
let translateResult = '';
switch(menuItem) {
case 'New Folder':
translateResult = gettext('New Folder');
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 'Open in New Tab':
translateResult = gettext('Open in New Tab');
break;
default:
break;
}
return translateResult;
}
onDropdownToggleClick = (e) => {
e.preventDefault();
this.toggleOperationMenu(e);
}
toggleOperationMenu = (e) => {
e.stopPropagation();
this.setState(
{isItemMenuShow: !this.state.isItemMenuShow }, () => {
if (this.state.isItemMenuShow) {
this.props.onFreezedItem();
} else {
this.props.onUnFreezedItem();
}
}
);
}
onMenuItemClick = (event) => {
let operation = event.target.dataset.toggle;
let node = this.props.node;
this.props.onMenuItemClick(operation, node);
}
render() {
return (
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleOperationMenu}>
<DropdownToggle
tag="i"
className="fas fa-ellipsis-v"
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isItemMenuShow}
onClick={this.onDropdownToggleClick}
/>
<DropdownMenu>
{this.state.menuList.map((menuItem, index) => {
return (
<DropdownItem key={index} data-toggle={menuItem} onClick={this.onMenuItemClick}>{this.translateMenuItem(menuItem)}</DropdownItem>
);
})}
</DropdownMenu>
</Dropdown>
);
}
}
TreeNodeMenu.propTypes = propTypes;
export default TreeNodeMenu;

View File

@@ -1,7 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import TreeNodeMenu from './tree-node-menu';
import { permission } from '../../utils/constants';
import TextTranslation from '../../utils/text-translation';
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
const propTypes = {
repoPermission: PropTypes.bool,
@@ -14,8 +15,8 @@ const propTypes = {
onNodeExpanded: PropTypes.func.isRequired,
onNodeCollapse: PropTypes.func.isRequired,
onNodeDragStart: PropTypes.func.isRequired,
onFreezedItem: PropTypes.func.isRequired,
onUnFreezedItem: PropTypes.func.isRequired,
freezeItem: PropTypes.func.isRequired,
unfreezeItem: PropTypes.func.isRequired,
onMenuItemClick: PropTypes.func,
registerHandlers: PropTypes.func,
unregisterHandlers: PropTypes.func,
@@ -112,12 +113,12 @@ class TreeNodeView extends React.Component {
this.props.onNodeDrop(e, this.props.node);
}
onUnFreezedItem = () => {
unfreezeItem = () => {
this.setState({isShowOperationMenu: false});
this.props.onUnFreezedItem();
this.props.unfreezeItem();
}
onMenuItemClick = (operation, node) => {
onMenuItemClick = (operation, event, node) => {
this.props.onMenuItemClick(operation, node);
}
@@ -168,6 +169,16 @@ class TreeNodeView extends React.Component {
return {icon, type};
}
caculateMenuList(node) {
let { NEW_FOLDER, NEW_FILE, COPY, MOVE, RENAME, DELETE, OPEN_VIA_CLIENT} = TextTranslation;
if (node.object.type === 'dir') {
return [NEW_FOLDER, NEW_FILE, COPY, MOVE, RENAME, DELETE];
}
return [RENAME, DELETE, COPY, MOVE, OPEN_VIA_CLIENT];
}
renderChildren = () => {
let { node, paddingLeft } = this.props;
if (!node.hasChildren()) {
@@ -188,9 +199,9 @@ class TreeNodeView extends React.Component {
onNodeClick={this.props.onNodeClick}
onNodeCollapse={this.props.onNodeCollapse}
onNodeExpanded={this.props.onNodeExpanded}
onFreezedItem={this.props.onFreezedItem}
onMenuItemClick={this.onMenuItemClick}
onUnFreezedItem={this.onUnFreezedItem}
freezeItem={this.props.freezeItem}
onMenuItemClick={this.props.onMenuItemClick}
unfreezeItem={this.unfreezeItem}
onNodeChanged={this.props.onNodeChanged}
registerHandlers={this.props.registerHandlers}
unregisterHandlers={this.props.unregisterHandlers}
@@ -242,14 +253,13 @@ class TreeNodeView extends React.Component {
{isNodeMenuShow && (
<div className="right-icon">
{((this.props.repoPermission || permission) && this.state.isShowOperationMenu) && (
<TreeNodeMenu
node={this.props.node}
<ItemDropdownMenu
item={this.props.node}
toggleClass={'fas fa-ellipsis-v'}
getMenuList={this.caculateMenuList}
onMenuItemClick={this.onMenuItemClick}
onUnFreezedItem={this.onUnFreezedItem}
onFreezedItem={this.props.onFreezedItem}
registerHandlers={this.props.registerHandlers}
unregisterHandlers={this.props.unregisterHandlers}
appMenuType={this.props.appMenuType}
freezeItem={this.props.freezeItem}
unfreezeItem={this.unfreezeItem}
/>
)}
</div>

View File

@@ -112,11 +112,11 @@ class TreeView extends React.Component {
this.onItemMove(this.props.currentRepoInfo, nodeDirent, dropNodeData.path, nodeParentPath);
}
onFreezedItem = () => {
freezeItem = () => {
this.setState({isItemFreezed: true});
}
onUnFreezedItem = () => {
unfreezeItem = () => {
this.setState({isItemFreezed: false});
}
@@ -194,11 +194,11 @@ class TreeView extends React.Component {
}
onShowMenu = () => {
this.onFreezedItem();
this.freezeItem();
}
onHideMenu = () => {
this.onUnFreezedItem();
this.unfreezeItem();
}
render() {
@@ -223,8 +223,8 @@ class TreeView extends React.Component {
onNodeExpanded={this.props.onNodeExpanded}
onNodeCollapse={this.props.onNodeCollapse}
onNodeDragStart={this.onNodeDragStart}
onFreezedItem={this.onFreezedItem}
onUnFreezedItem={this.onUnFreezedItem}
freezeItem={this.freezeItem}
unfreezeItem={this.unfreezeItem}
onNodeDragMove={this.onNodeDragMove}
onNodeDrop={this.onNodeDrop}
onNodeDragEnter={this.onNodeDragEnter}