diff --git a/stickyheaders.js b/stickyheaders.js index 5fd386a..9eecddd 100644 --- a/stickyheaders.js +++ b/stickyheaders.js @@ -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'; + } + } } } } diff --git a/treegrid.css b/treegrid.css index cae7b25..d75d715 100644 --- a/treegrid.css +++ b/treegrid.css @@ -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 diff --git a/treegrid.js b/treegrid.js index 7199c76..fc773ff 100644 --- a/treegrid.js +++ b/treegrid.js @@ -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); }