Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / pybind / mgr / dashboard / static / AdminLTE-2.3.7 / plugins / datatables / extensions / FixedColumns / js / dataTables.fixedColumns.js
1 /*! FixedColumns 3.0.4
2  * ©2010-2014 SpryMedia Ltd - datatables.net/license
3  */
4
5 /**
6  * @summary     FixedColumns
7  * @description Freeze columns in place on a scrolling DataTable
8  * @version     3.0.4
9  * @file        dataTables.fixedColumns.js
10  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
11  * @contact     www.sprymedia.co.uk/contact
12  * @copyright   Copyright 2010-2014 SpryMedia Ltd.
13  *
14  * This source file is free software, available under the following license:
15  *   MIT license - http://datatables.net/license/mit
16  *
17  * This source file is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20  *
21  * For details please refer to: http://www.datatables.net
22  */
23
24
25 (function(window, document, undefined) {
26
27
28 var factory = function( $, DataTable ) {
29 "use strict";
30
31 /**
32  * When making use of DataTables' x-axis scrolling feature, you may wish to
33  * fix the left most column in place. This plug-in for DataTables provides
34  * exactly this option (note for non-scrolling tables, please use the
35  * FixedHeader plug-in, which can fix headers, footers and columns). Key
36  * features include:
37  *
38  * * Freezes the left or right most columns to the side of the table
39  * * Option to freeze two or more columns
40  * * Full integration with DataTables' scrolling options
41  * * Speed - FixedColumns is fast in its operation
42  *
43  *  @class
44  *  @constructor
45  *  @global
46  *  @param {object} dt DataTables instance. With DataTables 1.10 this can also
47  *    be a jQuery collection, a jQuery selector, DataTables API instance or
48  *    settings object.
49  *  @param {object} [init={}] Configuration object for FixedColumns. Options are
50  *    defined by {@link FixedColumns.defaults}
51  *
52  *  @requires jQuery 1.7+
53  *  @requires DataTables 1.8.0+
54  *
55  *  @example
56  *      var table = $('#example').dataTable( {
57  *        "scrollX": "100%"
58  *      } );
59  *      new $.fn.dataTable.fixedColumns( table );
60  */
61 var FixedColumns = function ( dt, init ) {
62         var that = this;
63
64         /* Sanity check - you just know it will happen */
65         if ( ! ( this instanceof FixedColumns ) )
66         {
67                 alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
68                 return;
69         }
70
71         if ( typeof init == 'undefined' )
72         {
73                 init = {};
74         }
75
76         // Use the DataTables Hungarian notation mapping method, if it exists to
77         // provide forwards compatibility for camel case variables
78         var camelToHungarian = $.fn.dataTable.camelToHungarian;
79         if ( camelToHungarian ) {
80                 camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
81                 camelToHungarian( FixedColumns.defaults, init );
82         }
83
84         // v1.10 allows the settings object to be got form a number of sources
85         var dtSettings = $.fn.dataTable.Api ?
86                 new $.fn.dataTable.Api( dt ).settings()[0] :
87                 dt.fnSettings();
88
89         /**
90          * Settings object which contains customisable information for FixedColumns instance
91          * @namespace
92          * @extends FixedColumns.defaults
93          * @private
94          */
95         this.s = {
96                 /**
97                  * DataTables settings objects
98                  *  @type     object
99                  *  @default  Obtained from DataTables instance
100                  */
101                 "dt": dtSettings,
102
103                 /**
104                  * Number of columns in the DataTable - stored for quick access
105                  *  @type     int
106                  *  @default  Obtained from DataTables instance
107                  */
108                 "iTableColumns": dtSettings.aoColumns.length,
109
110                 /**
111                  * Original outer widths of the columns as rendered by DataTables - used to calculate
112                  * the FixedColumns grid bounding box
113                  *  @type     array.<int>
114                  *  @default  []
115                  */
116                 "aiOuterWidths": [],
117
118                 /**
119                  * Original inner widths of the columns as rendered by DataTables - used to apply widths
120                  * to the columns
121                  *  @type     array.<int>
122                  *  @default  []
123                  */
124                 "aiInnerWidths": []
125         };
126
127
128         /**
129          * DOM elements used by the class instance
130          * @namespace
131          * @private
132          *
133          */
134         this.dom = {
135                 /**
136                  * DataTables scrolling element
137                  *  @type     node
138                  *  @default  null
139                  */
140                 "scroller": null,
141
142                 /**
143                  * DataTables header table
144                  *  @type     node
145                  *  @default  null
146                  */
147                 "header": null,
148
149                 /**
150                  * DataTables body table
151                  *  @type     node
152                  *  @default  null
153                  */
154                 "body": null,
155
156                 /**
157                  * DataTables footer table
158                  *  @type     node
159                  *  @default  null
160                  */
161                 "footer": null,
162
163                 /**
164                  * Display grid elements
165                  * @namespace
166                  */
167                 "grid": {
168                         /**
169                          * Grid wrapper. This is the container element for the 3x3 grid
170                          *  @type     node
171                          *  @default  null
172                          */
173                         "wrapper": null,
174
175                         /**
176                          * DataTables scrolling element. This element is the DataTables
177                          * component in the display grid (making up the main table - i.e.
178                          * not the fixed columns).
179                          *  @type     node
180                          *  @default  null
181                          */
182                         "dt": null,
183
184                         /**
185                          * Left fixed column grid components
186                          * @namespace
187                          */
188                         "left": {
189                                 "wrapper": null,
190                                 "head": null,
191                                 "body": null,
192                                 "foot": null
193                         },
194
195                         /**
196                          * Right fixed column grid components
197                          * @namespace
198                          */
199                         "right": {
200                                 "wrapper": null,
201                                 "head": null,
202                                 "body": null,
203                                 "foot": null
204                         }
205                 },
206
207                 /**
208                  * Cloned table nodes
209                  * @namespace
210                  */
211                 "clone": {
212                         /**
213                          * Left column cloned table nodes
214                          * @namespace
215                          */
216                         "left": {
217                                 /**
218                                  * Cloned header table
219                                  *  @type     node
220                                  *  @default  null
221                                  */
222                                 "header": null,
223
224                                 /**
225                                  * Cloned body table
226                                  *  @type     node
227                                  *  @default  null
228                                  */
229                                 "body": null,
230
231                                 /**
232                                  * Cloned footer table
233                                  *  @type     node
234                                  *  @default  null
235                                  */
236                                 "footer": null
237                         },
238
239                         /**
240                          * Right column cloned table nodes
241                          * @namespace
242                          */
243                         "right": {
244                                 /**
245                                  * Cloned header table
246                                  *  @type     node
247                                  *  @default  null
248                                  */
249                                 "header": null,
250
251                                 /**
252                                  * Cloned body table
253                                  *  @type     node
254                                  *  @default  null
255                                  */
256                                 "body": null,
257
258                                 /**
259                                  * Cloned footer table
260                                  *  @type     node
261                                  *  @default  null
262                                  */
263                                 "footer": null
264                         }
265                 }
266         };
267
268         /* Attach the instance to the DataTables instance so it can be accessed easily */
269         dtSettings._oFixedColumns = this;
270
271         /* Let's do it */
272         if ( ! dtSettings._bInitComplete )
273         {
274                 dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
275                         that._fnConstruct( init );
276                 }, 'FixedColumns' );
277         }
278         else
279         {
280                 this._fnConstruct( init );
281         }
282 };
283
284
285
286 FixedColumns.prototype = /** @lends FixedColumns.prototype */{
287         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
288          * Public methods
289          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
290
291         /**
292          * Update the fixed columns - including headers and footers. Note that FixedColumns will
293          * automatically update the display whenever the host DataTable redraws.
294          *  @returns {void}
295          *  @example
296          *      var table = $('#example').dataTable( {
297          *          "scrollX": "100%"
298          *      } );
299          *      var fc = new $.fn.dataTable.fixedColumns( table );
300          *
301          *      // at some later point when the table has been manipulated....
302          *      fc.fnUpdate();
303          */
304         "fnUpdate": function ()
305         {
306                 this._fnDraw( true );
307         },
308
309
310         /**
311          * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
312          * This is useful if you update the width of the table container. Note that FixedColumns will
313          * perform this function automatically when the window.resize event is fired.
314          *  @returns {void}
315          *  @example
316          *      var table = $('#example').dataTable( {
317          *          "scrollX": "100%"
318          *      } );
319          *      var fc = new $.fn.dataTable.fixedColumns( table );
320          *
321          *      // Resize the table container and then have FixedColumns adjust its layout....
322          *      $('#content').width( 1200 );
323          *      fc.fnRedrawLayout();
324          */
325         "fnRedrawLayout": function ()
326         {
327                 this._fnColCalc();
328                 this._fnGridLayout();
329                 this.fnUpdate();
330         },
331
332
333         /**
334          * Mark a row such that it's height should be recalculated when using 'semiauto' row
335          * height matching. This function will have no effect when 'none' or 'auto' row height
336          * matching is used.
337          *  @param   {Node} nTr TR element that should have it's height recalculated
338          *  @returns {void}
339          *  @example
340          *      var table = $('#example').dataTable( {
341          *          "scrollX": "100%"
342          *      } );
343          *      var fc = new $.fn.dataTable.fixedColumns( table );
344          *
345          *      // manipulate the table - mark the row as needing an update then update the table
346          *      // this allows the redraw performed by DataTables fnUpdate to recalculate the row
347          *      // height
348          *      fc.fnRecalculateHeight();
349          *      table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
350          */
351         "fnRecalculateHeight": function ( nTr )
352         {
353                 delete nTr._DTTC_iHeight;
354                 nTr.style.height = 'auto';
355         },
356
357
358         /**
359          * Set the height of a given row - provides cross browser compatibility
360          *  @param   {Node} nTarget TR element that should have it's height recalculated
361          *  @param   {int} iHeight Height in pixels to set
362          *  @returns {void}
363          *  @example
364          *      var table = $('#example').dataTable( {
365          *          "scrollX": "100%"
366          *      } );
367          *      var fc = new $.fn.dataTable.fixedColumns( table );
368          *
369          *      // You may want to do this after manipulating a row in the fixed column
370          *      fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
371          */
372         "fnSetRowHeight": function ( nTarget, iHeight )
373         {
374                 nTarget.style.height = iHeight+"px";
375         },
376
377
378         /**
379          * Get data index information about a row or cell in the table body.
380          * This function is functionally identical to fnGetPosition in DataTables,
381          * taking the same parameter (TH, TD or TR node) and returning exactly the
382          * the same information (data index information). THe difference between
383          * the two is that this method takes into account the fixed columns in the
384          * table, so you can pass in nodes from the master table, or the cloned
385          * tables and get the index position for the data in the main table.
386          *  @param {node} node TR, TH or TD element to get the information about
387          *  @returns {int} If nNode is given as a TR, then a single index is 
388          *    returned, or if given as a cell, an array of [row index, column index
389          *    (visible), column index (all)] is given.
390          */
391         "fnGetPosition": function ( node )
392         {
393                 var idx;
394                 var inst = this.s.dt.oInstance;
395
396                 if ( ! $(node).parents('.DTFC_Cloned').length )
397                 {
398                         // Not in a cloned table
399                         return inst.fnGetPosition( node );
400                 }
401                 else
402                 {
403                         // Its in the cloned table, so need to look up position
404                         if ( node.nodeName.toLowerCase() === 'tr' ) {
405                                 idx = $(node).index();
406                                 return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
407                         }
408                         else
409                         {
410                                 var colIdx = $(node).index();
411                                 idx = $(node.parentNode).index();
412                                 var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
413
414                                 return [
415                                         row,
416                                         colIdx,
417                                         inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
418                                 ];
419                         }
420                 }
421         },
422
423
424
425         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
426          * Private methods (they are of course public in JS, but recommended as private)
427          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
428
429         /**
430          * Initialisation for FixedColumns
431          *  @param   {Object} oInit User settings for initialisation
432          *  @returns {void}
433          *  @private
434          */
435         "_fnConstruct": function ( oInit )
436         {
437                 var i, iLen, iWidth,
438                         that = this;
439
440                 /* Sanity checking */
441                 if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
442                      this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
443                 {
444                         alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
445                                 "Please upgrade your DataTables installation" );
446                         return;
447                 }
448
449                 if ( this.s.dt.oScroll.sX === "" )
450                 {
451                         this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
452                                 "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
453                                 "column fixing when scrolling is not enabled" );
454                         return;
455                 }
456
457                 /* Apply the settings from the user / defaults */
458                 this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
459
460                 /* Set up the DOM as we need it and cache nodes */
461                 var classes = this.s.dt.oClasses;
462                 this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
463                 this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
464
465                 /* Set up the DOM that we want for the fixed column layout grid */
466                 this._fnColCalc();
467                 this._fnGridSetup();
468
469                 /* Event handlers */
470                 var mouseController;
471
472                 // When the body is scrolled - scroll the left and right columns
473                 $(this.dom.scroller)
474                         .on( 'mouseover.DTFC touchstart.DTFC', function () {
475                                 mouseController = 'main';
476                         } )
477                         .on( 'scroll.DTFC', function () {
478                                 if ( mouseController === 'main' ) {
479                                         if ( that.s.iLeftColumns > 0 ) {
480                                                 that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
481                                         }
482                                         if ( that.s.iRightColumns > 0 ) {
483                                                 that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
484                                         }
485                                 }
486                         } );
487
488                 var wheelType = 'onwheel' in document.createElement('div') ?
489                         'wheel.DTFC' :
490                         'mousewheel.DTFC';
491
492                 if ( that.s.iLeftColumns > 0 ) {
493                         // When scrolling the left column, scroll the body and right column
494                         $(that.dom.grid.left.liner)
495                                 .on( 'mouseover.DTFC touchstart.DTFC', function () {
496                                         mouseController = 'left';
497                                 } )
498                                 .on( 'scroll.DTFC', function () {
499                                         if ( mouseController === 'left' ) {
500                                                 that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
501                                                 if ( that.s.iRightColumns > 0 ) {
502                                                         that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
503                                                 }
504                                         }
505                                 } )
506                                 .on( wheelType, function(e) { // xxx update the destroy as well
507                                         // Pass horizontal scrolling through
508                                         var xDelta = e.type === 'wheel' ?
509                                                 -e.originalEvent.deltaX :
510                                                 e.originalEvent.wheelDeltaX;
511                                         that.dom.scroller.scrollLeft -= xDelta;
512                                 } );
513                 }
514
515                 if ( that.s.iRightColumns > 0 ) {
516                         // When scrolling the right column, scroll the body and the left column
517                         $(that.dom.grid.right.liner)
518                                 .on( 'mouseover.DTFC touchstart.DTFC', function () {
519                                         mouseController = 'right';
520                                 } )
521                                 .on( 'scroll.DTFC', function () {
522                                         if ( mouseController === 'right' ) {
523                                                 that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
524                                                 if ( that.s.iLeftColumns > 0 ) {
525                                                         that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
526                                                 }
527                                         }
528                                 } )
529                                 .on( wheelType, function(e) {
530                                         // Pass horizontal scrolling through
531                                         var xDelta = e.type === 'wheel' ?
532                                                 -e.originalEvent.deltaX :
533                                                 e.originalEvent.wheelDeltaX;
534                                         that.dom.scroller.scrollLeft -= xDelta;
535                                 } );
536                 }
537
538                 $(window).on( 'resize.DTFC', function () {
539                         that._fnGridLayout.call( that );
540                 } );
541
542                 var bFirstDraw = true;
543                 var jqTable = $(this.s.dt.nTable);
544
545                 jqTable
546                         .on( 'draw.dt.DTFC', function () {
547                                 that._fnDraw.call( that, bFirstDraw );
548                                 bFirstDraw = false;
549                         } )
550                         .on( 'column-sizing.dt.DTFC', function () {
551                                 that._fnColCalc();
552                                 that._fnGridLayout( that );
553                         } )
554                         .on( 'column-visibility.dt.DTFC', function () {
555                                 that._fnColCalc();
556                                 that._fnGridLayout( that );
557                                 that._fnDraw( true );
558                         } )
559                         .on( 'destroy.dt.DTFC', function () {
560                                 jqTable.off( 'column-sizing.dt.DTFC destroy.dt.DTFC draw.dt.DTFC' );
561
562                                 $(that.dom.scroller).off( 'scroll.DTFC mouseover.DTFC' );
563                                 $(window).off( 'resize.DTFC' );
564
565                                 $(that.dom.grid.left.liner).off( 'scroll.DTFC mouseover.DTFC '+wheelType );
566                                 $(that.dom.grid.left.wrapper).remove();
567
568                                 $(that.dom.grid.right.liner).off( 'scroll.DTFC mouseover.DTFC '+wheelType );
569                                 $(that.dom.grid.right.wrapper).remove();
570                         } );
571
572                 /* Get things right to start with - note that due to adjusting the columns, there must be
573                  * another redraw of the main table. It doesn't need to be a full redraw however.
574                  */
575                 this._fnGridLayout();
576                 this.s.dt.oInstance.fnDraw(false);
577         },
578
579
580         /**
581          * Calculate the column widths for the grid layout
582          *  @returns {void}
583          *  @private
584          */
585         "_fnColCalc": function ()
586         {
587                 var that = this;
588                 var iLeftWidth = 0;
589                 var iRightWidth = 0;
590
591                 this.s.aiInnerWidths = [];
592                 this.s.aiOuterWidths = [];
593
594                 $.each( this.s.dt.aoColumns, function (i, col) {
595                         var th = $(col.nTh);
596                         var border;
597
598                         if ( ! th.filter(':visible').length ) {
599                                 that.s.aiInnerWidths.push( 0 );
600                                 that.s.aiOuterWidths.push( 0 );
601                         }
602                         else
603                         {
604                                 // Inner width is used to assign widths to cells
605                                 // Outer width is used to calculate the container
606                                 var iWidth = th.outerWidth();
607
608                                 // When working with the left most-cell, need to add on the
609                                 // table's border to the outerWidth, since we need to take
610                                 // account of it, but it isn't in any cell
611                                 if ( that.s.aiOuterWidths.length === 0 ) {
612                                         border = $(that.s.dt.nTable).css('border-left-width');
613                                         iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 );
614                                 }
615
616                                 // Likewise with the final column on the right
617                                 if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
618                                         border = $(that.s.dt.nTable).css('border-right-width');
619                                         iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 );
620                                 }
621
622                                 that.s.aiOuterWidths.push( iWidth );
623                                 that.s.aiInnerWidths.push( th.width() );
624
625                                 if ( i < that.s.iLeftColumns )
626                                 {
627                                         iLeftWidth += iWidth;
628                                 }
629
630                                 if ( that.s.iTableColumns-that.s.iRightColumns <= i )
631                                 {
632                                         iRightWidth += iWidth;
633                                 }
634                         }
635                 } );
636
637                 this.s.iLeftWidth = iLeftWidth;
638                 this.s.iRightWidth = iRightWidth;
639         },
640
641
642         /**
643          * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
644          * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
645          * puts into the DOM) and the right column. In each of he two fixed column elements there is a
646          * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
647          * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
648          *  @returns {void}
649          *  @private
650          */
651         "_fnGridSetup": function ()
652         {
653                 var that = this;
654                 var oOverflow = this._fnDTOverflow();
655                 var block;
656
657                 this.dom.body = this.s.dt.nTable;
658                 this.dom.header = this.s.dt.nTHead.parentNode;
659                 this.dom.header.parentNode.parentNode.style.position = "relative";
660
661                 var nSWrapper =
662                         $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
663                                 '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;">'+
664                                         '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
665                                         '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
666                                                 '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
667                                         '</div>'+
668                                         '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
669                                 '</div>'+
670                                 '<div class="DTFC_RightWrapper" style="position:absolute; top:0; left:0;">'+
671                                         '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
672                                                 '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
673                                         '</div>'+
674                                         '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
675                                                 '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
676                                         '</div>'+
677                                         '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
678                                                 '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
679                                         '</div>'+
680                                 '</div>'+
681                         '</div>')[0];
682                 var nLeft = nSWrapper.childNodes[0];
683                 var nRight = nSWrapper.childNodes[1];
684
685                 this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
686                 nSWrapper.appendChild( this.dom.grid.dt );
687
688                 this.dom.grid.wrapper = nSWrapper;
689
690                 if ( this.s.iLeftColumns > 0 )
691                 {
692                         this.dom.grid.left.wrapper = nLeft;
693                         this.dom.grid.left.head = nLeft.childNodes[0];
694                         this.dom.grid.left.body = nLeft.childNodes[1];
695                         this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
696
697                         nSWrapper.appendChild( nLeft );
698                 }
699
700                 if ( this.s.iRightColumns > 0 )
701                 {
702                         this.dom.grid.right.wrapper = nRight;
703                         this.dom.grid.right.head = nRight.childNodes[0];
704                         this.dom.grid.right.body = nRight.childNodes[1];
705                         this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
706
707                         block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
708                         block.style.width = oOverflow.bar+"px";
709                         block.style.right = -oOverflow.bar+"px";
710                         this.dom.grid.right.headBlock = block;
711
712                         block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
713                         block.style.width = oOverflow.bar+"px";
714                         block.style.right = -oOverflow.bar+"px";
715                         this.dom.grid.right.footBlock = block;
716
717                         nSWrapper.appendChild( nRight );
718                 }
719
720                 if ( this.s.dt.nTFoot )
721                 {
722                         this.dom.footer = this.s.dt.nTFoot.parentNode;
723                         if ( this.s.iLeftColumns > 0 )
724                         {
725                                 this.dom.grid.left.foot = nLeft.childNodes[2];
726                         }
727                         if ( this.s.iRightColumns > 0 )
728                         {
729                                 this.dom.grid.right.foot = nRight.childNodes[2];
730                         }
731                 }
732         },
733
734
735         /**
736          * Style and position the grid used for the FixedColumns layout
737          *  @returns {void}
738          *  @private
739          */
740         "_fnGridLayout": function ()
741         {
742                 var oGrid = this.dom.grid;
743                 var iWidth = $(oGrid.wrapper).width();
744                 var iBodyHeight = $(this.s.dt.nTable.parentNode).outerHeight();
745                 var iFullHeight = $(this.s.dt.nTable.parentNode.parentNode).outerHeight();
746                 var oOverflow = this._fnDTOverflow();
747                 var
748                         iLeftWidth = this.s.iLeftWidth,
749                         iRightWidth = this.s.iRightWidth,
750                         iRight;
751                 var scrollbarAdjust = function ( node, width ) {
752                         if ( ! oOverflow.bar ) {
753                                 // If there is no scrollbar (Macs) we need to hide the auto scrollbar
754                                 node.style.width = (width+20)+"px";
755                                 node.style.paddingRight = "20px";
756                                 node.style.boxSizing = "border-box";
757                         }
758                         else {
759                                 // Otherwise just overflow by the scrollbar
760                                 node.style.width = (width+oOverflow.bar)+"px";
761                         }
762                 };
763
764                 // When x scrolling - don't paint the fixed columns over the x scrollbar
765                 if ( oOverflow.x )
766                 {
767                         iBodyHeight -= oOverflow.bar;
768                 }
769
770                 oGrid.wrapper.style.height = iFullHeight+"px";
771
772                 if ( this.s.iLeftColumns > 0 )
773                 {
774                         oGrid.left.wrapper.style.width = iLeftWidth+"px";
775                         oGrid.left.wrapper.style.height = "1px";
776                         oGrid.left.body.style.height = iBodyHeight+"px";
777                         if ( oGrid.left.foot ) {
778                                 oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
779                         }
780
781                         scrollbarAdjust( oGrid.left.liner, iLeftWidth );
782                         oGrid.left.liner.style.height = iBodyHeight+"px";
783                 }
784
785                 if ( this.s.iRightColumns > 0 )
786                 {
787                         iRight = iWidth - iRightWidth;
788                         if ( oOverflow.y )
789                         {
790                                 iRight -= oOverflow.bar;
791                         }
792
793                         oGrid.right.wrapper.style.width = iRightWidth+"px";
794                         oGrid.right.wrapper.style.left = iRight+"px";
795                         oGrid.right.wrapper.style.height = "1px";
796                         oGrid.right.body.style.height = iBodyHeight+"px";
797                         if ( oGrid.right.foot ) {
798                                 oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
799                         }
800
801                         scrollbarAdjust( oGrid.right.liner, iRightWidth );
802                         oGrid.right.liner.style.height = iBodyHeight+"px";
803
804                         oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
805                         oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
806                 }
807         },
808
809
810         /**
811          * Get information about the DataTable's scrolling state - specifically if the table is scrolling
812          * on either the x or y axis, and also the scrollbar width.
813          *  @returns {object} Information about the DataTables scrolling state with the properties:
814          *    'x', 'y' and 'bar'
815          *  @private
816          */
817         "_fnDTOverflow": function ()
818         {
819                 var nTable = this.s.dt.nTable;
820                 var nTableScrollBody = nTable.parentNode;
821                 var out = {
822                         "x": false,
823                         "y": false,
824                         "bar": this.s.dt.oScroll.iBarWidth
825                 };
826
827                 if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
828                 {
829                         out.x = true;
830                 }
831
832                 if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
833                 {
834                         out.y = true;
835                 }
836
837                 return out;
838         },
839
840
841         /**
842          * Clone and position the fixed columns
843          *  @returns {void}
844          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
845          *  @private
846          */
847         "_fnDraw": function ( bAll )
848         {
849                 this._fnGridLayout();
850                 this._fnCloneLeft( bAll );
851                 this._fnCloneRight( bAll );
852
853                 /* Draw callback function */
854                 if ( this.s.fnDrawCallback !== null )
855                 {
856                         this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
857                 }
858
859                 /* Event triggering */
860                 $(this).trigger( 'draw.dtfc', {
861                         "leftClone": this.dom.clone.left,
862                         "rightClone": this.dom.clone.right
863                 } );
864         },
865
866
867         /**
868          * Clone the right columns
869          *  @returns {void}
870          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
871          *  @private
872          */
873         "_fnCloneRight": function ( bAll )
874         {
875                 if ( this.s.iRightColumns <= 0 ) {
876                         return;
877                 }
878
879                 var that = this,
880                         i, jq,
881                         aiColumns = [];
882
883                 for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
884                         if ( this.s.dt.aoColumns[i].bVisible ) {
885                                 aiColumns.push( i );
886                         }
887                 }
888
889                 this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
890         },
891
892
893         /**
894          * Clone the left columns
895          *  @returns {void}
896          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
897          *  @private
898          */
899         "_fnCloneLeft": function ( bAll )
900         {
901                 if ( this.s.iLeftColumns <= 0 ) {
902                         return;
903                 }
904
905                 var that = this,
906                         i, jq,
907                         aiColumns = [];
908
909                 for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
910                         if ( this.s.dt.aoColumns[i].bVisible ) {
911                                 aiColumns.push( i );
912                         }
913                 }
914
915                 this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
916         },
917
918
919         /**
920          * Make a copy of the layout object for a header or footer element from DataTables. Note that
921          * this method will clone the nodes in the layout object.
922          *  @returns {Array} Copy of the layout array
923          *  @param   {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
924          *  @param   {Object} aiColumns Columns to copy
925          *  @private
926          */
927         "_fnCopyLayout": function ( aoOriginal, aiColumns )
928         {
929                 var aReturn = [];
930                 var aClones = [];
931                 var aCloned = [];
932
933                 for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
934                 {
935                         var aRow = [];
936                         aRow.nTr = $(aoOriginal[i].nTr).clone(true, true)[0];
937
938                         for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
939                         {
940                                 if ( $.inArray( j, aiColumns ) === -1 )
941                                 {
942                                         continue;
943                                 }
944
945                                 var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
946                                 if ( iCloned === -1 )
947                                 {
948                                         var nClone = $(aoOriginal[i][j].cell).clone(true, true)[0];
949                                         aClones.push( nClone );
950                                         aCloned.push( aoOriginal[i][j].cell );
951
952                                         aRow.push( {
953                                                 "cell": nClone,
954                                                 "unique": aoOriginal[i][j].unique
955                                         } );
956                                 }
957                                 else
958                                 {
959                                         aRow.push( {
960                                                 "cell": aClones[ iCloned ],
961                                                 "unique": aoOriginal[i][j].unique
962                                         } );
963                                 }
964                         }
965
966                         aReturn.push( aRow );
967                 }
968
969                 return aReturn;
970         },
971
972
973         /**
974          * Clone the DataTable nodes and place them in the DOM (sized correctly)
975          *  @returns {void}
976          *  @param   {Object} oClone Object containing the header, footer and body cloned DOM elements
977          *  @param   {Object} oGrid Grid object containing the display grid elements for the cloned
978          *                    column (left or right)
979          *  @param   {Array} aiColumns Column indexes which should be operated on from the DataTable
980          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
981          *  @private
982          */
983         "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
984         {
985                 var that = this,
986                         i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
987                         jqCloneThead, aoFixedHeader,
988                         dt = this.s.dt;
989
990                 /*
991                  * Header
992                  */
993                 if ( bAll )
994                 {
995                         if ( oClone.header !== null )
996                         {
997                                 oClone.header.parentNode.removeChild( oClone.header );
998                         }
999                         oClone.header = $(this.dom.header).clone(true, true)[0];
1000                         oClone.header.className += " DTFC_Cloned";
1001                         oClone.header.style.width = "100%";
1002                         oGrid.head.appendChild( oClone.header );
1003
1004                         /* Copy the DataTables layout cache for the header for our floating column */
1005                         aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns );
1006                         jqCloneThead = $('>thead', oClone.header);
1007                         jqCloneThead.empty();
1008
1009                         /* Add the created cloned TR elements to the table */
1010                         for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
1011                         {
1012                                 jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
1013                         }
1014
1015                         /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
1016                          * calculations for us
1017                          */
1018                         dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
1019                 }
1020                 else
1021                 {
1022                         /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
1023                          * etc, we make a copy of the header from the DataTable again, but don't insert the
1024                          * cloned cells, just copy the classes across. To get the matching layout for the
1025                          * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
1026                          */
1027                         aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns );
1028                         aoFixedHeader=[];
1029
1030                         dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
1031
1032                         for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
1033                         {
1034                                 for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
1035                                 {
1036                                         aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
1037
1038                                         // If jQuery UI theming is used we need to copy those elements as well
1039                                         $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
1040                                                 this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
1041                                         } );
1042                                 }
1043                         }
1044                 }
1045                 this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
1046
1047                 /*
1048                  * Body
1049                  */
1050                 if ( this.s.sHeightMatch == 'auto' )
1051                 {
1052                         /* Remove any heights which have been applied already and let the browser figure it out */
1053                         $('>tbody>tr', that.dom.body).css('height', 'auto');
1054                 }
1055
1056                 if ( oClone.body !== null )
1057                 {
1058                         oClone.body.parentNode.removeChild( oClone.body );
1059                         oClone.body = null;
1060                 }
1061
1062                 oClone.body = $(this.dom.body).clone(true)[0];
1063                 oClone.body.className += " DTFC_Cloned";
1064                 oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
1065                 oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
1066                 if ( oClone.body.getAttribute('id') !== null )
1067                 {
1068                         oClone.body.removeAttribute('id');
1069                 }
1070
1071                 $('>thead>tr', oClone.body).empty();
1072                 $('>tfoot', oClone.body).remove();
1073
1074                 var nBody = $('tbody', oClone.body)[0];
1075                 $(nBody).empty();
1076                 if ( dt.aiDisplay.length > 0 )
1077                 {
1078                         /* Copy the DataTables' header elements to force the column width in exactly the
1079                          * same way that DataTables does it - have the header element, apply the width and
1080                          * colapse it down
1081                          */
1082                         var nInnerThead = $('>thead>tr', oClone.body)[0];
1083                         for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
1084                         {
1085                                 iColumn = aiColumns[iIndex];
1086
1087                                 nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
1088                                 nClone.innerHTML = "";
1089
1090                                 var oStyle = nClone.style;
1091                                 oStyle.paddingTop = "0";
1092                                 oStyle.paddingBottom = "0";
1093                                 oStyle.borderTopWidth = "0";
1094                                 oStyle.borderBottomWidth = "0";
1095                                 oStyle.height = 0;
1096                                 oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
1097
1098                                 nInnerThead.appendChild( nClone );
1099                         }
1100
1101                         /* Add in the tbody elements, cloning form the master table */
1102                         $('>tbody>tr', that.dom.body).each( function (z) {
1103                                 var n = this.cloneNode(false);
1104                                 n.removeAttribute('id');
1105                                 var i = that.s.dt.oFeatures.bServerSide===false ?
1106                                         that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
1107                                 var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
1108
1109                                 for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
1110                                 {
1111                                         iColumn = aiColumns[iIndex];
1112
1113                                         if ( aTds.length > 0 )
1114                                         {
1115                                                 nClone = $( aTds[iColumn] ).clone(true, true)[0];
1116                                                 n.appendChild( nClone );
1117                                         }
1118                                 }
1119                                 nBody.appendChild( n );
1120                         } );
1121                 }
1122                 else
1123                 {
1124                         $('>tbody>tr', that.dom.body).each( function (z) {
1125                                 nClone = this.cloneNode(true);
1126                                 nClone.className += ' DTFC_NoData';
1127                                 $('td', nClone).html('');
1128                                 nBody.appendChild( nClone );
1129                         } );
1130                 }
1131
1132                 oClone.body.style.width = "100%";
1133                 oClone.body.style.margin = "0";
1134                 oClone.body.style.padding = "0";
1135
1136                 // Interop with Scroller - need to use a height forcing element in the
1137                 // scrolling area in the same way that Scroller does in the body scroll.
1138                 if ( dt.oScroller !== undefined )
1139                 {
1140                         var scrollerForcer = dt.oScroller.dom.force;
1141
1142                         if ( ! oGrid.forcer ) {
1143                                 oGrid.forcer = scrollerForcer.cloneNode( true );
1144                                 oGrid.liner.appendChild( oGrid.forcer );
1145                         }
1146                         else {
1147                                 oGrid.forcer.style.height = scrollerForcer.style.height;
1148                         }
1149                 }
1150
1151                 oGrid.liner.appendChild( oClone.body );
1152
1153                 this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
1154
1155                 /*
1156                  * Footer
1157                  */
1158                 if ( dt.nTFoot !== null )
1159                 {
1160                         if ( bAll )
1161                         {
1162                                 if ( oClone.footer !== null )
1163                                 {
1164                                         oClone.footer.parentNode.removeChild( oClone.footer );
1165                                 }
1166                                 oClone.footer = $(this.dom.footer).clone(true, true)[0];
1167                                 oClone.footer.className += " DTFC_Cloned";
1168                                 oClone.footer.style.width = "100%";
1169                                 oGrid.foot.appendChild( oClone.footer );
1170
1171                                 /* Copy the footer just like we do for the header */
1172                                 aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns );
1173                                 var jqCloneTfoot = $('>tfoot', oClone.footer);
1174                                 jqCloneTfoot.empty();
1175
1176                                 for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
1177                                 {
1178                                         jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
1179                                 }
1180                                 dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
1181                         }
1182                         else
1183                         {
1184                                 aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns );
1185                                 var aoCurrFooter=[];
1186
1187                                 dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
1188
1189                                 for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
1190                                 {
1191                                         for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
1192                                         {
1193                                                 aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
1194                                         }
1195                                 }
1196                         }
1197                         this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
1198                 }
1199
1200                 /* Equalise the column widths between the header footer and body - body get's priority */
1201                 var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
1202                 $(anUnique).each( function (i) {
1203                         iColumn = aiColumns[i];
1204                         this.style.width = that.s.aiInnerWidths[iColumn]+"px";
1205                 } );
1206
1207                 if ( that.s.dt.nTFoot !== null )
1208                 {
1209                         anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
1210                         $(anUnique).each( function (i) {
1211                                 iColumn = aiColumns[i];
1212                                 this.style.width = that.s.aiInnerWidths[iColumn]+"px";
1213                         } );
1214                 }
1215         },
1216
1217
1218         /**
1219          * From a given table node (THEAD etc), get a list of TR direct child elements
1220          *  @param   {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
1221          *  @returns {Array} List of TR elements found
1222          *  @private
1223          */
1224         "_fnGetTrNodes": function ( nIn )
1225         {
1226                 var aOut = [];
1227                 for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
1228                 {
1229                         if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
1230                         {
1231                                 aOut.push( nIn.childNodes[i] );
1232                         }
1233                 }
1234                 return aOut;
1235         },
1236
1237
1238         /**
1239          * Equalise the heights of the rows in a given table node in a cross browser way
1240          *  @returns {void}
1241          *  @param   {String} nodeName Node type - thead, tbody or tfoot
1242          *  @param   {Node} original Original node to take the heights from
1243          *  @param   {Node} clone Copy the heights to
1244          *  @private
1245          */
1246         "_fnEqualiseHeights": function ( nodeName, original, clone )
1247         {
1248                 if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
1249                 {
1250                         return;
1251                 }
1252
1253                 var that = this,
1254                         i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
1255                         rootOriginal = original.getElementsByTagName(nodeName)[0],
1256                         rootClone    = clone.getElementsByTagName(nodeName)[0],
1257                         jqBoxHack    = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
1258                         iBoxHack     = jqBoxHack.outerHeight() - jqBoxHack.height(),
1259                         anOriginal   = this._fnGetTrNodes( rootOriginal ),
1260                         anClone      = this._fnGetTrNodes( rootClone ),
1261                         heights      = [];
1262
1263                 for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
1264                 {
1265                         iHeightOriginal = anOriginal[i].offsetHeight;
1266                         iHeightClone = anClone[i].offsetHeight;
1267                         iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
1268
1269                         if ( this.s.sHeightMatch == 'semiauto' )
1270                         {
1271                                 anOriginal[i]._DTTC_iHeight = iHeight;
1272                         }
1273
1274                         heights.push( iHeight );
1275                 }
1276
1277                 for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
1278                 {
1279                         anClone[i].style.height = heights[i]+"px";
1280                         anOriginal[i].style.height = heights[i]+"px";
1281                 }
1282         }
1283 };
1284
1285
1286
1287 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1288  * Statics
1289  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1290
1291 /**
1292  * FixedColumns default settings for initialisation
1293  *  @name FixedColumns.defaults
1294  *  @namespace
1295  *  @static
1296  */
1297 FixedColumns.defaults = /** @lends FixedColumns.defaults */{
1298         /**
1299          * Number of left hand columns to fix in position
1300          *  @type     int
1301          *  @default  1
1302          *  @static
1303          *  @example
1304          *      var  = $('#example').dataTable( {
1305          *          "scrollX": "100%"
1306          *      } );
1307          *      new $.fn.dataTable.fixedColumns( table, {
1308          *          "leftColumns": 2
1309          *      } );
1310          */
1311         "iLeftColumns": 1,
1312
1313         /**
1314          * Number of right hand columns to fix in position
1315          *  @type     int
1316          *  @default  0
1317          *  @static
1318          *  @example
1319          *      var table = $('#example').dataTable( {
1320          *          "scrollX": "100%"
1321          *      } );
1322          *      new $.fn.dataTable.fixedColumns( table, {
1323          *          "rightColumns": 1
1324          *      } );
1325          */
1326         "iRightColumns": 0,
1327
1328         /**
1329          * Draw callback function which is called when FixedColumns has redrawn the fixed assets
1330          *  @type     function(object, object):void
1331          *  @default  null
1332          *  @static
1333          *  @example
1334          *      var table = $('#example').dataTable( {
1335          *          "scrollX": "100%"
1336          *      } );
1337          *      new $.fn.dataTable.fixedColumns( table, {
1338          *          "drawCallback": function () {
1339          *                  alert( "FixedColumns redraw" );
1340          *              }
1341          *      } );
1342          */
1343         "fnDrawCallback": null,
1344
1345         /**
1346          * Height matching algorthim to use. This can be "none" which will result in no height
1347          * matching being applied by FixedColumns (height matching could be forced by CSS in this
1348          * case), "semiauto" whereby the height calculation will be performed once, and the result
1349          * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
1350          * "auto" when height matching is performed on every draw (slowest but must accurate)
1351          *  @type     string
1352          *  @default  semiauto
1353          *  @static
1354          *  @example
1355          *      var table = $('#example').dataTable( {
1356          *          "scrollX": "100%"
1357          *      } );
1358          *      new $.fn.dataTable.fixedColumns( table, {
1359          *          "heightMatch": "auto"
1360          *      } );
1361          */
1362         "sHeightMatch": "semiauto"
1363 };
1364
1365
1366
1367
1368 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1369  * Constants
1370  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1371
1372 /**
1373  * FixedColumns version
1374  *  @name      FixedColumns.version
1375  *  @type      String
1376  *  @default   See code
1377  *  @static
1378  */
1379 FixedColumns.version = "3.0.4";
1380
1381
1382
1383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1384  * Fired events (for documentation)
1385  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1386
1387
1388 /**
1389  * Event fired whenever FixedColumns redraws the fixed columns (i.e. clones the table elements from the main DataTable). This will occur whenever the DataTable that the FixedColumns instance is attached does its own draw.
1390  * @name FixedColumns#draw.dtfc
1391  * @event
1392  * @param {event} e jQuery event object
1393  * @param {object} o Event parameters from FixedColumns
1394  * @param {object} o.leftClone Instance's object dom.clone.left for easy reference. This object contains references to the left fixed clumn column's nodes
1395  * @param {object} o.rightClone Instance's object dom.clone.right for easy reference. This object contains references to the right fixed clumn column's nodes
1396  */
1397
1398
1399 // Make FixedColumns accessible from the DataTables instance
1400 $.fn.dataTable.FixedColumns = FixedColumns;
1401 $.fn.DataTable.FixedColumns = FixedColumns;
1402
1403
1404 return FixedColumns;
1405 }; // /factory
1406
1407
1408 // Define as an AMD module if possible
1409 if ( typeof define === 'function' && define.amd ) {
1410         define( ['jquery', 'datatables'], factory );
1411 }
1412 else if ( typeof exports === 'object' ) {
1413     // Node/CommonJS
1414     factory( require('jquery'), require('datatables') );
1415 }
1416 else if ( jQuery && !jQuery.fn.dataTable.FixedColumns ) {
1417         // Otherwise simply initialise as normal, stopping multiple evaluation
1418         factory( jQuery, jQuery.fn.dataTable );
1419 }
1420
1421
1422 })(window, document);
1423