source: public/vendors/dataTable/FixedColumns-3.3.0/js/dataTables.fixedColumns.js@ 79aa35c

Last change on this file since 79aa35c was 7304c7f, checked in by beratkjufliju <kufliju@…>, 3 years ago

added user authentication, create & forgot password methods and blades

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