1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-17 07:41:26 +00:00

Merge pull request #3332 from haiwen/Add-container-contextmenu

Add container contextmenu
This commit is contained in:
Daniel Pan
2019-04-22 11:39:04 +08:00
committed by GitHub
5 changed files with 228 additions and 33 deletions

View File

@@ -28,6 +28,7 @@ const propTypes = {
updateDirent: PropTypes.func.isRequired,
showShareBtn: PropTypes.bool.isRequired,
showDirentDetail: PropTypes.func.isRequired,
onAddFolder: PropTypes.func.isRequired,
};
class DirGridView extends React.Component {
@@ -74,6 +75,7 @@ class DirGridView extends React.Component {
onGridItemClick={this.props.onGridItemClick}
isDirentDetailShow={this.props.isDirentDetailShow}
onItemRename={this.props.onItemRename}
onAddFolder={this.props.onAddFolder}
/>
</Fragment>
);

View File

@@ -9,14 +9,54 @@ const propTypes = {
dirent: PropTypes.object.isRequired,
onItemClick: PropTypes.func.isRequired,
showImagePopup: PropTypes.func.isRequired,
handleContextClick: PropTypes.func.isRequired,
onGridItemContextMenu: PropTypes.func.isRequired,
onGridItemClick: PropTypes.func.isRequired,
activeDirent: PropTypes.object,
onGridItemMouseDown: PropTypes.func,
};
class DirentGridItem extends React.Component {
constructor(props) {
super(props);
this.state = {
isGridSelected: false,
isGridDropTipShow: false,
}
}
componentWillReceiveProps(nextProps) {
this.setState({isGridSelected: false}, () => {
if (nextProps.activeDirent && nextProps.activeDirent.name === nextProps.dirent.name) {
this.setState({isGridSelected: true});
}
})
}
onItemMove = (destRepo, dirent, selectedPath, currentPath) => {
this.props.onItemMove(destRepo, dirent, selectedPath, currentPath);
}
onItemClick = (e) => {
e.preventDefault();
e.stopPropagation();
const dirent = this.props.dirent;
if (this.props.dirent === this.props.activeDirent) {
this.setState({isGridSelected: false});
if (Utils.imageCheck(dirent.name)) {
this.props.showImagePopup(dirent);
} else {
this.props.onItemClick(dirent);
}
} else {
this.setState({isGridSelected: false});
this.props.onGridItemClick(this.props.dirent)
}
}
onItemLinkClick = (e) => {
e.preventDefault();
const dirent = this.props.dirent;
if (Utils.imageCheck(dirent.name)) {
this.props.showImagePopup(dirent);
@@ -25,6 +65,55 @@ class DirentGridItem extends React.Component {
}
}
onGridItemDragStart = (e) => {
let dragStartItemData = {nodeDirent: this.props.dirent, nodeParentPath: this.props.path};
dragStartItemData = JSON.stringify(dragStartItemData);
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('applicaiton/drag-item-info', dragStartItemData);
}
onGridItemDragEnter = (e) => {
if (this.props.dirent.type === 'dir') {
this.setState({isGridDropTipShow: true});
}
}
onGridItemDragOver = (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
}
onGridItemDragLeave = (e) => {
this.setState({isGridDropTipShow: false});
}
onGridItemDragDrop = (e) => {
this.setState({isGridDropTipShow: false});
if (e.dataTransfer.files.length) { // uploaded files
return;
}
let dragStartItemData = e.dataTransfer.getData('applicaiton/drag-item-info');
dragStartItemData = JSON.parse(dragStartItemData);
let {nodeDirent, nodeParentPath} = dragStartItemData;
let dropItemData = this.props.dirent;
if (nodeDirent.name === dropItemData.name) {
return;
}
if (dropItemData.type !== 'dir') {
return;
}
let selectedPath = Utils.joinPath(this.props.path, this.props.dirent.name);
this.onItemMove(this.props.currentRepoInfo, nodeDirent, selectedPath, nodeParentPath);
}
onGridItemMouseDown = (event) =>{
this.props.onGridItemMouseDown(event);
}
getFileUrl = (url) => {
let fileUrlArr = url.split('/');
if (fileUrlArr.indexOf('48') !== -1) {
@@ -34,12 +123,9 @@ class DirentGridItem extends React.Component {
return fileUrl;
}
onItemContextMenu = (event) => {
this.handleContextClick(event);
}
handleContextClick = (event) => {
this.props.handleContextClick(event, this.props.dirent);
onGridItemContextMenu = (event) => {
let dirent = this.props.dirent;
this.props.onGridItemContextMenu(event, dirent);
}
render() {
@@ -54,13 +140,22 @@ class DirentGridItem extends React.Component {
}
let fileHref = siteRoot + 'lib/' + this.props.repoID + '/file' + Utils.encodePath(direntPath);
let gridClass = 'grid-file-img-link cursor-pointer'
gridClass += this.state.isGridSelected ? " grid-selected-active" : " ";
gridClass += this.state.isGridDropTipShow ? " grid-drop-show" : " ";
return(
<Fragment>
<li className="grid-item" onContextMenu={this.onItemContextMenu}>
<li className="grid-item" onContextMenu={this.onGridItemContextMenu} onMouseDown={this.onGridItemMouseDown}>
<div
className="grid-file-img-link cursor-pointer"
className={gridClass}
draggable="true"
onClick={this.onItemClick}
onDragStart={this.onGridItemDragStart}
onDragEnter={this.onGridItemDragEnter}
onDragOver={this.onGridItemDragOver}
onDragLeave={this.onGridItemDragLeave}
onDrop={this.onGridItemDragDrop}
>
{dirent.encoded_thumbnail_src ?
<img src={`${siteRoot}${fileUrl}`} ref={this.gridIcon} className="thumbnail" onClick={this.onItemClick} alt=""/> :
@@ -68,8 +163,8 @@ class DirentGridItem extends React.Component {
}
{dirent.is_locked && <img className="grid-file-locked-icon" src={mediaUrl + 'img/file-locked-32.png'} alt={gettext('locked')} title={dirent.lock_owner_name}/>}
</div>
<div className="grid-file-name">
<a className="grid-file-name-link" href={dirent.type === 'dir' ? dirHref : fileHref} onClick={this.onItemClick}>{dirent.name}</a>
<div className="grid-file-name" onDragStart={this.onGridItemDragStart} draggable="true" >
<a className={`grid-file-name-link ${this.state.isGridSelected ? "grid-link-selected-active" : ""}`} href={dirent.type === 'dir' ? dirHref : fileHref} onClick={this.onItemLinkClick}>{dirent.name}</a>
</div>
</li>
</Fragment>

View File

@@ -16,6 +16,8 @@ import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ShareDialog from '../dialog/share-dialog';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import Rename from '../../components/dialog/rename-grid-item-dialog';
import CreateFile from '../dialog/create-file-dialog';
import CreateFolder from '../dialog/create-folder-dialog';
import '../../css/grid-view.css';
@@ -37,6 +39,7 @@ const propTypes = {
updateDirent: PropTypes.func.isRequired,
isDirentDetailShow: PropTypes.bool.isRequired,
onGridItemClick: PropTypes.func,
onAddFolder: PropTypes.func.isRequired,
};
class DirentGridView extends React.Component{
@@ -46,20 +49,33 @@ class DirentGridView extends React.Component{
isImagePopupOpen: false,
imageItems: [],
imageIndex: 0,
isCreateFileDialogShow: false,
// onmenuClick
isShareDialogShow: false,
isMoveDialogShow: false,
isCopyDialogShow: false,
isZipDialogOpen: false,
isRenameDialogShow: false,
isCreateFolderDialogShow: false,
isCreateFileDialogShow: false,
isMutipleOperation: false,
dirent: '',
isGridItemFreezed: false,
activeDirent: null,
}
this.isRepoOwner = props.currentRepoInfo.owner_email === username;
}
onCreateFileToggle = () => {
this.setState({
isCreateFileDialogShow: !this.state.isCreateFileDialogShow,
});
}
onGridItemClick = (dirent) => {
this.setState({activeDirent: dirent});
this.props.onGridItemClick(dirent);
}
onMoveToggle = () => {
this.setState({isMoveDialogShow: !this.state.isMoveDialogShow});
}
@@ -73,6 +89,11 @@ class DirentGridView extends React.Component{
this.props.onAddFile(filePath, isDraft);
}
onAddFolder = (dirPath) => {
this.setState({isCreateFolderDialogShow: false});
this.props.onAddFolder(dirPath);
}
onItemShare = (e) => {
e.nativeEvent.stopImmediatePropagation(); //for document event
this.setState({isShareDialogShow: !this.state.isShareDialogShow});
@@ -126,6 +147,12 @@ class DirentGridView extends React.Component{
case 'Details':
this.onDetails(currentObject);
break;
case 'New Folder':
this.onCreateFolderToggle(currentObject);
break;
case 'New File':
this.onCreateFileToggle(currentObject);
break;
case 'Access Log':
this.onAccessLog();
break;
@@ -168,6 +195,12 @@ class DirentGridView extends React.Component{
}
}
onCreateFolderToggle = () => {
this.setState({
isCreateFolderDialogShow: !this.state.isCreateFolderDialogShow,
});
}
onItemRenameToggle = () => {
this.setState({
isRenameDialogShow: !this.state.isRenameDialogShow,
@@ -230,7 +263,7 @@ class DirentGridView extends React.Component{
this.setState({
isRenameDialogShow: !this.state.isRenameDialogShow,
});
this.props.onItemRename(this.state.dirent, newName)
this.props.onItemRename(this.state.activeDirent, newName)
}
@@ -299,13 +332,41 @@ class DirentGridView extends React.Component{
return isDuplicated;
}
gridContainerClick = () => {
if (!this.props.isDirentDetailShow) {
this.props.onGridItemClick(null);
// common contextmenu handle
onMouseDown = (event) => {
event.stopPropagation();
if (event.button === 2) {
return;
}
}
handleContextClick = (event, currentObject) => {
onGridContainerMouseDown = (event) => {
this.onMouseDown(event)
}
onGridItemMouseDown = (event) => {
this.onMouseDown(event);
}
gridContainerClick = () => {
if (!this.props.isDirentDetailShow) {
this.onGridItemClick(null);
}
}
onGridContainerContextMenu = (event) => {
let id = "dirent-grid-container-menu"
let menuList = [TextTranslation.NEW_FOLDER, TextTranslation.NEW_FILE];
this.handleContextClick(event, id, menuList);
}
onGridItemContextMenu = (event, dirent) => {
let id = 'grid-item-contextmenu';
let menuList = this.getDirentItemMenuList(dirent, true);
this.handleContextClick(event, id, menuList, dirent);
}
handleContextClick = (event, id, menuList, currentObject = null) => {
event.preventDefault();
event.stopPropagation();
@@ -320,13 +381,11 @@ class DirentGridView extends React.Component{
}
hideMenu();
let menuList = this.getDirentItemMenuList(currentObject, true);
this.setState({dirent: currentObject});
this.setState({activeDirent: currentObject});
let showMenuConfig = {
id: 'grid-item-contextmenu',
id: id,
position: { x, y },
target: event.target,
currentObject: currentObject,
@@ -415,7 +474,7 @@ class DirentGridView extends React.Component{
render() {
let {direntList, path} = this.props;
let dirent = this.state.dirent;
let dirent = this.state.activeDirent ? this.state.activeDirent : '';
let direntPath = Utils.joinPath(path, dirent.name);
if (this.props.isDirentListLoading) {
@@ -424,7 +483,7 @@ class DirentGridView extends React.Component{
return (
<Fragment>
<ul className="grid-view" onClick={this.gridContainerClick}>
<ul className="grid-view" onClick={this.gridContainerClick} onContextMenu={this.onGridContainerContextMenu} onMouseDown={this.onGridContainerMouseDown}>
{
direntList.length !== 0 && direntList.map((dirent, index) => {
return (
@@ -436,8 +495,11 @@ class DirentGridView extends React.Component{
onItemClick={this.props.onItemClick}
currentRepoInfo={this.props.currentRepoInfo}
showImagePopup={this.showImagePopup}
handleContextClick={this.handleContextClick}
onGridItemContextMenu={this.onGridItemContextMenu}
onItemMove={this.props.onItemMove}
onGridItemMouseDown={this.onGridItemMouseDown}
onGridItemClick={this.onGridItemClick}
activeDirent={this.state.activeDirent}
/>
)
})
@@ -447,6 +509,30 @@ class DirentGridView extends React.Component{
id={'grid-item-contextmenu'}
onMenuItemClick={this.onMenuItemClick}
/>
<ContextMenu
id={'dirent-grid-container-menu'}
onMenuItemClick={this.onMenuItemClick}
/>
{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}
onAddFile={this.onAddFile}
checkDuplicatedName={this.checkDuplicatedName}
addFileCancel={this.onCreateFileToggle}
/>
</ModalPortal>
)}
{this.state.isMoveDialogShow &&
<MoveDirentDialog
path={this.props.path}
@@ -455,7 +541,7 @@ class DirentGridView extends React.Component{
isMutipleOperation={this.state.isMutipleOperation}
onItemMove={this.props.onItemMove}
onCancelMove={this.onMoveToggle}
dirent={this.state.dirent}
dirent={this.state.activeDirent}
/>
}
{this.state.isZipDialogOpen &&
@@ -476,7 +562,7 @@ class DirentGridView extends React.Component{
isMutipleOperation={this.state.isMutipleOperation}
onItemCopy={this.props.onItemCopy}
onCancelCopy={this.onCopyToggle}
dirent={this.state.dirent}
dirent={this.state.activeDirent}
/>
}
{this.state.isShareDialogShow &&
@@ -497,7 +583,7 @@ class DirentGridView extends React.Component{
{this.state.isRenameDialogShow && (
<ModalPortal>
<Rename
dirent={this.state.dirent}
dirent={this.state.activeDirent}
onRename={this.onItemRename}
checkDuplicatedName={this.checkDuplicatedName}
toggleCancel={this.onItemRenameToggle}

View File

@@ -1,5 +1,5 @@
.grid-view {
padding-top: 10px;
padding: 0.625rem 1rem 10rem;
list-style: none;
display: flex;
flex-wrap: wrap;
@@ -24,15 +24,14 @@
}
.grid-file-img-link {
width: 100px;
height: 100px;
width: 96px;
height: 96px;
margin: 0 auto 6px;
position: relative;
border-radius: 3px;
font-size: 0;
text-align: center;
line-height: 0;
padding: 2px;
}
.grid-file-img-link .thumbnail {
@@ -71,4 +70,16 @@
bottom: 0;
right: 10px;
width: 16px;
}
.grid-selected-active {
background-color: #f8f8f8;
}
.grid-link-selected-active {
color: #eb8205;
}
.grid-drop-show {
background: #f8f8f8;
}

View File

@@ -116,6 +116,7 @@ class LibContentContainer extends React.Component {
onGridItemClick = (dirent) => {
this.setState({currentDirent: dirent});
this.props.onDirentClick(dirent);
}
// on '<tr>'