diff -urp --strip-trailing-cr ../drupal-6.x-dev/misc/tableheader.js ./misc/tableheader.js --- ../drupal-6.x-dev/misc/tableheader.js 2007-10-02 09:09:51.000000000 +0200 +++ ./misc/tableheader.js 2007-12-18 02:08:13.000000000 +0100 @@ -9,12 +9,13 @@ Drupal.behaviors.tableHeader = function // Keep track of all header cells. var cells = []; - var z = 0; + // Only first time: Clone all table headers and initialize data. $('table thead:not(.tableHeader-processed)', context).each(function () { // Find table height. var table = $(this).parent('table')[0]; var height = $(table).addClass('sticky-table').height(); var i = 0; + var z = 1; // Find all header cells. $('th', this).each(function () { @@ -28,48 +29,121 @@ Drupal.behaviors.tableHeader = function html = ''+ html +''; } - // Clone and wrap cell contents in sticky wrapper that overlaps the cell's padding. - $('').prependTo(this); + // Clone and wrap cell contents in sticky wrapper that overlaps the cell's padding, + // and emulates its borders. + $('').prependTo(this); var div = $('div.sticky-header', this).css({ - 'marginLeft': '-'+ $(this).css('paddingLeft'), - 'marginRight': '-'+ $(this).css('paddingRight'), - 'paddingLeft': $(this).css('paddingLeft'), - 'paddingTop': $(this).css('paddingTop'), - 'paddingBottom': $(this).css('paddingBottom'), + 'borderLeft': $(this).css('borderLeft'), + 'borderRight': $(this).css('borderRight'), + 'borderTop': $(this).css('borderTop'), + 'borderBottom': $(this).css('borderBottom'), 'z-index': ++z })[0]; cells.push(div); - // Adjust width to fit cell/table. - var ref = this; + // Prepare various dimensions for the cell + var paddingL = parseInt($(this).css('paddingLeft')); + var paddingR = parseInt($(this).css('paddingRight')); + var paddingT = parseInt($(this).css('paddingTop')); + var paddingB = parseInt($(this).css('paddingBottom')); + + if ($(this).css('borderCollapse') == 'collapse') { + div.addH = paddingL + paddingR + parseInt($(this).css('borderRightWidth')); + } + else { + div.addH = paddingL + paddingR; + } + + div.addV = paddingB + paddingT; + div.cellOffset = parseInt($(this).css('borderLeftWidth')) + parseInt($(table).css('borderLeftWidth')); + var scrollH = document.documentElement.scrollLeft || document.body.scrollLeft; + + // Note that height() and width() are not used, because they sometimes + // return distorted values. + div.cellWidth = parseInt($(this).css('width')) + div.addH; + div.cellHeight = parseInt($(this).css('height')) + div.addV; + div.cellLeft = $(this).offset().left - div.cellOffset - scrollH; + + // Wrap the contents in another wrapper, to re-introduce its padding. + $(div).wrapInner('
'); + $(div).children().css({ + 'paddingLeft': paddingL, + 'paddingRight': paddingR, + 'paddingTop': paddingT, + 'paddingBottom': paddingB + })[0]; + + // Remember first/last cell. if (!i++) { - // The first cell is as wide as the table to prevent gaps. - ref = table; - div.wide = true; + table.first = div; } - $(div).width(Math.max(0, $(ref).width() - parseInt($(div).css('paddingLeft')))); + table.last = div; + + // Set position and size of the cloned cell. + $(div).css({ + 'left': div.cellLeft, + 'width': div.cellWidth, + 'height': div.cellHeight + }); - // Get position and store. + // Store data for later updates. div.cell = this; div.table = table; div.stickyMax = height; div.stickyPosition = $(this).offset().top; + div.savedScrollH = scrollH; }); + + // Adjust first/last cell order for RTL. + if ($('body').css('direction') == 'rtl') { + var temp = table.first; + table.first = table.last; + table.last = temp; + } + + // Wrap the contents of leftmost cell into yet another sticky wrapper, to + // ensure correct position and alignment, and make the outer wrapper as + // wide as the table, to serve as background and mask any gaps between + // cloned cells. + table.first.innerOffset = parseInt($(table.first).css('borderLeftWidth')); + $(table.first).wrapInner('
'); + $(table.first).children().css({ + 'z-index': parseInt($(table.first).css('z-index')), + 'left': table.first.cellLeft + table.first.innerOffset, + 'width': table.first.cellWidth + })[0]; + + $(table.first).css({ + 'z-index': 1, + 'width': table.last.cellLeft - table.first.cellLeft + table.last.cellWidth + })[0]; + table.first.wide = true; + $(this).addClass('tableHeader-processed'); }); // Track scrolling. var scroll = function() { $(cells).each(function () { - // Fetch scrolling position. + // Vertical. var scroll = document.documentElement.scrollTop || document.body.scrollTop; var offset = scroll - this.stickyPosition - 4; - if (offset > 0 && offset < this.stickyMax - 100) { + if (offset > 0 && offset < this.stickyMax - 50) { $(this).css('visibility', 'visible'); } else { $(this).css('visibility', 'hidden'); } + // Horizontal. + var scrollH = document.documentElement.scrollLeft || document.body.scrollLeft; + if (this.savedScrollH != scrollH) { + this.savedScrollH = scrollH; + var cellLeft = $(this.cell).offset().left - this.cellOffset - scrollH; + if (this.wide) { + $(this).children('div').css('left', cellLeft + this.innerOffset); + } + $(this).css('left', cellLeft); + } }); }; $(window).scroll(scroll); @@ -87,22 +161,38 @@ Drupal.behaviors.tableHeader = function // Precalculate table heights $('table.sticky-table').each(function () { this.savedHeight = $(this).height(); - }); - - $('table.sticky-table div.sticky-header').each(function () { - // Get position. - this.stickyPosition = $(this.cell).offset().top; - this.stickyMax = this.table.savedHeight; - // Reflow the cell. - var ref = this.cell; - if (this.wide) { - // Resize the first cell to fit the table. - ref = this.table; - } - $(this).width(Math.max(0, $(ref).width() - parseInt($(this).css('paddingLeft')))); + $('div.sticky-header', this).each(function () { + // Get position. + this.stickyPosition = $(this.cell).offset().top; + this.stickyMax = this.table.savedHeight; + var scrollH = document.documentElement.scrollLeft || document.body.scrollLeft; + this.cellWidth = parseInt($(this.cell).css('width')) + this.addH; + this.cellLeft = $(this.cell).offset().left - this.cellOffset - scrollH; + this.cellHeight = parseInt($(this.cell).css('height')) + this.addV; + + // Reflow the cell. + $(this).css({ + 'left': this.cellLeft, + 'width': this.cellWidth, + 'height': this.cellHeight + }); + }); + + // Update the special leftmost cell. + $(this.first).children('div').css({ + 'left': this.first.cellLeft + this.first.innerOffset, + 'width': this.first.cellWidth + })[0]; + + $(this.first).css({ + 'width': this.last.cellLeft - this.first.cellLeft + this.last.cellWidth + })[0]; }); + // Resizing may change position of the tables, so update visibility. + $(scroll); + // Reset timer time = null; }, 250);