comparison DataTables-1.9.4/extras/FixedHeader/js/FixedHeader.js @ 0:ac5f9272033b draft

first upload
author saskia-hiltemann
date Tue, 01 Jul 2014 11:42:23 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ac5f9272033b
1 /*
2 * File: FixedHeader.js
3 * Version: 2.0.6
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
7 * Language: Javascript
8 * License: GPL v2 or BSD 3 point style
9 * Project: Just a little bit of fun - enjoy :-)
10 * Contact: www.sprymedia.co.uk/contact
11 *
12 * Copyright 2009-2012 Allan Jardine, all rights reserved.
13 *
14 * This source file is free software, under either the GPL v2 license or a
15 * BSD style license, available at:
16 * http://datatables.net/license_gpl2
17 * http://datatables.net/license_bsd
18 */
19
20 /*
21 * Function: FixedHeader
22 * Purpose: Provide 'fixed' header, footer and columns on an HTML table
23 * Returns: object:FixedHeader - must be called with 'new'
24 * Inputs: mixed:mTable - target table
25 * 1. DataTable object - when using FixedHeader with DataTables, or
26 * 2. HTML table node - when using FixedHeader without DataTables
27 * object:oInit - initialisation settings, with the following properties (each optional)
28 * bool:top - fix the header (default true)
29 * bool:bottom - fix the footer (default false)
30 * bool:left - fix the left most column (default false)
31 * bool:right - fix the right most column (default false)
32 * int:zTop - fixed header zIndex
33 * int:zBottom - fixed footer zIndex
34 * int:zLeft - fixed left zIndex
35 * int:zRight - fixed right zIndex
36 */
37 var FixedHeader = function ( mTable, oInit ) {
38 /* Sanity check - you just know it will happen */
39 if ( typeof this.fnInit != 'function' )
40 {
41 alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." );
42 return;
43 }
44
45 var that = this;
46 var oSettings = {
47 "aoCache": [],
48 "oSides": {
49 "top": true,
50 "bottom": false,
51 "left": false,
52 "right": false
53 },
54 "oZIndexes": {
55 "top": 104,
56 "bottom": 103,
57 "left": 102,
58 "right": 101
59 },
60 "oMes": {
61 "iTableWidth": 0,
62 "iTableHeight": 0,
63 "iTableLeft": 0,
64 "iTableRight": 0, /* note this is left+width, not actually "right" */
65 "iTableTop": 0,
66 "iTableBottom": 0 /* note this is top+height, not actually "bottom" */
67 },
68 "oOffset": {
69 "top": 0
70 },
71 "nTable": null,
72 "bUseAbsPos": false,
73 "bFooter": false
74 };
75
76 /*
77 * Function: fnGetSettings
78 * Purpose: Get the settings for this object
79 * Returns: object: - settings object
80 * Inputs: -
81 */
82 this.fnGetSettings = function () {
83 return oSettings;
84 };
85
86 /*
87 * Function: fnUpdate
88 * Purpose: Update the positioning and copies of the fixed elements
89 * Returns: -
90 * Inputs: -
91 */
92 this.fnUpdate = function () {
93 this._fnUpdateClones();
94 this._fnUpdatePositions();
95 };
96
97 /*
98 * Function: fnPosition
99 * Purpose: Update the positioning of the fixed elements
100 * Returns: -
101 * Inputs: -
102 */
103 this.fnPosition = function () {
104 this._fnUpdatePositions();
105 };
106
107 /* Let's do it */
108 this.fnInit( mTable, oInit );
109
110 /* Store the instance on the DataTables object for easy access */
111 if ( typeof mTable.fnSettings == 'function' )
112 {
113 mTable._oPluginFixedHeader = this;
114 }
115 };
116
117
118 /*
119 * Variable: FixedHeader
120 * Purpose: Prototype for FixedHeader
121 * Scope: global
122 */
123 FixedHeader.prototype = {
124 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
125 * Initialisation
126 */
127
128 /*
129 * Function: fnInit
130 * Purpose: The "constructor"
131 * Returns: -
132 * Inputs: {as FixedHeader function}
133 */
134 fnInit: function ( oTable, oInit )
135 {
136 var s = this.fnGetSettings();
137 var that = this;
138
139 /* Record the user definable settings */
140 this.fnInitSettings( s, oInit );
141
142 /* DataTables specific stuff */
143 if ( typeof oTable.fnSettings == 'function' )
144 {
145 if ( typeof oTable.fnVersionCheck == 'functon' &&
146 oTable.fnVersionCheck( '1.6.0' ) !== true )
147 {
148 alert( "FixedHeader 2 required DataTables 1.6.0 or later. "+
149 "Please upgrade your DataTables installation" );
150 return;
151 }
152
153 var oDtSettings = oTable.fnSettings();
154
155 if ( oDtSettings.oScroll.sX != "" || oDtSettings.oScroll.sY != "" )
156 {
157 alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" );
158 return;
159 }
160
161 s.nTable = oDtSettings.nTable;
162 oDtSettings.aoDrawCallback.push( {
163 "fn": function () {
164 FixedHeader.fnMeasure();
165 that._fnUpdateClones.call(that);
166 that._fnUpdatePositions.call(that);
167 },
168 "sName": "FixedHeader"
169 } );
170 }
171 else
172 {
173 s.nTable = oTable;
174 }
175
176 s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false;
177
178 /* "Detect" browsers that don't support absolute positioing - or have bugs */
179 s.bUseAbsPos = (jQuery.browser.msie && (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0"));
180
181 /* Add the 'sides' that are fixed */
182 if ( s.oSides.top )
183 {
184 s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) );
185 }
186 if ( s.oSides.bottom )
187 {
188 s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) );
189 }
190 if ( s.oSides.left )
191 {
192 s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft ) );
193 }
194 if ( s.oSides.right )
195 {
196 s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight ) );
197 }
198
199 /* Event listeners for window movement */
200 FixedHeader.afnScroll.push( function () {
201 that._fnUpdatePositions.call(that);
202 } );
203
204 jQuery(window).resize( function () {
205 FixedHeader.fnMeasure();
206 that._fnUpdateClones.call(that);
207 that._fnUpdatePositions.call(that);
208 } );
209
210 /* Get things right to start with */
211 FixedHeader.fnMeasure();
212 that._fnUpdateClones();
213 that._fnUpdatePositions();
214 },
215
216
217 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
218 * Support functions
219 */
220
221 /*
222 * Function: fnInitSettings
223 * Purpose: Take the user's settings and copy them to our local store
224 * Returns: -
225 * Inputs: object:s - the local settings object
226 * object:oInit - the user's settings object
227 */
228 fnInitSettings: function ( s, oInit )
229 {
230 if ( typeof oInit != 'undefined' )
231 {
232 if ( typeof oInit.top != 'undefined' ) {
233 s.oSides.top = oInit.top;
234 }
235 if ( typeof oInit.bottom != 'undefined' ) {
236 s.oSides.bottom = oInit.bottom;
237 }
238 if ( typeof oInit.left != 'undefined' ) {
239 s.oSides.left = oInit.left;
240 }
241 if ( typeof oInit.right != 'undefined' ) {
242 s.oSides.right = oInit.right;
243 }
244
245 if ( typeof oInit.zTop != 'undefined' ) {
246 s.oZIndexes.top = oInit.zTop;
247 }
248 if ( typeof oInit.zBottom != 'undefined' ) {
249 s.oZIndexes.bottom = oInit.zBottom;
250 }
251 if ( typeof oInit.zLeft != 'undefined' ) {
252 s.oZIndexes.left = oInit.zLeft;
253 }
254 if ( typeof oInit.zRight != 'undefined' ) {
255 s.oZIndexes.right = oInit.zRight;
256 }
257
258 if ( typeof oInit.offsetTop != 'undefined' ) {
259 s.oOffset.top = oInit.offsetTop;
260 }
261 }
262
263 /* Detect browsers which have poor position:fixed support so we can use absolute positions.
264 * This is much slower since the position must be updated for each scroll, but widens
265 * compatibility
266 */
267 s.bUseAbsPos = (jQuery.browser.msie &&
268 (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0"));
269 },
270
271 /*
272 * Function: _fnCloneTable
273 * Purpose: Clone the table node and do basic initialisation
274 * Returns: -
275 * Inputs: -
276 */
277 _fnCloneTable: function ( sType, sClass, fnClone )
278 {
279 var s = this.fnGetSettings();
280 var nCTable;
281
282 /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how
283 * DataTables works. Therefore, we can set this to be relatively position (if it is not
284 * alreadu absolute, and use this as the base point for the cloned header
285 */
286 if ( jQuery(s.nTable.parentNode).css('position') != "absolute" )
287 {
288 s.nTable.parentNode.style.position = "relative";
289 }
290
291 /* Just a shallow clone will do - we only want the table node */
292 nCTable = s.nTable.cloneNode( false );
293 nCTable.removeAttribute( 'id' );
294
295 var nDiv = document.createElement( 'div' );
296 nDiv.style.position = "absolute";
297 nDiv.style.top = "0px";
298 nDiv.style.left = "0px";
299 nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass;
300
301 /* Set the zIndexes */
302 if ( sType == "fixedHeader" )
303 {
304 nDiv.style.zIndex = s.oZIndexes.top;
305 }
306 if ( sType == "fixedFooter" )
307 {
308 nDiv.style.zIndex = s.oZIndexes.bottom;
309 }
310 if ( sType == "fixedLeft" )
311 {
312 nDiv.style.zIndex = s.oZIndexes.left;
313 }
314 else if ( sType == "fixedRight" )
315 {
316 nDiv.style.zIndex = s.oZIndexes.right;
317 }
318
319 /* remove margins since we are going to poistion it absolutely */
320 nCTable.style.margin = "0";
321
322 /* Insert the newly cloned table into the DOM, on top of the "real" header */
323 nDiv.appendChild( nCTable );
324 document.body.appendChild( nDiv );
325
326 return {
327 "nNode": nCTable,
328 "nWrapper": nDiv,
329 "sType": sType,
330 "sPosition": "",
331 "sTop": "",
332 "sLeft": "",
333 "fnClone": fnClone
334 };
335 },
336
337 /*
338 * Function: _fnUpdatePositions
339 * Purpose: Get the current positioning of the table in the DOM
340 * Returns: -
341 * Inputs: -
342 */
343 _fnMeasure: function ()
344 {
345 var
346 s = this.fnGetSettings(),
347 m = s.oMes,
348 jqTable = jQuery(s.nTable),
349 oOffset = jqTable.offset(),
350 iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ),
351 iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' );
352
353 m.iTableWidth = jqTable.outerWidth();
354 m.iTableHeight = jqTable.outerHeight();
355 m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft;
356 m.iTableTop = oOffset.top + iParentScrollTop;
357 m.iTableRight = m.iTableLeft + m.iTableWidth;
358 m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth;
359 m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight;
360 },
361
362 /*
363 * Function: _fnSumScroll
364 * Purpose: Sum node parameters all the way to the top
365 * Returns: int: sum
366 * Inputs: node:n - node to consider
367 * string:side - scrollTop or scrollLeft
368 */
369 _fnSumScroll: function ( n, side )
370 {
371 var i = n[side];
372 while ( n = n.parentNode )
373 {
374 if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' )
375 {
376 break;
377 }
378 i = n[side];
379 }
380 return i;
381 },
382
383 /*
384 * Function: _fnUpdatePositions
385 * Purpose: Loop over the fixed elements for this table and update their positions
386 * Returns: -
387 * Inputs: -
388 */
389 _fnUpdatePositions: function ()
390 {
391 var s = this.fnGetSettings();
392 this._fnMeasure();
393
394 for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ )
395 {
396 if ( s.aoCache[i].sType == "fixedHeader" )
397 {
398 this._fnScrollFixedHeader( s.aoCache[i] );
399 }
400 else if ( s.aoCache[i].sType == "fixedFooter" )
401 {
402 this._fnScrollFixedFooter( s.aoCache[i] );
403 }
404 else if ( s.aoCache[i].sType == "fixedLeft" )
405 {
406 this._fnScrollHorizontalLeft( s.aoCache[i] );
407 }
408 else
409 {
410 this._fnScrollHorizontalRight( s.aoCache[i] );
411 }
412 }
413 },
414
415 /*
416 * Function: _fnUpdateClones
417 * Purpose: Loop over the fixed elements for this table and call their cloning functions
418 * Returns: -
419 * Inputs: -
420 */
421 _fnUpdateClones: function ()
422 {
423 var s = this.fnGetSettings();
424 for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ )
425 {
426 s.aoCache[i].fnClone.call( this, s.aoCache[i] );
427 }
428 },
429
430
431 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
432 * Scrolling functions
433 */
434
435 /*
436 * Function: _fnScrollHorizontalLeft
437 * Purpose: Update the positioning of the scrolling elements
438 * Returns: -
439 * Inputs: object:oCache - the cahced values for this fixed element
440 */
441 _fnScrollHorizontalRight: function ( oCache )
442 {
443 var
444 s = this.fnGetSettings(),
445 oMes = s.oMes,
446 oWin = FixedHeader.oWin,
447 oDoc = FixedHeader.oDoc,
448 nTable = oCache.nWrapper,
449 iFixedWidth = jQuery(nTable).outerWidth();
450
451 if ( oWin.iScrollRight < oMes.iTableRight )
452 {
453 /* Fully right aligned */
454 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
455 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
456 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iFixedWidth)+"px", 'left', nTable.style );
457 }
458 else if ( oMes.iTableLeft < oDoc.iWidth-oWin.iScrollRight-iFixedWidth )
459 {
460 /* Middle */
461 if ( s.bUseAbsPos )
462 {
463 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
464 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
465 this._fnUpdateCache( oCache, 'sLeft', (oDoc.iWidth-oWin.iScrollRight-iFixedWidth)+"px", 'left', nTable.style );
466 }
467 else
468 {
469 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
470 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style );
471 this._fnUpdateCache( oCache, 'sLeft', (oWin.iWidth-iFixedWidth)+"px", 'left', nTable.style );
472 }
473 }
474 else
475 {
476 /* Fully left aligned */
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', oMes.iTableLeft+"px", 'left', nTable.style );
480 }
481 },
482
483 /*
484 * Function: _fnScrollHorizontalLeft
485 * Purpose: Update the positioning of the scrolling elements
486 * Returns: -
487 * Inputs: object:oCache - the cahced values for this fixed element
488 */
489 _fnScrollHorizontalLeft: function ( oCache )
490 {
491 var
492 s = this.fnGetSettings(),
493 oMes = s.oMes,
494 oWin = FixedHeader.oWin,
495 oDoc = FixedHeader.oDoc,
496 nTable = oCache.nWrapper,
497 iCellWidth = jQuery(nTable).outerWidth();
498
499 if ( oWin.iScrollLeft < oMes.iTableLeft )
500 {
501 /* Fully left align */
502 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
503 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
504 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
505 }
506 else if ( oWin.iScrollLeft < oMes.iTableLeft+oMes.iTableWidth-iCellWidth )
507 {
508 /* Middle */
509 if ( s.bUseAbsPos )
510 {
511 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
512 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
513 this._fnUpdateCache( oCache, 'sLeft', oWin.iScrollLeft+"px", 'left', nTable.style );
514 }
515 else
516 {
517 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
518 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style );
519 this._fnUpdateCache( oCache, 'sLeft', "0px", 'left', nTable.style );
520 }
521 }
522 else
523 {
524 /* Fully right align */
525 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
526 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
527 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iCellWidth)+"px", 'left', nTable.style );
528 }
529 },
530
531 /*
532 * Function: _fnScrollFixedFooter
533 * Purpose: Update the positioning of the scrolling elements
534 * Returns: -
535 * Inputs: object:oCache - the cahced values for this fixed element
536 */
537 _fnScrollFixedFooter: function ( oCache )
538 {
539 var
540 s = this.fnGetSettings(),
541 oMes = s.oMes,
542 oWin = FixedHeader.oWin,
543 oDoc = FixedHeader.oDoc,
544 nTable = oCache.nWrapper,
545 iTheadHeight = jQuery("thead", s.nTable).outerHeight(),
546 iCellHeight = jQuery(nTable).outerHeight();
547
548 if ( oWin.iScrollBottom < oMes.iTableBottom )
549 {
550 /* Below */
551 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
552 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+oMes.iTableHeight-iCellHeight)+"px", 'top', nTable.style );
553 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
554 }
555 else if ( oWin.iScrollBottom < oMes.iTableBottom+oMes.iTableHeight-iCellHeight-iTheadHeight )
556 {
557 /* Middle */
558 if ( s.bUseAbsPos )
559 {
560 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
561 this._fnUpdateCache( oCache, 'sTop', (oDoc.iHeight-oWin.iScrollBottom-iCellHeight)+"px", 'top', nTable.style );
562 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
563 }
564 else
565 {
566 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
567 this._fnUpdateCache( oCache, 'sTop', (oWin.iHeight-iCellHeight)+"px", 'top', nTable.style );
568 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
569 }
570 }
571 else
572 {
573 /* Above */
574 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
575 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iCellHeight)+"px", 'top', nTable.style );
576 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
577 }
578 },
579
580 /*
581 * Function: _fnScrollFixedHeader
582 * Purpose: Update the positioning of the scrolling elements
583 * Returns: -
584 * Inputs: object:oCache - the cahced values for this fixed element
585 */
586 _fnScrollFixedHeader: function ( oCache )
587 {
588 var
589 s = this.fnGetSettings(),
590 oMes = s.oMes,
591 oWin = FixedHeader.oWin,
592 oDoc = FixedHeader.oDoc,
593 nTable = oCache.nWrapper,
594 iTbodyHeight = 0,
595 anTbodies = s.nTable.getElementsByTagName('tbody');
596
597 for (var i = 0; i < anTbodies.length; ++i) {
598 iTbodyHeight += anTbodies[i].offsetHeight;
599 }
600
601 if ( oMes.iTableTop > oWin.iScrollTop + s.oOffset.top )
602 {
603 /* Above the table */
604 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
605 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
606 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
607 }
608 else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight )
609 {
610 /* At the bottom of the table */
611 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
612 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style );
613 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
614 }
615 else
616 {
617 /* In the middle of the table */
618 if ( s.bUseAbsPos )
619 {
620 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
621 this._fnUpdateCache( oCache, 'sTop', oWin.iScrollTop+"px", 'top', nTable.style );
622 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
623 }
624 else
625 {
626 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
627 this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style );
628 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
629 }
630 }
631 },
632
633 /*
634 * Function: _fnUpdateCache
635 * Purpose: Check the cache and update cache and value if needed
636 * Returns: -
637 * Inputs: object:oCache - local cache object
638 * string:sCache - cache property
639 * string:sSet - value to set
640 * string:sProperty - object property to set
641 * object:oObj - object to update
642 */
643 _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj )
644 {
645 if ( oCache[sCache] != sSet )
646 {
647 oObj[sProperty] = sSet;
648 oCache[sCache] = sSet;
649 }
650 },
651
652
653
654 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
655 * Cloning functions
656 */
657
658 /*
659 * Function: _fnCloneThead
660 * Purpose: Clone the thead element
661 * Returns: -
662 * Inputs: object:oCache - the cahced values for this fixed element
663 */
664 _fnCloneThead: function ( oCache )
665 {
666 var s = this.fnGetSettings();
667 var nTable = oCache.nNode;
668
669 /* Set the wrapper width to match that of the cloned table */
670 oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px";
671
672 /* Remove any children the cloned table has */
673 while ( nTable.childNodes.length > 0 )
674 {
675 jQuery('thead th', nTable).unbind( 'click' );
676 nTable.removeChild( nTable.childNodes[0] );
677 }
678
679 /* Clone the DataTables header */
680 var nThead = jQuery('thead', s.nTable).clone(true)[0];
681 nTable.appendChild( nThead );
682
683 /* Copy the widths across - apparently a clone isn't good enough for this */
684 jQuery("thead>tr th", s.nTable).each( function (i) {
685 jQuery("thead>tr th:eq("+i+")", nTable).width( jQuery(this).width() );
686 } );
687
688 jQuery("thead>tr td", s.nTable).each( function (i) {
689 jQuery("thead>tr td:eq("+i+")", nTable).width( jQuery(this).width() );
690 } );
691 },
692
693 /*
694 * Function: _fnCloneTfoot
695 * Purpose: Clone the tfoot element
696 * Returns: -
697 * Inputs: object:oCache - the cahced values for this fixed element
698 */
699 _fnCloneTfoot: function ( oCache )
700 {
701 var s = this.fnGetSettings();
702 var nTable = oCache.nNode;
703
704 /* Set the wrapper width to match that of the cloned table */
705 oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px";
706
707 /* Remove any children the cloned table has */
708 while ( nTable.childNodes.length > 0 )
709 {
710 nTable.removeChild( nTable.childNodes[0] );
711 }
712
713 /* Clone the DataTables footer */
714 var nTfoot = jQuery('tfoot', s.nTable).clone(true)[0];
715 nTable.appendChild( nTfoot );
716
717 /* Copy the widths across - apparently a clone isn't good enough for this */
718 jQuery("tfoot:eq(0)>tr th", s.nTable).each( function (i) {
719 jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( jQuery(this).width() );
720 } );
721
722 jQuery("tfoot:eq(0)>tr td", s.nTable).each( function (i) {
723 jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable)[0].style.width( jQuery(this).width() );
724 } );
725 },
726
727 /*
728 * Function: _fnCloneTLeft
729 * Purpose: Clone the left column
730 * Returns: -
731 * Inputs: object:oCache - the cached values for this fixed element
732 */
733 _fnCloneTLeft: function ( oCache )
734 {
735 var s = this.fnGetSettings();
736 var nTable = oCache.nNode;
737 var nBody = $('tbody', s.nTable)[0];
738 var iCols = $('tbody tr:eq(0) td', s.nTable).length;
739 var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
740
741 /* Remove any children the cloned table has */
742 while ( nTable.childNodes.length > 0 )
743 {
744 nTable.removeChild( nTable.childNodes[0] );
745 }
746
747 /* Is this the most efficient way to do this - it looks horrible... */
748 nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] );
749 nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] );
750 if ( s.bFooter )
751 {
752 nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] );
753 }
754
755 /* Remove unneeded cells */
756 $('thead tr', nTable).each( function (k) {
757 $('th:gt(0)', this).remove();
758 } );
759
760 $('tfoot tr', nTable).each( function (k) {
761 $('th:gt(0)', this).remove();
762 } );
763
764 $('tbody tr', nTable).each( function (k) {
765 $('td:gt(0)', this).remove();
766 } );
767
768 this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
769
770 var iWidth = jQuery('thead tr th:eq(0)', s.nTable).outerWidth();
771 nTable.style.width = iWidth+"px";
772 oCache.nWrapper.style.width = iWidth+"px";
773 },
774
775 /*
776 * Function: _fnCloneTRight
777 * Purpose: Clone the right most colun
778 * Returns: -
779 * Inputs: object:oCache - the cahced values for this fixed element
780 */
781 _fnCloneTRight: function ( oCache )
782 {
783 var s = this.fnGetSettings();
784 var nBody = $('tbody', s.nTable)[0];
785 var nTable = oCache.nNode;
786 var iCols = jQuery('tbody tr:eq(0) td', s.nTable).length;
787 var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
788
789 /* Remove any children the cloned table has */
790 while ( nTable.childNodes.length > 0 )
791 {
792 nTable.removeChild( nTable.childNodes[0] );
793 }
794
795 /* Is this the most efficient way to do this - it looks horrible... */
796 nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] );
797 nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] );
798 if ( s.bFooter )
799 {
800 nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] );
801 }
802 jQuery('thead tr th:not(:nth-child('+iCols+'n))', nTable).remove();
803 jQuery('tfoot tr th:not(:nth-child('+iCols+'n))', nTable).remove();
804
805 /* Remove unneeded cells */
806 $('tbody tr', nTable).each( function (k) {
807 $('td:lt('+(iCols-1)+')', this).remove();
808 } );
809
810 this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
811
812 var iWidth = jQuery('thead tr th:eq('+(iCols-1)+')', s.nTable).outerWidth();
813 nTable.style.width = iWidth+"px";
814 oCache.nWrapper.style.width = iWidth+"px";
815 },
816
817
818 /**
819 * Equalise the heights of the rows in a given table node in a cross browser way. Note that this
820 * is more or less lifted as is from FixedColumns
821 * @method fnEqualiseHeights
822 * @returns void
823 * @param {string} parent Node type - thead, tbody or tfoot
824 * @param {element} original Original node to take the heights from
825 * @param {element} clone Copy the heights to
826 * @private
827 */
828 "fnEqualiseHeights": function ( parent, original, clone )
829 {
830 var that = this,
831 jqBoxHack = $(parent+' tr:eq(0)', original).children(':eq(0)'),
832 iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
833 bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
834
835 /* Remove cells which are not needed and copy the height from the original table */
836 $(parent+' tr', clone).each( function (k) {
837 /* Can we use some kind of object detection here?! This is very nasty - damn browsers */
838 if ( $.browser.mozilla || $.browser.opera )
839 {
840 $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() );
841 }
842 else
843 {
844 $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() - iBoxHack );
845 }
846
847 if ( !bRubbishOldIE )
848 {
849 $(parent+' tr:eq('+k+')', original).height( $(parent+' tr:eq('+k+')', original).outerHeight() );
850 }
851 } );
852 }
853 };
854
855
856 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
857 * Static properties and methods
858 * We use these for speed! This information is common to all instances of FixedHeader, so no
859 * point if having them calculated and stored for each different instance.
860 */
861
862 /*
863 * Variable: oWin
864 * Purpose: Store information about the window positioning
865 * Scope: FixedHeader
866 */
867 FixedHeader.oWin = {
868 "iScrollTop": 0,
869 "iScrollRight": 0,
870 "iScrollBottom": 0,
871 "iScrollLeft": 0,
872 "iHeight": 0,
873 "iWidth": 0
874 };
875
876 /*
877 * Variable: oDoc
878 * Purpose: Store information about the document size
879 * Scope: FixedHeader
880 */
881 FixedHeader.oDoc = {
882 "iHeight": 0,
883 "iWidth": 0
884 };
885
886 /*
887 * Variable: afnScroll
888 * Purpose: Array of functions that are to be used for the scrolling components
889 * Scope: FixedHeader
890 */
891 FixedHeader.afnScroll = [];
892
893 /*
894 * Function: fnMeasure
895 * Purpose: Update the measurements for the window and document
896 * Returns: -
897 * Inputs: -
898 */
899 FixedHeader.fnMeasure = function ()
900 {
901 var
902 jqWin = jQuery(window),
903 jqDoc = jQuery(document),
904 oWin = FixedHeader.oWin,
905 oDoc = FixedHeader.oDoc;
906
907 oDoc.iHeight = jqDoc.height();
908 oDoc.iWidth = jqDoc.width();
909
910 oWin.iHeight = jqWin.height();
911 oWin.iWidth = jqWin.width();
912 oWin.iScrollTop = jqWin.scrollTop();
913 oWin.iScrollLeft = jqWin.scrollLeft();
914 oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth;
915 oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight;
916 };
917
918
919 FixedHeader.VERSION = "2.0.6";
920 FixedHeader.prototype.VERSION = FixedHeader.VERSION;
921
922
923 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
924 * Global processing
925 */
926
927 /*
928 * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is
929 * done as an optimisation, to reduce calculation and proagation time
930 */
931 jQuery(window).scroll( function () {
932 FixedHeader.fnMeasure();
933 for ( var i=0, iLen=FixedHeader.afnScroll.length ; i<iLen ; i++ )
934 {
935 FixedHeader.afnScroll[i]();
936 }
937 } );