Mercurial > repos > saskia-hiltemann > ireport
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 } ); |