blessed-contrib
Version:
Build dashboards (or any other application) using ascii/ansi art and javascript.
167 lines (129 loc) • 4.24 kB
JavaScript
'use strict';
var blessed = require('blessed'),
Node = blessed.Node,
Box = blessed.Box;
function Tree(options) {
if (!(this instanceof Node)) {
return new Tree(options);
}
var self = this;
options = options || {};
options.bold = true;
this.options = options;
this.data = {};
this.nodeLines = [];
this.lineNbr = 0;
Box.call(this, options);
options.extended = options.extended || false;
options.keys = options.keys || ['+', 'space', 'enter'];
options.template = options.template || {};
options.template.extend = options.template.extend || ' [+]';
options.template.retract = options.template.retract || ' [-]';
options.template.lines = options.template.lines || false;
// Do not set height, since this create a bug where the first line is not always displayed
this.rows = blessed.list({
top: 1,
width: 0,
left: 1,
style: options.style,
padding: options.padding,
keys: true,
tags: options.tags,
input: options.input,
vi: options.vi,
ignoreKeys: options.ignoreKeys,
scrollable: options.scrollable,
mouse: options.mouse,
selectedBg: options.selectedBg || 'blue',
selectedFg: options.selectedFg || 'black',
});
this.append(this.rows);
this.rows.key(options.keys, function() {
var selectedNode = self.nodeLines[this.getItemIndex(this.selected)];
if (selectedNode.children) {
selectedNode.extended = !selectedNode.extended;
self.setData(self.data);
self.screen.render();
}
self.emit('select', selectedNode, this.getItemIndex(this.selected));
});
}
Tree.prototype = Object.create(Box.prototype);
Tree.prototype.walk = function(node, treeDepth) {
var lines = [];
if (!node.parent) {
// root level
this.lineNbr = 0;
this.nodeLines.length = 0;
node.parent = null;
}
if (treeDepth === '' && node.name) {
this.lineNbr = 0;
this.nodeLines[this.lineNbr++] = node;
lines.push(node.name);
treeDepth = ' ';
}
node.depth = treeDepth.length - 1;
if (node.children && node.extended) {
var i = 0;
if (typeof node.children === 'function')
node.childrenContent = node.children(node);
if (!node.childrenContent)
node.childrenContent = node.children;
for (var child in node.childrenContent) {
if (!node.childrenContent[child].name)
node.childrenContent[child].name = child;
child = node.childrenContent[child];
child.parent = node;
child.position = i++;
if (typeof child.extended === 'undefined')
child.extended = this.options.extended;
if (typeof child.children === 'function')
child.childrenContent = child.children(child);
else
child.childrenContent = child.children;
var isLastChild = child.position === Object.keys(child.parent.childrenContent).length - 1;
var treePrefix;
var suffix = '';
if (isLastChild)
treePrefix = '└';
else
treePrefix = '├';
if (!child.childrenContent || Object.keys(child.childrenContent).length === 0) {
treePrefix += '─';
} else if (child.extended) {
treePrefix += '┬';
suffix = this.options.template.retract;
} else {
treePrefix += '─';
suffix = this.options.template.extend;
}
if (!this.options.template.lines) treePrefix = '|-';
if (this.options.template.spaces) treePrefix = ' ';
lines.push(treeDepth + treePrefix + child.name + suffix);
this.nodeLines[this.lineNbr++] = child;
var parentTree;
if (isLastChild || !this.options.template.lines)
parentTree = treeDepth + ' ';
else
parentTree = treeDepth + '│';
lines = lines.concat(this.walk(child, parentTree));
}
}
return lines;
};
Tree.prototype.focus = function() {
this.rows.focus();
};
Tree.prototype.render = function() {
if (this.screen.focused === this.rows) this.rows.focus();
this.rows.width = this.width - 3;
this.rows.height = this.height - 3;
Box.prototype.render.call(this);
};
Tree.prototype.setData = function(nodes) {
this.data = nodes;
this.rows.setItems(this.walk(nodes, ''));
};
Tree.prototype.type = 'tree';
module.exports = Tree;