2016-02-20 13:31:29 +03:00
|
|
|
/**
|
|
|
|
* Very simple and fast tree grid/table, compatible with dynamic loading and jQuery fixedHeaderTable
|
2016-03-09 23:52:32 +03:00
|
|
|
* License: MPL 2.0+, (c) Vitaliy Filippov 2016+
|
2016-05-15 11:16:50 +03:00
|
|
|
* Version: 2016-05-15
|
2016-02-20 13:31:29 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* USAGE:
|
|
|
|
*
|
|
|
|
* var TG = new TreeGrid(items, header);
|
|
|
|
* document.body.appendChild(TG.table);
|
|
|
|
*
|
|
|
|
* items: [ node={
|
|
|
|
* cells: [ 'html' or { innerHTML, style, className, title }, ... ],
|
|
|
|
* children: [ node... ],
|
|
|
|
* leaf: true/false,
|
2016-02-24 17:08:00 +03:00
|
|
|
* collapsed: true/false,
|
|
|
|
* data: <user data>
|
2016-02-20 13:31:29 +03:00
|
|
|
* }, ... ]
|
|
|
|
*
|
|
|
|
* header: [ 'html' or { innerHTML, style, className, title }, ... ]
|
2016-03-10 15:04:09 +03:00
|
|
|
*
|
|
|
|
* Readonly properties:
|
|
|
|
*
|
|
|
|
* TG.table - grid <table> element
|
|
|
|
* TG.root - root node
|
|
|
|
*
|
|
|
|
* Methods:
|
|
|
|
*
|
|
|
|
* // change header and clear grid contents
|
|
|
|
* TG.setHeader(header);
|
|
|
|
*
|
|
|
|
* // change "leaf" status of a node and its children
|
|
|
|
* node.setChildren(isLeaf, newChildren);
|
|
|
|
*
|
|
|
|
* // expand/collapse a node
|
|
|
|
* node.toggle();
|
|
|
|
*
|
|
|
|
* // use simple cell editing
|
2016-03-10 15:59:57 +03:00
|
|
|
* TG.initCellEditing();
|
2016-03-10 15:04:09 +03:00
|
|
|
*
|
|
|
|
* // use simple mouse cell selection
|
2016-03-10 15:59:57 +03:00
|
|
|
* // HTMLElement restrictToNode: the element to listen for mousedown events
|
|
|
|
* TG.initCellSelection(restrictToNode);
|
|
|
|
*
|
|
|
|
* Callbacks:
|
|
|
|
*
|
|
|
|
* // called before expanding node. should return false if you want to prevent expanding the node
|
|
|
|
* TG.onExpand = function(node) {};
|
|
|
|
* // called before a cell is selected with mouse
|
|
|
|
* TG.onCellSelect = function(node, colIndex, td) { return <whether to allow selection (boolean)>; }
|
|
|
|
* // called when a cell is deselected with mouse
|
|
|
|
* TG.onCellDeselect = function(node, colIndex, td) {}
|
|
|
|
* // called before a cell is edited
|
|
|
|
* TG.onStartCellEdit = function(node, colIndex, td) { return {
|
|
|
|
* abort: <whether to prevent editing>,
|
|
|
|
* value: <override initial textbox value>
|
|
|
|
* } }
|
|
|
|
* // called before a cell is stopped being edited
|
|
|
|
* TG.onStopCellEdit = function (node, colIndex, value, td) { return { html: <new cell content> } }
|
|
|
|
*
|
2016-02-20 13:31:29 +03:00
|
|
|
*/
|
|
|
|
function TreeGrid(items, header)
|
|
|
|
{
|
|
|
|
this.bindProps = { 'style': 1, 'className': 1, 'title': 1, 'innerHTML': 1 };
|
|
|
|
this.levelIndent = 20;
|
|
|
|
this.table = document.createElement('table');
|
|
|
|
this.table.className = 'grid';
|
|
|
|
this.thead = document.createElement('thead');
|
|
|
|
this.tbody = document.createElement('tbody');
|
|
|
|
this.table.appendChild(this.thead);
|
|
|
|
this.table.appendChild(this.tbody);
|
|
|
|
this.thead.appendChild(document.createElement('tr'));
|
|
|
|
this.setHeader(header);
|
|
|
|
new TreeGridNode({ children: items }, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGrid.prototype.setHeader = function(newHeader)
|
|
|
|
{
|
|
|
|
var tr = this.thead.rows[0];
|
|
|
|
tr.innerHTML = '';
|
|
|
|
for (var i = 0; i < newHeader.length; i++)
|
|
|
|
{
|
|
|
|
var th = document.createElement('th');
|
|
|
|
this._setProps(th, newHeader[i]);
|
|
|
|
tr.appendChild(th);
|
|
|
|
}
|
|
|
|
this.header = newHeader;
|
2016-03-10 13:23:16 +03:00
|
|
|
this.editedCells = [];
|
2016-02-20 13:31:29 +03:00
|
|
|
// header change clears the whole grid by now
|
|
|
|
if (this.root)
|
2016-03-04 12:27:56 +03:00
|
|
|
this.root.setChildren(false, []);
|
2016-02-20 13:31:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TreeGrid.prototype.onExpand = function(node)
|
|
|
|
{
|
|
|
|
// handle node expand/collapse here
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGrid.prototype._setProps = function(el, props)
|
|
|
|
{
|
|
|
|
if (typeof props == 'string')
|
|
|
|
el.innerHTML = props;
|
|
|
|
else
|
|
|
|
for (var j in this.bindProps)
|
|
|
|
if (props[j])
|
|
|
|
el[j] = props[j];
|
|
|
|
}
|
|
|
|
|
2016-03-09 23:52:32 +03:00
|
|
|
// Simple cell editing
|
|
|
|
|
|
|
|
TreeGrid.prototype.getNodeIndex = function(n)
|
|
|
|
{
|
2016-03-10 13:23:16 +03:00
|
|
|
var i = 0;
|
|
|
|
while ((n = n.previousSibling))
|
2016-03-09 23:52:32 +03:00
|
|
|
i += (n.nodeType != 3 ? 1 : 0);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2016-03-10 15:59:57 +03:00
|
|
|
TreeGrid.prototype.initCellEditing = function()
|
2016-03-09 23:52:32 +03:00
|
|
|
{
|
|
|
|
var self = this;
|
2016-03-10 13:23:16 +03:00
|
|
|
self.editedCells = []; // FIXME maybe remove and use just class selector
|
2016-03-09 23:52:32 +03:00
|
|
|
addListener(this.table, 'dblclick', function(evt)
|
|
|
|
{
|
2016-03-10 14:26:55 +03:00
|
|
|
evt = evt||window.event;
|
2016-03-09 23:52:32 +03:00
|
|
|
var td = evt.target||evt.srcElement;
|
|
|
|
while (td.nodeName != 'TABLE' && td.nodeName != 'TD')
|
|
|
|
td = td.parentNode;
|
|
|
|
if (td.nodeName == 'TD' && td.parentNode._node && td.previousSibling && td.className != 'celleditor')
|
|
|
|
{
|
2016-03-10 13:23:16 +03:00
|
|
|
var params = self.onStartCellEdit && self.onStartCellEdit(td.parentNode._node, self.getNodeIndex(td), td) || {};
|
2016-03-09 23:52:32 +03:00
|
|
|
if (params.abort)
|
|
|
|
return;
|
|
|
|
self.editedCells.push(td);
|
|
|
|
td.className += ' celleditor';
|
|
|
|
if (params.value === undefined)
|
|
|
|
params.value = td.innerHTML;
|
2016-03-10 13:23:16 +03:00
|
|
|
td.innerHTML = '<input type="text" value="'+htmlspecialchars(params.value)+'" />';
|
2016-03-09 23:52:32 +03:00
|
|
|
addListener(td.firstChild, 'keydown', function(evt)
|
|
|
|
{
|
|
|
|
if (evt.keyCode == 13 || evt.keyCode == 10)
|
|
|
|
self.stopCellEditing(td);
|
|
|
|
});
|
|
|
|
td.firstChild.focus();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
addListener(document.body, 'click', function(evt)
|
|
|
|
{
|
|
|
|
if (!self.editedCells.length)
|
|
|
|
return;
|
|
|
|
var td = evt.target||evt.srcElement;
|
|
|
|
while (td && td.nodeName != 'TD')
|
|
|
|
td = td.parentNode;
|
|
|
|
if (td && /\bcelleditor\b/.exec(td.className))
|
|
|
|
return;
|
|
|
|
for (var i = self.editedCells.length-1; i >= 0; i--)
|
|
|
|
self.stopCellEditing(self.editedCells[i], 1);
|
|
|
|
self.editedCells = [];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGrid.prototype.stopCellEditing = function(td, _int)
|
|
|
|
{
|
2016-03-10 13:23:16 +03:00
|
|
|
var i = this.getNodeIndex(td);
|
|
|
|
var params = this.onStopCellEdit && this.onStopCellEdit(td.parentNode._node, i, td.firstChild.value, td) || {};
|
2016-03-17 15:47:46 +03:00
|
|
|
td.innerHTML = params.html === undefined || params.html === null ? td.firstChild.value : params.html;
|
2016-03-10 13:23:16 +03:00
|
|
|
if (typeof td.parentNode._node.cells[i] == 'object')
|
|
|
|
td.parentNode._node.cells[i].innerHTML = td.innerHTML;
|
|
|
|
else
|
|
|
|
td.parentNode._node.cells[i] = td.innerHTML;
|
2016-03-09 23:52:32 +03:00
|
|
|
td.className = '';
|
|
|
|
if (!_int)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < this.editedCells.length; i++)
|
|
|
|
{
|
|
|
|
if (this.editedCells[i] == td)
|
|
|
|
{
|
|
|
|
this.editedCells.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 14:46:50 +03:00
|
|
|
// Simple cell selection
|
|
|
|
|
2016-03-10 15:59:57 +03:00
|
|
|
TreeGrid.prototype.initCellSelection = function(restrictToNode)
|
2016-03-10 14:46:50 +03:00
|
|
|
{
|
|
|
|
var startDrag, dragDiv;
|
|
|
|
|
|
|
|
var self = this;
|
2016-03-10 15:59:57 +03:00
|
|
|
|
2016-04-13 15:51:34 +03:00
|
|
|
self.selectCell = function(cell)
|
|
|
|
{
|
|
|
|
if (!cell.parentNode._node || cell.className.indexOf(' selected') >= 0)
|
|
|
|
return;
|
|
|
|
var i = self.getNodeIndex(cell);
|
|
|
|
if (!self.onCellSelect || self.onCellSelect(cell.parentNode._node, i, cell))
|
|
|
|
cell.className += ' selected';
|
|
|
|
};
|
|
|
|
|
|
|
|
self.deselectCell = function(cell)
|
|
|
|
{
|
|
|
|
self.onCellDeselect && self.onCellDeselect(cell.parentNode._node, self.getNodeIndex(cell), cell);
|
|
|
|
cell.className = cell.className.replace(' selected', '');
|
|
|
|
};
|
|
|
|
|
2016-03-10 15:59:57 +03:00
|
|
|
addListener(restrictToNode || document.body, 'mousedown', function(evt)
|
2016-03-10 14:46:50 +03:00
|
|
|
{
|
2016-03-10 15:59:57 +03:00
|
|
|
evt = getEventCoord(evt);
|
|
|
|
if (!evt.shiftKey)
|
2016-03-10 14:46:50 +03:00
|
|
|
{
|
2016-03-10 15:59:57 +03:00
|
|
|
var els = self.table.querySelectorAll('td.selected');
|
|
|
|
for (var i = 0; i < els.length; i++)
|
2016-04-13 15:51:34 +03:00
|
|
|
self.deselectCell(els[i]);
|
2016-03-10 14:46:50 +03:00
|
|
|
}
|
|
|
|
if (evt.which != 1)
|
|
|
|
return;
|
|
|
|
startDrag = [ evt.pageX, evt.pageY ];
|
|
|
|
if (!dragDiv)
|
|
|
|
{
|
|
|
|
dragDiv = document.createElement('div');
|
|
|
|
dragDiv.className = 'selection-rect';
|
2016-04-04 14:14:48 +03:00
|
|
|
dragDiv.style.display = 'none';
|
2016-03-10 14:46:50 +03:00
|
|
|
document.body.appendChild(dragDiv);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
addListener(document.body, 'mousemove', function(evt)
|
|
|
|
{
|
|
|
|
if (startDrag)
|
|
|
|
{
|
|
|
|
evt = getEventCoord(evt);
|
2016-04-04 14:14:48 +03:00
|
|
|
if (dragDiv.style.display == 'none')
|
|
|
|
{
|
|
|
|
if ((startDrag[0] < evt.pageX-10 || startDrag[0] > evt.pageX+10) &&
|
|
|
|
(startDrag[1] < evt.pageY-10 || startDrag[1] > evt.pageY+10))
|
|
|
|
dragDiv.style.display = 'block';
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
2016-03-10 14:46:50 +03:00
|
|
|
if (startDrag[0] < evt.pageX)
|
|
|
|
{
|
|
|
|
dragDiv.style.left = startDrag[0]+'px';
|
|
|
|
dragDiv.style.width = (evt.pageX-startDrag[0])+'px';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dragDiv.style.left = evt.pageX+'px';
|
|
|
|
dragDiv.style.width = (startDrag[0]-evt.pageX)+'px';
|
|
|
|
}
|
|
|
|
if (startDrag[1] < evt.pageY)
|
|
|
|
{
|
|
|
|
dragDiv.style.top = startDrag[1]+'px';
|
|
|
|
dragDiv.style.height = (evt.pageY-startDrag[1])+'px';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dragDiv.style.top = evt.pageY+'px';
|
|
|
|
dragDiv.style.height = (startDrag[1]-evt.pageY)+'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
addListener(document.body, 'mouseup', function(evt)
|
|
|
|
{
|
|
|
|
if (startDrag)
|
|
|
|
{
|
|
|
|
evt = getEventCoord(evt);
|
|
|
|
dragDiv.style.display = 'none';
|
|
|
|
var x1 = startDrag[0], y1 = startDrag[1], x2 = evt.pageX, y2 = evt.pageY;
|
|
|
|
if (x2 < x1)
|
|
|
|
{
|
|
|
|
var t = x2;
|
|
|
|
x2 = x1;
|
|
|
|
x1 = t;
|
|
|
|
}
|
|
|
|
if (y2 < y1)
|
|
|
|
{
|
|
|
|
var t = y2;
|
|
|
|
y2 = y1;
|
|
|
|
y1 = t;
|
|
|
|
}
|
|
|
|
startDrag = null;
|
|
|
|
if (x2 > x1+10 && y2 > y1+10)
|
2016-04-13 15:51:34 +03:00
|
|
|
rectangleSelect(self.table.getElementsByTagName('td'), x1, y1, x2, y2, self.selectCell);
|
2016-04-04 14:14:48 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
var t = evt.target || evt.srcElement;
|
2016-04-13 15:51:34 +03:00
|
|
|
self.selectCell(t);
|
2016-04-04 14:14:48 +03:00
|
|
|
}
|
|
|
|
if (x2 > x1+10 && y2 > y1+10 || evt.shiftKey)
|
2016-03-10 14:46:50 +03:00
|
|
|
{
|
2016-03-10 15:59:57 +03:00
|
|
|
if (document.selection)
|
|
|
|
document.selection.empty();
|
|
|
|
else
|
|
|
|
window.getSelection().removeAllRanges();
|
2016-03-10 14:46:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
function rectangleSelect(elements, x1, y1, x2, y2, cb)
|
|
|
|
{
|
|
|
|
for (var i = 0; i < elements.length; i++)
|
|
|
|
{
|
|
|
|
var offset = getOffset(elements[i]);
|
|
|
|
var w = elements[i].offsetWidth;
|
|
|
|
var h = elements[i].offsetHeight;
|
|
|
|
if (offset.left+w >= x1 && offset.top+h >= y1 && offset.left <= x2 && offset.top <= y2)
|
2016-04-13 15:51:34 +03:00
|
|
|
cb(elements[i]);
|
2016-03-10 14:46:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 23:52:32 +03:00
|
|
|
// Tree grid node class
|
|
|
|
|
2016-02-20 13:31:29 +03:00
|
|
|
function TreeGridNode(node, grid, level, insertBefore, startHidden)
|
|
|
|
{
|
|
|
|
this.grid = grid;
|
|
|
|
this.level = level;
|
2016-02-24 17:08:00 +03:00
|
|
|
this.data = node.data;
|
2016-02-20 13:31:29 +03:00
|
|
|
if (this.level === undefined)
|
|
|
|
this.level = -1;
|
|
|
|
if (!grid.root)
|
|
|
|
grid.root = this;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.leaf = node.leaf;
|
|
|
|
this.collapsed = node.collapsed || !node.leaf && (!node.children || !node.children.length);
|
|
|
|
this.cells = node.cells || [];
|
|
|
|
this.tr = document.createElement('tr');
|
|
|
|
if (startHidden)
|
|
|
|
this.tr.style.display = 'none';
|
2016-02-24 18:48:09 +03:00
|
|
|
this.tr._node = this;
|
2016-02-20 13:31:29 +03:00
|
|
|
for (var i = 0; i < this.grid.header.length; i++)
|
|
|
|
{
|
|
|
|
var td = document.createElement('td');
|
|
|
|
if (this.cells[i])
|
|
|
|
grid._setProps(td, this.cells[i]);
|
|
|
|
this.tr.appendChild(td);
|
|
|
|
}
|
|
|
|
var collapser = document.createElement('div');
|
|
|
|
if (this.leaf)
|
|
|
|
collapser.className = 'collapser collapser-inactive';
|
|
|
|
else
|
|
|
|
{
|
|
|
|
collapser.className = this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded';
|
2016-05-15 11:16:50 +03:00
|
|
|
addListener(collapser, 'click', this._getToggleHandler());
|
2016-02-20 13:31:29 +03:00
|
|
|
}
|
|
|
|
var c0 = this.tr.cells[0];
|
|
|
|
c0.childNodes.length ? c0.insertBefore(collapser, c0.firstChild) : c0.appendChild(collapser);
|
|
|
|
if (grid._initialPadding === undefined)
|
|
|
|
{
|
|
|
|
var p0 = curStyle(c0).paddingLeft || '';
|
|
|
|
if (p0.substr(p0.length-2) == 'px')
|
|
|
|
p0 = parseInt(p0.substr(0, p0.length-2));
|
|
|
|
else
|
|
|
|
p0 = 0;
|
|
|
|
grid._initialPadding = p0;
|
|
|
|
}
|
2016-03-09 12:36:51 +03:00
|
|
|
c0.style.paddingLeft = (grid._initialPadding + grid.levelIndent * level + 20) + 'px';
|
2016-02-20 13:31:29 +03:00
|
|
|
insertBefore ? grid.tbody.insertBefore(this.tr, insertBefore) : grid.tbody.appendChild(this.tr);
|
|
|
|
}
|
|
|
|
this.children = [];
|
|
|
|
if (node.children)
|
|
|
|
for (var i = 0; i < node.children.length; i++)
|
|
|
|
this.children.push(new TreeGridNode(node.children[i], grid, this.level+1, insertBefore, this.collapsed));
|
|
|
|
}
|
|
|
|
|
2016-05-15 11:16:50 +03:00
|
|
|
TreeGridNode.prototype._getToggleHandler = function()
|
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
if (!self._toggleHandlerClosure)
|
|
|
|
self._toggleHandlerClosure = function(e) { self._toggleHandler(); };
|
|
|
|
return self._toggleHandlerClosure;
|
|
|
|
}
|
|
|
|
|
2016-02-20 13:31:29 +03:00
|
|
|
TreeGridNode.prototype._toggleHandler = function()
|
|
|
|
{
|
|
|
|
if (!this.grid.onExpand(this))
|
|
|
|
return;
|
|
|
|
this.toggle();
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGridNode.prototype.toggle = function()
|
|
|
|
{
|
|
|
|
if (this.leaf)
|
|
|
|
return;
|
|
|
|
this.collapsed = !this.collapsed;
|
|
|
|
this.tr.cells[0].firstChild.className = this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded';
|
|
|
|
if (this.collapsed)
|
|
|
|
{
|
|
|
|
// collapse all children
|
|
|
|
var c = this.tr.nextSibling;
|
2016-02-24 18:48:09 +03:00
|
|
|
while (c && c._node.level > this.level)
|
2016-02-20 13:31:29 +03:00
|
|
|
{
|
|
|
|
c.style.display = 'none';
|
|
|
|
c = c.nextSibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// expand all children except children of collapsed subnodes
|
|
|
|
var st = this.children.concat([]);
|
|
|
|
while (st.length)
|
|
|
|
{
|
|
|
|
var e = st.pop();
|
|
|
|
e.tr.style.display = '';
|
|
|
|
if (!e.collapsed)
|
|
|
|
st = st.concat(e.children);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGridNode.prototype.setChildren = function(isLeaf, newChildren)
|
|
|
|
{
|
|
|
|
if (!this.tr)
|
|
|
|
this.grid.tbody.innerHTML = '';
|
|
|
|
else
|
2016-03-04 12:27:56 +03:00
|
|
|
{
|
2016-02-24 18:48:09 +03:00
|
|
|
while (this.tr.nextSibling && this.tr.nextSibling._node.level > this.level)
|
2016-02-20 13:31:29 +03:00
|
|
|
this.grid.tbody.removeChild(this.tr.nextSibling);
|
2016-05-15 11:16:50 +03:00
|
|
|
if (this.leaf != isLeaf)
|
|
|
|
{
|
|
|
|
if (isLeaf)
|
|
|
|
{
|
|
|
|
this.tr.cells[0].firstChild.className = 'collapser collapser-inactive';
|
|
|
|
removeListener(this.tr.cells[0].firstChild, 'click', this._getToggleHandler());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.tr.cells[0].firstChild.className = this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded';
|
|
|
|
addListener(this.tr.cells[0].firstChild, 'click', this._getToggleHandler());
|
|
|
|
}
|
|
|
|
}
|
2016-03-04 12:27:56 +03:00
|
|
|
}
|
2016-05-15 11:16:50 +03:00
|
|
|
this.leaf = isLeaf;
|
2016-02-20 13:31:29 +03:00
|
|
|
this.children = [];
|
2016-03-25 18:47:55 +03:00
|
|
|
this.addChildren(newChildren);
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeGridNode.prototype.addChildren = function(newChildren)
|
|
|
|
{
|
2016-02-20 13:31:29 +03:00
|
|
|
var insertBefore = this.tr && this.tr.nextSibling;
|
2016-03-25 18:47:55 +03:00
|
|
|
while (insertBefore && insertBefore.nextSibling && insertBefore._node.level > this.level)
|
|
|
|
insertBefore = insertBefore.nextSibling;
|
2016-02-20 13:31:29 +03:00
|
|
|
for (var i = 0; i < newChildren.length; i++)
|
|
|
|
this.children.push(new TreeGridNode(newChildren[i], this.grid, this.level+1, insertBefore, this.collapsed));
|
|
|
|
}
|