4 * Description: "Fix" a header at the top of the table, so it scrolls with the table
5 * Author: Allan Jardine (www.sprymedia.co.uk)
6 * Created: Wed 16 Sep 2009 19:46:30 BST
9 * Project: Just a little bit of fun - enjoy :-)
10 * Contact: www.sprymedia.co.uk/contact
12 * Copyright 2009-2010 Allan Jardine, all rights reserved.
16 * Function: FixedHeader
17 * Purpose: Provide 'fixed' header, footer and columns on an HTML table
18 * Returns: object:FixedHeader - must be called with 'new'
19 * Inputs: mixed:mTable - target table
20 * 1. DataTable object - when using FixedHeader with DataTables, or
21 * 2. HTML table node - when using FixedHeader without DataTables
22 * object:oInit - initialisation settings, with the following properties (each optional)
23 * bool:top - fix the header (default true)
24 * bool:bottom - fix the footer (default false)
25 * bool:left - fix the left most column (default false)
26 * bool:right - fix the right most column (default false)
27 * int:zTop - fixed header zIndex
28 * int:zBottom - fixed footer zIndex
29 * int:zLeft - fixed left zIndex
30 * int:zRight - fixed right zIndex
32 var FixedHeader = function ( mTable
, oInit
) {
33 /* Sanity check - you just know it will happen */
34 if ( typeof this.fnInit
!= 'function' )
36 alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." );
59 "iTableRight": 0, /* note this is left+width, not actually "right" */
61 "iTableBottom": 0 /* note this is top+height, not actually "bottom" */
69 * Function: fnGetSettings
70 * Purpose: Get the settings for this object
71 * Returns: object: - settings object
74 this.fnGetSettings = function () {
80 * Purpose: Update the positioning and copies of the fixed elements
84 this.fnUpdate = function () {
85 this._fnUpdateClones();
86 this._fnUpdatePositions();
90 this.fnInit( mTable
, oInit
);
95 * Variable: FixedHeader
96 * Purpose: Prototype for FixedHeader
99 FixedHeader
.prototype = {
100 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
106 * Purpose: The "constructor"
108 * Inputs: {as FixedHeader function}
110 fnInit: function ( oTable
, oInit
)
112 var s
= this.fnGetSettings();
115 /* Record the user definable settings */
116 this.fnInitSettings( s
, oInit
);
118 /* DataTables specific stuff */
119 if ( typeof oTable
.fnSettings
== 'function' )
121 if ( typeof oTable
.fnVersionCheck
== 'functon' &&
122 oTable
.fnVersionCheck( '1.6.0' ) !== true )
124 alert( "FixedHeader 2 required DataTables 1.6.0 or later. "+
125 "Please upgrade your DataTables installation" );
129 var oDtSettings
= oTable
.fnSettings();
131 if ( oDtSettings
.oScroll
.sX
!= "" || oDtSettings
.oScroll
.sY
!= "" )
133 alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" );
137 s
.nTable
= oDtSettings
.nTable
;
138 oDtSettings
.aoDrawCallback
.push( {
140 FixedHeader
.fnMeasure();
141 that
._fnUpdateClones
.call(that
);
142 that
._fnUpdatePositions
.call(that
);
144 "sName": "FixedHeader"
152 s
.bFooter
= ($('>tfoot', s
.nTable
).length
> 0) ? true : false;
154 /* "Detect" browsers that don't support absolute positioing - or have bugs */
155 s
.bUseAbsPos
= (jQuery
.browser
.msie
&& (jQuery
.browser
.version
=="6.0"||jQuery
.browser
.version
=="7.0"));
157 /* Add the 'sides' that are fixed */
160 s
.aoCache
.push( that
._fnCloneTable( "fixedHeader", "FixedHeader_Header", that
._fnCloneThead
) );
162 if ( s
.oSides
.bottom
)
164 s
.aoCache
.push( that
._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that
._fnCloneTfoot
) );
168 s
.aoCache
.push( that
._fnCloneTable( "fixedLeft", "FixedHeader_Left", that
._fnCloneTLeft
) );
170 if ( s
.oSides
.right
)
172 s
.aoCache
.push( that
._fnCloneTable( "fixedRight", "FixedHeader_Right", that
._fnCloneTRight
) );
175 /* Event listeners for window movement */
176 FixedHeader
.afnScroll
.push( function () {
177 that
._fnUpdatePositions
.call(that
);
180 jQuery(window
).resize( function () {
181 FixedHeader
.fnMeasure();
182 that
._fnUpdateClones
.call(that
);
183 that
._fnUpdatePositions
.call(that
);
186 /* Get things right to start with */
187 FixedHeader
.fnMeasure();
188 that
._fnUpdateClones();
189 that
._fnUpdatePositions();
193 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
198 * Function: fnInitSettings
199 * Purpose: Take the user's settings and copy them to our local store
201 * Inputs: object:s - the local settings object
202 * object:oInit - the user's settings object
204 fnInitSettings: function ( s
, oInit
)
206 if ( typeof oInit
!= 'undefined' )
208 if ( typeof oInit
.top
!= 'undefined' ) {
209 s
.oSides
.top
= oInit
.top
;
211 if ( typeof oInit
.bottom
!= 'undefined' ) {
212 s
.oSides
.bottom
= oInit
.bottom
;
214 if ( typeof oInit
.left
!= 'undefined' ) {
215 s
.oSides
.left
= oInit
.left
;
217 if ( typeof oInit
.right
!= 'undefined' ) {
218 s
.oSides
.right
= oInit
.right
;
221 if ( typeof oInit
.zTop
!= 'undefined' ) {
222 s
.oZIndexes
.top
= oInit
.zTop
;
224 if ( typeof oInit
.zBottom
!= 'undefined' ) {
225 s
.oZIndexes
.bottom
= oInit
.zBottom
;
227 if ( typeof oInit
.zLeft
!= 'undefined' ) {
228 s
.oZIndexes
.left
= oInit
.zLeft
;
230 if ( typeof oInit
.zRight
!= 'undefined' ) {
231 s
.oZIndexes
.right
= oInit
.zRight
;
235 /* Detect browsers which have poor position:fixed support so we can use absolute positions.
236 * This is much slower since the position must be updated for each scroll, but widens
239 s
.bUseAbsPos
= (jQuery
.browser
.msie
&&
240 (jQuery
.browser
.version
=="6.0"||jQuery
.browser
.version
=="7.0"));
244 * Function: _fnCloneTable
245 * Purpose: Clone the table node and do basic initialisation
249 _fnCloneTable: function ( sType
, sClass
, fnClone
)
251 var s
= this.fnGetSettings();
254 /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how
255 * DataTables works. Therefore, we can set this to be relatively position (if it is not
256 * alreadu absolute, and use this as the base point for the cloned header
258 if ( jQuery(s
.nTable
.parentNode
).css('position') != "absolute" )
260 s
.nTable
.parentNode
.style
.position
= "relative";
263 /* Just a shallow clone will do - we only want the table node */
264 nCTable
= s
.nTable
.cloneNode( false );
266 var nDiv
= document
.createElement( 'div' );
267 nDiv
.style
.position
= "absolute";
268 nDiv
.className
+= " FixedHeader_Cloned "+sType
+" "+sClass
;
270 /* Set the zIndexes */
271 if ( sType
== "fixedHeader" )
273 nDiv
.style
.zIndex
= s
.oZIndexes
.top
;
275 if ( sType
== "fixedFooter" )
277 nDiv
.style
.zIndex
= s
.oZIndexes
.bottom
;
279 if ( sType
== "fixedLeft" )
281 nDiv
.style
.zIndex
= s
.oZIndexes
.left
;
283 else if ( sType
== "fixedRight" )
285 nDiv
.style
.zIndex
= s
.oZIndexes
.right
;
288 /* Insert the newly cloned table into the DOM, on top of the "real" header */
289 nDiv
.appendChild( nCTable
);
290 document
.body
.appendChild( nDiv
);
304 * Function: _fnUpdatePositions
305 * Purpose: Get the current positioning of the table in the DOM
309 _fnMeasure: function ()
312 s
= this.fnGetSettings(),
314 jqTable
= jQuery(s
.nTable
),
315 oOffset
= jqTable
.offset(),
316 iParentScrollTop
= this._fnSumScroll( s
.nTable
.parentNode
, 'scrollTop' ),
317 iParentScrollLeft
= this._fnSumScroll( s
.nTable
.parentNode
, 'scrollLeft' );
319 m
.iTableWidth
= jqTable
.outerWidth();
320 m
.iTableHeight
= jqTable
.outerHeight();
321 m
.iTableLeft
= oOffset
.left
+ s
.nTable
.parentNode
.scrollLeft
;
322 m
.iTableTop
= oOffset
.top
+ iParentScrollTop
;
323 m
.iTableRight
= m
.iTableLeft
+ m
.iTableWidth
;
324 m
.iTableRight
= FixedHeader
.oDoc
.iWidth
- m
.iTableLeft
- m
.iTableWidth
;
325 m
.iTableBottom
= FixedHeader
.oDoc
.iHeight
- m
.iTableTop
- m
.iTableHeight
;
329 * Function: _fnSumScroll
330 * Purpose: Sum node parameters all the way to the top
332 * Inputs: node:n - node to consider
333 * string:side - scrollTop or scrollLeft
335 _fnSumScroll: function ( n
, side
)
338 while ( n
= n
.parentNode
)
340 if ( n
.nodeName
!= 'HTML' && n
.nodeName
!= 'BODY' )
350 * Function: _fnUpdatePositions
351 * Purpose: Loop over the fixed elements for this table and update their positions
355 _fnUpdatePositions: function ()
357 var s
= this.fnGetSettings();
360 for ( var i
=0, iLen
=s
.aoCache
.length
; i
<iLen
; i
++ )
362 if ( s
.aoCache
[i
].sType
== "fixedHeader" )
364 this._fnScrollFixedHeader( s
.aoCache
[i
] );
366 else if ( s
.aoCache
[i
].sType
== "fixedFooter" )
368 this._fnScrollFixedFooter( s
.aoCache
[i
] );
370 else if ( s
.aoCache
[i
].sType
== "fixedLeft" )
372 this._fnScrollHorizontalLeft( s
.aoCache
[i
] );
376 this._fnScrollHorizontalRight( s
.aoCache
[i
] );
382 * Function: _fnUpdateClones
383 * Purpose: Loop over the fixed elements for this table and call their cloning functions
387 _fnUpdateClones: function ()
389 var s
= this.fnGetSettings();
390 for ( var i
=0, iLen
=s
.aoCache
.length
; i
<iLen
; i
++ )
392 s
.aoCache
[i
].fnClone
.call( this, s
.aoCache
[i
] );
397 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
398 * Scrolling functions
402 * Function: _fnScrollHorizontalLeft
403 * Purpose: Update the positioning of the scrolling elements
405 * Inputs: object:oCache - the cahced values for this fixed element
407 _fnScrollHorizontalRight: function ( oCache
)
410 s
= this.fnGetSettings(),
412 oWin
= FixedHeader
.oWin
,
413 oDoc
= FixedHeader
.oDoc
,
414 nTable
= oCache
.nWrapper
,
415 iFixedWidth
= jQuery(nTable
).outerWidth();
417 if ( oWin
.iScrollRight
< oMes
.iTableRight
)
419 /* Fully right aligned */
420 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
421 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
422 this._fnUpdateCache( oCache
, 'sLeft', (oMes
.iTableLeft
+oMes
.iTableWidth
-iFixedWidth
)+"px", 'left', nTable
.style
);
424 else if ( oMes
.iTableLeft
< oDoc
.iWidth
-oWin
.iScrollRight
-iFixedWidth
)
429 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
430 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
431 this._fnUpdateCache( oCache
, 'sLeft', (oDoc
.iWidth
-oWin
.iScrollRight
-iFixedWidth
)+"px", 'left', nTable
.style
);
435 this._fnUpdateCache( oCache
, 'sPosition', 'fixed', 'position', nTable
.style
);
436 this._fnUpdateCache( oCache
, 'sTop', (oMes
.iTableTop
-oWin
.iScrollTop
)+"px", 'top', nTable
.style
);
437 this._fnUpdateCache( oCache
, 'sLeft', (oWin
.iWidth
-iFixedWidth
)+"px", 'left', nTable
.style
);
442 /* Fully left aligned */
443 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
444 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
445 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
450 * Function: _fnScrollHorizontalLeft
451 * Purpose: Update the positioning of the scrolling elements
453 * Inputs: object:oCache - the cahced values for this fixed element
455 _fnScrollHorizontalLeft: function ( oCache
)
458 s
= this.fnGetSettings(),
460 oWin
= FixedHeader
.oWin
,
461 oDoc
= FixedHeader
.oDoc
,
462 nTable
= oCache
.nWrapper
,
463 iCellWidth
= jQuery(nTable
).outerWidth();
465 if ( oWin
.iScrollLeft
< oMes
.iTableLeft
)
467 /* Fully left align */
468 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
469 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
470 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
472 else if ( oWin
.iScrollLeft
< oMes
.iTableLeft
+oMes
.iTableWidth
-iCellWidth
)
477 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
478 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
479 this._fnUpdateCache( oCache
, 'sLeft', oWin
.iScrollLeft
+"px", 'left', nTable
.style
);
483 this._fnUpdateCache( oCache
, 'sPosition', 'fixed', 'position', nTable
.style
);
484 this._fnUpdateCache( oCache
, 'sTop', (oMes
.iTableTop
-oWin
.iScrollTop
)+"px", 'top', nTable
.style
);
485 this._fnUpdateCache( oCache
, 'sLeft', "0px", 'left', nTable
.style
);
490 /* Fully right align */
491 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
492 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
493 this._fnUpdateCache( oCache
, 'sLeft', (oMes
.iTableLeft
+oMes
.iTableWidth
-iCellWidth
)+"px", 'left', nTable
.style
);
498 * Function: _fnScrollFixedFooter
499 * Purpose: Update the positioning of the scrolling elements
501 * Inputs: object:oCache - the cahced values for this fixed element
503 _fnScrollFixedFooter: function ( oCache
)
506 s
= this.fnGetSettings(),
508 oWin
= FixedHeader
.oWin
,
509 oDoc
= FixedHeader
.oDoc
,
510 nTable
= oCache
.nWrapper
,
511 iTheadHeight
= jQuery("thead", s
.nTable
).outerHeight(),
512 iCellHeight
= jQuery(nTable
).outerHeight();
514 if ( oWin
.iScrollBottom
< oMes
.iTableBottom
)
517 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
518 this._fnUpdateCache( oCache
, 'sTop', (oMes
.iTableTop
+oMes
.iTableHeight
-iCellHeight
)+"px", 'top', nTable
.style
);
519 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
521 else if ( oWin
.iScrollBottom
< oMes
.iTableBottom
+oMes
.iTableHeight
-iCellHeight
-iTheadHeight
)
526 this._fnUpdateCache( oCache
, 'sPosition', "absolute", 'position', nTable
.style
);
527 this._fnUpdateCache( oCache
, 'sTop', (oDoc
.iHeight
-oWin
.iScrollBottom
-iCellHeight
)+"px", 'top', nTable
.style
);
528 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
532 this._fnUpdateCache( oCache
, 'sPosition', 'fixed', 'position', nTable
.style
);
533 this._fnUpdateCache( oCache
, 'sTop', (oWin
.iHeight
-iCellHeight
)+"px", 'top', nTable
.style
);
534 this._fnUpdateCache( oCache
, 'sLeft', (oMes
.iTableLeft
-oWin
.iScrollLeft
)+"px", 'left', nTable
.style
);
540 this._fnUpdateCache( oCache
, 'sPosition', 'absolute', 'position', nTable
.style
);
541 this._fnUpdateCache( oCache
, 'sTop', (oMes
.iTableTop
+iCellHeight
)+"px", 'top', nTable
.style
);
542 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
547 * Function: _fnScrollFixedHeader
548 * Purpose: Update the positioning of the scrolling elements
550 * Inputs: object:oCache - the cahced values for this fixed element
552 _fnScrollFixedHeader: function ( oCache
)
555 s
= this.fnGetSettings(),
557 oWin
= FixedHeader
.oWin
,
558 oDoc
= FixedHeader
.oDoc
,
559 nTable
= oCache
.nWrapper
,
560 iTbodyHeight
= s
.nTable
.getElementsByTagName('tbody')[0].offsetHeight
;
562 if ( oMes
.iTableTop
> oWin
.iScrollTop
)
564 /* Above the table */
565 this._fnUpdateCache( oCache
, 'sPosition', "absolute", 'position', nTable
.style
);
566 this._fnUpdateCache( oCache
, 'sTop', oMes
.iTableTop
+"px", 'top', nTable
.style
);
567 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
569 else if ( oWin
.iScrollTop
> oMes
.iTableTop
+iTbodyHeight
)
571 /* At the bottom of the table */
572 this._fnUpdateCache( oCache
, 'sPosition', "absolute", 'position', nTable
.style
);
573 this._fnUpdateCache( oCache
, 'sTop', (oMes
.iTableTop
+iTbodyHeight
)+"px", 'top', nTable
.style
);
574 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
578 /* In the middle of the table */
581 this._fnUpdateCache( oCache
, 'sPosition', "absolute", 'position', nTable
.style
);
582 this._fnUpdateCache( oCache
, 'sTop', oWin
.iScrollTop
+"px", 'top', nTable
.style
);
583 this._fnUpdateCache( oCache
, 'sLeft', oMes
.iTableLeft
+"px", 'left', nTable
.style
);
587 this._fnUpdateCache( oCache
, 'sPosition', 'fixed', 'position', nTable
.style
);
588 this._fnUpdateCache( oCache
, 'sTop', "0px", 'top', nTable
.style
);
589 this._fnUpdateCache( oCache
, 'sLeft', (oMes
.iTableLeft
-oWin
.iScrollLeft
)+"px", 'left', nTable
.style
);
595 * Function: _fnUpdateCache
596 * Purpose: Check the cache and update cache and value if needed
598 * Inputs: object:oCache - local cache object
599 * string:sCache - cache property
600 * string:sSet - value to set
601 * string:sProperty - object property to set
602 * object:oObj - object to update
604 _fnUpdateCache: function ( oCache
, sCache
, sSet
, sProperty
, oObj
)
606 if ( oCache
[sCache
] != sSet
)
608 oObj
[sProperty
] = sSet
;
609 oCache
[sCache
] = sSet
;
615 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
620 * Function: _fnCloneThead
621 * Purpose: Clone the thead element
623 * Inputs: object:oCache - the cahced values for this fixed element
625 _fnCloneThead: function ( oCache
)
627 var s
= this.fnGetSettings();
628 var nTable
= oCache
.nNode
;
630 /* Set the wrapper width to match that of the cloned table */
631 oCache
.nWrapper
.style
.width
= jQuery(s
.nTable
).outerWidth()+"px";
633 /* Remove any children the cloned table has */
634 while ( nTable
.childNodes
.length
> 0 )
636 jQuery('thead th', nTable
).unbind( 'click' );
637 nTable
.removeChild( nTable
.childNodes
[0] );
640 /* Clone the DataTables header */
641 var nThead
= jQuery('thead', s
.nTable
).clone(true)[0];
642 nTable
.appendChild( nThead
);
644 /* Copy the widths across - apparently a clone isn't good enough for this */
645 jQuery("thead:eq(0)>tr th", s
.nTable
).each( function (i
) {
646 jQuery("thead:eq(0)>tr th:eq("+i
+")", nTable
).width( jQuery(this).width() );
649 jQuery("thead:eq(0)>tr td", s
.nTable
).each( function (i
) {
650 jQuery("thead:eq(0)>tr th:eq("+i
+")", nTable
)[0].style
.width( jQuery(this).width() );
655 * Function: _fnCloneTfoot
656 * Purpose: Clone the tfoot element
658 * Inputs: object:oCache - the cahced values for this fixed element
660 _fnCloneTfoot: function ( oCache
)
662 var s
= this.fnGetSettings();
663 var nTable
= oCache
.nNode
;
665 /* Set the wrapper width to match that of the cloned table */
666 oCache
.nWrapper
.style
.width
= jQuery(s
.nTable
).outerWidth()+"px";
668 /* Remove any children the cloned table has */
669 while ( nTable
.childNodes
.length
> 0 )
671 nTable
.removeChild( nTable
.childNodes
[0] );
674 /* Clone the DataTables footer */
675 var nTfoot
= jQuery('tfoot', s
.nTable
).clone(true)[0];
676 nTable
.appendChild( nTfoot
);
678 /* Copy the widths across - apparently a clone isn't good enough for this */
679 jQuery("tfoot:eq(0)>tr th", s
.nTable
).each( function (i
) {
680 jQuery("tfoot:eq(0)>tr th:eq("+i
+")", nTable
).width( jQuery(this).width() );
683 jQuery("tfoot:eq(0)>tr td", s
.nTable
).each( function (i
) {
684 jQuery("tfoot:eq(0)>tr th:eq("+i
+")", nTable
)[0].style
.width( jQuery(this).width() );
689 * Function: _fnCloneTLeft
690 * Purpose: Clone the left column
692 * Inputs: object:oCache - the cahced values for this fixed element
694 _fnCloneTLeft: function ( oCache
)
696 var s
= this.fnGetSettings();
697 var nTable
= oCache
.nNode
;
698 var iCols
= jQuery('tbody tr:eq(0) td', s
.nTable
).length
;
699 var bRubbishOldIE
= ($.browser
.msie
&& ($.browser
.version
== "6.0" || $.browser
.version
== "7.0"));
701 /* Remove any children the cloned table has */
702 while ( nTable
.childNodes
.length
> 0 )
704 nTable
.removeChild( nTable
.childNodes
[0] );
707 /* Is this the most efficient way to do this - it looks horrible... */
708 nTable
.appendChild( jQuery("thead", s
.nTable
).clone(true)[0] );
709 nTable
.appendChild( jQuery("tbody", s
.nTable
).clone(true)[0] );
712 nTable
.appendChild( jQuery("tfoot", s
.nTable
).clone(true)[0] );
715 jQuery('thead tr th:gt(0)', nTable
).remove();
716 jQuery('tfoot tr th:gt(0)', nTable
).remove();
718 /* Basically the same as used in FixedColumns - remove and copy heights */
719 $('tbody tr', nTable
).each( function (k
) {
720 $('td:gt(0)', this).remove();
722 /* Can we use some kind of object detection here?! This is very nasty - damn browsers */
723 if ( $.browser
.mozilla
|| $.browser
.opera
)
725 $('td', this).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() );
729 $('td', this).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() - iBoxHack
);
732 if ( !bRubbishOldIE
)
734 $('tbody tr:eq('+k
+')', that
.dom
.body
).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() );
738 var iWidth
= jQuery('thead tr th:eq(0)', s
.nTable
).outerWidth();
739 nTable
.style
.width
= iWidth
+"px";
740 oCache
.nWrapper
.style
.width
= iWidth
+"px";
744 * Function: _fnCloneTRight
745 * Purpose: Clone the right most colun
747 * Inputs: object:oCache - the cahced values for this fixed element
749 _fnCloneTRight: function ( oCache
)
751 var s
= this.fnGetSettings();
752 var nTable
= oCache
.nNode
;
753 var iCols
= jQuery('tbody tr:eq(0) td', s
.nTable
).length
;
754 var bRubbishOldIE
= ($.browser
.msie
&& ($.browser
.version
== "6.0" || $.browser
.version
== "7.0"));
756 /* Remove any children the cloned table has */
757 while ( nTable
.childNodes
.length
> 0 )
759 nTable
.removeChild( nTable
.childNodes
[0] );
762 /* Is this the most efficient way to do this - it looks horrible... */
763 nTable
.appendChild( jQuery("thead", s
.nTable
).clone(true)[0] );
764 nTable
.appendChild( jQuery("tbody", s
.nTable
).clone(true)[0] );
767 nTable
.appendChild( jQuery("tfoot", s
.nTable
).clone(true)[0] );
769 jQuery('thead tr th:not(:nth-child('+iCols
+'n))', nTable
).remove();
770 jQuery('tfoot tr th:not(:nth-child('+iCols
+'n))', nTable
).remove();
772 /* Basically the same as used in FixedColumns - remove and copy heights */
773 $('tbody tr', nTable
).each( function (k
) {
774 $('td:lt('+iCols
-1+')', this).remove();
776 /* Can we use some kind of object detection here?! This is very nasty - damn browsers */
777 if ( $.browser
.mozilla
|| $.browser
.opera
)
779 $('td', this).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() );
783 $('td', this).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() - iBoxHack
);
786 if ( !bRubbishOldIE
)
788 $('tbody tr:eq('+k
+')', that
.dom
.body
).height( $('tbody tr:eq('+k
+')', that
.dom
.body
).outerHeight() );
792 var iWidth
= jQuery('thead tr th:eq('+(iCols
-1)+')', s
.nTable
).outerWidth();
793 nTable
.style
.width
= iWidth
+"px";
794 oCache
.nWrapper
.style
.width
= iWidth
+"px";
799 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
800 * Static properties and methods
801 * We use these for speed! This information is common to all instances of FixedHeader, so no
802 * point if having them calculated and stored for each different instance.
807 * Purpose: Store information about the window positioning
821 * Purpose: Store information about the document size
830 * Variable: afnScroll
831 * Purpose: Array of functions that are to be used for the scrolling components
834 FixedHeader
.afnScroll
= [];
837 * Function: fnMeasure
838 * Purpose: Update the measurements for the window and document
842 FixedHeader
.fnMeasure = function ()
845 jqWin
= jQuery(window
),
846 jqDoc
= jQuery(document
),
847 oWin
= FixedHeader
.oWin
,
848 oDoc
= FixedHeader
.oDoc
;
850 oDoc
.iHeight
= jqDoc
.height();
851 oDoc
.iWidth
= jqDoc
.width();
853 oWin
.iHeight
= jqWin
.height();
854 oWin
.iWidth
= jqWin
.width();
855 oWin
.iScrollTop
= jqWin
.scrollTop();
856 oWin
.iScrollLeft
= jqWin
.scrollLeft();
857 oWin
.iScrollRight
= oDoc
.iWidth
- oWin
.iScrollLeft
- oWin
.iWidth
;
858 oWin
.iScrollBottom
= oDoc
.iHeight
- oWin
.iScrollTop
- oWin
.iHeight
;
862 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
867 * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is
868 * done as an optimisation, to reduce calculation and proagation time
870 jQuery(window
).scroll( function () {
871 FixedHeader
.fnMeasure();
872 for ( var i
=0, iLen
=FixedHeader
.afnScroll
.length
; i
<iLen
; i
++ )
874 FixedHeader
.afnScroll
[i
]();