Post-refuck fixes
- fix cell editing when virtual scroll is in use - fix slight height targeting problems in Chrome and IE - fix node hover highlight - fix dynamic node list modificationmaster
parent
8f565469ac
commit
b5060d0296
|
@ -184,8 +184,8 @@ table.grid .celleditor input
|
|||
{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
|
|
137
treegrid.js
137
treegrid.js
|
@ -6,7 +6,7 @@
|
|||
* - dynamic loading of child nodes
|
||||
*
|
||||
* License: MPL 2.0+, (c) Vitaliy Filippov 2016+
|
||||
* Version: 2017-07-10
|
||||
* Version: 2017-07-12
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -180,6 +180,7 @@ function TreeGrid(options)
|
|||
// table body wrapper
|
||||
this.wrapper.className = 'grid-wrapper';
|
||||
this.tableWrapper = document.createElement('div');
|
||||
this.tableWrapper.tabIndex = 1;
|
||||
this.tableWrapper.className = 'grid-body-wrapper';
|
||||
this.tableSizer = document.createElement('div');
|
||||
this.tableSizer.className = 'grid-fixed-col-sizer';
|
||||
|
@ -242,9 +243,7 @@ function TreeGridNode(node, grid, parentNode, insertIndex, skipSync)
|
|||
if (node.children)
|
||||
{
|
||||
for (var i = 0; i < node.children.length; i++)
|
||||
{
|
||||
new TreeGridNode(node.children[i], grid, this, i, true);
|
||||
}
|
||||
}
|
||||
if (!skipSync)
|
||||
this.grid.syncView();
|
||||
|
@ -403,18 +402,6 @@ TreeGrid.prototype._syncStart = function(nodes)
|
|||
}
|
||||
|
||||
TreeGrid.prototype._setPlaceholder = function(name, height)
|
||||
{
|
||||
this.placeholders[name][0].firstChild.setAttribute('colspan', this.header.length-(this.fixedColBody ? 1 : 0));
|
||||
this.placeholders[name][0].style.height = height+'px';
|
||||
this.placeholders[name][0].style.display = height > 0 ? '' : 'none';
|
||||
if (this.fixedColBody)
|
||||
{
|
||||
this.placeholders[name][1].style.height = height+'px';
|
||||
this.placeholders[name][1].style.display = height > 0 ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
TreeGrid.prototype._addPlaceholder = function(name, height)
|
||||
{
|
||||
if (!this.placeholders[name])
|
||||
{
|
||||
|
@ -427,7 +414,21 @@ TreeGrid.prototype._addPlaceholder = function(name, height)
|
|||
}
|
||||
}
|
||||
if (height !== undefined)
|
||||
this._setPlaceholder(name, height);
|
||||
{
|
||||
this.placeholders[name][0].firstChild.setAttribute('colspan', this.header.length-(this.fixedColBody ? 1 : 0));
|
||||
this.placeholders[name][0].style.height = height+'px';
|
||||
this.placeholders[name][0].style.display = height > 0 ? '' : 'none';
|
||||
if (this.fixedColBody)
|
||||
{
|
||||
this.placeholders[name][1].style.height = height+'px';
|
||||
this.placeholders[name][1].style.display = height > 0 ? '' : 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TreeGrid.prototype._addPlaceholder = function(name, height)
|
||||
{
|
||||
this._setPlaceholder(name, height);
|
||||
this._syncStartNode(this.placeholders[name][0], this.placeholders[name][1]);
|
||||
}
|
||||
|
||||
|
@ -439,6 +440,13 @@ TreeGrid.prototype._finishSync = function()
|
|||
{
|
||||
if (!this.oldRenderedNodes[i]._reuse && this.oldRenderedNodes[i].tr)
|
||||
{
|
||||
if (this.oldRenderedNodes[i].unrenderHooks)
|
||||
{
|
||||
var hooks = this.oldRenderedNodes[i].unrenderHooks;
|
||||
for (var k in hooks)
|
||||
hooks[k]();
|
||||
delete this.oldRenderedNodes[i].unrenderHooks;
|
||||
}
|
||||
this.oldRenderedNodes[i].tr = null;
|
||||
this.oldRenderedNodes[i].col_tr = null;
|
||||
this.oldRenderedNodes[i]._oldCells = [];
|
||||
|
@ -503,13 +511,17 @@ TreeGrid.prototype.syncView = function()
|
|||
{
|
||||
if (!this.table.offsetParent)
|
||||
return;
|
||||
var offsetHeight = this.wrapper.getBoundingClientRect().height - (this.stickyRow ? this.thead.getBoundingClientRect().height : 0);
|
||||
var headerHeight = (this.stickyRow ? this.thead.getBoundingClientRect().height : 0);
|
||||
var offsetHeight = this.tableWrapper.clientHeight - headerHeight;
|
||||
var scrollTop = this.tableWrapper.scrollTop;
|
||||
var visibleItems = Math.ceil(offsetHeight/this.minItemHeight);
|
||||
var endStart = this.nodeCount - visibleItems;
|
||||
var targetHeight;
|
||||
if (endStart < 0)
|
||||
endStart = 0;
|
||||
// Always render last items
|
||||
var lastNodes = this._findNodes(this.root, endStart, this.nodeCount-endStart);
|
||||
this._setPlaceholder('top', 0);
|
||||
this._beginSync();
|
||||
this._renderNodes(lastNodes);
|
||||
this._syncEnd(lastNodes);
|
||||
|
@ -519,18 +531,18 @@ TreeGrid.prototype.syncView = function()
|
|||
var lastFirst = endStart+this._findVisibleNodeOffset(lastNodes, offsetHeight);
|
||||
var avgItemHeight = this.endItemHeight / lastNodes.length;
|
||||
avgItemHeight = (avgItemHeight < this.minItemHeight ? this.minItemHeight : avgItemHeight);
|
||||
targetHeight = headerHeight + this.nodeCount*avgItemHeight;
|
||||
if (this.stickyColumn)
|
||||
this.fixedColSizer.style.height = (this.nodeCount*avgItemHeight)+'px';
|
||||
this.tableSizer.style.height = (this.nodeCount*avgItemHeight)+'px';
|
||||
var tbwh = this.tableWrapper.getBoundingClientRect().height;
|
||||
var scrollPos = this.nodeCount*avgItemHeight > tbwh ?
|
||||
this.tableWrapper.scrollTop / (this.nodeCount*avgItemHeight - tbwh) : 0;
|
||||
this.fixedColSizer.style.height = targetHeight+'px';
|
||||
this.tableSizer.style.height = targetHeight+'px';
|
||||
var scrollPos = targetHeight > offsetHeight ? scrollTop / (targetHeight - offsetHeight) : 0;
|
||||
if (scrollPos > 1)
|
||||
scrollPos = 1;
|
||||
var firstVisible = scrollPos*lastFirst;
|
||||
var rangeStart = Math.floor(firstVisible);
|
||||
var rangeCount = visibleItems;
|
||||
this._addPlaceholder('top', 0);
|
||||
this._setPlaceholder('mid', 0);
|
||||
var firstItemHeight;
|
||||
if (rangeStart >= endStart)
|
||||
{
|
||||
|
@ -554,7 +566,7 @@ TreeGrid.prototype.syncView = function()
|
|||
this._addPlaceholder('mid', 0);
|
||||
firstItemHeight = getNodeHeight(visibleNodes[0])*(firstVisible-rangeStart);
|
||||
}
|
||||
this._setPlaceholder('top', this.tableWrapper.scrollTop-firstItemHeight);
|
||||
this._setPlaceholder('top', scrollTop-firstItemHeight-headerHeight);
|
||||
}
|
||||
else if (this.stickyColumn)
|
||||
{
|
||||
|
@ -571,12 +583,13 @@ TreeGrid.prototype.syncView = function()
|
|||
else
|
||||
{
|
||||
this.syncStickyRow();
|
||||
for (var i = 0; i < this.tbody.rows.length; i++)
|
||||
total += (this.tbody.rows[i].getBoundingClientRect().height||0);
|
||||
if (endStart > 0 && endStart > rangeStart+rangeCount)
|
||||
for (var i = 0; i < this.tbody.rows.length; i++)
|
||||
total += (this.tbody.rows[i].getBoundingClientRect().height||0);
|
||||
}
|
||||
if (endStart > 0 && endStart > rangeStart+rangeCount)
|
||||
{
|
||||
this._setPlaceholder('mid', this.nodeCount*avgItemHeight - total - (this.tableWrapper.scrollTop-firstItemHeight));
|
||||
this._setPlaceholder('mid', targetHeight - total - (scrollTop-firstItemHeight));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,9 +607,11 @@ TreeGrid.prototype.nodeOnHover = function(hover, ev)
|
|||
e = e.previousSibling;
|
||||
subrow++;
|
||||
}
|
||||
if (!e._node.tr)
|
||||
return;
|
||||
if (hover)
|
||||
{
|
||||
if (this.hoveredNode)
|
||||
if (this.hoveredNode && this.hoveredNode.tr)
|
||||
{
|
||||
this.hoveredNode.tr[this.hoveredRow].className = this.hoveredNode.tr[this.hoveredRow].className.replace(/ hover/g, '');
|
||||
if (this.stickyColumn)
|
||||
|
@ -834,11 +849,13 @@ TreeGrid.prototype.initCellEditing = function()
|
|||
td = td.parentNode;
|
||||
if (td.nodeName == 'TD' && td.parentNode._node && td.className.indexOf('celleditor') < 0)
|
||||
{
|
||||
var params = self.onStartCellEdit &&
|
||||
self.onStartCellEdit(td.parentNode._node, self._getSubrow(td), self._getCellIndex(td, true), td) || {};
|
||||
var node = td.parentNode._node;
|
||||
var subrow = self._getSubrow(td);
|
||||
var cellIndex = self._getCellIndex(td, true);
|
||||
var params = self.onStartCellEdit && self.onStartCellEdit(node, subrow, cellIndex, td) || {};
|
||||
if (params.abort)
|
||||
return;
|
||||
self.startCellEditing(td, params);
|
||||
self.startCellEditing(td, params, node, subrow, cellIndex);
|
||||
}
|
||||
});
|
||||
addListener(document.body, 'click', function(evt)
|
||||
|
@ -851,14 +868,25 @@ TreeGrid.prototype.initCellEditing = function()
|
|||
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.stopCellEditing(self.editedCells[i], true);
|
||||
self.editedCells = [];
|
||||
});
|
||||
}
|
||||
|
||||
TreeGrid.prototype.startCellEditing = function(td, params)
|
||||
TreeGrid.prototype.startCellEditing = function(td, params, node, subrow, cellIndex)
|
||||
{
|
||||
var self = this;
|
||||
if (!node)
|
||||
{
|
||||
node = td.parentNode._node;
|
||||
subrow = self._getSubrow(td);
|
||||
cellIndex = self._getCellIndex(td, true);
|
||||
}
|
||||
node.unrenderHooks = node.unrenderHooks||{};
|
||||
node.unrenderHooks.editing = function()
|
||||
{
|
||||
self.stopCellEditing(td, false, node, subrow, cellIndex);
|
||||
};
|
||||
self.editedCells.push(td);
|
||||
if (params.value === undefined)
|
||||
params.value = td.innerHTML;
|
||||
|
@ -884,18 +912,25 @@ TreeGrid.prototype.startCellEditing = function(td, params)
|
|||
inp.focus();
|
||||
}
|
||||
|
||||
TreeGrid.prototype.stopCellEditing = function(td, _int)
|
||||
TreeGrid.prototype.stopCellEditing = function(td, _int, node, subrow, cellIndex)
|
||||
{
|
||||
var i = this._getCellIndex(td, true);
|
||||
var subrow = this._getSubrow(td);
|
||||
var node = td.parentNode._node;
|
||||
node._oldCells[i] = undefined;
|
||||
if (td.offsetParent)
|
||||
{
|
||||
node = td.parentNode._node;
|
||||
subrow = this._getSubrow(td);
|
||||
cellIndex = this._getCellIndex(td, true);
|
||||
}
|
||||
delete node.unrenderHooks.editing;
|
||||
td.style.width = td._origWidth;
|
||||
td.style.minWidth = td._origMinWidth;
|
||||
var inp = td.getElementsByTagName('input')[0];
|
||||
node._oldCells[cellIndex] = undefined;
|
||||
var params = this.onStopCellEdit &&
|
||||
this.onStopCellEdit(node, subrow, i, inp ? inp.value : null, td) || {};
|
||||
node.render(i, subrow, true, 0);
|
||||
this.onStopCellEdit(node, subrow, cellIndex, inp ? inp.value : null, td) || {};
|
||||
if (td.offsetParent)
|
||||
{
|
||||
node.render(cellIndex, subrow, true, 0);
|
||||
}
|
||||
if (!_int)
|
||||
{
|
||||
for (var i = 0; i < this.editedCells.length; i++)
|
||||
|
@ -910,6 +945,7 @@ TreeGrid.prototype.stopCellEditing = function(td, _int)
|
|||
}
|
||||
|
||||
// Simple cell selection
|
||||
// FIXME add to unrenderHooks?
|
||||
|
||||
TreeGrid.prototype.initCellSelection = function(useMultiple)
|
||||
{
|
||||
|
@ -1252,20 +1288,30 @@ function setHiddenNodes(node)
|
|||
}
|
||||
}
|
||||
|
||||
TreeGridNode.prototype.toggle = function()
|
||||
TreeGridNode.prototype.toggle = function(skipSync)
|
||||
{
|
||||
if (this.leaf)
|
||||
return;
|
||||
this.collapsed = !this.collapsed;
|
||||
(this.col_tr || this.tr)[0].cells[0].firstChild.className =
|
||||
this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded';
|
||||
if (this.tr)
|
||||
{
|
||||
(this.col_tr || this.tr)[0].cells[0].firstChild.className =
|
||||
this.collapsed ? 'collapser collapser-collapsed' : 'collapser collapser-expanded';
|
||||
}
|
||||
setHiddenNodes(this);
|
||||
this.grid.syncView();
|
||||
if (!skipSync)
|
||||
this.grid.syncView();
|
||||
}
|
||||
|
||||
TreeGridNode.prototype.setChildren = function(isLeaf, newChildren, skipSync)
|
||||
{
|
||||
this.leaf = isLeaf;
|
||||
if (this.visible)
|
||||
{
|
||||
this.visible = false;
|
||||
setHiddenNodes(this);
|
||||
this.visible = true;
|
||||
}
|
||||
this.children = [];
|
||||
this.childrenByKey = {};
|
||||
this.addChildren(newChildren, null, skipSync);
|
||||
|
@ -1297,10 +1343,7 @@ TreeGridNode.prototype.addChildren = function(nodes, insertBefore, skipSync)
|
|||
e = this.children[insertBefore];
|
||||
for (var i = 0; i < nodes.length; i++)
|
||||
{
|
||||
var child = new TreeGridNode(nodes[i], this.grid, this, i, true);
|
||||
this.children.splice(insertBefore+i, 0, child);
|
||||
if (child.key !== undefined)
|
||||
this.childrenByKey[child.key] = child;
|
||||
new TreeGridNode(nodes[i], this.grid, this, insertBefore+i, true);
|
||||
}
|
||||
if (!skipSync)
|
||||
this.grid.syncView();
|
||||
|
|
Loading…
Reference in New Issue