Minimise reflows even more, fix bugs

rel-1.0
Vitaliy Filippov 2016-08-12 17:08:01 +03:00
parent f48f8cbdec
commit ea22e29fea
3 changed files with 52 additions and 36 deletions

View File

@ -6,9 +6,11 @@
// USAGE:
// makeStickyHeaders(table): add sticky header and footer to table
// table.parentNode is assumed to be the scroll container
// initStickyRow(table, tr): initialise table row (tr) if not yet
// fixStickyRow(table, tr): fix table row (tr) after modifications
// initStickyRows(table, trs): initialise table rows (trs = array[TableRow]) if not yet
// fixStickyRows(table, trs): fix table row (trs = array[TableRow]) after modifications
// fixStickyHeader(table): fix table header after modifications
// fixStickyColumnSizes(table, force): adjust column sizes if something is modified
// if force == true, reposition all fixed cells (header row and column)
// WARNING 1: after using this plugin all columns and rows except 0th ones become shifted by 1.
// table.rows[1] and table.rows[*].cells[1] become special invisible rows/cells with copies of first
@ -17,11 +19,14 @@
// WARNING 2: this plugin does NOT support border-collapse because it is implemented by non-integer border
// sizes O_o and slightly differently in different browsers which leads to problems calculating cell positions.
// WARNING 3: for these hacks to work correctly, you need 'position: relative' on your table rows.
// WARNING 3: for these hacks to work correctly, you need 'position: relative' on your table and table rows.
// WARNING 4: all table cells should obviously have non-transparent background
// because fixed ones are positioned over normal.
// WARNING 5: make sure you have no CSS rules that will differ on the original header row/column and cloned one,
// and that min/max width/height rules apply to the second row/column, not the first header one.
var _scri = 0;
function makeStickyHeaders(table)
@ -38,6 +43,7 @@ function makeStickyHeaders(table)
var w = [], l = [], h = rs[0].offsetHeight;
var sr = rs[0].cloneNode(true);
sr.insertBefore(document.createElement('td'), sr.firstChild);
sr.style.visibility = 'hidden';
sr.children[0].style.width = '0';
sr.children[0].style.display = 'block';
sr.children[0].style.position = 'absolute';
@ -104,10 +110,11 @@ function makeStickyHeaders(table)
e.style.height = hs[i]+'px';
e.style.width = w[0]+'px';
}
table.parentNode.addEventListener('scroll', function(e)
var row0top = rs[0].offsetTop;
addListener(table.parentNode, 'scroll', function(e)
{
var l = this.scrollLeft, t = this.scrollTop;
table.rows[0].style.top = t+'px';
table.rows[0].style.top = (t+row0top)+'px';
table._scrstyle.innerHTML = '._scri'+table._scri+' { left: '+l+'px; }';
});
}
@ -177,51 +184,58 @@ function fixStickyRows(table, trs, nocols)
fixStickyColumnSizes(table);
}
// handle non-header row change
function fixStickyRow(table, tr, nocols)
{
fixStickyRows(table, [ tr ], nocols);
}
function fixStickyColumnSizes(table)
function fixStickyColumnSizes(table, force)
{
// check&fix column sizes
var changed = false;
var changed = false, resizeFixed = false;
for (var i = 1; i < table._sizerow.children.length; i++)
{
var ne = table._sizerow.children[i];
var nw = ne.offsetWidth;
var cw = table._widths[i-1];
if (nw != cw)
if (nw != cw || force)
{
table._widths[i-1] = nw;
changed = true;
if (i == 1)
{
// resize fixed column
for (var j = 0; j < table.rows.length; j++)
{
if (table.rows[j] != table._sizerow)
{
table.rows[j].children[0].style.width = nw+'px';
table.rows[j].children[0].style.height = (j == 0 ? table._sizerow.offsetHeight : table.rows[j].offsetHeight)+'px';
}
}
}
resizeFixed = true;
}
}
if (changed)
{
// reposition fixed header
var b = table._sizerow.children[1];
table.rows[0].children[0].style.width = b.offsetWidth+'px';
table.rows[0].children[0].style.height = b.offsetHeight+'px';
for (var i = 2; i < table._sizerow.children.length; i++)
var w = [], h = [], l = [], b;
for (var i = 0; i < table._sizerow.children.length; i++)
{
b = table._sizerow.children[i];
table.rows[0].children[i].style.left = b.offsetLeft+'px';
table.rows[0].children[i].style.width = b.offsetWidth+'px';
table.rows[0].children[i].style.height = b.offsetHeight+'px';
w[i] = b.offsetWidth;
h[i] = b.offsetHeight;
l[i] = b.offsetLeft;
}
b = table.rows[0].children[0];
b.style.width = w[1]+'px';
b.style.height = h[1]+'px';
for (var i = 2; i < table._sizerow.children.length; i++)
{
b = table.rows[0].children[i];
b.style.left = l[i]+'px';
b.style.width = w[i]+'px';
b.style.height = h[i]+'px';
}
if (resizeFixed)
{
// resize fixed column
var h = [];
for (var i = 0; i < table.rows.length; i++)
h[i] = table.rows[i].children[1].offsetHeight;
for (var i = 0; i < table.rows.length; i++)
{
if (i != 1)
{
table.rows[i].children[0].style.width = w[1]+'px';
table.rows[i].children[0].style.height = h[i == 0 ? 1 : i]+'px';
}
}
}
}
}

View File

@ -9,10 +9,9 @@ body { -moz-text-size-adjust: none; } /* do not scale fonts in mobile firefox */
/* scroll div styles */
.scroller
{
float: left;
position: relative;
height: 100%;
width: 100%;
overflow: auto;
}
/* fixed header table styles */
@ -93,6 +92,7 @@ table.grid .collapser-expanded
background: #0097ff;
opacity: 0.1;
display: none;
z-index: 10;
}
.disable-text-select

View File

@ -337,9 +337,10 @@ TreeGrid.prototype.initCellSelection = function(restrictToNode)
var row = e1.parentNode;
do
{
if (row.style.display != 'none')
if (row.style.display != 'none' && row.style.visibility != 'hidden')
for (var i = col1; i <= col2; i++)
self.selectCell(row.cells[i]);
if (!self.stickyInit || i != 1)
self.selectCell(row.cells[i]);
if (row == e2.parentNode)
break;
row = row.nextSibling;
@ -678,6 +679,7 @@ TreeGridNode.prototype.addChildren = function(nodes, insertBefore)
this.children.splice(insertBefore+i, 0, child);
if (child.key !== undefined)
this.childrenByKey[child.key] = child;
// TODO: fix sticky only once per whole node batch, including children
if (this.grid.stickyInit && !this.collapsed)
trs.push(child.tr);
}