Blame | Letzte Änderung | Log anzeigen | RSS feed
/*! FixedHeader 3.0.0* ©2009-2015 SpryMedia Ltd - datatables.net/license*//*** @summary FixedHeader* @description Fix a table's header or footer, so it is always visible while* scrolling* @version 3.0.0* @file dataTables.fixedHeader.js* @author SpryMedia Ltd (www.sprymedia.co.uk)* @contact www.sprymedia.co.uk/contact* @copyright Copyright 2009-2015 SpryMedia Ltd.** This source file is free software, available under the following license:* MIT license - http://datatables.net/license/mit** This source file is distributed in the hope that it will be useful, but* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.** For details please refer to: http://www.datatables.net*/(function(window, document, undefined) {var factory = function( $, DataTable ) {"use strict";var _instCounter = 0;var FixedHeader = function ( dt, config ) {// Sanity check - you just know it will happenif ( ! (this instanceof FixedHeader) ) {throw "FixedHeader must be initialised with the 'new' keyword.";}// Allow a boolean true for defaultsif ( config === true ) {config = {};}dt = new DataTable.Api( dt );this.c = $.extend( true, {}, FixedHeader.defaults, config );this.s = {dt: dt,position: {theadTop: 0,tbodyTop: 0,tfootTop: 0,tfootBottom: 0,width: 0,left: 0,tfootHeight: 0,theadHeight: 0,windowHeight: $(window).height(),visible: true},headerMode: null,footerMode: null,namespace: '.dtfc'+(_instCounter++)};this.dom = {floatingHeader: null,thead: $(dt.table().header()),tbody: $(dt.table().body()),tfoot: $(dt.table().footer()),header: {host: null,floating: null,placeholder: null},footer: {host: null,floating: null,placeholder: null}};this.dom.header.host = this.dom.thead.parent();this.dom.footer.host = this.dom.tfoot.parent();var dtSettings = dt.settings()[0];if ( dtSettings._fixedHeader ) {throw "FixedHeader already initialised on table "+dtSettings.nTable.id;}dtSettings._fixedHeader = this;this._constructor();};/** Variable: FixedHeader* Purpose: Prototype for FixedHeader* Scope: global*/FixedHeader.prototype = {/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** API methods*//*** Recalculate the position of the fixed elements and force them into place*/update: function () {this._positions();this._scroll( true );},/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** Constructor*//*** FixedHeader constructor - adding the required event listeners and* simple initialisation** @private*/_constructor: function (){var that = this;var dt = this.s.dt;$(window).on( 'scroll'+this.s.namespace, function () {that._scroll();} ).on( 'resize'+this.s.namespace, function () {that.s.position.windowHeight = $(window).height();that._positions();that._scroll( true );} );dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc', function () {that._positions();that._scroll( true );} ).on( 'draw.dtfc', function () {that._positions();that._scroll();} );dt.on( 'destroy.dtfc', function () {dt.off( '.dtfc' );$(window).off( this.s.namespace );} );this._positions();this._scroll();},/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** Private methods*//*** Clone a fixed item to act as a place holder for the original element* which is moved into a clone of the table element, and moved around the* document to give the fixed effect.** @param {string} item 'header' or 'footer'* @param {boolean} force Force the clone to happen, or allow automatic* decision (reuse existing if available)* @private*/_clone: function ( item, force ){var dt = this.s.dt;var itemDom = this.dom[ item ];var itemElement = item === 'header' ?this.dom.thead :this.dom.tfoot;if ( ! force && itemDom.floating ) {// existing floating element - reuse ititemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );}else {if ( itemDom.floating ) {itemDom.placeholder.remove();itemDom.floating.children().detach();itemDom.floating.remove();}itemDom.floating = $( dt.table().node().cloneNode( false ) ).removeAttr( 'id' ).append( itemElement ).appendTo( 'body' );// Insert a fake thead/tfoot into the DataTable to stop it jumping arounditemDom.placeholder = itemElement.clone( false );itemDom.host.append( itemDom.placeholder );// Footer needs sizes cloned acrossif ( item === 'footer' ) {this._footerMatch( itemDom.placeholder, itemDom.floating );}}},/*** Copy widths from the cells in one element to another. This is required* for the footer as the footer in the main table takes its sizes from the* header columns. That isn't present in the footer so to have it still* align correctly, the sizes need to be copied over.** @param {jQuery} from Copy widths from* @param {jQuery} to Copy widths to* @private*/_footerMatch: function ( from, to ) {var type = function ( name ) {var toWidths = $(name, from).map( function () {return $(this).width();} ).toArray();$(name, to).each( function ( i ) {$(this).width( toWidths[i] );} );};type( 'th' );type( 'td' );},/*** Remove assigned widths from the cells in an element. This is required* when inserting the footer back into the main table so the size is defined* by the header columns.** @private*/_footerUnsize: function () {var footer = this.dom.footer.floating;if ( footer ) {$('th, td', footer).css( 'width', '' );}},/*** Change from one display mode to another. Each fixed item can be in one* of:** * `in-place` - In the main DataTable* * `in` - Floating over the DataTable* * `below` - (Header only) Fixed to the bottom of the table body* * `above` - (Footer only) Fixed to the top of the table body** @param {string} mode Mode that the item should be shown in* @param {string} item 'header' or 'footer'* @param {boolean} forceChange Force a redraw of the mode, even if already* in that mode.* @private*/_modeChange: function ( mode, item, forceChange ){var dt = this.s.dt;var itemDom = this.dom[ item ];var position = this.s.position;if ( mode === 'in-place' ) {// Insert the header back into the table's real headerif ( itemDom.placeholder ) {itemDom.placeholder.remove();itemDom.placeholder = null;}itemDom.host.append( item === 'header' ?this.dom.thead :this.dom.tfoot);if ( itemDom.floating ) {itemDom.floating.remove();itemDom.floating = null;}if ( item === 'footer' ) {this._footerUnsize();}}else if ( mode === 'in' ) {// Remove the header from the read header and insert into a fixed// positioned floating table clonethis._clone( item, forceChange );itemDom.floating.addClass( 'fixedHeader-floating' ).css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] ).css( 'left', position.left+'px' ).css( 'width', position.width+'px' );if ( item === 'footer' ) {itemDom.floating.css( 'top', '' );}}else if ( mode === 'below' ) { // only used for the header// Fix the position of the floating header at base of the table bodythis._clone( item, forceChange );itemDom.floating.addClass( 'fixedHeader-locked' ).css( 'top', position.tfootTop - position.theadHeight ).css( 'left', position.left+'px' ).css( 'width', position.width+'px' );}else if ( mode === 'above' ) { // only used for the footer// Fix the position of the floating footer at top of the table bodythis._clone( item, forceChange );itemDom.floating.addClass( 'fixedHeader-locked' ).css( 'top', position.tbodyTop ).css( 'left', position.left+'px' ).css( 'width', position.width+'px' );}this.s[item+'Mode'] = mode;},/*** Cache the positional information that is required for the mode* calculations that FixedHeader performs.** @private*/_positions: function (){var dt = this.s.dt;var table = dt.table();var position = this.s.position;var dom = this.dom;var tableNode = $(table.node());// Need to use the header and footer that are in the main table,// regardless of if they are clones, since they hold the positions we// want to measure fromvar thead = tableNode.children('thead');var tfoot = tableNode.children('tfoot');var tbody = dom.tbody;position.visible = tableNode.is(':visible');position.width = tableNode.outerWidth();position.left = tableNode.offset().left;position.theadTop = thead.offset().top;position.tbodyTop = tbody.offset().top;position.theadHeight = position.tbodyTop - position.theadTop;if ( tfoot.length ) {position.tfootTop = tfoot.offset().top;position.tfootBottom = position.tfootTop + tfoot.outerHeight();position.tfootHeight = position.tfootBottom - position.tfootTop;}else {position.tfootTop = position.tbodyTop + tbody.outerHeight();position.tfootBottom = position.tfootTop;position.tfootHeight = position.tfootTop;}},/*** Mode calculation - determine what mode the fixed items should be placed* into.** @param {boolean} forceChange Force a redraw of the mode, even if already* in that mode.* @private*/_scroll: function ( forceChange ){var windowTop = $(document).scrollTop();var position = this.s.position;var headerMode, footerMode;if ( this.c.header ) {if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {headerMode = 'in-place';}else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {headerMode = 'in';}else {headerMode = 'below';}if ( forceChange || headerMode !== this.s.headerMode ) {this._modeChange( headerMode, 'header', forceChange );}}if ( this.c.footer && this.dom.tfoot.length ) {if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {footerMode = 'in-place';}else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {footerMode = 'in';}else {footerMode = 'above';}if ( forceChange || footerMode !== this.s.footerMode ) {this._modeChange( footerMode, 'footer', forceChange );}}}};/*** Version* @type {String}* @static*/FixedHeader.version = "3.0.0";/*** Defaults* @type {Object}* @static*/FixedHeader.defaults = {header: true,footer: false,headerOffset: 0,footerOffset: 0};/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** DataTables interfaces*/// Attach for constructor access$.fn.dataTable.FixedHeader = FixedHeader;$.fn.DataTable.FixedHeader = FixedHeader;// DataTables creation - check if the FixedHeader option has been defined on the// table and if so, initialise$(document).on( 'init.dt.dtb', function (e, settings, json) {if ( e.namespace !== 'dt' ) {return;}var opts = settings.oInit.fixedHeader || DataTable.defaults.fixedHeader;if ( opts && ! settings._buttons ) {new FixedHeader( settings, opts );}} );// DataTables API methodsDataTable.Api.register( 'fixedHeader()', function () {} );DataTable.Api.register( 'fixedHeader.adjust()', function () {return this.iterator( 'table', function ( ctx ) {var fh = ctx._fixedHeader;if ( fh ) {fh.update();}} );} );return FixedHeader;}; // /factory// Define as an AMD module if possibleif ( typeof define === 'function' && define.amd ) {define( ['jquery', 'datatables'], factory );}else if ( typeof exports === 'object' ) {// Node/CommonJSfactory( require('jquery'), require('datatables') );}else if ( jQuery && !jQuery.fn.dataTable.FixedHeader ) {// Otherwise simply initialise as normal, stopping multiple evaluationfactory( jQuery, jQuery.fn.dataTable );}})(window, document);