2011-05-01 01:06:58 +04:00
|
|
|
// jQuery Plugin FixedHeaderTable
|
|
|
|
// A pluging for adding fixed headers to HTML tables
|
|
|
|
// version 1.2, April 30th, 2011
|
|
|
|
// by Mark Malek
|
|
|
|
|
|
|
|
(function($) {
|
|
|
|
|
|
|
|
// here it goes!
|
|
|
|
$.fn.fixedHeaderTable = function(method) {
|
|
|
|
|
|
|
|
// plugin's default options
|
|
|
|
var defaults = {
|
2011-05-01 04:44:30 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
width: '100%',
|
|
|
|
height: '100%',
|
|
|
|
borderCollapse: true,
|
|
|
|
|
2011-05-01 04:44:30 +04:00
|
|
|
autoShow: true,
|
2011-05-01 01:06:58 +04:00
|
|
|
loader: false,
|
2011-05-01 04:45:15 +04:00
|
|
|
footer: false,
|
|
|
|
cloneHeadToFoot: false,
|
|
|
|
cloneHeaderToFooter: false, // deprecated option
|
2011-05-01 01:06:58 +04:00
|
|
|
autoResize: false,
|
2011-05-01 04:45:15 +04:00
|
|
|
complete: null
|
2011-05-01 01:06:58 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// this will hold the merged default and user-provided properties
|
|
|
|
// you will have to access the plugin's properties through this object!
|
|
|
|
// settings.propertyName
|
|
|
|
var settings = {}
|
|
|
|
|
|
|
|
// public methods
|
|
|
|
// to keep the $.fn namespace uncluttered, collect all of the plugin's methods in an object literal and call
|
|
|
|
// them by passing the string name of the method to the plugin
|
|
|
|
//
|
|
|
|
// public methods can be called as
|
|
|
|
// $(selector).pluginName('methodName', arg1, arg2, ... argn)
|
|
|
|
// where "pluginName" is the name of your plugin and "methodName" is the name of a function available in
|
|
|
|
// the "methods" object below; arg1 ... argn are arguments to be passed to the method
|
|
|
|
//
|
|
|
|
// or, from within the plugin itself, as
|
|
|
|
// methods.methodName(arg1, arg2, ... argn)
|
|
|
|
// where "methodName" is the name of a function available in the "methods" object below
|
|
|
|
var methods = {
|
|
|
|
|
|
|
|
// this the constructor method that gets called when the object is created
|
|
|
|
init : function(options) {
|
|
|
|
|
|
|
|
// the plugin's final properties are the merged default and user-provided properties (if any)
|
|
|
|
// this has the advantage of not polluting the defaults, making the same instace re-usable with
|
|
|
|
// new options; thanks to Steven Black for suggesting this
|
|
|
|
settings = $.extend({}, defaults, options);
|
|
|
|
|
|
|
|
// iterate through all the DOM elements we are attaching the plugin to
|
|
|
|
return this.each(function() {
|
|
|
|
|
|
|
|
var $self = $(this), // reference the jQuery version of the current DOM element
|
|
|
|
self = this; // reference to the actual DOM element
|
|
|
|
|
|
|
|
if ( helpers._isTable($self) ) {
|
|
|
|
methods.setup.apply(this, Array.prototype.slice.call(arguments, 1));
|
2011-05-01 04:45:15 +04:00
|
|
|
|
|
|
|
$.isFunction(options.complete) && options.complete.call(this);
|
|
|
|
} else {
|
|
|
|
$.error('Invalid table mark-up');
|
2011-05-01 01:06:58 +04:00
|
|
|
}
|
2011-05-01 04:45:15 +04:00
|
|
|
|
2011-05-01 01:06:58 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
setup: function( options ) {
|
2011-05-01 01:06:58 +04:00
|
|
|
var $self = $(this),
|
|
|
|
self = this,
|
|
|
|
$thead = $self.find('thead'),
|
|
|
|
$tfoot = $self.find('tfoot'),
|
|
|
|
$tbody = $self.find('tbody'),
|
|
|
|
$wrapper,
|
|
|
|
$divHead,
|
|
|
|
$divFoot,
|
|
|
|
$divBody,
|
|
|
|
$fixedHeadRow,
|
|
|
|
$temp;
|
2011-05-01 04:45:15 +04:00
|
|
|
|
|
|
|
settings.scrollbarOffset = helpers._getScrollbarWidth();
|
|
|
|
settings.themeClassName = $self.attr('class');
|
|
|
|
|
|
|
|
$self.css({
|
|
|
|
width: settings.width - settings.scrollbarOffset,
|
|
|
|
height: settings.height
|
|
|
|
});
|
|
|
|
|
2011-05-01 01:06:58 +04:00
|
|
|
if ( !$self.closest('.fht-table-wrapper').length ) {
|
|
|
|
$self.addClass('fht-table');
|
|
|
|
$self.wrap('<div class="fht-table-wrapper"></div>');
|
|
|
|
}
|
|
|
|
|
|
|
|
$wrapper = $self.closest('.fht-table-wrapper');
|
|
|
|
|
|
|
|
$wrapper.css({
|
2011-05-01 04:45:15 +04:00
|
|
|
width: settings.width,
|
|
|
|
height: settings.height
|
2011-05-01 01:06:58 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
if ( !$self.hasClass('fht-table-init') ) {
|
|
|
|
|
|
|
|
$self.wrap('<div class="fht-tbody"></div>');
|
2011-05-01 04:45:15 +04:00
|
|
|
|
|
|
|
}
|
2011-05-01 01:06:58 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
var tableProps = helpers._getTableProps($self);
|
|
|
|
|
|
|
|
if ( !$self.hasClass('fht-table-init') ) {
|
2011-05-01 01:06:58 +04:00
|
|
|
$divHead = $('<div class="fht-head"><table class="fht-table"></table></div>').prependTo($wrapper);
|
|
|
|
|
|
|
|
$thead.clone().appendTo($divHead.find('table'));
|
2011-05-01 04:45:15 +04:00
|
|
|
} else {
|
|
|
|
$divHead = $wrapper.find('div.fht-head');
|
|
|
|
}
|
|
|
|
|
|
|
|
$divHead.find('table')
|
|
|
|
.addClass(settings.themeClassName);
|
2011-05-01 01:06:58 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
helpers._setupClone( $divHead, tableProps.thead );
|
|
|
|
|
|
|
|
$self.css({
|
|
|
|
'margin-top': -$thead.outerHeight(true) - tableProps.border
|
|
|
|
});
|
2011-05-01 01:06:58 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
if ( settings.footer ) {
|
|
|
|
|
|
|
|
if ( !$self.hasClass('fht-table-init') ) {
|
|
|
|
$divFoot = $('<div class="tfoot"><table class="fht-table"></table></div>').appendTo($wrapper);
|
|
|
|
} else {
|
|
|
|
$divFoot = $wrapper.find('div.tfoot');
|
|
|
|
}
|
2011-05-01 01:06:58 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
$divFoot.find('table')
|
|
|
|
.addClass(settings.themeClassName);
|
|
|
|
|
|
|
|
if ( settings.cloneHeadToFoot || settings.cloneHeaderToFooter ) {
|
|
|
|
$thead.find('tr').clone().appendTo($divFoot.find('table tfoot'));
|
|
|
|
|
|
|
|
helpers._setupClone( $divFoot, tableProps.thead );
|
|
|
|
} else if ( !$self.find('tfoot').length && ( !settings.cloneHeadToFoot || !settings.cloneHeaderToFooter ) ) {
|
|
|
|
$.error( 'Invalid markup: tfoot does not exist in table!');
|
|
|
|
|
|
|
|
return self;
|
|
|
|
} else {
|
2011-05-01 01:06:58 +04:00
|
|
|
|
|
|
|
$tfoot.appendTo($divFoot.find('table'));
|
2011-05-01 04:45:15 +04:00
|
|
|
$divFoot.find('table')
|
|
|
|
.css({
|
|
|
|
'margin-top': -tableProps.border
|
|
|
|
});
|
|
|
|
|
|
|
|
helpers._setupClone( $divFoot, tableProps.thead );
|
2011-05-01 01:06:58 +04:00
|
|
|
|
2011-05-01 04:44:30 +04:00
|
|
|
}
|
2011-05-01 01:06:58 +04:00
|
|
|
}
|
2011-05-01 04:44:30 +04:00
|
|
|
|
2011-05-01 04:45:15 +04:00
|
|
|
var tbodyHeight = $wrapper.height() - $thead.outerHeight(true) - $tfoot.outerHeight(true) - tableProps.border;
|
|
|
|
$divBody = $self.closest('.fht-tbody');
|
|
|
|
$divBody.css({
|
|
|
|
'height': tbodyHeight
|
|
|
|
});
|
|
|
|
|
|
|
|
if ( !settings.autoShow ) {
|
|
|
|
$wrapper.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
$self.addClass('fht-table-init');
|
|
|
|
|
2011-05-01 04:44:30 +04:00
|
|
|
return self;
|
2011-05-01 01:06:58 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
show: function() {
|
2011-05-01 04:44:30 +04:00
|
|
|
var $self = $(this),
|
|
|
|
self = this;
|
|
|
|
|
|
|
|
$self.closest('.fht-table-wrapper')
|
|
|
|
.show();
|
|
|
|
|
|
|
|
return this;
|
2011-05-01 01:06:58 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
hide: function() {
|
2011-05-01 04:44:30 +04:00
|
|
|
var $self = $(this),
|
|
|
|
self = this;
|
|
|
|
|
|
|
|
$self.closest('.fht-table-wrapper')
|
|
|
|
.hide();
|
|
|
|
|
|
|
|
return this;
|
2011-05-01 01:06:58 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
destroy: function() {
|
2011-05-01 04:44:30 +04:00
|
|
|
var $self = $(this),
|
|
|
|
self = this,
|
|
|
|
$wrapper = $self.closest('.fht-table-wrapper');
|
|
|
|
|
|
|
|
$self.insertBefore($wrapper)
|
|
|
|
.removeAttr('style')
|
|
|
|
.append($wrapper.find('tfoot'))
|
2011-05-01 04:45:15 +04:00
|
|
|
.removeClass('fht-table fht-table-init')
|
|
|
|
.find('.fht-cell')
|
|
|
|
.remove();
|
2011-05-01 04:44:30 +04:00
|
|
|
|
|
|
|
$wrapper.remove();
|
|
|
|
|
|
|
|
return this;
|
2011-05-01 01:06:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// private methods
|
|
|
|
// these methods can be called only from within the plugin
|
|
|
|
//
|
|
|
|
// private methods can be called as
|
|
|
|
// helpers.methodName(arg1, arg2, ... argn)
|
|
|
|
// where "methodName" is the name of a function available in the "helpers" object below; arg1 ... argn are
|
|
|
|
// arguments to be passed to the method
|
|
|
|
var helpers = {
|
|
|
|
|
|
|
|
_isTable: function( $obj ) {
|
|
|
|
var $self = $obj,
|
|
|
|
hasTable = $self.is('table'),
|
|
|
|
hasThead = $self.find('thead').length > 0,
|
|
|
|
hasTbody = $self.find('tbody').length > 0;
|
|
|
|
|
|
|
|
if ( hasTable && hasThead && hasTbody ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_getTableProps: function( $obj ) {
|
|
|
|
var tableProp = {
|
|
|
|
thead: {},
|
2011-05-01 04:45:15 +04:00
|
|
|
tbody: {},
|
|
|
|
border: 0
|
2011-05-01 01:06:58 +04:00
|
|
|
};
|
2011-05-01 04:45:15 +04:00
|
|
|
|
|
|
|
tableProp.border = ( $obj.find('th:first-child').outerWidth() - $obj.find('th:first-child').innerWidth() ) / 2;
|
|
|
|
|
2011-05-01 01:06:58 +04:00
|
|
|
$obj.find('thead th').each(function(index) {
|
2011-05-01 04:45:15 +04:00
|
|
|
|
|
|
|
tableProp.thead[index] = $(this).width() + tableProp.border;
|
2011-05-01 01:06:58 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
$obj.find('tbody tr:first-child td').each(function(index) {
|
2011-05-01 04:45:15 +04:00
|
|
|
tableProp.tbody[index] = $(this).width() + tableProp.border;
|
2011-05-01 01:06:58 +04:00
|
|
|
});
|
2011-05-01 04:45:15 +04:00
|
|
|
|
2011-05-01 01:06:58 +04:00
|
|
|
return tableProp;
|
2011-05-01 04:45:15 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
_setupClone: function( $head, cellArray ) {
|
|
|
|
var $self = $head,
|
|
|
|
selector = ( $self.find('thead').length ) ?
|
|
|
|
'thead th' :
|
|
|
|
( $self.find('tfoot').length ) ?
|
|
|
|
'tfoot td' :
|
|
|
|
'tbody td',
|
|
|
|
$cell;
|
|
|
|
|
|
|
|
$self.css({
|
|
|
|
'margin-right': settings.scrollbarOffset
|
|
|
|
});
|
|
|
|
$self.find(selector).each(function(index) {
|
|
|
|
$cell = ( $(this).find('div.fht-cell').length ) ? $(this).find('div.fht-cell') : $('<div class="fht-cell"></div>').appendTo($(this));
|
|
|
|
|
|
|
|
$cell.css({
|
|
|
|
'width': cellArray[index]
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
_getScrollbarWidth: function() {
|
|
|
|
var scrollbarWidth = 0;
|
|
|
|
|
|
|
|
if ( !scrollbarWidth ) {
|
|
|
|
if ( $.browser.msie ) {
|
|
|
|
var $textarea1 = $('<textarea cols="10" rows="2"></textarea>')
|
|
|
|
.css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'),
|
|
|
|
$textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>')
|
|
|
|
.css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body');
|
|
|
|
scrollbarWidth = $textarea1.width() - $textarea2.width();
|
|
|
|
$textarea1.add($textarea2).remove();
|
|
|
|
} else {
|
|
|
|
var $div = $('<div />')
|
|
|
|
.css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 })
|
|
|
|
.prependTo('body').append('<div />').find('div')
|
|
|
|
.css({ width: '100%', height: 200 });
|
|
|
|
scrollbarWidth = 100 - $div.width();
|
|
|
|
$div.parent().remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return scrollbarWidth;
|
2011-05-01 01:06:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// if a method as the given argument exists
|
|
|
|
if (methods[method]) {
|
|
|
|
|
|
|
|
// call the respective method
|
|
|
|
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
|
|
|
|
|
|
// if an object is given as method OR nothing is given as argument
|
|
|
|
} else if (typeof method === 'object' || !method) {
|
|
|
|
|
|
|
|
// call the initialization method
|
|
|
|
return methods.init.apply(this, arguments);
|
|
|
|
|
|
|
|
// otherwise
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// trigger an error
|
|
|
|
$.error( 'Method "' + method + '" does not exist in fixedHeaderTable plugin!');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})(jQuery);
|