1
0
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:
shanshuirenjia
2018-09-04 17:16:50 +08:00
committed by Daniel Pan
parent b8662376a1
commit 681a4235a4
22 changed files with 1019 additions and 785 deletions

View File

@@ -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;

View File

@@ -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">

View File

@@ -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>
);

View File

@@ -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;