1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-04 16:31:13 +00:00

Grid view support drag drop item to path (#6429)

* feature - drag and drop file to target path in grid view

fix typo

* update target path item background color when drag enter

* fix bug - select-all checkbox is actived after the last item is moved to another path

* fix bug - drag drop action conflict with multi-select by keyboard

* remove console log

* fix type error
This commit is contained in:
Aries
2024-07-27 12:04:33 +08:00
committed by GitHub
parent 953f17e717
commit 559dfff42b
7 changed files with 85 additions and 9 deletions

View File

@@ -10,6 +10,7 @@ import ViewFileToolbar from '../../components/toolbar/view-file-toolbar';
import { PRIVATE_FILE_TYPE } from '../../constants'; import { PRIVATE_FILE_TYPE } from '../../constants';
const propTypes = { const propTypes = {
currentRepoInfo: PropTypes.object.isRequired,
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
repoName: PropTypes.string.isRequired, repoName: PropTypes.string.isRequired,
currentPath: PropTypes.string.isRequired, currentPath: PropTypes.string.isRequired,
@@ -32,10 +33,18 @@ const propTypes = {
repoTags: PropTypes.array.isRequired, repoTags: PropTypes.array.isRequired,
filePermission: PropTypes.string, filePermission: PropTypes.string,
onFileTagChanged: PropTypes.func.isRequired, onFileTagChanged: PropTypes.func.isRequired,
onItemMove: PropTypes.func.isRequired,
}; };
class DirPath extends React.Component { class DirPath extends React.Component {
constructor(props) {
super(props);
this.state = {
dropTargetPath: '',
};
}
onPathClick = (e) => { onPathClick = (e) => {
let path = Utils.getEventData(e, 'path'); let path = Utils.getEventData(e, 'path');
this.props.onPathClick(path); this.props.onPathClick(path);
@@ -54,6 +63,54 @@ class DirPath extends React.Component {
this.props.onTabNavClick(tabName, id); this.props.onTabNavClick(tabName, id);
}; };
onDragEnter = (e) => {
e.preventDefault();
if (Utils.isIEBrower()) {
return false;
}
this.setState({
dropTargetPath: e.target.dataset.path,
});
};
onDragLeave = (e) => {
e.preventDefault();
if (Utils.isIEBrower()) {
return false;
}
this.setState({
dropTargetPath: '',
});
};
onDragOver = (e) => {
if (Utils.isIEBrower()) {
return false;
}
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
};
onDrop = (e) => {
if (Utils.isIEBrower()) {
return false;
}
if (e.dataTransfer.files.length) {
return;
}
let dragStartItemData = e.dataTransfer.getData('application/drag-item-info');
dragStartItemData = JSON.parse(dragStartItemData);
let { nodeDirent, nodeParentPath } = dragStartItemData;
let selectedPath = Utils.getEventData(e, 'path');
this.props.onItemMove(this.props.currentRepoInfo, nodeDirent, selectedPath, nodeParentPath);
this.setState({
dropTargetPath: '',
});
};
turnPathToLink = (path) => { turnPathToLink = (path) => {
path = path[path.length - 1] === '/' ? path.slice(0, path.length - 1) : path; path = path[path.length - 1] === '/' ? path.slice(0, path.length - 1) : path;
let pathList = path.split('/'); let pathList = path.split('/');
@@ -126,7 +183,16 @@ class DirPath extends React.Component {
return ( return (
<Fragment key={index} > <Fragment key={index} >
<span className="path-split">/</span> <span className="path-split">/</span>
<span className="path-item" data-path={nodePath} onClick={this.onPathClick} role="button">{item}</span> <span
className={`path-item ${nodePath === this.state.dropTargetPath ? 'path-item-drop' : ''}`}
data-path={nodePath} onClick={this.onPathClick}
onDragEnter={this.onDragEnter}
onDragLeave={this.onDragLeave}
onDragOver={this.onDragOver}
onDrop={this.onDrop}
role="button">
{item}
</span>
</Fragment> </Fragment>
); );
} }

View File

@@ -6,6 +6,7 @@ import DirPath from './dir-path';
import DirTool from './dir-tool'; import DirTool from './dir-tool';
const propTypes = { const propTypes = {
currentRepoInfo: PropTypes.object.isRequired,
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
repoName: PropTypes.string.isRequired, repoName: PropTypes.string.isRequired,
userPerm: PropTypes.string, userPerm: PropTypes.string,
@@ -38,6 +39,7 @@ const propTypes = {
repoTags: PropTypes.array.isRequired, repoTags: PropTypes.array.isRequired,
onFileTagChanged: PropTypes.func.isRequired, onFileTagChanged: PropTypes.func.isRequired,
metadataViewId: PropTypes.string, metadataViewId: PropTypes.string,
onItemMove: PropTypes.func.isRequired,
}; };
class CurDirPath extends React.Component { class CurDirPath extends React.Component {
@@ -60,6 +62,7 @@ class CurDirPath extends React.Component {
return ( return (
<div className="cur-dir-path d-flex justify-content-between align-items-center"> <div className="cur-dir-path d-flex justify-content-between align-items-center">
<DirPath <DirPath
currentRepoInfo={this.props.currentRepoInfo}
repoID={this.props.repoID} repoID={this.props.repoID}
repoName={this.props.repoName} repoName={this.props.repoName}
repoEncrypted={this.props.repoEncrypted} repoEncrypted={this.props.repoEncrypted}
@@ -82,6 +85,7 @@ class CurDirPath extends React.Component {
filePermission={this.props.filePermission} filePermission={this.props.filePermission}
onFileTagChanged={this.props.onFileTagChanged} onFileTagChanged={this.props.onFileTagChanged}
repoTags={this.props.repoTags} repoTags={this.props.repoTags}
onItemMove={this.props.onItemMove}
/> />
{isDesktop && {isDesktop &&
<DirTool <DirTool

View File

@@ -56,27 +56,27 @@ class DirentGridItem extends React.Component {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
const { dirent, activeDirent } = this.props; const { dirent } = this.props;
if (this.clickTimeout) { if (this.clickTimeout) {
clearTimeout(this.clickTimeout); clearTimeout(this.clickTimeout);
this.clickTimeout = null; this.clickTimeout = null;
this.handleSingleClick(dirent, activeDirent, e); this.handleSingleClick(dirent, e);
return; return;
} }
this.clickTimeout = setTimeout(() => { this.clickTimeout = setTimeout(() => {
this.clickTimeout = null; this.clickTimeout = null;
this.handleSingleClick(dirent, activeDirent, e); this.handleSingleClick(dirent, e);
}, 100); // Clicks within 100 milliseconds is considered a single click. }, 100); // Clicks within 100 milliseconds is considered a single click.
}; };
handleSingleClick = (dirent, activeDirent, event) => { handleSingleClick = (dirent, event) => {
if (!this.canPreview) { if (!this.canPreview) {
return; return;
} }
if (dirent === activeDirent && !event.metaKey && !event.ctrlKey) { if (dirent.isSelected && !event.metaKey && !event.ctrlKey) {
this.handleDoubleClick(dirent, event); this.handleDoubleClick(dirent, event);
} else { } else {
this.props.onGridItemClick(dirent, event); this.props.onGridItemClick(dirent, event);
@@ -113,6 +113,7 @@ class DirentGridItem extends React.Component {
if (Utils.isIEBrower() || !this.canDrag) { if (Utils.isIEBrower() || !this.canDrag) {
return false; return false;
} }
let dragStartItemData = { nodeDirent: this.props.dirent, nodeParentPath: this.props.path }; let dragStartItemData = { nodeDirent: this.props.dirent, nodeParentPath: this.props.path };
dragStartItemData = JSON.stringify(dragStartItemData); dragStartItemData = JSON.stringify(dragStartItemData);

View File

@@ -597,7 +597,6 @@ class DirentGridView extends React.Component {
onGridItemMouseDown = (event) => { onGridItemMouseDown = (event) => {
event.stopPropagation(); event.stopPropagation();
event.preventDefault();
if (event.button === 2) { if (event.button === 2) {
return; return;
} }

View File

@@ -130,7 +130,7 @@
} }
.tree-node-drop { .tree-node-drop {
background-color: rgb(255, 239, 178); background-color: #FFEFB2;
} }
.tree-node-icon { .tree-node-icon {
@@ -282,6 +282,10 @@
color: #666; color: #666;
} }
.dir-view-path .path-item-drop{
background-color: #FFEFB2;
}
.dir-view-path .path-split { .dir-view-path .path-split {
padding: 0 2px; padding: 0 2px;
} }

View File

@@ -191,6 +191,7 @@ class LibContentContainer extends React.Component {
} }
<div className="cur-view-path d-block" style={curViewPathStyle}> <div className="cur-view-path d-block" style={curViewPathStyle}>
<CurDirPath <CurDirPath
currentRepoInfo={this.props.currentRepoInfo}
repoID={repoID} repoID={repoID}
repoName={this.props.currentRepoInfo.repo_name} repoName={this.props.currentRepoInfo.repo_name}
repoEncrypted={this.props.repoEncrypted} repoEncrypted={this.props.repoEncrypted}
@@ -223,6 +224,7 @@ class LibContentContainer extends React.Component {
onFileTagChanged={this.props.onToolbarFileTagChanged} onFileTagChanged={this.props.onToolbarFileTagChanged}
repoTags={this.props.repoTags} repoTags={this.props.repoTags}
metadataViewId={this.props.metadataViewId} metadataViewId={this.props.metadataViewId}
onItemMove={this.props.onItemMove}
/> />
<ToolbarForSelectedDirents <ToolbarForSelectedDirents
repoID={this.props.repoID} repoID={this.props.repoID}

View File

@@ -1912,7 +1912,7 @@ class LibContentView extends React.Component {
this.setState({ this.setState({
selectedDirentList: selectedDirentList, selectedDirentList: selectedDirentList,
isDirentSelected: selectedDirentList.length > 0, isDirentSelected: selectedDirentList.length > 0,
isAllDirentSelected: selectedDirentList.length === newDirentList.length, isAllDirentSelected: newDirentList.length ? selectedDirentList.length === newDirentList.length : false,
}); });
}; };