jquery-datatables-rails 1.9.1.3 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,937 @@
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
+ } );