]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/static/AdminLTE-2.3.7/plugins/datatables/extensions/FixedColumns/js/dataTables.fixedColumns.js
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / pybind / mgr / dashboard / static / AdminLTE-2.3.7 / plugins / datatables / extensions / FixedColumns / js / dataTables.fixedColumns.js
CommitLineData
31f18b77
FG
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
28var 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 */
61var 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
286FixedColumns.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 */
1297FixedColumns.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 */
1379FixedColumns.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
1404return FixedColumns;
1405}; // /factory
1406
1407
1408// Define as an AMD module if possible
1409if ( typeof define === 'function' && define.amd ) {
1410 define( ['jquery', 'datatables'], factory );
1411}
1412else if ( typeof exports === 'object' ) {
1413 // Node/CommonJS
1414 factory( require('jquery'), require('datatables') );
1415}
1416else 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