Subversion-Projekte lars-tiefland.zeldi.de_alt

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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