PHP Classes

File: assets/plugins/datatables/extensions/FixedHeader/js/dataTables.fixedHeader.js

Recommend this page to a friend!
  Classes of Kishor Mali   PHP User Feedback System   assets/plugins/datatables/extensions/FixedHeader/js/dataTables.fixedHeader.js   Download  
File: assets/plugins/datatables/extensions/FixedHeader/js/dataTables.fixedHeader.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: PHP User Feedback System
Application to record feedback from customers
Author: By
Last change:
Date: 3 years ago
Size: 29,308 bytes
 

Contents

Class file image Download
/*! FixedHeader 2.1.2 * ©2010-2014 SpryMedia Ltd - datatables.net/license */ /** * @summary FixedHeader * @description Fix a table's header or footer, so it is always visible while * Scrolling * @version 2.1.2 * @file dataTables.fixedHeader.js * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact * @copyright Copyright 2009-2014 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 */ /* Global scope for FixedColumns for backwards compatibility - will be removed * in future. Not documented in 1.1.x. */ /* Global scope for FixedColumns */ var FixedHeader; (function(window, document, undefined) { var factory = function( $, DataTable ) { "use strict"; /* * Function: FixedHeader * Purpose: Provide 'fixed' header, footer and columns for a DataTable * Returns: object:FixedHeader - must be called with 'new' * Inputs: mixed:mTable - target table * @param {object} dt DataTables instance or HTML table node. With DataTables * 1.10 this can also be a jQuery collection (with just a single table in its * result set), a jQuery selector, DataTables API instance or settings * object. * @param {object} [oInit] initialisation settings, with the following * properties (each optional) * * bool:top - fix the header (default true) * * bool:bottom - fix the footer (default false) * * int:left - fix the left column(s) (default 0) * * int:right - fix the right column(s) (default 0) * * int:zTop - fixed header zIndex * * int:zBottom - fixed footer zIndex * * int:zLeft - fixed left zIndex * * int:zRight - fixed right zIndex */ FixedHeader = function ( mTable, oInit ) { /* Sanity check - you just know it will happen */ if ( ! this instanceof FixedHeader ) { alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." ); return; } var that = this; var oSettings = { "aoCache": [], "oSides": { "top": true, "bottom": false, "left": 0, "right": 0 }, "oZIndexes": { "top": 104, "bottom": 103, "left": 102, "right": 101 }, "oCloneOnDraw": { "top": false, "bottom": false, "left": true, "right": true }, "oMes": { "iTableWidth": 0, "iTableHeight": 0, "iTableLeft": 0, "iTableRight": 0, /* note this is left+width, not actually "right" */ "iTableTop": 0, "iTableBottom": 0 /* note this is top+height, not actually "bottom" */ }, "oOffset": { "top": 0 }, "nTable": null, "bFooter": false, "bInitComplete": false }; /* * Function: fnGetSettings * Purpose: Get the settings for this object * Returns: object: - settings object * Inputs: - */ this.fnGetSettings = function () { return oSettings; }; /* * Function: fnUpdate * Purpose: Update the positioning and copies of the fixed elements * Returns: - * Inputs: - */ this.fnUpdate = function () { this._fnUpdateClones(); this._fnUpdatePositions(); }; /* * Function: fnPosition * Purpose: Update the positioning of the fixed elements * Returns: - * Inputs: - */ this.fnPosition = function () { this._fnUpdatePositions(); }; var dt = $.fn.dataTable.Api ? new $.fn.dataTable.Api( mTable ).settings()[0] : mTable.fnSettings(); dt._oPluginFixedHeader = this; /* Let's do it */ this.fnInit( dt, oInit ); }; /* * Variable: FixedHeader * Purpose: Prototype for FixedHeader * Scope: global */ FixedHeader.prototype = { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Initialisation */ /* * Function: fnInit * Purpose: The "constructor" * Returns: - * Inputs: {as FixedHeader function} */ fnInit: function ( oDtSettings, oInit ) { var s = this.fnGetSettings(); var that = this; /* Record the user definable settings */ this.fnInitSettings( s, oInit ); if ( oDtSettings.oScroll.sX !== "" || oDtSettings.oScroll.sY !== "" ) { alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" ); return; } s.nTable = oDtSettings.nTable; oDtSettings.aoDrawCallback.unshift( { "fn": function () { FixedHeader.fnMeasure(); that._fnUpdateClones.call(that); that._fnUpdatePositions.call(that); }, "sName": "FixedHeader" } ); s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false; /* Add the 'sides' that are fixed */ if ( s.oSides.top ) { s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) ); } if ( s.oSides.bottom ) { s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) ); } if ( s.oSides.left ) { s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft, s.oSides.left ) ); } if ( s.oSides.right ) { s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight, s.oSides.right ) ); } /* Event listeners for window movement */ FixedHeader.afnScroll.push( function () { that._fnUpdatePositions.call(that); } ); $(window).resize( function () { FixedHeader.fnMeasure(); that._fnUpdateClones.call(that); that._fnUpdatePositions.call(that); } ); $(s.nTable) .on('column-reorder.dt', function () { FixedHeader.fnMeasure(); that._fnUpdateClones( true ); that._fnUpdatePositions(); } ) .on('column-visibility.dt', function () { FixedHeader.fnMeasure(); that._fnUpdateClones( true ); that._fnUpdatePositions(); } ); /* Get things right to start with */ FixedHeader.fnMeasure(); that._fnUpdateClones(); that._fnUpdatePositions(); s.bInitComplete = true; }, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Support functions */ /* * Function: fnInitSettings * Purpose: Take the user's settings and copy them to our local store * Returns: - * Inputs: object:s - the local settings object * object:oInit - the user's settings object */ fnInitSettings: function ( s, oInit ) { if ( oInit !== undefined ) { if ( oInit.top !== undefined ) { s.oSides.top = oInit.top; } if ( oInit.bottom !== undefined ) { s.oSides.bottom = oInit.bottom; } if ( typeof oInit.left == 'boolean' ) { s.oSides.left = oInit.left ? 1 : 0; } else if ( oInit.left !== undefined ) { s.oSides.left = oInit.left; } if ( typeof oInit.right == 'boolean' ) { s.oSides.right = oInit.right ? 1 : 0; } else if ( oInit.right !== undefined ) { s.oSides.right = oInit.right; } if ( oInit.zTop !== undefined ) { s.oZIndexes.top = oInit.zTop; } if ( oInit.zBottom !== undefined ) { s.oZIndexes.bottom = oInit.zBottom; } if ( oInit.zLeft !== undefined ) { s.oZIndexes.left = oInit.zLeft; } if ( oInit.zRight !== undefined ) { s.oZIndexes.right = oInit.zRight; } if ( oInit.offsetTop !== undefined ) { s.oOffset.top = oInit.offsetTop; } if ( oInit.alwaysCloneTop !== undefined ) { s.oCloneOnDraw.top = oInit.alwaysCloneTop; } if ( oInit.alwaysCloneBottom !== undefined ) { s.oCloneOnDraw.bottom = oInit.alwaysCloneBottom; } if ( oInit.alwaysCloneLeft !== undefined ) { s.oCloneOnDraw.left = oInit.alwaysCloneLeft; } if ( oInit.alwaysCloneRight !== undefined ) { s.oCloneOnDraw.right = oInit.alwaysCloneRight; } } }, /* * Function: _fnCloneTable * Purpose: Clone the table node and do basic initialisation * Returns: - * Inputs: - */ _fnCloneTable: function ( sType, sClass, fnClone, iCells ) { var s = this.fnGetSettings(); var nCTable; /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how * DataTables works. Therefore, we can set this to be relatively position (if it is not * alreadu absolute, and use this as the base point for the cloned header */ if ( $(s.nTable.parentNode).css('position') != "absolute" ) { s.nTable.parentNode.style.position = "relative"; } /* Just a shallow clone will do - we only want the table node */ nCTable = s.nTable.cloneNode( false ); nCTable.removeAttribute( 'id' ); var nDiv = document.createElement( 'div' ); nDiv.style.position = "absolute"; nDiv.style.top = "0px"; nDiv.style.left = "0px"; nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass; /* Set the zIndexes */ if ( sType == "fixedHeader" ) { nDiv.style.zIndex = s.oZIndexes.top; } if ( sType == "fixedFooter" ) { nDiv.style.zIndex = s.oZIndexes.bottom; } if ( sType == "fixedLeft" ) { nDiv.style.zIndex = s.oZIndexes.left; } else if ( sType == "fixedRight" ) { nDiv.style.zIndex = s.oZIndexes.right; } /* remove margins since we are going to position it absolutely */ nCTable.style.margin = "0"; /* Insert the newly cloned table into the DOM, on top of the "real" header */ nDiv.appendChild( nCTable ); document.body.appendChild( nDiv ); return { "nNode": nCTable, "nWrapper": nDiv, "sType": sType, "sPosition": "", "sTop": "", "sLeft": "", "fnClone": fnClone, "iCells": iCells }; }, /* * Function: _fnMeasure * Purpose: Get the current positioning of the table in the DOM * Returns: - * Inputs: - */ _fnMeasure: function () { var s = this.fnGetSettings(), m = s.oMes, jqTable = $(s.nTable), oOffset = jqTable.offset(), iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ), iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' ); m.iTableWidth = jqTable.outerWidth(); m.iTableHeight = jqTable.outerHeight(); m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft; m.iTableTop = oOffset.top + iParentScrollTop; m.iTableRight = m.iTableLeft + m.iTableWidth; m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth; m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight; }, /* * Function: _fnSumScroll * Purpose: Sum node parameters all the way to the top * Returns: int: sum * Inputs: node:n - node to consider * string:side - scrollTop or scrollLeft */ _fnSumScroll: function ( n, side ) { var i = n[side]; while ( n = n.parentNode ) { if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' ) { break; } i = n[side]; } return i; }, /* * Function: _fnUpdatePositions * Purpose: Loop over the fixed elements for this table and update their positions * Returns: - * Inputs: - */ _fnUpdatePositions: function () { var s = this.fnGetSettings(); this._fnMeasure(); for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) { if ( s.aoCache[i].sType == "fixedHeader" ) { this._fnScrollFixedHeader( s.aoCache[i] ); } else if ( s.aoCache[i].sType == "fixedFooter" ) { this._fnScrollFixedFooter( s.aoCache[i] ); } else if ( s.aoCache[i].sType == "fixedLeft" ) { this._fnScrollHorizontalLeft( s.aoCache[i] ); } else { this._fnScrollHorizontalRight( s.aoCache[i] ); } } }, /* * Function: _fnUpdateClones * Purpose: Loop over the fixed elements for this table and call their cloning functions * Returns: - * Inputs: - */ _fnUpdateClones: function ( full ) { var s = this.fnGetSettings(); if ( full ) { // This is a little bit of a hack to force a full clone draw. When // `full` is set to true, we want to reclone the source elements, // regardless of the clone-on-draw settings s.bInitComplete = false; } for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) { s.aoCache[i].fnClone.call( this, s.aoCache[i] ); } if ( full ) { s.bInitComplete = true; } }, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Scrolling functions */ /* * Function: _fnScrollHorizontalLeft * Purpose: Update the positioning of the scrolling elements * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnScrollHorizontalRight: function ( oCache ) { var s = this.fnGetSettings(), oMes = s.oMes, oWin = FixedHeader.oWin, oDoc = FixedHeader.oDoc, nTable = oCache.nWrapper, iFixedWidth = $(nTable).outerWidth(); if ( oWin.iScrollRight < oMes.iTableRight ) { /* Fully right aligned */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iFixedWidth)+"px", 'left', nTable.style ); } else if ( oMes.iTableLeft < oDoc.iWidth-oWin.iScrollRight-iFixedWidth ) { /* Middle */ this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', (oWin.iWidth-iFixedWidth)+"px", 'left', nTable.style ); } else { /* Fully left aligned */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } }, /* * Function: _fnScrollHorizontalLeft * Purpose: Update the positioning of the scrolling elements * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnScrollHorizontalLeft: function ( oCache ) { var s = this.fnGetSettings(), oMes = s.oMes, oWin = FixedHeader.oWin, oDoc = FixedHeader.oDoc, nTable = oCache.nWrapper, iCellWidth = $(nTable).outerWidth(); if ( oWin.iScrollLeft < oMes.iTableLeft ) { /* Fully left align */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } else if ( oWin.iScrollLeft < oMes.iTableLeft+oMes.iTableWidth-iCellWidth ) { this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', "0px", 'left', nTable.style ); } else { /* Fully right align */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iCellWidth)+"px", 'left', nTable.style ); } }, /* * Function: _fnScrollFixedFooter * Purpose: Update the positioning of the scrolling elements * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnScrollFixedFooter: function ( oCache ) { var s = this.fnGetSettings(), oMes = s.oMes, oWin = FixedHeader.oWin, oDoc = FixedHeader.oDoc, nTable = oCache.nWrapper, iTheadHeight = $("thead", s.nTable).outerHeight(), iCellHeight = $(nTable).outerHeight(); if ( oWin.iScrollBottom < oMes.iTableBottom ) { /* Below */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+oMes.iTableHeight-iCellHeight)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } else if ( oWin.iScrollBottom < oMes.iTableBottom+oMes.iTableHeight-iCellHeight-iTheadHeight ) { this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oWin.iHeight-iCellHeight)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); } else { /* Above */ this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iCellHeight)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } }, /* * Function: _fnScrollFixedHeader * Purpose: Update the positioning of the scrolling elements * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnScrollFixedHeader: function ( oCache ) { var s = this.fnGetSettings(), oMes = s.oMes, oWin = FixedHeader.oWin, oDoc = FixedHeader.oDoc, nTable = oCache.nWrapper, iTbodyHeight = 0, anTbodies = s.nTable.getElementsByTagName('tbody'); for (var i = 0; i < anTbodies.length; ++i) { iTbodyHeight += anTbodies[i].offsetHeight; } if ( oMes.iTableTop > oWin.iScrollTop + s.oOffset.top ) { /* Above the table */ this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight ) { /* At the bottom of the table */ this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); } else { /* In the middle of the table */ this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style ); this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); } }, /* * Function: _fnUpdateCache * Purpose: Check the cache and update cache and value if needed * Returns: - * Inputs: object:oCache - local cache object * string:sCache - cache property * string:sSet - value to set * string:sProperty - object property to set * object:oObj - object to update */ _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj ) { if ( oCache[sCache] != sSet ) { oObj[sProperty] = sSet; oCache[sCache] = sSet; } }, /** * Copy the classes of all child nodes from one element to another. This implies * that the two have identical structure - no error checking is performed to that * fact. * @param {element} source Node to copy classes from * @param {element} dest Node to copy classes too */ _fnClassUpdate: function ( source, dest ) { var that = this; if ( source.nodeName.toUpperCase() === "TR" || source.nodeName.toUpperCase() === "TH" || source.nodeName.toUpperCase() === "TD" || source.nodeName.toUpperCase() === "SPAN" ) { dest.className = source.className; } $(source).children().each( function (i) { that._fnClassUpdate( $(source).children()[i], $(dest).children()[i] ); } ); }, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Cloning functions */ /* * Function: _fnCloneThead * Purpose: Clone the thead element * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnCloneThead: function ( oCache ) { var s = this.fnGetSettings(); var nTable = oCache.nNode; if ( s.bInitComplete && !s.oCloneOnDraw.top ) { this._fnClassUpdate( $('thead', s.nTable)[0], $('thead', nTable)[0] ); return; } /* Set the wrapper width to match that of the cloned table */ var iDtWidth = $(s.nTable).outerWidth(); oCache.nWrapper.style.width = iDtWidth+"px"; nTable.style.width = iDtWidth+"px"; /* Remove any children the cloned table has */ while ( nTable.childNodes.length > 0 ) { $('thead th', nTable).unbind( 'click' ); nTable.removeChild( nTable.childNodes[0] ); } /* Clone the DataTables header */ var nThead = $('thead', s.nTable).clone(true)[0]; nTable.appendChild( nThead ); /* Copy the widths across - apparently a clone isn't good enough for this */ var a = []; var b = []; $("thead>tr th", s.nTable).each( function (i) { a.push( $(this).width() ); } ); $("thead>tr td", s.nTable).each( function (i) { b.push( $(this).width() ); } ); $("thead>tr th", s.nTable).each( function (i) { $("thead>tr th:eq("+i+")", nTable).width( a[i] ); $(this).width( a[i] ); } ); $("thead>tr td", s.nTable).each( function (i) { $("thead>tr td:eq("+i+")", nTable).width( b[i] ); $(this).width( b[i] ); } ); // Stop DataTables 1.9 from putting a focus ring on the headers when // clicked to sort $('th.sorting, th.sorting_desc, th.sorting_asc', nTable).bind( 'click', function () { this.blur(); } ); }, /* * Function: _fnCloneTfoot * Purpose: Clone the tfoot element * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnCloneTfoot: function ( oCache ) { var s = this.fnGetSettings(); var nTable = oCache.nNode; /* Set the wrapper width to match that of the cloned table */ oCache.nWrapper.style.width = $(s.nTable).outerWidth()+"px"; /* Remove any children the cloned table has */ while ( nTable.childNodes.length > 0 ) { nTable.removeChild( nTable.childNodes[0] ); } /* Clone the DataTables footer */ var nTfoot = $('tfoot', s.nTable).clone(true)[0]; nTable.appendChild( nTfoot ); /* Copy the widths across - apparently a clone isn't good enough for this */ $("tfoot:eq(0)>tr th", s.nTable).each( function (i) { $("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( $(this).width() ); } ); $("tfoot:eq(0)>tr td", s.nTable).each( function (i) { $("tfoot:eq(0)>tr td:eq("+i+")", nTable).width( $(this).width() ); } ); }, /* * Function: _fnCloneTLeft * Purpose: Clone the left column(s) * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnCloneTLeft: function ( oCache ) { var s = this.fnGetSettings(); var nTable = oCache.nNode; var nBody = $('tbody', s.nTable)[0]; /* Remove any children the cloned table has */ while ( nTable.childNodes.length > 0 ) { nTable.removeChild( nTable.childNodes[0] ); } /* Is this the most efficient way to do this - it looks horrible... */ nTable.appendChild( $("thead", s.nTable).clone(true)[0] ); nTable.appendChild( $("tbody", s.nTable).clone(true)[0] ); if ( s.bFooter ) { nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] ); } /* Remove unneeded cells */ var sSelector = 'gt(' + (oCache.iCells - 1) + ')'; $('thead tr', nTable).each( function (k) { $('th:' + sSelector, this).remove(); } ); $('tfoot tr', nTable).each( function (k) { $('th:' + sSelector, this).remove(); } ); $('tbody tr', nTable).each( function (k) { $('td:' + sSelector, this).remove(); } ); this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable ); this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable ); var iWidth = 0; for (var i = 0; i < oCache.iCells; i++) { iWidth += $('thead tr th:eq(' + i + ')', s.nTable).outerWidth(); } nTable.style.width = iWidth+"px"; oCache.nWrapper.style.width = iWidth+"px"; }, /* * Function: _fnCloneTRight * Purpose: Clone the right most column(s) * Returns: - * Inputs: object:oCache - the cached values for this fixed element */ _fnCloneTRight: function ( oCache ) { var s = this.fnGetSettings(); var nBody = $('tbody', s.nTable)[0]; var nTable = oCache.nNode; var iCols = $('tbody tr:eq(0) td', s.nTable).length; /* Remove any children the cloned table has */ while ( nTable.childNodes.length > 0 ) { nTable.removeChild( nTable.childNodes[0] ); } /* Is this the most efficient way to do this - it looks horrible... */ nTable.appendChild( $("thead", s.nTable).clone(true)[0] ); nTable.appendChild( $("tbody", s.nTable).clone(true)[0] ); if ( s.bFooter ) { nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] ); } $('thead tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove(); $('tfoot tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove(); /* Remove unneeded cells */ $('tbody tr', nTable).each( function (k) { $('td:lt('+(iCols-oCache.iCells)+')', this).remove(); } ); this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable ); this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable ); var iWidth = 0; for (var i = 0; i < oCache.iCells; i++) { iWidth += $('thead tr th:eq('+(iCols-1-i)+')', s.nTable).outerWidth(); } nTable.style.width = iWidth+"px"; oCache.nWrapper.style.width = iWidth+"px"; }, /** * Equalise the heights of the rows in a given table node in a cross browser way. Note that this * is more or less lifted as is from FixedColumns * @method fnEqualiseHeights * @returns void * @param {string} parent Node type - thead, tbody or tfoot * @param {element} original Original node to take the heights from * @param {element} clone Copy the heights to * @private */ "fnEqualiseHeights": function ( parent, original, clone ) { var that = this; var originals = $(parent +' tr', original); var height; $(parent+' tr', clone).each( function (k) { height = originals.eq( k ).css('height'); // This is nasty :-(. IE has a sub-pixel error even when setting // the height below (the Firefox fix) which causes the fixed column // to go out of alignment. Need to add a pixel before the assignment // Can this be feature detected? Not sure how... if ( navigator.appName == 'Microsoft Internet Explorer' ) { height = parseInt( height, 10 ) + 1; } $(this).css( 'height', height ); // For Firefox to work, we need to also set the height of the // original row, to the value that we read from it! Otherwise there // is a sub-pixel rounding error originals.eq( k ).css( 'height', height ); } ); } }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Static properties and methods * We use these for speed! This information is common to all instances of FixedHeader, so no * point if having them calculated and stored for each different instance. */ /* * Variable: oWin * Purpose: Store information about the window positioning * Scope: FixedHeader */ FixedHeader.oWin = { "iScrollTop": 0, "iScrollRight": 0, "iScrollBottom": 0, "iScrollLeft": 0, "iHeight": 0, "iWidth": 0 }; /* * Variable: oDoc * Purpose: Store information about the document size * Scope: FixedHeader */ FixedHeader.oDoc = { "iHeight": 0, "iWidth": 0 }; /* * Variable: afnScroll * Purpose: Array of functions that are to be used for the scrolling components * Scope: FixedHeader */ FixedHeader.afnScroll = []; /* * Function: fnMeasure * Purpose: Update the measurements for the window and document * Returns: - * Inputs: - */ FixedHeader.fnMeasure = function () { var jqWin = $(window), jqDoc = $(document), oWin = FixedHeader.oWin, oDoc = FixedHeader.oDoc; oDoc.iHeight = jqDoc.height(); oDoc.iWidth = jqDoc.width(); oWin.iHeight = jqWin.height(); oWin.iWidth = jqWin.width(); oWin.iScrollTop = jqWin.scrollTop(); oWin.iScrollLeft = jqWin.scrollLeft(); oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth; oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight; }; FixedHeader.version = "2.1.2"; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Global processing */ /* * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is * done as an optimisation, to reduce calculation and proagation time */ $(window).scroll( function () { FixedHeader.fnMeasure(); for ( var i=0, iLen=FixedHeader.afnScroll.length ; i<iLen ; i++ ) { FixedHeader.afnScroll[i](); } } ); $.fn.dataTable.FixedHeader = FixedHeader; $.fn.DataTable.FixedHeader = FixedHeader; return FixedHeader; }; // /factory // Define as an AMD module if possible if ( typeof define === 'function' && define.amd ) { define( ['jquery', 'datatables'], factory ); } else if ( typeof exports === 'object' ) { // Node/CommonJS factory( require('jquery'), require('datatables') ); } else if ( jQuery && !jQuery.fn.dataTable.FixedHeader ) { // Otherwise simply initialise as normal, stopping multiple evaluation factory( jQuery, jQuery.fn.dataTable ); } })(window, document);