/* * Copyright 2007-2017 Charles du Jeu - Abstrium SAS * This file is part of Pydio. * * Pydio is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Pydio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Pydio. If not, see . * * The latest code can be found at . */ 'use strict'; exports.__esModule = true; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _utilDND = require('../util/DND'); var React = require('react'); var _Pydio$requireLib = Pydio.requireLib('hoc'); var withContextMenu = _Pydio$requireLib.withContextMenu; var ContextMenuWrapper = function ContextMenuWrapper(props) { return React.createElement('div', props); }; ContextMenuWrapper = withContextMenu(ContextMenuWrapper); /** * Tree Node */ var SimpleTreeNode = React.createClass({ displayName: 'SimpleTreeNode', propTypes: { collapse: React.PropTypes.bool, forceExpand: React.PropTypes.bool, childrenOnly: React.PropTypes.bool, depth: React.PropTypes.number, onNodeSelect: React.PropTypes.func, node: React.PropTypes.instanceOf(AjxpNode), dataModel: React.PropTypes.instanceOf(PydioDataModel), forceLabel: React.PropTypes.string, // Optional currently selected detection nodeIsSelected: React.PropTypes.func, // Optional checkboxes checkboxes: React.PropTypes.array, checkboxesValues: React.PropTypes.object, checkboxesComputeStatus: React.PropTypes.func, onCheckboxCheck: React.PropTypes.func }, getDefaultProps: function getDefaultProps() { return { collapse: false, childrenOnly: false, depth: 0, onNodeSelect: function onNodeSelect(node) {} }; }, listenToNode: function listenToNode(node) { this._childrenListener = (function () { if (!this.isMounted()) return; this.setState({ children: this._nodeToChildren(node) }); }).bind(this); this._nodeListener = (function () { if (!this.isMounted()) return; this.forceUpdate(); }).bind(this); node.observe("child_added", this._childrenListener); node.observe("child_removed", this._childrenListener); node.observe("node_replaced", this._nodeListener); }, stopListening: function stopListening(node) { node.stopObserving("child_added", this._childrenListener); node.stopObserving("child_removed", this._childrenListener); node.stopObserving("node_replaced", this._nodeListener); }, componentDidMount: function componentDidMount() { this.listenToNode(this.props.node); }, componentWillUnmount: function componentWillUnmount() { this.stopListening(this.props.node); }, componentWillReceiveProps: function componentWillReceiveProps(nextProps) { var oldNode = this.props.node; var newNode = nextProps.node; if (newNode == oldNode && newNode.getMetadata().get("paginationData")) { var remapedChildren = this.state.children.map(function (c) { c.setParent(newNode);return c; }); var remapedPathes = this.state.children.map(function (c) { return c.getPath(); }); var newChildren = this._nodeToChildren(newNode); newChildren.forEach(function (nc) { if (remapedPathes.indexOf(nc.getPath()) === -1) { remapedChildren.push(nc); } }); this.setState({ children: remapedChildren }); } else { this.setState({ children: this._nodeToChildren(newNode) }); } if (newNode !== oldNode) { this.stopListening(oldNode); this.listenToNode(newNode); } }, getInitialState: function getInitialState() { return { showChildren: !this.props.collapse || this.props.forceExpand, children: this._nodeToChildren(this.props.node) }; }, _nodeToChildren: function _nodeToChildren() { var children = []; this.props.node.getChildren().forEach(function (c) { if (!c.isLeaf() || c.getAjxpMime() === 'ajxp_browsable_archive') children.push(c); }); return children; }, onNodeSelect: function onNodeSelect(ev) { if (this.props.onNodeSelect) { this.props.onNodeSelect(this.props.node); } ev.preventDefault(); ev.stopPropagation(); }, onChildDisplayToggle: function onChildDisplayToggle(ev) { if (this.props.node.getChildren().size) { this.setState({ showChildren: !this.state.showChildren }); } ev.preventDefault(); ev.stopPropagation(); }, nodeIsSelected: function nodeIsSelected(n) { if (this.props.nodeIsSelected) return this.props.nodeIsSelected(n);else return this.props.dataModel.getSelectedNodes().indexOf(n) !== -1; }, render: function render() { var _this = this; var _props = this.props; var node = _props.node; var childrenOnly = _props.childrenOnly; var canDrop = _props.canDrop; var isOverCurrent = _props.isOverCurrent; var checkboxes = _props.checkboxes; var checkboxesComputeStatus = _props.checkboxesComputeStatus; var checkboxesValues = _props.checkboxesValues; var onCheckboxCheck = _props.onCheckboxCheck; var depth = _props.depth; var forceExpand = _props.forceExpand; var selectedItemStyle = _props.selectedItemStyle; var getItemStyle = _props.getItemStyle; var forceLabel = _props.forceLabel; var hasFolderChildrens = this.state.children.length ? true : false; var hasChildren; if (hasFolderChildrens) { hasChildren = React.createElement( 'span', { onClick: this.onChildDisplayToggle }, this.state.showChildren || forceExpand ? React.createElement('span', { className: 'tree-icon icon-angle-down' }) : React.createElement('span', { className: 'tree-icon icon-angle-right' }) ); } else { var cname = "tree-icon icon-angle-right"; if (node.isLoaded()) { cname += " no-folder-children"; } hasChildren = React.createElement('span', { className: cname }); } var isSelected = this.nodeIsSelected(node) ? 'mui-menu-item mui-is-selected' : 'mui-menu-item'; var selfLabel; if (!childrenOnly) { if (canDrop && isOverCurrent) { isSelected += ' droppable-active'; } var boxes; if (checkboxes) { var values = {}, inherited = false, disabled = {}, additionalClassName = ''; if (checkboxesComputeStatus) { var status = checkboxesComputeStatus(node); values = status.VALUES; inherited = status.INHERITED; disabled = status.DISABLED; if (status.CLASSNAME) additionalClassName = ' ' + status.CLASSNAME; } else if (checkboxesValues && checkboxesValues[node.getPath()]) { values = checkboxesValues[node.getPath()]; } var valueClasses = []; boxes = checkboxes.map((function (c) { var selected = values[c] !== undefined ? values[c] : false; var click = (function (event, value) { onCheckboxCheck(node, c, value); }).bind(this); if (selected) valueClasses.push(c); return React.createElement(ReactMUI.Checkbox, { name: c, key: c + "-" + (selected ? "true" : "false"), checked: selected, onCheck: click, disabled: disabled[c], className: "cbox-" + c }); }).bind(this)); isSelected += inherited ? " inherited " : ""; isSelected += valueClasses.length ? " checkbox-values-" + valueClasses.join('-') : " checkbox-values-empty"; boxes = React.createElement( 'div', { className: "tree-checkboxes" + additionalClassName }, boxes ); } var itemStyle = { paddingLeft: depth * 20 }; if (this.nodeIsSelected(node) && selectedItemStyle) { itemStyle = _extends({}, itemStyle, selectedItemStyle); } if (getItemStyle) { itemStyle = _extends({}, itemStyle, getItemStyle(node)); } var icon = 'mdi mdi-folder'; var ajxpMime = node.getAjxpMime(); if (ajxpMime === 'ajxp_browsable_archive') { icon = 'mdi mdi-archive'; } else if (ajxpMime === 'ajxp_recycle') { icon = 'mdi mdi-delete'; } selfLabel = React.createElement( ContextMenuWrapper, { node: node, className: 'tree-item ' + isSelected + (boxes ? ' has-checkboxes' : ''), style: itemStyle }, React.createElement( 'div', { className: 'tree-item-label', onClick: this.onNodeSelect, title: node.getLabel(), 'data-id': node.getPath() }, hasChildren, React.createElement('span', { className: "tree-icon " + icon }), forceLabel ? forceLabel : node.getLabel() ), boxes ); } var children = []; var connector = function connector(instance) { return instance; }; var draggable = false; if (window.ReactDND && this.props.connectDropTarget && this.props.connectDragSource) { (function () { var connectDragSource = _this.props.connectDragSource; var connectDropTarget = _this.props.connectDropTarget; connector = function (instance) { connectDragSource(ReactDOM.findDOMNode(instance)); connectDropTarget(ReactDOM.findDOMNode(instance)); }; draggable = true; })(); } if (this.state.showChildren || forceExpand) { children = this.state.children.map((function (child) { var props = _extends({}, this.props, { forceLabel: null, childrenOnly: false, key: child.getPath(), node: child, depth: depth + 1 }); return React.createElement(draggable ? DragDropTreeNode : SimpleTreeNode, props); }).bind(this)); } return React.createElement( 'li', { ref: connector, className: "treenode" + node.getPath().replace(/\//g, '_') }, selfLabel, React.createElement( 'ul', null, children ) ); } }); var DragDropTreeNode; if (window.ReactDND) { DragDropTreeNode = ReactDND.flow(ReactDND.DragSource(_utilDND.Types.NODE_PROVIDER, _utilDND.nodeDragSource, _utilDND.collect), ReactDND.DropTarget(_utilDND.Types.NODE_PROVIDER, _utilDND.nodeDropTarget, _utilDND.collectDrop))(SimpleTreeNode); } else { DragDropTreeNode = SimpleTreeNode; } /** * Simple openable / loadable tree taking AjxpNode as inputs */ var DNDTreeView = React.createClass({ displayName: 'DNDTreeView', propTypes: { showRoot: React.PropTypes.bool, rootLabel: React.PropTypes.string, onNodeSelect: React.PropTypes.func, node: React.PropTypes.instanceOf(AjxpNode).isRequired, dataModel: React.PropTypes.instanceOf(PydioDataModel).isRequired, selectable: React.PropTypes.bool, selectableMultiple: React.PropTypes.bool, initialSelectionModel: React.PropTypes.array, onSelectionChange: React.PropTypes.func, forceExpand: React.PropTypes.bool, // Optional currently selected detection nodeIsSelected: React.PropTypes.func, // Optional checkboxes checkboxes: React.PropTypes.array, checkboxesValues: React.PropTypes.object, checkboxesComputeStatus: React.PropTypes.func, onCheckboxCheck: React.PropTypes.func }, getDefaultProps: function getDefaultProps() { return { showRoot: true, onNodeSelect: this.onNodeSelect }; }, onNodeSelect: function onNodeSelect(node) { if (this.props.onNodeSelect) { this.props.onNodeSelect(node); } else { this.props.dataModel.setSelectedNodes([node]); } }, render: function render() { return React.createElement( 'ul', { className: this.props.className }, React.createElement(DragDropTreeNode, { childrenOnly: !this.props.showRoot, forceExpand: this.props.forceExpand, node: this.props.node ? this.props.node : this.props.dataModel.getRootNode(), dataModel: this.props.dataModel, onNodeSelect: this.onNodeSelect, nodeIsSelected: this.props.nodeIsSelected, forceLabel: this.props.rootLabel, checkboxes: this.props.checkboxes, checkboxesValues: this.props.checkboxesValues, checkboxesComputeStatus: this.props.checkboxesComputeStatus, onCheckboxCheck: this.props.onCheckboxCheck, selectedItemStyle: this.props.selectedItemStyle, getItemStyle: this.props.getItemStyle }) ); } }); var TreeView = React.createClass({ displayName: 'TreeView', propTypes: { showRoot: React.PropTypes.bool, rootLabel: React.PropTypes.string, onNodeSelect: React.PropTypes.func, node: React.PropTypes.instanceOf(AjxpNode).isRequired, dataModel: React.PropTypes.instanceOf(PydioDataModel).isRequired, selectable: React.PropTypes.bool, selectableMultiple: React.PropTypes.bool, initialSelectionModel: React.PropTypes.array, onSelectionChange: React.PropTypes.func, forceExpand: React.PropTypes.bool, // Optional currently selected detection nodeIsSelected: React.PropTypes.func, // Optional checkboxes checkboxes: React.PropTypes.array, checkboxesValues: React.PropTypes.object, checkboxesComputeStatus: React.PropTypes.func, onCheckboxCheck: React.PropTypes.func }, getDefaultProps: function getDefaultProps() { return { showRoot: true, onNodeSelect: this.onNodeSelect }; }, onNodeSelect: function onNodeSelect(node) { if (this.props.onNodeSelect) { this.props.onNodeSelect(node); } else { this.props.dataModel.setSelectedNodes([node]); } }, render: function render() { return React.createElement( 'ul', { className: this.props.className }, React.createElement(SimpleTreeNode, { childrenOnly: !this.props.showRoot, forceExpand: this.props.forceExpand, node: this.props.node ? this.props.node : this.props.dataModel.getRootNode(), dataModel: this.props.dataModel, onNodeSelect: this.onNodeSelect, nodeIsSelected: this.props.nodeIsSelected, forceLabel: this.props.rootLabel, checkboxes: this.props.checkboxes, checkboxesValues: this.props.checkboxesValues, checkboxesComputeStatus: this.props.checkboxesComputeStatus, onCheckboxCheck: this.props.onCheckboxCheck, selectedItemStyle: this.props.selectedItemStyle, getItemStyle: this.props.getItemStyle }) ); } }); var FoldersTree = React.createClass({ displayName: 'FoldersTree', propTypes: { pydio: React.PropTypes.instanceOf(Pydio).isRequired, dataModel: React.PropTypes.instanceOf(PydioDataModel).isRequired, className: React.PropTypes.string, onNodeSelected: React.PropTypes.func, draggable: React.PropTypes.bool }, nodeObserver: function nodeObserver() { var r = this.props.dataModel.getRootNode(); if (!r.isLoaded()) { r.observeOnce("loaded", (function () { this.forceUpdate(); }).bind(this)); } else { this.forceUpdate(); } }, componentDidMount: function componentDidMount() { var dm = this.props.dataModel; this._dmObs = this.nodeObserver; dm.observe("context_changed", this._dmObs); dm.observe("root_node_changed", this._dmObs); this.nodeObserver(); }, componentWillUnmount: function componentWillUnmount() { if (this._dmObs) { var dm = this.props.dataModel; dm.stopObserving("context_changed", this._dmObs); dm.stopObserving("root_node_changed", this._dmObs); } }, treeNodeSelected: function treeNodeSelected(n) { if (this.props.onNodeSelected) { this.props.onNodeSelected(n); } else { this.props.dataModel.requireContextChange(n); } }, nodeIsSelected: function nodeIsSelected(n) { return n === this.props.dataModel.getContextNode(); }, render: function render() { if (this.props.draggable) { return React.createElement(PydioComponents.DNDTreeView, { onNodeSelect: this.treeNodeSelected, nodeIsSelected: this.nodeIsSelected, dataModel: this.props.dataModel, node: this.props.dataModel.getRootNode(), showRoot: this.props.showRoot ? true : false, selectedItemStyle: this.props.selectedItemStyle, getItemStyle: this.props.getItemStyle, className: "folders-tree" + (this.props.className ? ' ' + this.props.className : '') }); } else { return React.createElement(PydioComponents.TreeView, { onNodeSelect: this.treeNodeSelected, nodeIsSelected: this.nodeIsSelected, dataModel: this.props.dataModel, node: this.props.dataModel.getRootNode(), selectedItemStyle: this.props.selectedItemStyle, getItemStyle: this.props.getItemStyle, showRoot: this.props.showRoot ? true : false, className: "folders-tree" + (this.props.className ? ' ' + this.props.className : '') }); } } }); exports.TreeView = TreeView; exports.DNDTreeView = DNDTreeView; exports.FoldersTree = FoldersTree;