mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 15:09:14 +00:00
[Wiki] Support show folder (#2334)
This commit is contained in:
committed by
Daniel Pan
parent
b8662376a1
commit
681a4235a4
@@ -1,85 +1,61 @@
|
||||
|
||||
|
||||
class Node {
|
||||
|
||||
static create(attrs = {}) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `Node` from a JSON `object`.
|
||||
*
|
||||
* @param {Object} object
|
||||
* @return {Node}
|
||||
*/
|
||||
static fromJSON(object) {
|
||||
const {
|
||||
name,
|
||||
type,
|
||||
isExpanded = true,
|
||||
children = [],
|
||||
} = object;
|
||||
static deserializefromJson(object) {
|
||||
const {name, type, size, last_update_time, isExpanded = true, children = []} = object;
|
||||
|
||||
const node = new Node({
|
||||
name,
|
||||
type,
|
||||
size,
|
||||
last_update_time,
|
||||
isExpanded,
|
||||
children: children.map(Node.fromJSON),
|
||||
children: children.map(item => Node.deserializefromJson(item)),
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
constructor({ name, type, isExpanded, children }) {
|
||||
|
||||
constructor({name, type, size, last_update_time, isExpanded, children}) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.children = children ? children : [];
|
||||
this.size = size;
|
||||
this.last_update_time = last_update_time;
|
||||
this.isExpanded = isExpanded !== undefined ? isExpanded : true;
|
||||
this.children = children ? children : [];
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
clone() {
|
||||
var n = new Node({
|
||||
name: this.name,
|
||||
type: this.type,
|
||||
size: this.size,
|
||||
last_update_time: this.last_update_time,
|
||||
isExpanded: this.isExpanded
|
||||
});
|
||||
n.children = this.children.map(child => {
|
||||
var newChild = child.clone();
|
||||
newChild.parent = n;
|
||||
return newChild;
|
||||
});
|
||||
return n;
|
||||
}
|
||||
|
||||
get path() {
|
||||
if (!this.parent) {
|
||||
return this.name;
|
||||
} else {
|
||||
var p = this.parent.path;
|
||||
if (p === "/")
|
||||
return p + this.name;
|
||||
else
|
||||
return p + "/" + this.name;
|
||||
let p = this.parent.path;
|
||||
return p === "/" ? (p + this.name) : (p + "/" + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
copy() {
|
||||
var n = new Node({
|
||||
name: this.name,
|
||||
type: this.type,
|
||||
isExpanded: this.isExpanded
|
||||
});
|
||||
n.children = this.children.map(child => { var newChild = child.copy(); newChild.parent = n; return newChild; });
|
||||
return n;
|
||||
}
|
||||
|
||||
isRoot() {
|
||||
return this.parent === undefined;
|
||||
}
|
||||
|
||||
hasChildren() {
|
||||
return this.children.length > 0;
|
||||
}
|
||||
|
||||
isImage() {
|
||||
let index = this.name.lastIndexOf(".");
|
||||
if (index == -1) {
|
||||
return false;
|
||||
} else {
|
||||
let type = this.name.substring(index).toLowerCase();
|
||||
if (type == ".png" || type == ".jpg") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isRoot() {
|
||||
return this.parent === undefined;
|
||||
}
|
||||
|
||||
isMarkdown() {
|
||||
@@ -100,39 +76,21 @@ class Node {
|
||||
return this.type == "dir";
|
||||
}
|
||||
|
||||
getleafPaths() {
|
||||
let paths = new Map();
|
||||
function getleafPath(node){
|
||||
if (node.hasChildren()) {
|
||||
let children = node.children;
|
||||
children.forEach(child => {
|
||||
if (child.hasChildren()) {
|
||||
getleafPath(child);
|
||||
} else {
|
||||
let path = child.path;
|
||||
paths.set(path,child);
|
||||
}
|
||||
});
|
||||
isImage() {
|
||||
let index = this.name.lastIndexOf(".");
|
||||
if (index == -1) {
|
||||
return false;
|
||||
} else {
|
||||
let type = this.name.substring(index).toLowerCase();
|
||||
if (type == ".png" || type == ".jpg") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
getleafPath(this);
|
||||
return paths;
|
||||
}
|
||||
|
||||
getNodeByPath(path) {
|
||||
let paths = this.getleafPaths();
|
||||
if (paths.has(path)) {
|
||||
return paths.get(path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON representation of the node.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
toJSON() {
|
||||
serializeToJson() {
|
||||
var children = []
|
||||
if (this.hasChildren()) {
|
||||
children = this.children.map(m => m.toJSON());
|
||||
@@ -141,6 +99,8 @@ class Node {
|
||||
const object = {
|
||||
name: this.name,
|
||||
type: this.type,
|
||||
size: this.size,
|
||||
last_update_time: this.last_update_time,
|
||||
isExpanded: this.isExpanded,
|
||||
children: children
|
||||
}
|
||||
@@ -150,5 +110,4 @@ class Node {
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { Node }
|
||||
export default Node;
|
@@ -44,10 +44,7 @@ class TreeNodeView extends React.Component {
|
||||
|
||||
handleCollapse = (e) => {
|
||||
e.stopPropagation();
|
||||
const { node } = this.props;
|
||||
if (this.props.treeView.toggleCollapse) {
|
||||
this.props.treeView.toggleCollapse(node);
|
||||
}
|
||||
this.props.onDirCollapse(e, this.props.node);
|
||||
}
|
||||
|
||||
onDragStart = (e) => {
|
||||
@@ -69,12 +66,12 @@ class TreeNodeView extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('click', this.hideMenuIcon);
|
||||
}
|
||||
document.addEventListener('click', this.hideMenuIcon);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.hideMenuIcon);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.hideMenuIcon);
|
||||
}
|
||||
|
||||
renderCollapse = () => {
|
||||
const { node } = this.props;
|
||||
@@ -115,6 +112,7 @@ class TreeNodeView extends React.Component {
|
||||
isNodeItemFrezee={this.props.isNodeItemFrezee}
|
||||
permission={this.props.permission}
|
||||
currentFilePath={this.props.currentFilePath}
|
||||
onDirCollapse={this.props.onDirCollapse}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -127,10 +125,11 @@ class TreeNodeView extends React.Component {
|
||||
|
||||
renderMenuController() {
|
||||
if (this.props.permission === "rw") {
|
||||
let isShow = (this.props.node.path === this.props.currentFilePath);
|
||||
return (
|
||||
<div className="right-icon">
|
||||
<MenuControl
|
||||
isShow={this.state.isMenuIconShow}
|
||||
isShow={this.state.isMenuIconShow || isShow}
|
||||
onClick={this.onMenuControlClick}
|
||||
/>
|
||||
</div>
|
||||
@@ -176,16 +175,15 @@ class TreeNodeView extends React.Component {
|
||||
if (node.path === this.props.currentFilePath) {
|
||||
hlClass = "tree-node-hight-light";
|
||||
}
|
||||
let customClass = "tree-node " + hlClass;
|
||||
|
||||
return (
|
||||
<div type={type} className={customClass} style={styles}>
|
||||
<div type={type} className="tree-node" style={styles}>
|
||||
<div
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onClick={this.onClick}
|
||||
type={type}
|
||||
className={`tree-node-inner text-nowrap ${node.name === '/'? 'hide': ''}`}
|
||||
className={`tree-node-inner text-nowrap ${hlClass} ${node.name === '/'? 'hide': ''}`}
|
||||
>
|
||||
<div className="tree-node-text" type={type} draggable="true" onDragStart={this.onDragStart}>{node.name}</div>
|
||||
<div className="left-icon">
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import TreeNodeView from './tree-node-view';
|
||||
import editorUtilities from '../../utils/editor-utilties'
|
||||
|
||||
class TreeView extends React.PureComponent {
|
||||
|
||||
@@ -10,29 +11,17 @@ class TreeView extends React.PureComponent {
|
||||
*/
|
||||
}
|
||||
|
||||
toggleCollapse = (node) => {
|
||||
const tree = this.props.treeData;
|
||||
node.isExpanded = !node.isExpanded;
|
||||
|
||||
// copy the tree to make PureComponent work
|
||||
this.setState({
|
||||
tree: tree.copy()
|
||||
});
|
||||
|
||||
this.change(tree);
|
||||
toggleCollapse = (e, node) => {
|
||||
this.props.onDirCollapse(e, node);
|
||||
}
|
||||
|
||||
onDragStart = (e, node) => {
|
||||
const url = this.props.editorUtilities.getFileURL(node);
|
||||
const url = editorUtilities.getFileURL(node);
|
||||
e.dataTransfer.setData("text/uri-list", url);
|
||||
e.dataTransfer.setData("text/plain", url);
|
||||
}
|
||||
|
||||
onNodeClick = (e, node) => {
|
||||
if (node.isDir()) {
|
||||
this.toggleCollapse(node);
|
||||
return;
|
||||
}
|
||||
this.props.onNodeClick(e, node);
|
||||
}
|
||||
|
||||
@@ -48,13 +37,14 @@ class TreeView extends React.PureComponent {
|
||||
return (
|
||||
<div className="tree-view tree">
|
||||
<TreeNodeView
|
||||
paddingLeft={20}
|
||||
paddingLeft={12}
|
||||
treeView={this}
|
||||
node={this.props.treeData.root}
|
||||
isNodeItemFrezee={this.props.isNodeItemFrezee}
|
||||
permission={this.props.permission}
|
||||
currentFilePath={this.props.currentFilePath}
|
||||
onShowContextMenu={this.props.onShowContextMenu}
|
||||
onDirCollapse={this.props.onDirCollapse}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,102 +1,145 @@
|
||||
import { Node } from './node'
|
||||
import Node from './node';
|
||||
import moment from 'moment';
|
||||
|
||||
class Tree {
|
||||
|
||||
|
||||
constructor() {
|
||||
this.root = null;
|
||||
}
|
||||
|
||||
copy() {
|
||||
clone() {
|
||||
var t = new Tree();
|
||||
if (this.root)
|
||||
t.root = this.root.copy();
|
||||
t.root = this.root.clone();
|
||||
return t;
|
||||
}
|
||||
|
||||
setRoot(dir) {
|
||||
this.root = dir;
|
||||
setRoot(node) {
|
||||
this.root = node;
|
||||
}
|
||||
|
||||
addChildToNode(node, child) {
|
||||
child.parent = node;
|
||||
node.children.push(child);
|
||||
return child;
|
||||
addNodeToParent(node, parentNode) {
|
||||
node.parent = parentNode;
|
||||
parentNode.children.push(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
addChild(node, child, insertIndex) {
|
||||
if (!(child instanceof Node)) {
|
||||
throw new TypeError('Child must be of type Node.');
|
||||
}
|
||||
if (insertIndex < 0 || insertIndex > node.children.length) {
|
||||
throw new Error('Invalid index.');
|
||||
}
|
||||
|
||||
child.parent = node;
|
||||
node.children.splice(insertIndex, 0, child);
|
||||
}
|
||||
|
||||
removeChildNode(node, child) {
|
||||
let children = node.children;
|
||||
removeNodeFromParent(node, parentNode) {
|
||||
let children = parentNode.children;
|
||||
let removeNode = null;
|
||||
let index = null;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (child.path === children[i].path) {
|
||||
if (node.path === children[i].path) {
|
||||
removeNode = children[i];
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
child.parent = null;
|
||||
node.children.splice(index, 1);
|
||||
node.parent = null;
|
||||
parentNode.children.splice(index, 1);
|
||||
return removeNode ? removeNode : null;
|
||||
}
|
||||
|
||||
addNodeToTree(node) {
|
||||
let parentNode = this.getNodeParentFromTree(node);
|
||||
this.addChildToNode(parentNode, node);
|
||||
}
|
||||
|
||||
removeNodeFromTree(node) {
|
||||
let parentNode = this.getNodeParentFromTree(node);
|
||||
this.removeChildNode(parentNode, node);
|
||||
}
|
||||
|
||||
getNodeParentFromTree(node) {
|
||||
let parentNode = node.parent;
|
||||
let findNode = null;
|
||||
function cb(node) {
|
||||
if(parentNode.path === node.path){
|
||||
findNode = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.traverseBF(cb);
|
||||
return findNode;
|
||||
}
|
||||
|
||||
getNodeByPath(path) {
|
||||
let findNode = null;
|
||||
function cb(node){
|
||||
if (node.path === path) {
|
||||
findNode = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.traverseBF(cb);
|
||||
return findNode;
|
||||
}
|
||||
|
||||
updateNodeParamValue(node, param, value) {
|
||||
let findNode = this.getNodeByPath(node.path);
|
||||
if (findNode[param]) {
|
||||
findNode[param] = value;
|
||||
addNode(node) {
|
||||
let treeNodeParent = this.findNodeParentFromTree(node);
|
||||
if (treeNodeParent) {
|
||||
this.addNodeToParent(node, treeNodeParent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
deleteNode(node) {
|
||||
let treeNodeParent = this.findNodeParentFromTree(node);
|
||||
if (treeNodeParent) {
|
||||
this.removeNodeFromParent(node, treeNodeParent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
updateNodeParam(node, param, newValue) {
|
||||
let treeNode = this.findNodeFromTree(node);
|
||||
if (treeNode && treeNode[param]) {
|
||||
treeNode[param] = newValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
findNode(node) {
|
||||
return this.findNodeFromTree(node);
|
||||
}
|
||||
|
||||
findNodeFromTree(node) {
|
||||
let findNode = this.getNodeByPath(node.path);
|
||||
return findNode;
|
||||
}
|
||||
|
||||
findNodeParentFromTree(node) {
|
||||
let parentNode = node.parent;
|
||||
let findNode = null;
|
||||
function cb(treeNode) {
|
||||
if (treeNode.path === parentNode.path) {
|
||||
findNode = treeNode;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.traverseDF(cb);
|
||||
return findNode;
|
||||
}
|
||||
|
||||
setNodeToActivated(node) {
|
||||
this.setTreeToUnActivated();
|
||||
let treeNode = this.findNodeFromTree(node);
|
||||
if (treeNode) {
|
||||
treeNode.isExpanded = true;
|
||||
while (treeNode.parent) {
|
||||
treeNode.parent.isExpanded = true;
|
||||
treeNode = treeNode.parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setTreeToUnActivated() {
|
||||
function cb(treeNode) {
|
||||
treeNode.isExpanded = false;
|
||||
return false;
|
||||
}
|
||||
this.traverseBF(cb);
|
||||
this.root.isExpanded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
getNodeByPath(path) {
|
||||
let findNode = null;
|
||||
function cb(treeNode) {
|
||||
if (treeNode.path === path) {
|
||||
findNode = treeNode;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.traverseBF(cb);
|
||||
return findNode;
|
||||
}
|
||||
|
||||
isNodeChild(parentNode, node) {
|
||||
let isChild = false;
|
||||
while(node.parent){
|
||||
if(node.parent.path === parentNode.path){
|
||||
isChild = true;
|
||||
break;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return isChild;
|
||||
}
|
||||
|
||||
|
||||
traverseDF(callback) {
|
||||
let stack = [];
|
||||
let found = false;
|
||||
@@ -125,105 +168,46 @@ class Tree {
|
||||
}
|
||||
}
|
||||
|
||||
setOneNodeToActived({node}) {
|
||||
this.setNoneNodeActived();
|
||||
let root = this.root;
|
||||
root.isExpanded = true;
|
||||
let layer2 = root.hasChildren() ? root.children : null; // direct to replace root child;
|
||||
let isLayer2 = false;
|
||||
for (let i = 0; i < layer2.length; i++) {
|
||||
if (node.path === layer2[i].path) {
|
||||
isLayer2 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isLayer2) {
|
||||
return;
|
||||
}
|
||||
let replaceNode = null;
|
||||
let needReplacedNode = null;
|
||||
while (node.parent) {
|
||||
let flag = false;
|
||||
node.parent.isExpanded = true;
|
||||
for (let i = 0; i < layer2.length; i++) {
|
||||
if (node.parent.path === layer2[i].path) {
|
||||
replaceNode = node.parent;
|
||||
needReplacedNode = layer2[i];
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
break;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
this.removeChildNode(root, needReplacedNode);
|
||||
this.addChildToNode(root, replaceNode);
|
||||
}
|
||||
|
||||
setNoneNodeActived() {
|
||||
function setNodeToDeactived(node) {
|
||||
if (node.isExpanded) {
|
||||
node.isExpanded = false;
|
||||
if (node.hasChildren()) {
|
||||
let children = node.children;
|
||||
children.forEach(function(child) {
|
||||
setNodeToDeactived(child);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
setNodeToDeactived(this.root);
|
||||
this.root.isExpanded = true; // default to show;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse tree from javascript object
|
||||
*/
|
||||
parse(model) {
|
||||
parseModelToTree(model) {
|
||||
var node = new Node({
|
||||
name: model.name,
|
||||
type: model.type,
|
||||
isExpanded: model.isExpanded
|
||||
size: model.size,
|
||||
last_update_time: moment.unix(model.last_update_time).fromNow(),
|
||||
isExpanded: false
|
||||
});
|
||||
this.root = node;
|
||||
for (let child of model.children) {
|
||||
this.addChildToNode(node, this.parseNode(child));
|
||||
if (model.children instanceof Array) {
|
||||
for (let child of model.children) {
|
||||
this.addNodeToParent(this.parseNodeToTree(child), node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
parseFromList(rootObj, nodeList) {
|
||||
var root = new Node({
|
||||
name: rootObj.name,
|
||||
type: rootObj.type,
|
||||
isExpanded: rootObj.isExpanded
|
||||
});
|
||||
this.root = root;
|
||||
|
||||
var map = new Map();
|
||||
map.set(root.name, root);
|
||||
|
||||
function joinPath(parent_path, name) {
|
||||
if (parent_path === "/")
|
||||
return parent_path + name;
|
||||
else
|
||||
return parent_path + "/" + name;
|
||||
parseListToTree(nodeList) {
|
||||
|
||||
function getNodePath(parentPath, nodeName) {
|
||||
return parentPath === "/" ? (parentPath + nodeName) : (parentPath + "/" + nodeName);
|
||||
}
|
||||
|
||||
var treeNodeList = []
|
||||
let root = new Node({name: '/', type: 'dir', isExpanded: true});
|
||||
this.root = root;
|
||||
|
||||
let map = new Map();
|
||||
map.set(root.name, root);
|
||||
let treeNodeList = [];
|
||||
for (let nodeObj of nodeList) {
|
||||
var node = new Node({
|
||||
let node = new Node({
|
||||
name: nodeObj.name,
|
||||
type: nodeObj.type,
|
||||
size: nodeObj.size,
|
||||
last_update_time: moment.unix(nodeObj.last_update_time).fromNow(),
|
||||
isExpanded: false
|
||||
});
|
||||
node.parent_path = nodeObj.parent_path;
|
||||
treeNodeList.push(node);
|
||||
if (nodeObj.type === "dir") {
|
||||
map.set(joinPath(nodeObj.parent_path, nodeObj.name), node);
|
||||
if (node.isDir()) {
|
||||
map.set(getNodePath(node.parent_path, node.name), node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,26 +216,28 @@ class Tree {
|
||||
if (p === undefined) {
|
||||
console.log("warning: node " + node.parent_path + " not exist");
|
||||
} else {
|
||||
this.addChildToNode(p, node);
|
||||
this.addNodeToParent(node, p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parseNode(model) {
|
||||
parseNodeToTree(node) {
|
||||
var node = new Node({
|
||||
name: model.name,
|
||||
type: model.type,
|
||||
isExpanded: model.isExpanded
|
||||
name: node.name,
|
||||
type: node.type,
|
||||
size: node.size,
|
||||
last_update_time: moment.unix(node.last_update_time).fromNow(),
|
||||
isExpanded: false
|
||||
});
|
||||
if (model.children instanceof Array) {
|
||||
for (let child of model.children) {
|
||||
this.addChildToNode(node, this.parseNode(child));
|
||||
if (node.children instanceof Array) {
|
||||
for (let child of node.children) {
|
||||
this.addNodeToParent(this.parseNodeToTree(child), node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default Tree;
|
||||
|
Reference in New Issue
Block a user