Skip to content

Instantly share code, notes, and snippets.

@AoJ
Forked from paranoiq/makeScrollable.js
Created September 11, 2011 18:22
Show Gist options
  • Save AoJ/1209932 to your computer and use it in GitHub Desktop.
Save AoJ/1209932 to your computer and use it in GitHub Desktop.
Scrollable table body
/**
* Make table body scrollable, with the table header always visible.
* If no min/max-height is given, table shrinks to fit the browser viewport.
*
* requirements:
* - jQuery framework required (tested with 1.6.2)
* - header must be wrapped in <thead> element
*
* warnings:
* - table <caption> is not supported
* - using with header including <input>s is not adviced
*
* @author Vlasta Neubauer [[email protected]]
* @license public domain
*
* @param object table element (DOM or jQuery)
* @param int minimal table height (optional)
* @param int maximal table height (optional)
*/
function makeScrollable(table, minHeight, maxHeight) {
var $ = jQuery;
// fuck IE7 and older
if ($.browser.msie && parseInt($.browser.version) < 8) return;
table = $(table);
// scrolling container
table.wrap('<div>');
var container = table.parent();
container.css({ 'display': 'inline-block', 'border': 'none', 'padding': 0 });
if (minHeight) container.css({ 'minHeight': minHeight });
container.css({ // cannot copy 'margin' (IE, FF, Webkit)
'marginTop': table.css('marginTop'), 'marginRight': table.css('marginRight'),
'marginBottom': table.css('marginBottom'), 'marginLeft': table.css('marginLeft') });
table.css({ 'margin': 0 });
var lastRow = table.find("tr:last").find("th, td");
container.css({ // cannot copy 'borderBottom' (IE, FF)
'borderBottomWidth': lastRow.css('borderBottomWidth'),
'borderBottomColor': lastRow.css('borderBottomColor'),
'borderBottomStyle': lastRow.css('borderBottomStyle') });
lastRow.css({ 'borderBottom': 'none' });
// fake header
var head = table.find("thead").clone(true);
head.css({ 'display': 'block', 'position': 'absolute' });
head.find("th:not(:last-child), td:not(:last-child)").css({ 'borderRight': 'none' });
head.find("tr:not(:last-child)").find("th, td").css({ 'borderBottom': 'none' });
head.insertBefore(table);
var origCells = table.find("thead tr:first-child").find("th, td");
var copyCells = head.find("tr:first-child").find("th, td");
$(window).resize(function (event) {
var oldPosition = container.scrollTop();
container.scrollTop(0); // FF looses position of header on refresh
head.css({ 'display': 'none', 'position': 'static' });
container.css({ 'maxHeight': 32000, 'overflowY': 'visible' }); // "maxHeight: auto" won't work
var tableHeight = table.outerHeight(true);
var containerHeight = tableHeight
- ($(document.body).outerHeight(true) - document.documentElement.clientHeight);
if ($.browser.opera || ($.browser.msie && parseInt($.browser.version) < 9)) containerHeight -= 4; // WTF?
if (maxHeight && containerHeight > maxHeight) containerHeight = maxHeight;
if (containerHeight >= tableHeight) {
return;
} else {
container.css({ 'maxHeight': containerHeight, 'overflowY': 'scroll' });
}
// sync column widths
origCells.each(function (n, th) {
if ($.browser.msie && parseInt($.browser.version) < 9) {
var columnWidth = th.clientWidth
- parseInt($(th).css('paddingLeft'))
- parseInt($(th).css('paddingRight'));
} else { // dimensions from cell itself are not reliable, specially in Opera
var columnWidth = th.getBoundingClientRect().width
- parseInt($(th).css('borderLeftWidth'))
- parseInt($(th).css('paddingLeft'))
- parseInt($(th).css('paddingRight'));
if ($.browser.mozilla) columnWidth -= parseInt($(th).css('borderRightWidth'));
}
$(copyCells.get(n)).css({ 'width': columnWidth, 'minWidth': columnWidth });
});
head.css({ 'display': 'block', 'position': 'absolute' });
container.scrollTop(oldPosition);
});
$(window).trigger('resize', null);
}
// jQuery plugin
(function ($) {
$.fn.makeScrollable = function (minHeight, maxHeight) {
this.each(function(n, table) {
makeScrollable(table, minHeight, maxHeight);
});
return this;
};
})(jQuery)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment