diff --git a/frontend/src/components/index-viewer.js b/frontend/src/components/index-viewer.js
index 98f87407d5..73e9ce801e 100644
--- a/frontend/src/components/index-viewer.js
+++ b/frontend/src/components/index-viewer.js
@@ -3,9 +3,8 @@ import PropTypes from 'prop-types';
import MarkdownViewer from '@seafile/seafile-editor/dist/viewer/markdown-viewer';
const viewerPropTypes = {
- onLinkClick: PropTypes.func,
- onContentRendered: PropTypes.func.isRequired,
- indexContent: PropTypes.string,
+ indexContent: PropTypes.string.isRequired,
+ onLinkClick: PropTypes.func.isRequired,
};
class IndexContentViewer extends React.Component {
@@ -15,6 +14,10 @@ class IndexContentViewer extends React.Component {
this.props.onLinkClick(event);
}
+ onContentRendered = () => {
+ // todo
+ }
+
render() {
return (
diff --git a/frontend/src/components/tree-view-2/tree-node-view.js b/frontend/src/components/tree-view-2/tree-node-view.js
deleted file mode 100644
index 469bb2dfb0..0000000000
--- a/frontend/src/components/tree-view-2/tree-node-view.js
+++ /dev/null
@@ -1,167 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import TreeNodeMenu from './tree-node-menu';
-import { permission } from '../../utils/constants';
-
-const propTypes = {
- node: PropTypes.object.isRequired,
- currentPath: PropTypes.string.isRequired,
- paddingLeft: PropTypes.number.isRequired,
- isItemFreezed: PropTypes.bool.isRequired,
- onNodeClick: PropTypes.func.isRequired,
- onNodeExpanded: PropTypes.func.isRequired,
- onNodeCollapse: PropTypes.func.isRequired,
- onNodeDragStart: PropTypes.func.isRequired,
- onFreezedItem: PropTypes.func.isRequired,
- onUnFreezedItem: PropTypes.func.isRequired,
-};
-
-class TreeNodeView extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- isHighlight: false,
- isShowOperationMenu: false
- };
- }
-
- onMouseEnter = () => {
- if (!this.props.isItemFreezed) {
- this.setState({
- isShowOperationMenu: true,
- isHighlight: true,
- });
- }
- }
-
- onMouseLeave = () => {
- if (!this.props.isItemFreezed) {
- this.setState({
- isShowOperationMenu: false,
- isHighlight: false,
- });
- }
- }
-
- onNodeClick = () => {
- this.props.onNodeClick(this.props.node);
- }
-
- onLoadToggle = () => {
- let { node } = this.props;
- if (node.isExpanded) {
- this.props.onNodeCollapse(node);
- } else {
- this.props.onNodeExpanded(node);
- }
- }
-
- onNodeDragStart = (e) => {
- this.props.onNodeDragStart(e, this.props.node);
- }
-
- onUnFreezedItem = () => {
- this.setState({isShowOperationMenu: false});
- this.props.onUnFreezedItem();
- }
-
- onMenuItemClick = (operation, node) => {
- this.props.onMenuItemClick(operation, node);
- }
-
- getNodeTypeAndIcon = () => {
- let { node } = this.props;
- let icon = '';
- let type = '';
- if (node.object.type === 'dir') {
- icon =
- type = 'dir';
- } else {
- let index = node.object.name.lastIndexOf('.');
- if (index === -1) {
- icon =
- type = 'file';
- } else {
- let suffix = node.object.name.slice(index).toLowerCase();
- if (suffix === '.png' || suffix === '.jpg') {
- icon =
- type = 'image';
- } else {
- icon =
- type = 'file';
- }
- }
- }
- return {icon, type};
- }
-
- renderChildren = () => {
- let { node, paddingLeft } = this.props;
- if (!node.hasChildren()) {
- return '';
- }
- return (
-
- {node.children.map(item => {
- return (
-
- );
- })}
-
- );
- }
-
- render() {
- let { currentPath, node } = this.props;
- let { type, icon } = this.getNodeTypeAndIcon();
- let hlClass = this.state.isHighlight ? 'tree-node-inner-hover ' : '';
- if (node.path === currentPath) {
- hlClass = 'tree-node-hight-light';
- }
- return (
-
-
-
{node.object.name}
-
- {type === 'dir' && (!node.isLoaded || (node.isLoaded && node.hasChildren())) && (
- e.stopPropagation()}
- onClick={this.onLoadToggle}
- >
- )}
- {icon}
-
-
- {(permission && this.state.isShowOperationMenu) && (
-
- )}
-
-
- {node.isExpanded && this.renderChildren()}
-
- );
- }
-}
-
-TreeNodeView.propTypes = propTypes;
-
-export default TreeNodeView;
diff --git a/frontend/src/components/tree-view-2/tree-view.js b/frontend/src/components/tree-view-2/tree-view.js
deleted file mode 100644
index 6b85ec3ddc..0000000000
--- a/frontend/src/components/tree-view-2/tree-view.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import TreeNodeView from './tree-node-view';
-
-const propTypes = {
- treeData: PropTypes.object.isRequired,
- currentPath: PropTypes.string.isRequired,
- onMenuItemClick: PropTypes.func.isRequired,
- onNodeClick: PropTypes.func.isRequired,
- onNodeExpanded: PropTypes.func.isRequired,
- onNodeCollapse: PropTypes.func.isRequired,
-};
-
-const PADDING_LEFT = 12;
-
-class TreeView extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- isItemFreezed: false,
- };
- }
-
- onNodeDragStart = (e, node) => {
- // todo
- }
-
- onFreezedItem = () => {
- this.setState({isItemFreezed: true});
- }
-
- onUnFreezedItem = () => {
- this.setState({isItemFreezed: false});
- }
-
- render() {
- return (
-
-
-
- );
- }
-}
-
-TreeView.propTypes = propTypes;
-
-export default TreeView;
diff --git a/frontend/src/components/tree-view-2/tree.js b/frontend/src/components/tree-view-2/tree.js
deleted file mode 100644
index dc1a148448..0000000000
--- a/frontend/src/components/tree-view-2/tree.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import TreeNode from './tree-node';
-
-class Tree {
-
- constructor() {
- this.root = null;
- }
-
- clone() {
- let tree = new Tree();
- if (this.root) {
- tree.root = this.root.clone();
- }
- return tree;
- }
-
- setRoot(node) {
- this.root = node;
- }
-
- getNodeByPath(path) {
- let findNode = null;
- function callback(currentNode) {
- if (currentNode.path === path) {
- findNode = currentNode;
- return true;
- }
- return false;
- }
- this.traverseDF(callback);
- return findNode;
- }
-
- getNodeChildrenObject(node) {
- let objects = node.children.map(item => {
- let object = item.object;
- return object;
- });
- return objects;
- }
-
- addNodeToParent(node, parentNode) {
- parentNode.addChild(node);
- }
-
- addNodeListToParent(nodeList, parentNode) {
- nodeList.forEach(node => {
- parentNode.addChild(node);
- });
- }
-
- deleteNode(node) {
- let parentNode = this.getNodeByPath(node.parentNode.path);
- parentNode.deleteChild(node);
- }
-
- deleteNodeList(nodeList) {
- nodeList.forEach(node => {
- this.deleteNode(node);
- });
- }
-
- renameNode(node, newName) {
- node.rename(newName);
- }
-
- updateNode(node, keys, newValues) {
- node.updateObjectParam(keys, newValues);
- }
-
- moveNode(node, destNode) {
- this.deleteNode(node);
- destNode.addChild(node);
- }
-
- copyNode(node, destNode) {
- destNode.addChild(node);
- }
-
- traverseDF(callback) {
- let stack = [];
- let found = false;
- stack.unshift(this.root);
- let currentNode = stack.shift();
- while (!found && currentNode) {
- found = callback(currentNode) == true ? true : false;
- if (!found) {
- stack.unshift(...currentNode.children);
- currentNode = stack.shift();
- }
- }
- }
-
- traverseBF(callback) {
- let queue = [];
- let found = false;
- queue.push(this.root);
- let currentNode = queue.shift();
- while (!found && currentNode) {
- found = callback(currentNode) === true ? true : false;
- if (!found) {
- queue.push(...currentNode.children);
- currentNode = queue.shift();
- }
- }
- }
-
- expandNode(node) {
- node.isExpanded = true;
- while (node.parentNode) {
- node.parentNode.isExpanded = true;
- node = node.parentNode;
- }
- }
-
- collapseNode(node) {
- node.isExpanded = false;
- }
-
- isNodeChild(node, parentNode) {
- return parentNode.children.some(item => {
- return item.path === node.path;
- });
- }
-
- serializeToJson() {
- return this.root.serializeToJson();
- }
-
- deserializefromJson(json) {
- let root = TreeNode.deserializefromJson(json);
- let tree = new Tree();
- tree.setRoot(root);
- return tree;
- }
-
-}
-
-export default Tree;
diff --git a/frontend/src/components/tree-view/node-menu.js b/frontend/src/components/tree-view/node-menu.js
deleted file mode 100644
index 1488c63d07..0000000000
--- a/frontend/src/components/tree-view/node-menu.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { gettext } from '../../utils/constants';
-
-const propTypes = {
- menuPosition: PropTypes.object.isRequired,
- currentNode: PropTypes.object.isRequired,
- toggleRename: PropTypes.func.isRequired,
- toggleDelete: PropTypes.func.isRequired,
- toggleAddFile: PropTypes.func.isRequired,
- toggleAddFolder: PropTypes.func.isRequired,
-};
-
-class NodeMenu extends React.Component {
-
- toggleAddFile = () => {
- this.props.toggleAddFile();
- }
-
- toggleAddFolder = () => {
- this.props.toggleAddFolder();
- }
-
- toggleRename = () => {
- this.props.toggleRename();
- }
-
- toggleDelete = () => {
- this.props.toggleDelete();
- }
-
- renderNodeMenu() {
- let position = this.props.menuPosition;
- let style = {position: 'fixed',left: position.left, top: position.top, display: 'block'};
-
- if (this.props.currentNode.type === 'dir') {
- if (this.props.currentNode.name === '/') {
- return (
-
- - {gettext('New Folder')}
- - {gettext('New File')}
-
- );
- }
-
- return (
-
- - {gettext('New Folder')}
- - {gettext('New File')}
- - {gettext('Rename')}
- - {gettext('Delete')}
-
- );
- }
-
- return (
-
- - {gettext('Rename')}
- - {gettext('Delete')}
-
- );
-
- }
-
- render() {
- if (!this.props.currentNode) {
- return (
);
- }
- return (
-
- {this.renderNodeMenu()}
-
- );
- }
-}
-
-NodeMenu.propTypes = propTypes;
-
-export default NodeMenu;
diff --git a/frontend/src/components/tree-view/node.js b/frontend/src/components/tree-view/node.js
deleted file mode 100644
index 42bbb8f9e9..0000000000
--- a/frontend/src/components/tree-view/node.js
+++ /dev/null
@@ -1,128 +0,0 @@
-class Node {
-
- static deserializefromJson(object) {
- const {name, type, size, last_update_time, permission, parent_path, isExpanded = true, children = []} = object;
-
- const node = new Node({
- name,
- type,
- size,
- last_update_time,
- permission,
- parent_path,
- isExpanded,
- children: children.map(item => Node.deserializefromJson(item)),
- });
-
- return node;
- }
-
- constructor({name, type, size, last_update_time, permission, parent_path, isExpanded, children}) {
- this.name = name;
- this.type = type;
- this.size = size;
- this.last_update_time = last_update_time;
- this.permission = permission;
- this.parent_path = parent_path;
- 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,
- permission: this.permission,
- parent_path: this.parent_path,
- 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 {
- let p = this.parent.path;
- return p === '/' ? (p + this.name) : (p + '/' + this.name);
- }
- }
-
- hasChildren() {
- return this.children.length > 0;
- }
-
- isRoot() {
- return this.parent === undefined;
- }
-
- isMarkdown() {
- if (this.isDir()) {
- return false;
- }
- let index = this.name.lastIndexOf('.');
- if (index == -1) {
- return false;
- } else {
- let type = this.name.substring(index).toLowerCase();
- if (type == '.md' || type == '.markdown') {
- return true;
- } else {
- return false;
- }
- }
- }
-
- isFile() {
- return this.type === 'file';
- }
-
- isDir() {
- return this.type == 'dir';
- }
-
- 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;
- }
- }
- }
-
- serializeToJson() {
- var children = [];
- if (this.hasChildren()) {
- children = this.children.map(m => m.toJSON());
- }
-
- const object = {
- name: this.name,
- type: this.type,
- size: this.size,
- last_update_time: this.last_update_time,
- permission: this.permission,
- parent_path: this.parent_path,
- isExpanded: this.isExpanded,
- children: children
- };
-
- return object;
- }
-
-}
-
-export default Node;
diff --git a/frontend/src/components/tree-view-2/tree-helper.js b/frontend/src/components/tree-view/tree-helper.js
similarity index 100%
rename from frontend/src/components/tree-view-2/tree-helper.js
rename to frontend/src/components/tree-view/tree-helper.js
diff --git a/frontend/src/components/tree-view-2/tree-node-menu.js b/frontend/src/components/tree-view/tree-node-menu.js
similarity index 100%
rename from frontend/src/components/tree-view-2/tree-node-menu.js
rename to frontend/src/components/tree-view/tree-node-menu.js
diff --git a/frontend/src/components/tree-view/tree-node-view.js b/frontend/src/components/tree-view/tree-node-view.js
index 2af8ec3dc3..51a3fd66a6 100644
--- a/frontend/src/components/tree-view/tree-node-view.js
+++ b/frontend/src/components/tree-view/tree-node-view.js
@@ -1,210 +1,169 @@
import React from 'react';
import PropTypes from 'prop-types';
-import MenuControl from '../menu-control';
+import TreeNodeMenu from './tree-node-menu';
import { permission } from '../../utils/constants';
const propTypes = {
- isNodeItemFrezee: PropTypes.bool.isRequired,
+ node: PropTypes.object.isRequired,
currentPath: PropTypes.string.isRequired,
paddingLeft: PropTypes.number.isRequired,
- node: PropTypes.object.isRequired,
- treeView: PropTypes.object.isRequired,
- onDirCollapse: PropTypes.func.isRequired,
+ isNodeMenuShow: PropTypes.bool.isRequired,
+ isItemFreezed: PropTypes.bool.isRequired,
+ onNodeClick: PropTypes.func.isRequired,
+ onNodeExpanded: PropTypes.func.isRequired,
+ onNodeCollapse: PropTypes.func.isRequired,
+ onNodeDragStart: PropTypes.func.isRequired,
+ onFreezedItem: PropTypes.func.isRequired,
+ onUnFreezedItem: PropTypes.func.isRequired,
};
-function sortByType(a, b) {
- if (a.type == 'dir' && b.type != 'dir') {
- return -1;
- } else if (a.type != 'dir' && b.type == 'dir') {
- return 1;
- } else {
- return a.name.localeCompare(b.name);
- }
-}
-
class TreeNodeView extends React.Component {
constructor(props) {
super(props);
this.state = {
- isMenuIconShow: false
+ isHighlight: false,
+ isShowOperationMenu: false
};
}
- onClick = () => {
- // e.nativeEvent.stopImmediatePropagation();
- let { node } = this.props;
- this.props.treeView.onNodeClick(node);
- }
-
onMouseEnter = () => {
- if (!this.props.isNodeItemFrezee) {
+ if (!this.props.isItemFreezed) {
this.setState({
- isMenuIconShow: true
+ isShowOperationMenu: true,
+ isHighlight: true,
});
}
}
onMouseLeave = () => {
- if (!this.props.isNodeItemFrezee) {
+ if (!this.props.isItemFreezed) {
this.setState({
- isMenuIconShow: false
+ isShowOperationMenu: false,
+ isHighlight: false,
});
}
}
- handleCollapse = (e) => {
- e.stopPropagation();
- this.props.onDirCollapse(this.props.node);
+ onNodeClick = () => {
+ this.props.onNodeClick(this.props.node);
}
- onDragStart = (e) => {
- const { node } = this.props;
- this.props.treeView.onDragStart(e, node);
- }
-
- onMenuControlClick = (e) => {
- e.stopPropagation();
- e.nativeEvent.stopImmediatePropagation();
- const { node } = this.props;
- this.props.treeView.onShowContextMenu(e, node);
- }
-
- hideMenuIcon = () => {
- this.setState({
- isMenuIconShow: false
- });
- }
-
- componentDidMount() {
- document.addEventListener('click', this.hideMenuIcon);
- }
-
- componentWillUnmount() {
- document.removeEventListener('click', this.hideMenuIcon);
- }
-
- renderCollapse = () => {
- const { node } = this.props;
-
- if (node.hasChildren()) {
- const { isExpanded } = node;
- return (
-
e.stopPropagation()}
- onClick={this.handleCollapse}
- />
- );
+ onLoadToggle = () => {
+ let { node } = this.props;
+ if (node.isExpanded) {
+ this.props.onNodeCollapse(node);
+ } else {
+ this.props.onNodeExpanded(node);
}
-
- return null;
}
- renderChildren = () => {
- const { node } = this.props;
- if (node.children && node.children.length) {
- const childrenStyles = {
- paddingLeft: this.props.paddingLeft
- };
- var l = node.children.sort(sortByType);
- /*
- the `key` property is needed. Otherwise there is a warning in the console
- */
- return (
-
- {l.map(child => {
- return (
-
- );
- })}
-
- );
- }
-
- return null;
+ onNodeDragStart = (e) => {
+ this.props.onNodeDragStart(e, this.props.node);
}
- renderMenuController() {
- if (permission) {
- let isShow = (this.props.node.path === this.props.currentPath);
- return (
-
-
-
- );
- }
- return;
+ onUnFreezedItem = () => {
+ this.setState({isShowOperationMenu: false});
+ this.props.onUnFreezedItem();
}
- getNodeTypeAndIcon() {
- const node = this.props.node;
+ onMenuItemClick = (operation, node) => {
+ this.props.onMenuItemClick(operation, node);
+ }
+
+ getNodeTypeAndIcon = () => {
+ let { node } = this.props;
let icon = '';
let type = '';
- if (node.type === 'dir') {
- icon = ;
+ if (node.object.type === 'dir') {
+ icon =
type = 'dir';
} else {
- let index = node.name.lastIndexOf('.');
- if (index === -1) {
- icon = ;
+ let index = node.object.name.lastIndexOf('.');
+ if (index === -1) {
+ icon =
type = 'file';
} else {
- type = node.name.substring(index).toLowerCase();
- if (type === '.png' || type === '.jpg') {
- icon = ;
+ let suffix = node.object.name.slice(index).toLowerCase();
+ if (suffix === '.png' || suffix === '.jpg') {
+ icon =
type = 'image';
} else {
- icon = ;
+ icon =
type = 'file';
}
}
}
-
- return { type, icon };
+ return {icon, type};
}
- render() {
- const styles = {};
- let node = this.props.node;
- let { type, icon } = this.getNodeTypeAndIcon();
- let hlClass = '';
- if (node.path === this.props.currentPath) {
- hlClass = 'tree-node-hight-light';
+ renderChildren = () => {
+ let { node, paddingLeft } = this.props;
+ if (!node.hasChildren()) {
+ return '';
}
-
return (
-
-
-
{node.name}
-
- {this.renderCollapse()}
- {icon}
-
- {this.renderMenuController()}
-
- {node.isExpanded ? this.renderChildren() : null}
+
+ {node.children.map(item => {
+ return (
+
+ );
+ })}
);
}
+ render() {
+ let { currentPath, node, isNodeMenuShow } = this.props;
+ let { type, icon } = this.getNodeTypeAndIcon();
+ let hlClass = this.state.isHighlight ? 'tree-node-inner-hover ' : '';
+ if (node.path === currentPath) {
+ hlClass = 'tree-node-hight-light';
+ }
+ return (
+
+
+
{node.object.name}
+
+ {type === 'dir' && (!node.isLoaded || (node.isLoaded && node.hasChildren())) && (
+ e.stopPropagation()}
+ onClick={this.onLoadToggle}
+ >
+ )}
+ {icon}
+
+ {isNodeMenuShow && (
+
+ {(permission && this.state.isShowOperationMenu) && (
+
+ )}
+
+ )}
+
+ {node.isExpanded && this.renderChildren()}
+
+ );
+ }
}
TreeNodeView.propTypes = propTypes;
diff --git a/frontend/src/components/tree-view-2/tree-node.js b/frontend/src/components/tree-view/tree-node.js
similarity index 100%
rename from frontend/src/components/tree-view-2/tree-node.js
rename to frontend/src/components/tree-view/tree-node.js
diff --git a/frontend/src/components/tree-view/tree-view.js b/frontend/src/components/tree-view/tree-view.js
index 1871211adb..fd986c098a 100644
--- a/frontend/src/components/tree-view/tree-view.js
+++ b/frontend/src/components/tree-view/tree-view.js
@@ -1,62 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import TreeNodeView from './tree-node-view';
-import editorUtilities from '../../utils/editor-utilties';
const propTypes = {
- permission: PropTypes.string,
- isNodeItemFrezee: PropTypes.bool.isRequired,
- currentPath: PropTypes.string.isRequired,
+ isNodeMenuShow: PropTypes.bool.isRequired,
treeData: PropTypes.object.isRequired,
- onShowContextMenu: PropTypes.func.isRequired,
+ currentPath: PropTypes.string.isRequired,
+ onMenuItemClick: PropTypes.func,
onNodeClick: PropTypes.func.isRequired,
- onDirCollapse: PropTypes.func.isRequired,
+ onNodeExpanded: PropTypes.func.isRequired,
+ onNodeCollapse: PropTypes.func.isRequired,
};
-class TreeView extends React.PureComponent {
+const PADDING_LEFT = 12;
- change = (tree) => {
- /*
- this._updated = true;
- if (this.props.onChange) this.props.onChange(tree.obj);
- */
+class TreeView extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isItemFreezed: false,
+ };
}
- onDragStart = (e, node) => {
- const url = editorUtilities.getFileURL(node);
- e.dataTransfer.setData('text/uri-list', url);
- e.dataTransfer.setData('text/plain', url);
+ onNodeDragStart = (e, node) => {
+ // todo
}
- onNodeClick = (node) => {
- this.props.onNodeClick(node);
+ onFreezedItem = () => {
+ this.setState({isItemFreezed: true});
}
- onShowContextMenu = (e, node) => {
- this.props.onShowContextMenu(e, node);
+ onUnFreezedItem = () => {
+ this.setState({isItemFreezed: false});
}
render() {
- if (!this.props.treeData.root) {
- return
Loading...
;
- }
-
return (
-
);
}
-
}
TreeView.propTypes = propTypes;
diff --git a/frontend/src/components/tree-view/tree.js b/frontend/src/components/tree-view/tree.js
index b094a5a725..dc1a148448 100644
--- a/frontend/src/components/tree-view/tree.js
+++ b/frontend/src/components/tree-view/tree.js
@@ -1,181 +1,82 @@
-import Node from './node';
-import moment from 'moment';
-import { Utils } from '../../utils/utils';
-
-const lang = window.app.config.lang;
-moment.locale(lang);
+import TreeNode from './tree-node';
class Tree {
-
+
constructor() {
this.root = null;
}
clone() {
- var t = new Tree();
- if (this.root)
- t.root = this.root.clone();
- return t;
+ let tree = new Tree();
+ if (this.root) {
+ tree.root = this.root.clone();
+ }
+ return tree;
}
setRoot(node) {
this.root = node;
}
- addNodeToParent(node, parentNode) {
- node.parent = parentNode;
- parentNode.children.push(node);
- return node;
- }
-
- removeNodeFromParent(node, parentNode) {
- let children = parentNode.children;
- let removeNode = null;
- let index = null;
- for (let i = 0; i < children.length; i++) {
- if (node.path === children[i].path) {
- removeNode = children[i];
- index = i;
- break;
+ getNodeByPath(path) {
+ let findNode = null;
+ function callback(currentNode) {
+ if (currentNode.path === path) {
+ findNode = currentNode;
+ return true;
}
+ return false;
}
- node.parent = null;
- parentNode.children.splice(index, 1);
- return removeNode ? removeNode : null;
+ this.traverseDF(callback);
+ return findNode;
}
- addNode(node) {
- let treeNodeParent = this.findNodeParentFromTree(node);
- if (treeNodeParent) {
- this.addNodeToParent(node, treeNodeParent);
- return true;
- }
- return false;
+ getNodeChildrenObject(node) {
+ let objects = node.children.map(item => {
+ let object = item.object;
+ return object;
+ });
+ return objects;
+ }
+
+ addNodeToParent(node, parentNode) {
+ parentNode.addChild(node);
+ }
+
+ addNodeListToParent(nodeList, parentNode) {
+ nodeList.forEach(node => {
+ parentNode.addChild(node);
+ });
}
deleteNode(node) {
- let treeNodeParent = this.findNodeParentFromTree(node);
- if (treeNodeParent) {
- this.removeNodeFromParent(node, treeNodeParent);
- return true;
- }
- return false;
+ let parentNode = this.getNodeByPath(node.parentNode.path);
+ parentNode.deleteChild(node);
}
- deleteNodeByPath(path) {
- let node = this.getNodeByPath(path);
- this.deleteNode(node);
- }
-
- moveNode(node, moveToNode, isDestroy) {
- let moveNode = node.clone();
- this.addNodeToParent(moveNode, moveToNode);
- if (isDestroy) {
+ deleteNodeList(nodeList) {
+ nodeList.forEach(node => {
this.deleteNode(node);
- }
+ });
}
- moveNodeByPath(path, moveToPath, isDestroy) {
- let node = this.getNodeByPath(path);
- let moveToNode = this.getNodeByPath(moveToPath);
- this.moveNode(node, moveToNode, isDestroy);
+ renameNode(node, newName) {
+ node.rename(newName);
}
- updateNodeParam(node, param, newValue) {
- let treeNode = this.findNodeFromTree(node);
- if (treeNode && treeNode[param]) {
- treeNode[param] = newValue;
- return true;
- }
- return false;
+ updateNode(node, keys, newValues) {
+ node.updateObjectParam(keys, newValues);
}
- updateNodeParamByPath(path, param, newValue) {
- let node = this.getNodeByPath(path);
- this.updateNodeParam(node, param, newValue);
+ moveNode(node, destNode) {
+ this.deleteNode(node);
+ destNode.addChild(node);
}
- findNode(node) {
- return this.findNodeFromTree(node);
+ copyNode(node, destNode) {
+ destNode.addChild(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;
- }
-
- expandNode(node) {
- let treeNode = this.findNodeFromTree(node);
- if (treeNode) {
- treeNode.isExpanded = true;
- while (treeNode.parent) {
- treeNode.parent.isExpanded = true;
- treeNode = treeNode.parent;
- }
- return true;
- }
- return false;
- }
-
- collapseNode(node) {
- let treeNode = this.findNodeFromTree(node);
- if (treeNode) {
- treeNode.isExpanded = false;
- return true;
- }
- return false;
- }
-
- resetTreeState() {
- 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;
@@ -204,82 +105,33 @@ class Tree {
}
}
- parseModelToTree(model) {
- var node = new Node({
- name: model.name,
- type: model.type,
- size: Utils.bytesToSize(model.size),
- last_update_time: moment.unix(model.last_update_time).fromNow(),
- permission: model.permission,
- parent_path: model.parent_path,
- isExpanded: false
- });
- if (model.children instanceof Array) {
- for (let child of model.children) {
- this.addNodeToParent(this.parseNodeToTree(child), node);
- }
+ expandNode(node) {
+ node.isExpanded = true;
+ while (node.parentNode) {
+ node.parentNode.isExpanded = true;
+ node = node.parentNode;
}
- return node;
+ }
+
+ collapseNode(node) {
+ node.isExpanded = false;
}
- parseListToTree(nodeList) {
-
- function getNodePath(parentPath, nodeName) {
- return parentPath === '/' ? (parentPath + nodeName) : (parentPath + '/' + nodeName);
- }
-
- 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) {
- let node = new Node({
- name: nodeObj.name,
- type: nodeObj.type,
- size: Utils.bytesToSize(nodeObj.size),
- last_update_time: moment.unix(nodeObj.last_update_time).fromNow(),
- permission: nodeObj.permission,
- parent_path: nodeObj.parent_path,
- isExpanded: false
- });
- node.parent_path = nodeObj.parent_path;
- treeNodeList.push(node);
- if (node.isDir()) {
- map.set(getNodePath(node.parent_path, node.name), node);
- }
- }
-
- for (let node of treeNodeList) {
- let p = map.get(node.parent_path);
- if (p === undefined) {
- /* eslint-disable */
- console.log('warning: node ' + node.parent_path + ' not exist');
- /* eslint-enable */
- } else {
- this.addNodeToParent(node, p);
- }
- }
-
+ isNodeChild(node, parentNode) {
+ return parentNode.children.some(item => {
+ return item.path === node.path;
+ });
}
- parseNodeToTree(node) {
- var newNode = new Node({
- name: node.name,
- type: node.type,
- size: Utils.bytesToSize(node.size),
- last_update_time: moment.unix(node.last_update_time).fromNow(),
- permission: node.permission,
- parent_path: node.parent_path,
- isExpanded: false
- });
- if (node.children instanceof Array) {
- for (let child of node.children) {
- this.addNodeToParent(this.parseNodeToTree(child), newNode);
- }
- }
- return newNode;
+ serializeToJson() {
+ return this.root.serializeToJson();
+ }
+
+ deserializefromJson(json) {
+ let root = TreeNode.deserializefromJson(json);
+ let tree = new Tree();
+ tree.setRoot(root);
+ return tree;
}
}
diff --git a/frontend/src/components/tree-dir-view/tree-dir-list.js b/frontend/src/components/wiki-dir-list-view/wiki-dir-list-item.js
similarity index 56%
rename from frontend/src/components/tree-dir-view/tree-dir-list.js
rename to frontend/src/components/wiki-dir-list-view/wiki-dir-list-item.js
index 8333fd2519..324159a53f 100644
--- a/frontend/src/components/tree-dir-view/tree-dir-list.js
+++ b/frontend/src/components/wiki-dir-list-view/wiki-dir-list-item.js
@@ -4,17 +4,17 @@ import { siteRoot } from '../../utils/constants';
import { Utils } from '../../utils/utils';
const propTypes = {
- node: PropTypes.object.isRequired,
- onMainNodeClick: PropTypes.func.isRequired,
+ path: PropTypes.string.isRequired,
+ dirent: PropTypes.object.isRequired,
+ onDirentClick: PropTypes.func.isRequired,
};
-class TreeDirList extends React.Component {
+class WikiDirListItem extends React.Component {
constructor(props) {
super(props);
this.state = {
highlight: false,
- isOperationShow: false,
};
}
@@ -26,22 +26,22 @@ class TreeDirList extends React.Component {
this.setState({highlight: false});
}
- onMainNodeClick = (e) => {
+ onDirentClick = (e) => {
e.preventDefault();
- this.props.onMainNodeClick(this.props.node);
+ this.props.onDirentClick(this.props.dirent);
}
render() {
- let node = this.props.node;
- let href = siteRoot + 'wikis' + node.path;
+ let { path, dirent } = this.props;
+ let href = siteRoot + 'wikis' + Utils.joinPath(path, dirent.name);
let size = Utils.isHiDPI() ? 48 : 24;
let iconUrl = '';
- if (node.type === 'file') {
- iconUrl = Utils.getFileIconUrl(node.name, size);
+ if (dirent.type === 'file') {
+ iconUrl = Utils.getFileIconUrl(dirent.name, size);
} else {
let isReadOnly = false;
- if (node.permission === 'r' || node.permission === 'preview') {
+ if (dirent.permission === 'r' || dirent.permission === 'preview') {
isReadOnly = true;
}
iconUrl = Utils.getFolderIconUrl({isReadOnly, size});
@@ -53,15 +53,15 @@ class TreeDirList extends React.Component {
- {node.name}
+ {dirent.name}
|
-
{node.size} |
-
{node.last_update_time} |
+
{dirent.size} |
+
{dirent.last_update_time} |
);
}
}
-TreeDirList.propTypes = propTypes;
+WikiDirListItem.propTypes = propTypes;
-export default TreeDirList;
+export default WikiDirListItem;
diff --git a/frontend/src/components/tree-dir-view/tree-dir-view.js b/frontend/src/components/wiki-dir-list-view/wiki-dir-list-view.js
similarity index 53%
rename from frontend/src/components/tree-dir-view/tree-dir-view.js
rename to frontend/src/components/wiki-dir-list-view/wiki-dir-list-view.js
index b349b985a1..f1069e2719 100644
--- a/frontend/src/components/tree-dir-view/tree-dir-view.js
+++ b/frontend/src/components/wiki-dir-list-view/wiki-dir-list-view.js
@@ -1,19 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants';
-import TreeDirList from './tree-dir-list';
+import WikiDirListItem from './wiki-dir-list-item';
const propTypes = {
- node: PropTypes.object.isRequired,
- onMainNodeClick: PropTypes.func.isRequired,
+ path: PropTypes.string.isRequired,
+ direntList: PropTypes.array.isRequired,
+ onDirentClick: PropTypes.func.isRequired,
};
-class TreeDirView extends React.Component {
+class WikiDirListView extends React.Component {
render() {
- let node = this.props.node;
- let children = node.hasChildren() ? node.children : null;
-
return (
@@ -25,9 +23,9 @@ class TreeDirView extends React.Component {
- {children && children.map((node, index) => {
+ {this.props.direntList.length !== 0 && this.props.direntList.map((dirent, index) => {
return (
-
+
);
})}
@@ -36,6 +34,6 @@ class TreeDirView extends React.Component {
}
}
-TreeDirView.propTypes = propTypes;
+WikiDirListView.propTypes = propTypes;
-export default TreeDirView;
\ No newline at end of file
+export default WikiDirListView;
diff --git a/frontend/src/pages/repo-wiki-mode/side-panel.js b/frontend/src/pages/repo-wiki-mode/side-panel.js
index 22e1508791..2f4a7dcd7c 100644
--- a/frontend/src/pages/repo-wiki-mode/side-panel.js
+++ b/frontend/src/pages/repo-wiki-mode/side-panel.js
@@ -1,9 +1,8 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import { gettext, permission } from '../../utils/constants';
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
-import { gettext } from '../../utils/constants';
-import { Utils } from '../../utils/utils';
-import TreeView from '../../components/tree-view-2/tree-view';
+import TreeView from '../../components/tree-view/tree-view';
import Logo from '../../components/logo';
import Loading from '../../components/loading';
import toaster from '../../components/toast';
@@ -43,6 +42,7 @@ class SidePanel extends Component {
isAddFolderDialogShow: false,
isRenameDialogShow: false,
};
+ this.isNodeMenuShow = true;
}
componentWillReceiveProps(nextProps) {
@@ -166,7 +166,7 @@ class SidePanel extends Component {
{gettext('Files')}
- {this.state.isMenuIconShow && (
+ {(permission && this.state.isMenuIconShow) && (
) :
( {
this.props.onMenuClick();
}
onEditClick = (e) => {
- // const w=window.open('about:blank')
e.preventDefault();
window.location.href= siteRoot + 'lib/' + repoID + '/file' + this.props.filePath + '?mode=edit';
}
@@ -47,16 +38,14 @@ class MainPanel extends Component {
this.props.onMainNavBarClick(e.target.dataset.path);
}
-
- render() {
-
- let filePathList = this.props.filePath.split('/');
+ renderNavPath = () => {
+ let paths = this.props.path.split('/');
let nodePath = '';
- let pathElem = filePathList.map((item, index) => {
+ let pathElem = paths.map((item, index) => {
if (item === '') {
return;
}
- if (index === (filePathList.length - 1)) {
+ if (index === (paths.length - 1)) {
return (
/{item}
);
@@ -75,18 +64,21 @@ class MainPanel extends Component {
);
}
});
+ return pathElem;
+ }
+
+ render() {
return (
- {loginUser &&
+ {username && (
- {
- this.props.permission === 'rw' &&
+ {this.props.permission === 'rw' && (
- }
+ )}
- }
+ )}
- {this.props.isViewFileState &&
+ {this.props.isDataLoading && }
+ {(!this.props.isDataLoading && this.props.isViewFile) && (
- }
- {!this.props.isViewFileState &&
-
- }
+ )}
+ {(!this.props.isDataLoading && !this.props.isViewFile) && (
+
+ )}
diff --git a/frontend/src/pages/wiki/side-panel.js b/frontend/src/pages/wiki/side-panel.js
index 5e80fa3061..059777e7a1 100644
--- a/frontend/src/pages/wiki/side-panel.js
+++ b/frontend/src/pages/wiki/side-panel.js
@@ -1,194 +1,52 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
-import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
import { gettext, siteRoot, repoID } from '../../utils/constants';
import Logo from '../../components/logo';
+import Loading from '../../components/loading';
import TreeView from '../../components/tree-view/tree-view';
-import NodeMenu from '../../components/tree-view/node-menu';
-import Delete from '../../components/dialog/delete-dialog';
-import Rename from '../../components/dialog/rename-dialog';
-import CreateFolder from '../../components/dialog/create-folder-dialog';
-import CreateFile from '../../components/dialog/create-file-dialog';
import IndexContentViewer from '../../components/index-viewer';
const propTypes = {
- changedNode: PropTypes.object,
- treeData: PropTypes.object.isRequired,
- currentPath: PropTypes.string.isRequired,
closeSideBar: PropTypes.bool.isRequired,
+ isTreeDataLoading: PropTypes.bool.isRequired,
+ treeData: PropTypes.object.isRequired,
+ indexNode: PropTypes.object,
+ indexContent: PropTypes.string.isRequired,
+ currentPath: PropTypes.string.isRequired,
onCloseSide: PropTypes.func.isRequired,
- onDirCollapse: PropTypes.func.isRequired,
onNodeClick: PropTypes.func.isRequired,
- onRenameNode: PropTypes.func.isRequired,
- onDeleteNode: PropTypes.func.isRequired,
- onAddFileNode: PropTypes.func.isRequired,
- onAddFolderNode: PropTypes.func.isRequired,
- onLinkClick: PropTypes.func,
- hasIndex: PropTypes.bool.isRequired,
- indexContent: PropTypes.string,
- indexPath: PropTypes.string,
- indexPermission: PropTypes.string,
+ onNodeCollapse: PropTypes.func.isRequired,
+ onNodeExpanded: PropTypes.func.isRequired,
+ onLinkClick: PropTypes.func.isRequired,
};
class SidePanel extends Component {
constructor(props) {
super(props);
- this.state = {
- currentNode: null,
- isNodeItemFrezee: false,
- isShowMenu: false,
- menuPosition: {
- left: 0,
- top: 0
- },
- isLoadFailed: false,
- isMenuIconShow: false,
- isHeaderMenuShow: false,
- isDeleteDialogShow: false,
- isAddFileDialogShow: false,
- isAddFolderDialogShow: false,
- isRenameDialogShow: false,
- };
- }
-
- componentDidMount() {
- document.addEventListener('click', this.onHideContextMenu);
- }
-
- componentWillReceiveProps(nextProps) {
- this.setState({currentNode: nextProps.changedNode});
- }
-
- componentWillUnmount() {
- document.removeEventListener('click', this.onHideContextMenu);
- }
-
- onMouseEnter = () => {
- this.setState({isMenuIconShow: true});
- }
-
- onMouseLeave = () => {
- this.setState({isMenuIconShow: false});
- }
-
- onDropdownToggleClick = (e) => {
- e.preventDefault();
- this.toggleOperationMenu();
- }
-
- toggleOperationMenu = () => {
- this.setState({isHeaderMenuShow: !this.state.isHeaderMenuShow});
- }
-
- onNodeClick = (e, node) => {
- this.setState({currentNode: node});
- this.props.onNodeClick(e, node);
- }
-
- onShowContextMenu = (e, node) => {
- let left = e.clientX - 8*16;
- let top = e.clientY + 10;
- let position = Object.assign({},this.state.menuPosition, {left: left, top: top});
- this.setState({
- isShowMenu: !this.state.isShowMenu,
- currentNode: node,
- menuPosition: position,
- isNodeItemFrezee: true
- });
- }
-
- onHideContextMenu = () => {
- if (!this.state.isShowMenu) {
- return;
- }
- this.setState({
- isShowMenu: false,
- isNodeItemFrezee: false
- });
- }
-
- onAddFolderToggle = () => {
- this.setState({isAddFolderDialogShow: !this.state.isAddFolderDialogShow});
- this.onHideContextMenu();
- }
-
- onAddFileToggle = () => {
- this.setState({isAddFileDialogShow: !this.state.isAddFileDialogShow});
- this.onHideContextMenu();
- }
-
- onRenameToggle = () => {
- this.setState({isRenameDialogShow: !this.state.isRenameDialogShow});
- this.onHideContextMenu();
- }
-
- onDeleteToggle = () => {
- this.setState({isDeleteDialogShow: !this.state.isDeleteDialogShow});
- this.onHideContextMenu();
- }
-
- onAddFolderNode = (dirPath) => {
- this.setState({isAddFolderDialogShow: !this.state.isAddFolderDialogShow});
- this.props.onAddFolderNode(dirPath);
- }
-
- onAddFileNode = (filePath) => {
- this.setState({isAddFileDialogShow: !this.state.isAddFileDialogShow});
- this.props.onAddFileNode(filePath);
- }
-
- onRenameNode = (newName) => {
- this.setState({isRenameDialogShow: !this.state.isRenameDialogShow});
- let node = this.state.currentNode;
- this.props.onRenameNode(node, newName);
- }
-
- onDeleteNode = () => {
- this.setState({isDeleteDialogShow: !this.state.isDeleteDialogShow});
- let node = this.state.currentNode;
- this.props.onDeleteNode(node);
- }
-
- addFolderCancel = () => {
- this.setState({isAddFolderDialogShow: !this.state.isAddFolderDialogShow});
- }
-
- addFileCancel = () => {
- this.setState({isAddFileDialogShow: !this.state.isAddFileDialogShow});
- }
-
- deleteCancel = () => {
- this.setState({isDeleteDialogShow: !this.state.isDeleteDialogShow});
- }
-
- renameCancel = () => {
- this.setState({isRenameDialogShow: !this.state.isRenameDialogShow});
+ this.isNodeMenuShow = false;
}
onEditClick = (e) => {
e.preventDefault();
- window.location.href= siteRoot + 'lib/' + repoID + '/file' + this.props.indexPath + '?mode=edit';
- }
-
- onContentRendered = () => {
- // todo
+ let indexNode = this.props.indexNode
+ window.location.href= siteRoot + 'lib/' + repoID + '/file' + indexNode.path + '?mode=edit';
}
renderIndexView = () => {
+ let indexNode = this.props.indexNode;
return (
{gettext('Contents')}
- {this.props.indexPermission === 'rw' &&
+ {indexNode.object.permission === 'rw' &&
}
@@ -198,76 +56,16 @@ class SidePanel extends Component {
renderTreeView = () => {
return (
-
- {gettext('Pages')}
-
- {this.state.isMenuIconShow && (
-
-
-
- {gettext('New Folder')}
- {gettext('New File')}
-
-
- )}
-
-
+ {gettext('Pages')}
{this.props.treeData && (
- )}
- {this.state.isShowMenu && (
-
- )}
- {this.state.isDeleteDialogShow && (
-
- )}
- {this.state.isAddFileDialogShow && (
-
- )}
- {this.state.isAddFolderDialogShow && (
-
- )}
- {this.state.isRenameDialogShow && (
-
)}
@@ -282,7 +80,9 @@ class SidePanel extends Component {
- {this.props.hasIndex ? this.renderIndexView() : this.renderTreeView()}}
+ {this.props.isTreeDataLoading && }
+ {!this.props.isTreeDataLoading && this.props.indexNode && this.renderIndexView() }
+ {!this.props.isTreeDataLoading && !this.props.indexNode && this.renderTreeView() }
);
diff --git a/frontend/src/repo-wiki-mode.js b/frontend/src/repo-wiki-mode.js
index 590e2540cc..d483bea0a0 100644
--- a/frontend/src/repo-wiki-mode.js
+++ b/frontend/src/repo-wiki-mode.js
@@ -7,8 +7,8 @@ import { Utils } from './utils/utils';
import collabServer from './utils/collab-server';
import SidePanel from './pages/repo-wiki-mode/side-panel';
import MainPanel from './pages/repo-wiki-mode/main-panel';
-import TreeNode from './components/tree-view-2/tree-node';
-import treeHelper from './components/tree-view-2/tree-helper';
+import TreeNode from './components/tree-view/tree-node';
+import treeHelper from './components/tree-view/tree-helper';
import toaster from './components/toast';
import LibDecryptDialog from './components/dialog/lib-decrypt-dialog';
import ModalPortal from './components/modal-portal';
@@ -332,7 +332,7 @@ class Wiki extends Component {
onSearchedClick = (item) => {
let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path;
- if (this.state.currentFilePath === path) {
+ if (this.state.currentPath === path) {
return;
}
diff --git a/frontend/src/wiki.js b/frontend/src/wiki.js
index 4413fbaf17..67c15e4b66 100644
--- a/frontend/src/wiki.js
+++ b/frontend/src/wiki.js
@@ -1,13 +1,15 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
+import moment from 'moment';
+import { slug, repoID, siteRoot, initialPath, isDir } from './utils/constants';
+import { Utils } from './utils/utils';
+import { seafileAPI } from './utils/seafile-api';
+import Dirent from './models/dirent';
+import TreeNode from './components/tree-view/tree-node';
+import treeHelper from './components/tree-view/tree-helper';
import SidePanel from './pages/wiki/side-panel';
import MainPanel from './pages/wiki/main-panel';
-import moment from 'moment';
-import { slug, repoID, siteRoot, initialPath } from './utils/constants';
-import editorUtilities from './utils/editor-utilties';
-import { Utils } from './utils/utils';
-import Node from './components/tree-view/node';
-import Tree from './components/tree-view/tree';
+
import './assets/css/fa-solid.css';
import './assets/css/fa-regular.css';
import './assets/css/fontawesome.css';
@@ -17,104 +19,183 @@ import './css/wiki.css';
import './css/toolbar.css';
import './css/search.css';
+
class Wiki extends Component {
constructor(props) {
super(props);
this.state = {
- content: '',
- tree_data: new Tree(),
+ path: '',
+ pathExist: true,
closeSideBar: false,
- filePath: '',
- latestContributor: '',
- lastModified: '',
+ isViewFile: true,
+ isDataLoading: true,
+ direntList: [],
+ content: '',
permission: '',
- isFileLoading: false,
- changedNode: null,
- isViewFileState: true,
- hasIndex: false,
+ lastModified: '',
+ latestContributor: '',
+ isTreeDataLoading: true,
+ treeData: treeHelper.buildTree(),
+ currentNode: null,
+ indexNode: null,
indexContent: '',
- indexPath: '',
- indexPermission: '',
};
+
window.onpopstate = this.onpopstate;
+ this.indexPath = '/index.md';
+ this.homePath = '/home.md';
}
componentDidMount() {
- this.initWikiData(initialPath);
+ this.loadWikiData(initialPath);
}
- getIndexContent = (files) => {
- files.some(file => {
- if (file.parent_path === '/' && file.type === 'file' && file.name === 'index.md') {
- let filePath = Utils.joinPath(file.parent_path, file.name);
- editorUtilities.getWikiFileContent(slug, filePath).then((res) => {
- this.setState({
- hasIndex: true,
- indexContent: res.data.content,
- indexPath: filePath,
- indexPermission: res.data.permission,
+ loadWikiData = () => {
+ this.loadSidePanel(initialPath);
+
+ if (isDir === 'None') {
+ this.setState({pathExist: false});
+ } else if (isDir === 'True') {
+ this.showDir(initialPath);
+ } else if (isDir === 'False') {
+ this.showFile(initialPath);
+ }
+ }
+
+ loadSidePanel = (initialPath) => {
+ if (initialPath === this.homePath || isDir === 'None') {
+ seafileAPI.listDir(repoID, '/').then(res => {
+ let tree = this.state.treeData;
+ this.addResponseListToNode(res.data.dirent_list, tree.root);
+ let indexNode = tree.getNodeByPath(this.indexPath);
+ if (indexNode) {
+ seafileAPI.getFileDownloadLink(repoID, indexNode.path).then(res => {
+ seafileAPI.getFileContent(res.data).then(res => {
+ this.setState({
+ treeData: tree,
+ indexNode: indexNode,
+ indexContent: res.data,
+ isTreeDataLoading: false,
+ });
+ });
});
- return;
- });
- }
- });
+ } else {
+ this.setState({
+ treeData: tree,
+ isTreeDataLoading: false,
+ });
+ }
+ }).catch(() => {
+ this.setState({isLoadFailed: true});
+ });
+ } else {
+ this.loadNodeAndParentsByPath(initialPath);
+ }
}
- initWikiData(filePath){
- this.setState({isFileLoading: true});
- editorUtilities.getFiles().then((files) => {
- // construct the tree object
- var treeData = new Tree();
- treeData.parseListToTree(files);
+ showDir = (dirPath) => {
+ this.loadDirentList(dirPath);
- let node = treeData.getNodeByPath(filePath);
- treeData.expandNode(node);
- if (node.isDir()) {
- this.exitViewFileState(treeData, node);
- this.setState({isFileLoading: false});
- } else {
- treeData.expandNode(node);
- editorUtilities.getWikiFileContent(slug, filePath).then(res => {
+ // update location url
+ let fileUrl = siteRoot + 'wikis/' + slug + dirPath;
+ window.history.pushState({url: fileUrl, path: dirPath}, dirPath, fileUrl);
+ }
+
+ showFile = (filePath) => {
+ this.setState({
+ isDataLoading: true,
+ isViewFile: true,
+ path: filePath,
+ });
+
+ seafileAPI.getFileInfo(repoID, filePath).then(res => {
+ let { mtime, permission, last_modifier_name } = res.data;
+ seafileAPI.getFileDownloadLink(repoID, filePath).then(res => {
+ seafileAPI.getFileContent(res.data).then(res => {
this.setState({
- tree_data: treeData,
- content: res.data.content,
- latestContributor: res.data.latest_contributor,
- lastModified: moment.unix(res.data.last_modified).fromNow(),
- permission: res.data.permission,
- filePath: filePath,
- isFileLoading: false
+ isDataLoading: false,
+ content: res.data,
+ permission: permission,
+ lastModified: moment.unix(mtime).fromNow(),
+ latestContributor: last_modifier_name,
});
});
- const hash = window.location.hash;
- let fileUrl = siteRoot + 'wikis/' + slug + filePath + hash;
- window.history.pushState({urlPath: fileUrl, filePath: filePath}, filePath, fileUrl);
- }
- this.getIndexContent(files);
- }, () => {
- this.setState({
- isLoadFailed: true
});
});
- }
-
- initMainPanelData(filePath){
- this.setState({isFileLoading: true});
- editorUtilities.getWikiFileContent(slug, filePath)
- .then(res => {
- this.setState({
- content: res.data.content,
- isViewFileState: true,
- latestContributor: res.data.latest_contributor,
- lastModified: moment.unix(res.data.last_modified).fromNow(),
- permission: res.data.permission,
- filePath: filePath,
- isFileLoading: false
- });
- });
const hash = window.location.hash;
let fileUrl = siteRoot + 'wikis/' + slug + filePath + hash;
- window.history.pushState({urlPath: fileUrl, filePath: filePath}, filePath, fileUrl);
+ window.history.pushState({url: fileUrl, path: filePath}, filePath, fileUrl);
+ }
+
+ loadDirentList = (dirPath) => {
+ this.setState({isDataLoading: true});
+ seafileAPI.listDir(repoID, dirPath).then(res => {
+ let direntList = res.data.dirent_list.map(item => {
+ let dirent = new Dirent(item);
+ return dirent;
+ });
+ direntList = Utils.sortDirents(direntList, 'name', 'asc');
+ this.setState({
+ path: dirPath,
+ isViewFile: false,
+ direntList: direntList,
+ isDataLoading: false,
+ });
+ }).catch(() => {
+ this.setState({isLoadFailed: true})
+ });
+ }
+
+ loadTreeNodeByPath = (path) => {
+ let tree = this.state.treeData.clone();
+ let node = tree.getNodeByPath(path);
+ if (!node.isLoaded) {
+ seafileAPI.listDir(repoID, node.path).then(res => {
+ this.addResponseListToNode(res.data.dirent_list, node);
+ let parentNode = tree.getNodeByPath(node.parentNode.path);
+ parentNode.isExpanded = true;
+ this.setState({
+ treeData: tree,
+ currentNode: node
+ });
+ })
+ } else {
+ let parentNode = tree.getNodeByPath(node.parentNode.path);
+ parentNode.isExpanded = true;
+ this.setState({treeData: tree, currentNode: node}); //tree
+ }
+ }
+
+ loadNodeAndParentsByPath = (path) => {
+ let tree = this.state.treeData.clone();
+ if (Utils.isMarkdownFile(path)) {
+ path = Utils.getDirName(path);
+ }
+ seafileAPI.listDir(repoID, path, {with_parents: true}).then(res => {
+ let direntList = res.data.dirent_list;
+ let results = {};
+ for (let i = 0; i < direntList.length; i++) {
+ let object = direntList[i];
+ let key = object.parent_dir;
+ if (!results[key]) {
+ results[key] = [];
+ }
+ results[key].push(object);
+ }
+ for (let key in results) {
+ let node = tree.getNodeByPath(key);
+ if (!node.isLoaded) {
+ this.addResponseListToNode(results[key], node);
+ }
+ }
+ this.setState({
+ isTreeDataLoading: false,
+ treeData: tree
+ });
+ }).catch(() => {
+ this.setState({isLoadFailed: true});
+ });
}
onLinkClick = (link) => {
@@ -131,365 +212,203 @@ class Wiki extends Component {
}
onpopstate = (event) => {
- if (event.state && event.state.filePath) {
- this.initMainPanelData(event.state.filePath);
+ if (event.state && event.state.path) {
+ let path = event.state.path;
+ if (Utils.isMarkdownFile(path)) {
+ this.showFile(path);
+ } else {
+ this.loadDirentList(path);
+ this.setState({
+ path: path,
+ isViewFile: false
+ });
+ }
}
}
onSearchedClick = (item) => {
+ let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path;
+ if (this.state.currentPath === path) {
+ return;
+ }
+
+ // load sidePanel
+ let index = -1;
+ let paths = Utils.getPaths(path);
+ for (let i = 0; i < paths.length; i++) {
+ let node = this.state.treeData.getNodeByPath(node);
+ if (!node) {
+ index = i;
+ break;
+ }
+ }
+ if (index === -1) { // all the data has been loaded already.
+ let tree = this.state.treeData.clone();
+ let node = tree.getNodeByPath(item.path);
+ treeHelper.expandNode(node);
+ this.setState({treeData: tree});
+ } else {
+ this.loadNodeAndParentsByPath(path);
+ }
+
+ // load mainPanel
if (item.is_dir) {
- let path = item.path.slice(0, item.path.length - 1);
- if (this.state.filePath !== path) {
- let tree = this.state.tree_data.clone();
- let node = tree.getNodeByPath(path);
- tree.expandNode(node);
- this.exitViewFileState(tree, node);
- }
- } else if (Utils.isMarkdownFile(item.path)) {
- let path = item.path;
- if (this.state.filePath !== path) {
- this.initMainPanelData(path);
-
- let tree = this.state.tree_data.clone();
- let node = tree.getNodeByPath(path);
- tree.expandNode(node);
- this.enterViewFileState(tree, node, node.path);
- }
+ this.showDir(path);
} else {
- let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(item.path);
- let newWindow = window.open('about:blank');
- newWindow.location.href = url;
- }
- }
-
- onMainNavBarClick = (nodePath) => {
- let tree = this.state.tree_data.clone();
- let node = tree.getNodeByPath(nodePath);
- tree.expandNode(node);
-
- this.exitViewFileState(tree, node);
-
- // update location url
- let fileUrl = siteRoot + 'wikis/' + slug + node.path;
- window.history.pushState({urlPath: fileUrl, filePath: node.path},node.path, fileUrl);
- }
-
- onMainNodeClick = (node) => {
- let tree = this.state.tree_data.clone();
- tree.expandNode(node);
- if (node.isMarkdown()) {
- this.initMainPanelData(node.path);
- this.enterViewFileState(tree, node, node.path);
- } else if (node.isDir()){
- this.exitViewFileState(tree, node);
- } else {
- const w=window.open('about:blank');
- const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path);
- w.location.href = url;
- }
- }
-
- onNodeClick = (node) => {
- if (node instanceof Node && node.isMarkdown()){
- let tree = this.state.tree_data.clone();
- this.initMainPanelData(node.path);
- this.enterViewFileState(tree, node, node.path);
- } else if(node instanceof Node && node.isDir()){
- let tree = this.state.tree_data.clone();
- if (this.state.filePath === node.path) {
- if (node.isExpanded) {
- tree.collapseNode(node);
- } else {
- tree.expandNode(node);
- }
+ if (Utils.isMarkdownFile(path)) {
+ this.showFile(path);
+ } else {
+ let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(path);
+ let newWindow = window.open('about:blank');
+ newWindow.location.href = url;
}
- this.exitViewFileState(tree, node);
- } else {
- const w=window.open('about:blank');
- const url = siteRoot + 'lib/' + repoID + '/file' + node.path;
- w.location.href = url;
}
}
- onDirCollapse = (node) => {
- let tree = this.state.tree_data.clone();
- let findNode = tree.getNodeByPath(node.path);
- findNode.isExpanded = !findNode.isExpanded;
- this.setState({tree_data: tree});
- }
-
onMenuClick = () => {
- this.setState({
- closeSideBar: !this.state.closeSideBar,
- });
+ this.setState({closeSideBar: !this.state.closeSideBar,});
+ }
+
+ onMainNavBarClick = (nodePath) => {
+ let tree = this.state.treeData.clone();
+ let node = tree.getNodeByPath(nodePath);
+ tree.expandNode(node);
+
+ this.setState({treeData: tree, currentNode: node});
+ this.showDir(node.path);
+ }
+
+ onDirentClick = (dirent) => {
+ let direntPath = Utils.joinPath(this.state.path, dirent.name);
+ if (dirent.isDir()) { // is dir
+ this.loadTreeNodeByPath(direntPath);
+ this.showDir(direntPath);
+ } else { // is file
+ if (Utils.isMarkdownFile(direntPath)) {
+ this.showFile(direntPath);
+ } else {
+ const w=window.open('about:blank');
+ const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath);
+ w.location.href = url;
+ }
+ }
}
onCloseSide = () => {
- this.setState({
- closeSideBar: !this.state.closeSideBar,
- });
+ this.setState({closeSideBar: !this.state.closeSideBar});
}
- onAddFolderNode = (dirPath) => {
- editorUtilities.createDir(dirPath).then(res => {
- let tree = this.state.tree_data.clone();
- let name = this.getFileNameByPath(dirPath);
- let index = dirPath.lastIndexOf('/');
- let parentPath = dirPath.substring(0, index);
- if (!parentPath) {
- parentPath = '/';
- }
- let node = this.buildNewNode(name, 'dir');
- let parentNode = tree.getNodeByPath(parentPath);
- tree.addNodeToParent(node, parentNode);
- if (this.state.isViewFileState) {
- tree.expandNode(node);
- this.setState({
- tree_data: tree,
- changedNode: node
+ onNodeClick = (node) => {
+ if (!this.state.pathExist) {
+ this.setState({pathExist: true});
+ }
+
+ if (node.object.isDir()) {
+ if (!node.isLoaded) {
+ let tree = this.state.treeData.clone();
+ node = tree.getNodeByPath(node.path);
+ seafileAPI.listDir(repoID, node.path).then(res => {
+ this.addResponseListToNode(res.data.dirent_list, node);
+ tree.collapseNode(node);
+ this.setState({treeData: tree});
});
- } else {
- this.exitViewFileState(tree, parentNode);
}
- });
- }
-
- onAddFileNode = (filePath) => {
- editorUtilities.createFile(filePath).then(res => {
- let tree = this.state.tree_data.clone();
- let name = this.getFileNameByPath(filePath);
- let index = filePath.lastIndexOf('/');
- let parentPath = filePath.substring(0, index);
- if (!parentPath) {
- parentPath = '/';
- }
- let node = this.buildNewNode(name, 'file');
- let parentNode = tree.getNodeByPath(parentPath);
- tree.addNodeToParent(node, parentNode);
- if (this.state.isViewFileState) {
- tree.expandNode(node);
- this.setState({
- tree_data: tree,
- changedNode: node
- });
- } else {
- this.exitViewFileState(tree, parentNode);
- }
- });
- }
-
- onRenameNode = (node, newName) => {
- let tree = this.state.tree_data.clone();
- let filePath = node.path;
- if (node.isMarkdown()) {
- editorUtilities.renameFile(filePath, newName).then(res => {
- let cloneNode = node.clone();
-
- tree.updateNodeParam(node, 'name', newName);
- node.name = newName;
- let date = new Date().getTime()/1000;
- tree.updateNodeParam(node, 'last_update_time', moment.unix(date).fromNow());
- node.last_update_time = moment.unix(date).fromNow();
-
- if (this.state.isViewFileState) {
- if (this.isModifyCurrentFile(cloneNode)) {
- tree.expandNode(node);
- this.setState({
- tree_data: tree,
- changedNode: node
- });
- this.initMainPanelData(node.path);
- } else {
- this.setState({tree_data: tree});
- }
+ if (node.path === this.state.path) {
+ if (node.isExpanded) {
+ let tree = treeHelper.collapseNode(this.state.treeData, node);
+ this.setState({treeData: tree});
} else {
- let parentNode = tree.findNodeParentFromTree(node);
- this.setState({
- tree_data: tree,
- changedNode: parentNode
- });
+ let tree = this.state.treeData.clone();
+ node = tree.getNodeByPath(node.path);
+ tree.expandNode(node);
+ this.setState({treeData: tree});
}
- });
- } else if (node.isDir()) {
- editorUtilities.renameDir(filePath, newName).then(res => {
-
- let currentFilePath = this.state.filePath;
- let currentFileNode = tree.getNodeByPath(currentFilePath);
- let nodePath = node.path;
-
- tree.updateNodeParam(node, 'name', newName);
- node.name = newName;
- let date = new Date().getTime()/1000;
- tree.updateNodeParam(node, 'last_update_time', moment.unix(date).fromNow());
- node.last_update_time = moment.unix(date).fromNow();
-
- if (this.state.isViewFileState) {
- if (currentFilePath.indexOf(nodePath) > -1) {
- tree.expandNode(currentFileNode);
- this.setState({
- tree_data: tree,
- changedNode: currentFileNode
- });
- this.initMainPanelData(currentFileNode.path);
- } else {
- this.setState({tree_data: tree});
- }
- } else {
- if (nodePath === currentFilePath) { // old node
- tree.expandNode(node);
- this.exitViewFileState(tree, node);
- } else if (node.path.indexOf(currentFilePath) > -1) { // new node
- tree.expandNode(currentFileNode);
- this.exitViewFileState(tree, currentFileNode);
- } else {
- this.setState({tree_data: tree});
- }
- }
- });
- }
- }
-
- onDeleteNode = (node) => {
- let filePath = node.path;
- if (node.isDir()) {
- editorUtilities.deleteDir(filePath);
- } else {
- editorUtilities.deleteFile(filePath);
- }
-
-
- let isCurrentFile = false;
- if (node.isDir()) {
- isCurrentFile = this.isModifyContainsCurrentFile(node);
- } else {
- isCurrentFile = this.isModifyCurrentFile(node);
- }
-
- let tree = this.state.tree_data.clone();
-
- if (this.state.isViewFileState) {
- if (isCurrentFile) {
- let homeNode = this.getHomeNode(tree);
- tree.expandNode(homeNode);
- this.setState({
- tree_data: tree,
- changedNode: homeNode
- });
- this.initMainPanelData(homeNode.path);
- } else {
- this.setState({tree_data: tree});
- }
- } else {
- let parentNode = tree.getNodeByPath(this.state.filePath);
- let isChild = tree.isNodeChild(parentNode, node);
- if (isChild) {
- this.exitViewFileState(tree, parentNode);
- } else {
- this.setState({tree_data: tree});
}
}
- tree.deleteNode(node);
- }
-
- enterViewFileState(newTree, newNode, newPath) {
- this.setState({
- tree_data: newTree,
- changedNode: newNode,
- filePath: newPath,
- isViewFileState: true
- });
- }
-
- exitViewFileState(newTree, newNode) {
- this.setState({
- tree_data: newTree,
- changedNode: newNode,
- filePath: newNode.path,
- isViewFileState: false
- });
- let fileUrl = siteRoot + 'wikis/' + slug + newNode.path;
- window.history.pushState({urlPath: fileUrl, filePath: newNode.path}, newNode.path, fileUrl);
- }
-
- getFileNameByPath(path) {
- let index = path.lastIndexOf('/');
- if (index === -1) {
- return '';
+ if (node.path === this.state.path ) {
+ return;
}
- return path.slice(index+1);
- }
- getHomeNode(treeData) {
- return treeData.getNodeByPath('/home.md');
- }
-
- buildNewNode(name, type) {
- let date = new Date().getTime()/1000;
- let node = new Node({
- name : name,
- type: type,
- size: '0',
- last_update_time: moment.unix(date).fromNow(),
- isExpanded: false,
- children: []
- });
- return node;
- }
-
- isModifyCurrentFile(node) {
- let nodeName = node.name;
- let fileName = this.getFileNameByPath(this.state.filePath);
- return nodeName === fileName;
- }
-
- isModifyContainsCurrentFile(node) {
- let filePath = this.state.filePath;
- let nodePath = node.path;
-
- if (filePath.indexOf(nodePath) > -1) {
- return true;
+ if (node.object.isDir()) { // isDir
+ this.showDir(node.path);
+ } else {
+ if (Utils.isMarkdownFile(node.path)) {
+ if (node.path !== this.state.path) {
+ this.showFile(node.path);
+ }
+ } else {
+ const w = window.open('about:blank');
+ const url = siteRoot + 'lib/' + repoID + '/file' + node.path;
+ w.location.href = url;
+ }
}
- return false;
+ }
+
+ onNodeCollapse = (node) => {
+ let tree = treeHelper.collapseNode(this.state.treeData, node);
+ this.setState({treeData: tree});
+ }
+
+ onNodeExpanded = (node) => {
+ let tree = this.state.treeData.clone();
+ node = tree.getNodeByPath(node.path);
+ if (!node.isLoaded) {
+ seafileAPI.listDir(repoID, node.path).then(res => {
+ this.addResponseListToNode(res.data.dirent_list, node);
+ this.setState({treeData: tree});
+ });
+ } else {
+ tree.expandNode(node);
+ this.setState({treeData: tree});
+ }
+ }
+
+ addResponseListToNode = (list, node) => {
+ node.isLoaded = true;
+ node.isExpanded = true;
+ let direntList = list.map(item => {
+ return new Dirent(item);
+ });
+ direntList = Utils.sortDirents(direntList, 'name', 'asc');
+
+ let nodeList = direntList.map(object => {
+ return new TreeNode({object});
+ });
+ node.addChildren(nodeList);
}
render() {
return (
);
diff --git a/seahub/templates/wiki/wiki.html b/seahub/templates/wiki/wiki.html
index 43fb099ba4..011b35e301 100644
--- a/seahub/templates/wiki/wiki.html
+++ b/seahub/templates/wiki/wiki.html
@@ -11,7 +11,9 @@
slug: "{{ wiki.slug }}",
repoId: "{{ wiki.repo_id }}",
initial_path: "{{ file_path }}",
+ permission: "{{ user_can_write }}",
isPublicWiki: "{{ is_public_wiki }}",
+ isDir: "{{ is_dir }}",
}
};
diff --git a/seahub/wiki/views.py b/seahub/wiki/views.py
index 1031087d8e..4914a951c6 100644
--- a/seahub/wiki/views.py
+++ b/seahub/wiki/views.py
@@ -4,6 +4,7 @@ import urllib2
import posixpath
import seaserv
+from seaserv import seafile_api
from django.core.urlresolvers import reverse
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404, redirect
@@ -42,15 +43,25 @@ def wiki_list(request):
def slug(request, slug, file_path="home.md"):
"""Show wiki page.
"""
- # compatible with old wiki url
- if len(file_path.split('.')) == 1:
- new_path = file_path + '.md'
- return HttpResponseRedirect(reverse('wiki:slug', args=[slug, new_path]))
-
# get wiki object or 404
wiki = get_object_or_404(Wiki, slug=slug)
file_path = "/" + file_path
+ is_dir = None
+ file_id = seafile_api.get_file_id_by_path(wiki.repo_id, file_path)
+ if file_id:
+ is_dir = False
+
+ dir_id = seafile_api.get_dir_id_by_path(wiki.repo_id, file_path)
+ if dir_id:
+ is_dir = True
+
+ # compatible with old wiki url
+ if is_dir is None:
+ if len(file_path.split('.')) == 1:
+ new_path = file_path[1:] + '.md'
+ return HttpResponseRedirect(reverse('wiki:slug', args=[slug, new_path]))
+
# perm check
req_user = request.user.username
@@ -65,6 +76,14 @@ def slug(request, slug, file_path="home.md"):
file_url = reverse('view_lib_file', args=[wiki.repo_id, file_path])
return HttpResponseRedirect(file_url + "?raw=1")
+ if not req_user:
+ user_can_write = False
+ elif req_user == wiki.username or check_folder_permission(
+ request, wiki.repo_id, '/') == 'rw':
+ user_can_write = True
+ else:
+ user_can_write = False
+
is_public_wiki = False
if wiki.permission == 'public':
is_public_wiki = True
@@ -72,11 +91,13 @@ def slug(request, slug, file_path="home.md"):
return render(request, "wiki/wiki.html", {
"wiki": wiki,
"page_name": file_path,
+ "user_can_write": user_can_write,
"file_path": file_path,
"repo_id": wiki.repo_id,
"search_repo_id": wiki.repo_id,
"search_wiki": True,
"is_public_wiki": is_public_wiki,
+ "is_dir": is_dir,
})