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