var classNames = require('classnames');
var AppActions = require('../actions/AppActions');
var Files = require('../stores/Files');
var React = require('react');
var ReactBootstrap = require('react-bootstrap');
var Glyphicon = ReactBootstrap.Glyphicon;
// The DepotTree is a React tree control that expects to interact with a
// server API that doesn't like to provide tree data, just lists of one
// level at a time.
//
// This control creates it's own cache of the available depot, since our 'store'
// doesn't really know much about the existing server. What this means, is that
// all directories are generally expandable, even if they don't have children,
// and we won't know if the dir contains anything until they are expanded.
//
// Properties:
// - dirsOnly: when true, will not display files
//
var DepotTree = React.createClass({
getInitialState: function() {
return {
depots: [],
selected: null
};
},
componentDidMount: function() {
Files.addDepotsListedListener(this.handleDepotsListed);
Files.addDirListedListener(this.handleDirListed);
AppActions.listDepots();
},
componentWillUnmount: function() {
Files.removeDepotsListedListener(this.handleDepotsListed);
Files.removeDirListedListener(this.handleDirListed);
},
render: function() {
var self = this;
return (
{this.state.depots.map(function(x) { return renderItem(self, x); })}
);
},
handleDepotsListed: function(depots) {
depots.sort(function(x, y) { return x.name.localeCompare(y.name); });
this.setState({ depots: depots });
},
handleDirListed: function(dirPath, items) {
var dir = findDir(this.state.depots, dirPath);
items.forEach(function(i) { dir.insert(i) });
dir.sortChildren();
dir.loaded = true;
this.setState({ depots: this.state.depots });
},
openFolder: function(dir, evt) {
dir.expanded = true;
if (!dir.loaded) {
AppActions.listDir(dir.pathId.join('/'));
}
this.setState({ depots: this.state.depots });
evt.stopPropagation();
},
closeFolder: function(dir, evt) {
dir.expanded = false;
this.setState({ depots: this.state.depots });
evt.stopPropagation();
},
clickItem: function(dir, evt) {
var cur = this.state.selected;
if (cur && cur.pathId.join('/') == dir.pathId.join('/')) {
// Same node
dir.selected = false;
this.state.selected = null;
} else {
if (cur) {
cur.selected = false;
}
dir.selected = true;
this.state.selected = dir;
}
if (this.state.selected && typeof this.props.onSelect == "function") {
this.props.onSelect(this.state.selected);
}
this.setState({ depots: this.state.depots });
evt.stopPropagation();
}
});
//----------------------------------------------------------------------------
// Local (private) helper methods
//----------------------------------------------------------------------------
// Render a row of our depot tree, and all children
function renderItem(view, item) {
if (view.props.dirsOnly && !item.children) {
return null;
}
var children = null;
if (item.children && item.expanded) {
children = item.children.map(function(child) {
return renderItem(view, child);
});
}
var control = renderControl(view, item);
var icon = renderIcon(item);
var text = renderText(item);
var classes = classNames({
'depot-tree-item': true,
'selected': item.selected
});
return (
{control}
{icon}
{text}
{children}
)
}
// The control depends on the 'expanded' attribute being set to 'true'.
function renderControl(view, item) {
if (item.children) {
if (item.expanded) {
return ;
} else {
return ;
}
}
}
function renderIcon(item) {
if (item.children) {
if (item.expanded) {
return
} else {
return
}
} else {
return
}
}
// We *might* want to render folders in a different font than files. We'll see.
function renderText(item) {
return { item.name };
}
function findDir(depots, dirPath) {
if (dirPath.startsWith('//')) {
dirPath = dirPath.substring(2);
}
var paths = dirPath.split('/');
return findDirRecurse(depots, paths, 0);
}
function findDirRecurse(items, paths, level) {
var curName = paths[level];
var item = items.find(function(x) { return x.name == curName; });
// Halting condition. Item can be null, in which case we've not found it.
if (level == (paths.length - 1)) {
return item;
}
if (item && item.children) {
return findDirRecurse(item.children, paths, level + 1);
}
return null;
}
module.exports = DepotTree;