about summary refs log tree commit diff
diff options
context:
space:
mode:
authorzsloan2015-07-23 16:20:55 +0000
committerzsloan2015-07-23 16:20:55 +0000
commitc053ff453e6c8354e61b227d028378712ab240d6 (patch)
tree1b754cb3c1e6670c9078c799b0990313169b54d1
parent1e190b22c35c5a7d71eafa8c7136fd9b8cbd0688 (diff)
downloadgenenetwork2-c053ff453e6c8354e61b227d028378712ab240d6.tar.gz
Committing most recent changes to tables so Lei can pull; still have a few more issues to resolve, like setting initial column width
-rw-r--r--wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js1372
-rw-r--r--wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js1669
-rw-r--r--wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css4
-rw-r--r--wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js1027
-rwxr-xr-xwqflask/wqflask/templates/correlation_page.html27
-rwxr-xr-xwqflask/wqflask/templates/search_result_page.html55
-rwxr-xr-xwqflask/wqflask/templates/show_trait.html131
-rwxr-xr-xwqflask/wqflask/templates/show_trait_edit_data.html25
8 files changed, 3417 insertions, 893 deletions
diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js
new file mode 100644
index 00000000..58e7656e
--- /dev/null
+++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js
@@ -0,0 +1,1372 @@
+/*! ColReorder 1.1.3
+ * ©2010-2014 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary     ColReorder
+ * @description Provide the ability to reorder columns in a DataTable
+ * @version     1.1.3
+ * @file        dataTables.colReorder.js
+ * @author      SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact     www.sprymedia.co.uk/contact
+ * @copyright   Copyright 2010-2014 SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ *   MIT license - http://datatables.net/license/mit
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+(function(window, document, undefined) {
+
+
+/**
+ * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
+ * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
+ *  @method  fnInvertKeyValues
+ *  @param   array aIn Array to switch around
+ *  @returns array
+ */
+function fnInvertKeyValues( aIn )
+{
+	var aRet=[];
+	for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
+	{
+		aRet[ aIn[i] ] = i;
+	}
+	return aRet;
+}
+
+
+/**
+ * Modify an array by switching the position of two elements
+ *  @method  fnArraySwitch
+ *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)
+ *  @param   int iFrom From point
+ *  @param   int iTo Insert point
+ *  @returns void
+ */
+function fnArraySwitch( aArray, iFrom, iTo )
+{
+	var mStore = aArray.splice( iFrom, 1 )[0];
+	aArray.splice( iTo, 0, mStore );
+}
+
+
+/**
+ * Switch the positions of nodes in a parent node (note this is specifically designed for
+ * table rows). Note this function considers all element nodes under the parent!
+ *  @method  fnDomSwitch
+ *  @param   string sTag Tag to consider
+ *  @param   int iFrom Element to move
+ *  @param   int Point to element the element to (before this point), can be null for append
+ *  @returns void
+ */
+function fnDomSwitch( nParent, iFrom, iTo )
+{
+	var anTags = [];
+	for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
+	{
+		if ( nParent.childNodes[i].nodeType == 1 )
+		{
+			anTags.push( nParent.childNodes[i] );
+		}
+	}
+	var nStore = anTags[ iFrom ];
+
+	if ( iTo !== null )
+	{
+		nParent.insertBefore( nStore, anTags[iTo] );
+	}
+	else
+	{
+		nParent.appendChild( nStore );
+	}
+}
+
+
+
+var factory = function( $, DataTable ) {
+"use strict";
+
+/**
+ * Plug-in for DataTables which will reorder the internal column structure by taking the column
+ * from one position (iFrom) and insert it into a given point (iTo).
+ *  @method  $.fn.dataTableExt.oApi.fnColReorder
+ *  @param   object oSettings DataTables settings object - automatically added by DataTables!
+ *  @param   int iFrom Take the column to be repositioned from this point
+ *  @param   int iTo and insert it into this point
+ *  @returns void
+ */
+$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo )
+{
+	var v110 = $.fn.dataTable.Api ? true : false;
+	var i, iLen, j, jLen, iCols=oSettings.aoColumns.length, nTrs, oCol;
+	var attrMap = function ( obj, prop, mapping ) {
+		if ( ! obj[ prop ] ) {
+			return;
+		}
+
+		var a = obj[ prop ].split('.');
+		var num = a.shift();
+
+		if ( isNaN( num*1 ) ) {
+			return;
+		}
+
+		obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
+	};
+
+	/* Sanity check in the input */
+	if ( iFrom == iTo )
+	{
+		/* Pointless reorder */
+		return;
+	}
+
+	if ( iFrom < 0 || iFrom >= iCols )
+	{
+		this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
+		return;
+	}
+
+	if ( iTo < 0 || iTo >= iCols )
+	{
+		this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
+		return;
+	}
+
+	/*
+	 * Calculate the new column array index, so we have a mapping between the old and new
+	 */
+	var aiMapping = [];
+	for ( i=0, iLen=iCols ; i<iLen ; i++ )
+	{
+		aiMapping[i] = i;
+	}
+	fnArraySwitch( aiMapping, iFrom, iTo );
+	var aiInvertMapping = fnInvertKeyValues( aiMapping );
+
+
+	/*
+	 * Convert all internal indexing to the new column order indexes
+	 */
+	/* Sorting */
+	for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
+	{
+		oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
+	}
+
+	/* Fixed sorting */
+	if ( oSettings.aaSortingFixed !== null )
+	{
+		for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
+		{
+			oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
+		}
+	}
+
+	/* Data column sorting (the column which the sort for a given column should take place on) */
+	for ( i=0, iLen=iCols ; i<iLen ; i++ )
+	{
+		oCol = oSettings.aoColumns[i];
+		for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
+		{
+			oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
+		}
+
+		// Update the column indexes
+		if ( v110 ) {
+			oCol.idx = aiInvertMapping[ oCol.idx ];
+		}
+	}
+
+	if ( v110 ) {
+		// Update 1.10 optimised sort class removal variable
+		$.each( oSettings.aLastSort, function (i, val) {
+			oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
+		} );
+	}
+
+	/* Update the Get and Set functions for each column */
+	for ( i=0, iLen=iCols ; i<iLen ; i++ )
+	{
+		oCol = oSettings.aoColumns[i];
+
+		if ( typeof oCol.mData == 'number' ) {
+			oCol.mData = aiInvertMapping[ oCol.mData ];
+
+			// regenerate the get / set functions
+			oSettings.oApi._fnColumnOptions( oSettings, i, {} );
+		}
+		else if ( $.isPlainObject( oCol.mData ) ) {
+			// HTML5 data sourced
+			attrMap( oCol.mData, '_',      aiInvertMapping );
+			attrMap( oCol.mData, 'filter', aiInvertMapping );
+			attrMap( oCol.mData, 'sort',   aiInvertMapping );
+			attrMap( oCol.mData, 'type',   aiInvertMapping );
+
+			// regenerate the get / set functions
+			oSettings.oApi._fnColumnOptions( oSettings, i, {} );
+		}
+	}
+
+
+	/*
+	 * Move the DOM elements
+	 */
+	if ( oSettings.aoColumns[iFrom].bVisible )
+	{
+		/* Calculate the current visible index and the point to insert the node before. The insert
+		 * before needs to take into account that there might not be an element to insert before,
+		 * in which case it will be null, and an appendChild should be used
+		 */
+		var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
+		var iInsertBeforeIndex = null;
+
+		i = iTo < iFrom ? iTo : iTo + 1;
+		while ( iInsertBeforeIndex === null && i < iCols )
+		{
+			iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
+			i++;
+		}
+
+		/* Header */
+		nTrs = oSettings.nTHead.getElementsByTagName('tr');
+		for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+		{
+			fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
+		}
+
+		/* Footer */
+		if ( oSettings.nTFoot !== null )
+		{
+			nTrs = oSettings.nTFoot.getElementsByTagName('tr');
+			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+			{
+				fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
+			}
+		}
+
+		/* Body */
+		for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+		{
+			if ( oSettings.aoData[i].nTr !== null )
+			{
+				fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
+			}
+		}
+	}
+
+	/*
+	 * Move the internal array elements
+	 */
+	/* Columns */
+	fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
+
+	/* Search columns */
+	fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
+
+	/* Array array - internal data anodes cache */
+	for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+	{
+		var data = oSettings.aoData[i];
+
+		if ( v110 ) {
+			// DataTables 1.10+
+			if ( data.anCells ) {
+				fnArraySwitch( data.anCells, iFrom, iTo );
+			}
+
+			// For DOM sourced data, the invalidate will reread the cell into
+			// the data array, but for data sources as an array, they need to
+			// be flipped
+			if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
+				fnArraySwitch( data._aData, iFrom, iTo );
+			}
+		}
+		else {
+			// DataTables 1.9-
+			if ( $.isArray( data._aData ) ) {
+				fnArraySwitch( data._aData, iFrom, iTo );
+			}
+			fnArraySwitch( data._anHidden, iFrom, iTo );
+		}
+	}
+
+	/* Reposition the header elements in the header layout array */
+	for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
+	{
+		fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
+	}
+
+	if ( oSettings.aoFooter !== null )
+	{
+		for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
+		{
+			fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
+		}
+	}
+
+	// In 1.10 we need to invalidate row cached data for sorting, filtering etc
+	if ( v110 ) {
+		var api = new $.fn.dataTable.Api( oSettings );
+		api.rows().invalidate();
+	}
+
+	/*
+	 * Update DataTables' event handlers
+	 */
+
+	/* Sort listener */
+	for ( i=0, iLen=iCols ; i<iLen ; i++ )
+	{
+		$(oSettings.aoColumns[i].nTh).off('click.DT');
+		this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
+	}
+
+
+	/* Fire an event so other plug-ins can update */
+	$(oSettings.oInstance).trigger( 'column-reorder', [ oSettings, {
+		"iFrom": iFrom,
+		"iTo": iTo,
+		"aiInvertMapping": aiInvertMapping
+	} ] );
+};
+
+
+/**
+ * ColReorder provides column visibility control for DataTables
+ * @class ColReorder
+ * @constructor
+ * @param {object} dt DataTables settings object
+ * @param {object} opts ColReorder options
+ */
+var ColReorder = function( dt, opts )
+{
+	var oDTSettings;
+
+	if ( $.fn.dataTable.Api ) {
+		oDTSettings = new $.fn.dataTable.Api( dt ).settings()[0];
+	}
+	// 1.9 compatibility
+	else if ( dt.fnSettings ) {
+		// DataTables object, convert to the settings object
+		oDTSettings = dt.fnSettings();
+	}
+	else if ( typeof dt === 'string' ) {
+		// jQuery selector
+		if ( $.fn.dataTable.fnIsDataTable( $(dt)[0] ) ) {
+			oDTSettings = $(dt).eq(0).dataTable().fnSettings();
+		}
+	}
+	else if ( dt.nodeName && dt.nodeName.toLowerCase() === 'table' ) {
+		// Table node
+		if ( $.fn.dataTable.fnIsDataTable( dt.nodeName ) ) {
+			oDTSettings = $(dt.nodeName).dataTable().fnSettings();
+		}
+	}
+	else if ( dt instanceof jQuery ) {
+		// jQuery object
+		if ( $.fn.dataTable.fnIsDataTable( dt[0] ) ) {
+			oDTSettings = dt.eq(0).dataTable().fnSettings();
+		}
+	}
+	else {
+		// DataTables settings object
+		oDTSettings = dt;
+	}
+
+	// Ensure that we can't initialise on the same table twice
+	if ( oDTSettings._colReorder ) {
+		throw "ColReorder already initialised on table #"+oDTSettings.nTable.id;
+	}
+
+	// Convert from camelCase to Hungarian, just as DataTables does
+	var camelToHungarian = $.fn.dataTable.camelToHungarian;
+	if ( camelToHungarian ) {
+		camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
+		camelToHungarian( ColReorder.defaults, opts || {} );
+	}
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Public class variables
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	/**
+	 * @namespace Settings object which contains customisable information for ColReorder instance
+	 */
+	this.s = {
+		/**
+		 * DataTables settings object
+		 *  @property dt
+		 *  @type     Object
+		 *  @default  null
+		 */
+		"dt": null,
+
+		/**
+		 * Initialisation object used for this instance
+		 *  @property init
+		 *  @type     object
+		 *  @default  {}
+		 */
+		"init": $.extend( true, {}, ColReorder.defaults, opts ),
+
+		/**
+		 * Number of columns to fix (not allow to be reordered)
+		 *  @property fixed
+		 *  @type     int
+		 *  @default  0
+		 */
+		"fixed": 0,
+
+		/**
+		 * Number of columns to fix counting from right (not allow to be reordered)
+		 *  @property fixedRight
+		 *  @type     int
+		 *  @default  0
+		 */
+		"fixedRight": 0,
+
+		/**
+		 * Callback function for once the reorder has been done
+		 *  @property reorderCallback
+		 *  @type     function
+		 *  @default  null
+		 */
+		"reorderCallback": null,
+
+		/**
+		 * @namespace Information used for the mouse drag
+		 */
+		"mouse": {
+			"startX": -1,
+			"startY": -1,
+			"offsetX": -1,
+			"offsetY": -1,
+			"target": -1,
+			"targetIndex": -1,
+			"fromIndex": -1
+		},
+
+		/**
+		 * Information which is used for positioning the insert cusor and knowing where to do the
+		 * insert. Array of objects with the properties:
+		 *   x: x-axis position
+		 *   to: insert point
+		 *  @property aoTargets
+		 *  @type     array
+		 *  @default  []
+		 */
+		"aoTargets": []
+	};
+
+
+	/**
+	 * @namespace Common and useful DOM elements for the class instance
+	 */
+	this.dom = {
+		/**
+		 * Dragging element (the one the mouse is moving)
+		 *  @property drag
+		 *  @type     element
+		 *  @default  null
+		 */
+		"drag": null,
+
+		/**
+		 * The insert cursor
+		 *  @property pointer
+		 *  @type     element
+		 *  @default  null
+		 */
+		"pointer": null
+	};
+
+
+	/* Constructor logic */
+	this.s.dt = oDTSettings;
+	this.s.dt._colReorder = this;
+	this._fnConstruct();
+
+	/* Add destroy callback */
+	oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColReorder');
+
+	return this;
+};
+
+
+
+ColReorder.prototype = {
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Public methods
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	/**
+	 * Reset the column ordering to the original ordering that was detected on
+	 * start up.
+	 *  @return {this} Returns `this` for chaining.
+	 *
+	 *  @example
+	 *    // DataTables initialisation with ColReorder
+	 *    var table = $('#example').dataTable( {
+	 *        "sDom": 'Rlfrtip'
+	 *    } );
+	 *
+	 *    // Add click event to a button to reset the ordering
+	 *    $('#resetOrdering').click( function (e) {
+	 *        e.preventDefault();
+	 *        $.fn.dataTable.ColReorder( table ).fnReset();
+	 *    } );
+	 */
+	"fnReset": function ()
+	{
+		var a = [];
+		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+		{
+			a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
+		}
+
+		this._fnOrderColumns( a );
+
+		return this;
+	},
+
+	/**
+	 * `Deprecated` - Get the current order of the columns, as an array.
+	 *  @return {array} Array of column identifiers
+	 *  @deprecated `fnOrder` should be used in preference to this method.
+	 *      `fnOrder` acts as a getter/setter.
+	 */
+	"fnGetCurrentOrder": function ()
+	{
+		return this.fnOrder();
+	},
+
+	/**
+	 * Get the current order of the columns, as an array. Note that the values
+	 * given in the array are unique identifiers for each column. Currently
+	 * these are the original ordering of the columns that was detected on
+	 * start up, but this could potentially change in future.
+	 *  @return {array} Array of column identifiers
+	 *
+	 *  @example
+	 *    // Get column ordering for the table
+	 *    var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
+	 *//**
+	 * Set the order of the columns, from the positions identified in the
+	 * ordering array given. Note that ColReorder takes a brute force approach
+	 * to reordering, so it is possible multiple reordering events will occur
+	 * before the final order is settled upon.
+	 *  @param {array} [set] Array of column identifiers in the new order. Note
+	 *    that every column must be included, uniquely, in this array.
+	 *  @return {this} Returns `this` for chaining.
+	 *
+	 *  @example
+	 *    // Swap the first and second columns
+	 *    $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
+	 *
+	 *  @example
+	 *    // Move the first column to the end for the table `#example`
+	 *    var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
+	 *    var first = curr.shift();
+	 *    curr.push( first );
+	 *    $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
+	 *
+	 *  @example
+	 *    // Reverse the table's order
+	 *    $.fn.dataTable.ColReorder( '#example' ).fnOrder(
+	 *      $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
+	 *    );
+	 */
+	"fnOrder": function ( set )
+	{
+		if ( set === undefined )
+		{
+			var a = [];
+			for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+			{
+				a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
+			}
+			return a;
+		}
+
+		this._fnOrderColumns( fnInvertKeyValues( set ) );
+
+		return this;
+	},
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Private methods (they are of course public in JS, but recommended as private)
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	/**
+	 * Constructor logic
+	 *  @method  _fnConstruct
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnConstruct": function ()
+	{
+		var that = this;
+		var iLen = this.s.dt.aoColumns.length;
+		var i;
+
+		/* Columns discounted from reordering - counting left to right */
+		if ( this.s.init.iFixedColumns )
+		{
+			this.s.fixed = this.s.init.iFixedColumns;
+		}
+
+		/* Columns discounted from reordering - counting right to left */
+		this.s.fixedRight = this.s.init.iFixedColumnsRight ?
+			this.s.init.iFixedColumnsRight :
+			0;
+
+		/* Drop callback initialisation option */
+		if ( this.s.init.fnReorderCallback )
+		{
+			this.s.reorderCallback = this.s.init.fnReorderCallback;
+		}
+
+		/* Add event handlers for the drag and drop, and also mark the original column order */
+		for ( i = 0; i < iLen; i++ )
+		{
+			if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
+			{
+				this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
+			}
+
+			/* Mark the original column order for later reference */
+			this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
+		}
+
+		/* State saving */
+		this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
+			that._fnStateSave.call( that, oData );
+		}, "ColReorder_State" );
+
+		/* An initial column order has been specified */
+		var aiOrder = null;
+		if ( this.s.init.aiOrder )
+		{
+			aiOrder = this.s.init.aiOrder.slice();
+		}
+
+		/* State loading, overrides the column order given */
+		if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
+		  this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
+		{
+			aiOrder = this.s.dt.oLoadedState.ColReorder;
+		}
+
+		/* If we have an order to apply - do so */
+		if ( aiOrder )
+		{
+			/* We might be called during or after the DataTables initialisation. If before, then we need
+			 * to wait until the draw is done, if after, then do what we need to do right away
+			 */
+			if ( !that.s.dt._bInitComplete )
+			{
+				var bDone = false;
+				this.s.dt.aoDrawCallback.push( {
+					"fn": function () {
+						if ( !that.s.dt._bInitComplete && !bDone )
+						{
+							bDone = true;
+							var resort = fnInvertKeyValues( aiOrder );
+							that._fnOrderColumns.call( that, resort );
+						}
+					},
+					"sName": "ColReorder_Pre"
+				} );
+			}
+			else
+			{
+				var resort = fnInvertKeyValues( aiOrder );
+				that._fnOrderColumns.call( that, resort );
+			}
+		}
+		else {
+			this._fnSetColumnIndexes();
+		}
+	},
+
+
+	/**
+	 * Set the column order from an array
+	 *  @method  _fnOrderColumns
+	 *  @param   array a An array of integers which dictate the column order that should be applied
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnOrderColumns": function ( a )
+	{
+		if ( a.length != this.s.dt.aoColumns.length )
+		{
+			this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
+				"match known number of columns. Skipping." );
+			return;
+		}
+
+		for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+		{
+			var currIndex = $.inArray( i, a );
+			if ( i != currIndex )
+			{
+				/* Reorder our switching array */
+				fnArraySwitch( a, currIndex, i );
+
+				/* Do the column reorder in the table */
+				this.s.dt.oInstance.fnColReorder( currIndex, i );
+			}
+		}
+
+		/* When scrolling we need to recalculate the column sizes to allow for the shift */
+		if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
+		{
+			this.s.dt.oInstance.fnAdjustColumnSizing( false );
+		}
+
+		/* Save the state */
+		this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
+
+		this._fnSetColumnIndexes();
+		
+		if ( this.s.reorderCallback !== null )
+		{
+			this.s.reorderCallback.call( this );
+		}
+	},
+
+
+	/**
+	 * Because we change the indexes of columns in the table, relative to their starting point
+	 * we need to reorder the state columns to what they are at the starting point so we can
+	 * then rearrange them again on state load!
+	 *  @method  _fnStateSave
+	 *  @param   object oState DataTables state
+	 *  @returns string JSON encoded cookie string for DataTables
+	 *  @private
+	 */
+	"_fnStateSave": function ( oState )
+	{
+		var i, iLen, aCopy, iOrigColumn;
+		var oSettings = this.s.dt;
+		var columns = oSettings.aoColumns;
+
+		oState.ColReorder = [];
+
+		/* Sorting */
+		if ( oState.aaSorting ) {
+			// 1.10.0-
+			for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
+				oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
+			}
+
+			var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
+
+			for ( i=0, iLen=columns.length ; i<iLen ; i++ )
+			{
+				iOrigColumn = columns[i]._ColReorder_iOrigCol;
+
+				/* Column filter */
+				oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
+
+				/* Visibility */
+				oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
+
+				/* Column reordering */
+				oState.ColReorder.push( iOrigColumn );
+			}
+		}
+		else if ( oState.order ) {
+			// 1.10.1+
+			for ( i=0 ; i<oState.order.length ; i++ ) {
+				oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
+			}
+
+			var stateColumnsCopy = $.extend( true, [], oState.columns );
+
+			for ( i=0, iLen=columns.length ; i<iLen ; i++ )
+			{
+				iOrigColumn = columns[i]._ColReorder_iOrigCol;
+
+				/* Columns */
+				oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
+
+				/* Column reordering */
+				oState.ColReorder.push( iOrigColumn );
+			}
+		}
+	},
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Mouse drop and drag
+	 */
+
+	/**
+	 * Add a mouse down listener to a particluar TH element
+	 *  @method  _fnMouseListener
+	 *  @param   int i Column index
+	 *  @param   element nTh TH element clicked on
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnMouseListener": function ( i, nTh )
+	{
+		var that = this;
+		$(nTh).on( 'mousedown.ColReorder', function (e) {
+			e.preventDefault();
+			that._fnMouseDown.call( that, e, nTh );
+		} );
+	},
+
+
+	/**
+	 * Mouse down on a TH element in the table header
+	 *  @method  _fnMouseDown
+	 *  @param   event e Mouse event
+	 *  @param   element nTh TH element to be dragged
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnMouseDown": function ( e, nTh )
+	{
+		var that = this;
+
+		/* Store information about the mouse position */
+		var target = $(e.target).closest('th, td');
+		var offset = target.offset();
+		var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
+
+		if ( idx === undefined ) {
+			return;
+		}
+
+		this.s.mouse.startX = e.pageX;
+		this.s.mouse.startY = e.pageY;
+		this.s.mouse.offsetX = e.pageX - offset.left;
+		this.s.mouse.offsetY = e.pageY - offset.top;
+		this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
+		this.s.mouse.targetIndex = idx;
+		this.s.mouse.fromIndex = idx;
+
+		this._fnRegions();
+
+		/* Add event handlers to the document */
+		$(document)
+			.on( 'mousemove.ColReorder', function (e) {
+				that._fnMouseMove.call( that, e );
+			} )
+			.on( 'mouseup.ColReorder', function (e) {
+				that._fnMouseUp.call( that, e );
+			} );
+	},
+
+
+	/**
+	 * Deal with a mouse move event while dragging a node
+	 *  @method  _fnMouseMove
+	 *  @param   event e Mouse event
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnMouseMove": function ( e )
+	{
+		var that = this;
+
+		if ( this.dom.drag === null )
+		{
+			/* Only create the drag element if the mouse has moved a specific distance from the start
+			 * point - this allows the user to make small mouse movements when sorting and not have a
+			 * possibly confusing drag element showing up
+			 */
+			if ( Math.pow(
+				Math.pow(e.pageX - this.s.mouse.startX, 2) +
+				Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 )
+			{
+				return;
+			}
+			this._fnCreateDragNode();
+		}
+
+		/* Position the element - we respect where in the element the click occured */
+		this.dom.drag.css( {
+			left: e.pageX - this.s.mouse.offsetX,
+			top: e.pageY - this.s.mouse.offsetY
+		} );
+
+		/* Based on the current mouse position, calculate where the insert should go */
+		var bSet = false;
+		var lastToIndex = this.s.mouse.toIndex;
+
+		for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
+		{
+			if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
+			{
+				this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );
+				this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
+				bSet = true;
+				break;
+			}
+		}
+
+		// The insert element wasn't positioned in the array (less than
+		// operator), so we put it at the end
+		if ( !bSet )
+		{
+			this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );
+			this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
+		}
+
+		// Perform reordering if realtime updating is on and the column has moved
+		if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
+			this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
+			this.s.mouse.fromIndex = this.s.mouse.toIndex;
+			this._fnRegions();
+		}
+	},
+
+
+	/**
+	 * Finish off the mouse drag and insert the column where needed
+	 *  @method  _fnMouseUp
+	 *  @param   event e Mouse event
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnMouseUp": function ( e )
+	{
+		var that = this;
+
+		$(document).off( 'mousemove.ColReorder mouseup.ColReorder' );
+
+		if ( this.dom.drag !== null )
+		{
+			/* Remove the guide elements */
+			this.dom.drag.remove();
+			this.dom.pointer.remove();
+			this.dom.drag = null;
+			this.dom.pointer = null;
+
+			/* Actually do the reorder */
+			this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
+			this._fnSetColumnIndexes();
+
+			/* When scrolling we need to recalculate the column sizes to allow for the shift */
+			if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
+			{
+				this.s.dt.oInstance.fnAdjustColumnSizing( false );
+			}
+
+			/* Save the state */
+			this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
+
+			if ( this.s.reorderCallback !== null )
+			{
+				this.s.reorderCallback.call( this );
+			}
+		}
+	},
+
+
+	/**
+	 * Calculate a cached array with the points of the column inserts, and the
+	 * 'to' points
+	 *  @method  _fnRegions
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnRegions": function ()
+	{
+		var aoColumns = this.s.dt.aoColumns;
+
+		this.s.aoTargets.splice( 0, this.s.aoTargets.length );
+
+		this.s.aoTargets.push( {
+			"x":  $(this.s.dt.nTable).offset().left,
+			"to": 0
+		} );
+
+		var iToPoint = 0;
+		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
+		{
+			/* For the column / header in question, we want it's position to remain the same if the
+			 * position is just to it's immediate left or right, so we only incremement the counter for
+			 * other columns
+			 */
+			if ( i != this.s.mouse.fromIndex )
+			{
+				iToPoint++;
+			}
+
+			if ( aoColumns[i].bVisible )
+			{
+				this.s.aoTargets.push( {
+					"x":  $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
+					"to": iToPoint
+				} );
+			}
+		}
+
+		/* Disallow columns for being reordered by drag and drop, counting right to left */
+		if ( this.s.fixedRight !== 0 )
+		{
+			this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
+		}
+
+		/* Disallow columns for being reordered by drag and drop, counting left to right */
+		if ( this.s.fixed !== 0 )
+		{
+			this.s.aoTargets.splice( 0, this.s.fixed );
+		}
+	},
+
+
+	/**
+	 * Copy the TH element that is being drags so the user has the idea that they are actually
+	 * moving it around the page.
+	 *  @method  _fnCreateDragNode
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnCreateDragNode": function ()
+	{
+		var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
+
+		var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
+		var origTr = origCell.parentNode;
+		var origThead = origTr.parentNode;
+		var origTable = origThead.parentNode;
+		var cloneCell = $(origCell).clone();
+
+		// This is a slightly odd combination of jQuery and DOM, but it is the
+		// fastest and least resource intensive way I could think of cloning
+		// the table with just a single header cell in it.
+		this.dom.drag = $(origTable.cloneNode(false))
+			.addClass( 'DTCR_clonedTable' )
+			.append(
+				$(origThead.cloneNode(false)).append(
+					$(origTr.cloneNode(false)).append(
+						cloneCell[0]
+					)
+				)
+			)
+			.css( {
+				position: 'absolute',
+				top: 0,
+				left: 0,
+				width: $(origCell).outerWidth(),
+				height: $(origCell).outerHeight()
+			} )
+			.appendTo( 'body' );
+
+		this.dom.pointer = $('<div></div>')
+			.addClass( 'DTCR_pointer' )
+			.css( {
+				position: 'absolute',
+				top: scrolling ?
+					$('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
+					$(this.s.dt.nTable).offset().top,
+				height : scrolling ?
+					$('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
+					$(this.s.dt.nTable).height()
+			} )
+			.appendTo( 'body' );
+	},
+
+	/**
+	 * Clean up ColReorder memory references and event handlers
+	 *  @method  _fnDestroy
+	 *  @returns void
+	 *  @private
+	 */
+	"_fnDestroy": function ()
+	{
+		var i, iLen;
+
+		for ( i=0, iLen=this.s.dt.aoDrawCallback.length ; i<iLen ; i++ )
+		{
+			if ( this.s.dt.aoDrawCallback[i].sName === 'ColReorder_Pre' )
+			{
+				this.s.dt.aoDrawCallback.splice( i, 1 );
+				break;
+			}
+		}
+
+		$(this.s.dt.nTHead).find( '*' ).off( '.ColReorder' );
+
+		$.each( this.s.dt.aoColumns, function (i, column) {
+			$(column.nTh).removeAttr('data-column-index');
+		} );
+
+		this.s.dt._colReorder = null;
+		this.s = null;
+	},
+
+
+	/**
+	 * Add a data attribute to the column headers, so we know the index of
+	 * the row to be reordered. This allows fast detection of the index, and
+	 * for this plug-in to work with FixedHeader which clones the nodes.
+	 *  @private
+	 */
+	"_fnSetColumnIndexes": function ()
+	{
+		$.each( this.s.dt.aoColumns, function (i, column) {
+			$(column.nTh).attr('data-column-index', i);
+		} );
+	}
+};
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Static parameters
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/**
+ * ColReorder default settings for initialisation
+ *  @namespace
+ *  @static
+ */
+ColReorder.defaults = {
+	/**
+	 * Predefined ordering for the columns that will be applied automatically
+	 * on initialisation. If not specified then the order that the columns are
+	 * found to be in the HTML is the order used.
+	 *  @type array
+	 *  @default null
+	 *  @static
+	 *  @example
+	 *      // Using the `oColReorder` option in the DataTables options object
+	 *      $('#example').dataTable( {
+	 *          "sDom": 'Rlfrtip',
+	 *          "oColReorder": {
+	 *              "aiOrder": [ 4, 3, 2, 1, 0 ]
+	 *          }
+	 *      } );
+	 *
+	 *  @example
+	 *      // Using `new` constructor
+	 *      $('#example').dataTable()
+	 *
+	 *      new $.fn.dataTable.ColReorder( '#example', {
+	 *          "aiOrder": [ 4, 3, 2, 1, 0 ]
+	 *      } );
+	 */
+	aiOrder: null,
+
+	/**
+	 * Redraw the table's column ordering as the end user draws the column
+	 * (`true`) or wait until the mouse is released (`false` - default). Note
+	 * that this will perform a redraw on each reordering, which involves an
+	 * Ajax request each time if you are using server-side processing in
+	 * DataTables.
+	 *  @type boolean
+	 *  @default false
+	 *  @static
+	 *  @example
+	 *      // Using the `oColReorder` option in the DataTables options object
+	 *      $('#example').dataTable( {
+	 *          "sDom": 'Rlfrtip',
+	 *          "oColReorder": {
+	 *              "bRealtime": true
+	 *          }
+	 *      } );
+	 *
+	 *  @example
+	 *      // Using `new` constructor
+	 *      $('#example').dataTable()
+	 *
+	 *      new $.fn.dataTable.ColReorder( '#example', {
+	 *          "bRealtime": true
+	 *      } );
+	 */
+	bRealtime: false,
+
+	/**
+	 * Indicate how many columns should be fixed in position (counting from the
+	 * left). This will typically be 1 if used, but can be as high as you like.
+	 *  @type int
+	 *  @default 0
+	 *  @static
+	 *  @example
+	 *      // Using the `oColReorder` option in the DataTables options object
+	 *      $('#example').dataTable( {
+	 *          "sDom": 'Rlfrtip',
+	 *          "oColReorder": {
+	 *              "iFixedColumns": 1
+	 *          }
+	 *      } );
+	 *
+	 *  @example
+	 *      // Using `new` constructor
+	 *      $('#example').dataTable()
+	 *
+	 *      new $.fn.dataTable.ColReorder( '#example', {
+	 *          "iFixedColumns": 1
+	 *      } );
+	 */
+	iFixedColumns: 0,
+
+	/**
+	 * As `iFixedColumnsRight` but counting from the right.
+	 *  @type int
+	 *  @default 0
+	 *  @static
+	 *  @example
+	 *      // Using the `oColReorder` option in the DataTables options object
+	 *      $('#example').dataTable( {
+	 *          "sDom": 'Rlfrtip',
+	 *          "oColReorder": {
+	 *              "iFixedColumnsRight": 1
+	 *          }
+	 *      } );
+	 *
+	 *  @example
+	 *      // Using `new` constructor
+	 *      $('#example').dataTable()
+	 *
+	 *      new $.fn.dataTable.ColReorder( '#example', {
+	 *          "iFixedColumnsRight": 1
+	 *      } );
+	 */
+	iFixedColumnsRight: 0,
+
+	/**
+	 * Callback function that is fired when columns are reordered
+	 *  @type function():void
+	 *  @default null
+	 *  @static
+	 *  @example
+	 *      // Using the `oColReorder` option in the DataTables options object
+	 *      $('#example').dataTable( {
+	 *          "sDom": 'Rlfrtip',
+	 *          "oColReorder": {
+	 *              "fnReorderCallback": function () {
+	 *                  alert( 'Columns reordered' );
+	 *              }
+	 *          }
+	 *      } );
+	 *
+	 *  @example
+	 *      // Using `new` constructor
+	 *      $('#example').dataTable()
+	 *
+	 *      new $.fn.dataTable.ColReorder( '#example', {
+	 *          "fnReorderCallback": function () {
+	 *              alert( 'Columns reordered' );
+	 *          }
+	 *      } );
+	 */
+	fnReorderCallback: null
+};
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Constants
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/**
+ * ColReorder version
+ *  @constant  version
+ *  @type      String
+ *  @default   As code
+ */
+ColReorder.version = "1.1.3";
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables interfaces
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Expose
+$.fn.dataTable.ColReorder = ColReorder;
+$.fn.DataTable.ColReorder = ColReorder;
+
+
+// Register a new feature with DataTables
+if ( typeof $.fn.dataTable == "function" &&
+     typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
+     $.fn.dataTableExt.fnVersionCheck('1.9.3') )
+{
+	$.fn.dataTableExt.aoFeatures.push( {
+		"fnInit": function( settings ) {
+			var table = settings.oInstance;
+
+			if ( ! settings._colReorder ) {
+				var dtInit = settings.oInit;
+				var opts = dtInit.colReorder || dtInit.oColReorder || {};
+
+				new ColReorder( settings, opts );
+			}
+			else {
+				table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
+			}
+
+			return null; /* No node for DataTables to insert */
+		},
+		"cFeature": "R",
+		"sFeature": "ColReorder"
+	} );
+}
+else {
+	alert( "Warning: ColReorder requires DataTables 1.9.3 or greater - www.datatables.net/download");
+}
+
+
+// API augmentation
+if ( $.fn.dataTable.Api ) {
+	$.fn.dataTable.Api.register( 'colReorder.reset()', function () {
+		return this.iterator( 'table', function ( ctx ) {
+			ctx._colReorder.fnReset();
+		} );
+	} );
+
+	$.fn.dataTable.Api.register( 'colReorder.order()', function ( set ) {
+		if ( set ) {
+			return this.iterator( 'table', function ( ctx ) {
+				ctx._colReorder.fnOrder( set );
+			} );
+		}
+
+		return this.context.length ?
+			this.context[0]._colReorder.fnOrder() :
+			null;
+	} );
+}
+
+return ColReorder;
+}; // /factory
+
+
+// Define as an AMD module if possible
+if ( typeof define === 'function' && define.amd ) {
+	define( ['jquery', 'datatables'], factory );
+}
+else if ( typeof exports === 'object' ) {
+    // Node/CommonJS
+    factory( require('jquery'), require('datatables') );
+}
+else if ( jQuery && !jQuery.fn.dataTable.ColReorder ) {
+	// Otherwise simply initialise as normal, stopping multiple evaluation
+	factory( jQuery, jQuery.fn.dataTable );
+}
+
+
+})(window, document);
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js
index 2712750a..6ef9907a 100644
--- a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js
+++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js
@@ -1,846 +1,943 @@
-/*! ColResize 0.0.10
- */
-
-/**
- * @summary     ColResize
- * @description Provide the ability to resize columns in a DataTable
- * @version     0.0.10
- * @file        dataTables.colResize.js
- * @author      Silvacom Ltd.
- *
- * For details please refer to: http://www.datatables.net
- *
- * Special thank to everyone who has contributed to this plug in
- * - dykstrad
- * - tdillan (for 0.0.3 and 0.0.5 bug fixes)
- * - kylealonius (for 0.0.8 bug fix)
- * - the86freak (for 0.0.9 bug fix)
- */
-
-(function (window, document, undefined) {
-
-    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-     * DataTables plug-in API functions test
-     *
-     * This are required by ColResize in order to perform the tasks required, and also keep this
-     * code portable, to be used for other column resize projects with DataTables, if needed.
-     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-    var factory = function ($, DataTable) {
-        "use strict";
-
-        /**
-         * Plug-in for DataTables which will resize the columns depending on the handle clicked
-         *  @method  $.fn.dataTableExt.oApi.fnColResize
-         *  @param   object oSettings DataTables settings object - automatically added by DataTables!
-         *  @param   int iCol Take the column to be resized
-         *  @returns void
-         */
-        $.fn.dataTableExt.oApi.fnColResize = function (oSettings, iCol) {
-            var v110 = $.fn.dataTable.Api ? true : false;
-
-            /*
-             * Update DataTables' event handlers
-             */
-
-            /* Fire an event so other plug-ins can update */
-            $(oSettings.oInstance).trigger('column-resize', [ oSettings, {
-                "iCol": iCol
-            } ]);
-        };
-
-        /**
-         * ColResize provides column resize control for DataTables
-         * @class ColResize
-         * @constructor
-         * @param {object} dt DataTables settings object
-         * @param {object} opts ColResize options
-         */
-        var ColResize = function (dt, opts) {
-            var oDTSettings;
-
-            if ($.fn.dataTable.Api) {
-                oDTSettings = new $.fn.dataTable.Api(dt).settings()[0];
-            }
-            // 1.9 compatibility
-            else if (dt.fnSettings) {
-                // DataTables object, convert to the settings object
-                oDTSettings = dt.fnSettings();
-            }
-            else if (typeof dt === 'string') {
-                // jQuery selector
-                if ($.fn.dataTable.fnIsDataTable($(dt)[0])) {
-                    oDTSettings = $(dt).eq(0).dataTable().fnSettings();
-                }
+var dt;
+(function (dt) {
+    var ColResize = (function () {
+        function ColResize($, api, settings) {
+            this.$ = $;
+            this.tableSize = -1;
+            this.initialized = false;
+            this.dt = {};
+            this.dom = {
+                fixedLayout: false,
+                fixedHeader: null,
+                winResizeTimer: null,
+                mouse: {
+                    startX: -1,
+                    startWidth: null
+                },
+                table: {
+                    prevWidth: null
+                },
+                origState: true,
+                resize: false,
+                scrollHead: null,
+                scrollHeadTable: null,
+                scrollFoot: null,
+                scrollFootTable: null,
+                scrollFootInner: null,
+                scrollBody: null,
+                scrollBodyTable: null,
+                scrollX: false,
+                scrollY: false
+            };
+            this.settings = this.$.extend(true, {}, dt.ColResize.defaultSettings, settings);
+            this.dt.settings = api.settings()[0];
+            this.dt.api = api;
+            this.dt.settings.colResize = this;
+            this.registerCallbacks();
+        }
+        ColResize.prototype.initialize = function () {
+            var _this = this;
+            this.$.each(this.dt.settings.aoColumns, function (i, col) {
+                return _this.setupColumn(col);
+            });
+
+            //Initialize fixedHeader if specified
+            if (this.settings.fixedHeader)
+                this.setupFixedHeader();
+
+            //Save scroll head and body if found
+            this.dom.scrollHead = this.$('div.' + this.dt.settings.oClasses.sScrollHead, this.dt.settings.nTableWrapper);
+            this.dom.scrollHeadInner = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner, this.dom.scrollHead);
+            this.dom.scrollHeadTable = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner + ' > table', this.dom.scrollHead);
+
+            this.dom.scrollFoot = this.$('div.' + this.dt.settings.oClasses.sScrollFoot, this.dt.settings.nTableWrapper);
+            this.dom.scrollFootInner = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner, this.dom.scrollFoot);
+            this.dom.scrollFootTable = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner + ' > table', this.dom.scrollFoot);
+
+            this.dom.scrollBody = this.$('div.' + this.dt.settings.oClasses.sScrollBody, this.dt.settings.nTableWrapper);
+            this.dom.scrollBodyTable = this.$('> table', this.dom.scrollBody);
+            this.dt.api.on('draw.dt', this.onDraw.bind(this));
+            if (this.dom.scrollFootTable) {
+                this.dt.api.on('colPinFcDraw.dt', function (e, colPin, data) {
+                    if (data.leftClone.header)
+                        _this.$('tfoot', data.leftClone.header).remove();
+                    if (data.leftClone.footer)
+                        _this.$('thead', data.leftClone.footer).remove();
+                    if (data.rightClone.header)
+                        _this.$('tfoot', data.rightClone.header).remove();
+                    if (data.rightClone.footer)
+                        _this.$('thead', data.rightClone.footer).remove();
+                });
             }
-            else if (dt.nodeName && dt.nodeName.toLowerCase() === 'table') {
-                // Table node
-                if ($.fn.dataTable.fnIsDataTable(dt.nodeName)) {
-                    oDTSettings = $(dt.nodeName).dataTable().fnSettings();
-                }
+
+            this.dom.scrollX = this.dt.settings.oInit.sScrollX === undefined ? false : true;
+            this.dom.scrollY = this.dt.settings.oInit.sScrollY === undefined ? false : true;
+
+            //SaveTableWidth
+            this.dt.settings.sTableWidthOrig = this.$(this.dt.settings.nTable).width();
+            this.updateTableSize();
+
+            this.dt.settings.oFeatures.bAutoWidthOrig = this.dt.settings.oFeatures.bAutoWidth;
+            this.dt.settings.oFeatures.bAutoWidth = false;
+
+            if (this.dt.settings.oInit.bStateSave && this.dt.settings.oLoadedState) {
+                this.loadState(this.dt.settings.oLoadedState);
             }
-            else if (dt instanceof jQuery) {
-                // jQuery object
-                if ($.fn.dataTable.fnIsDataTable(dt[0])) {
-                    oDTSettings = dt.eq(0).dataTable().fnSettings();
-                }
+
+            this.onDraw();
+            this.dom.table.preWidth = parseFloat(this.dom.scrollBodyTable.css('width'));
+
+            if (!this.dom.scrollX && this.dom.scrollY && this.settings.fixedLayout && this.dt.settings._reszEvt) {
+                //We have to manually resize columns on window resize
+                var eventName = 'resize.DT-' + this.dt.settings.sInstance;
+                this.$(window).off(eventName);
+                this.$(window).on(eventName, function () {
+                    _this.proportionallyColumnSizing();
+                    //api._fnAdjustColumnSizing(this.dt.settings);
+                });
             }
-            else {
-                // DataTables settings object
-                oDTSettings = dt;
-            }
-
-            // Convert from camelCase to Hungarian, just as DataTables does
-            if ($.fn.dataTable.camelToHungarian) {
-                $.fn.dataTable.camelToHungarian(ColResize.defaults, opts || {});
-            }
-
-
-            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-             * Public class variables
-             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-            /**
-             * @namespace Settings object which contains customizable information for ColResize instance
-             */
-            this.s = {
-                /**
-                 * DataTables settings object
-                 *  @property dt
-                 *  @type     Object
-                 *  @default  null
-                 */
-                "dt": null,
-
-                /**
-                 * Initialisation object used for this instance
-                 *  @property init
-                 *  @type     object
-                 *  @default  {}
-                 */
-                "init": $.extend(true, {}, ColResize.defaults, opts),
-
-                /**
-                 * @namespace Information used for the mouse drag
-                 */
-                "mouse": {
-                    "startX": -1,
-                    "startY": -1,
-                    "targetIndex": -1,
-                    "targetColumn": -1,
-                    "neighbourIndex": -1,
-                    "neighbourColumn": -1
-                },
 
-                /**
-                 * Status variable keeping track of mouse down status
-                 *  @property isMousedown
-                 *  @type     boolean
-                 *  @default  false
-                 */
-                "isMousedown": false
-            };
+            if (this.dom.scrollX || this.dom.scrollY) {
+                this.dt.api.on('column-sizing.dt', this.fixFootAndHeadTables.bind(this));
+                this.dt.api.on('column-visibility.dt', this.fixFootAndHeadTables.bind(this));
+            }
 
+            this.initialized = true;
+            this.dt.settings.oApi._fnCallbackFire(this.dt.settings, 'colResizeInitCompleted', 'colResizeInitCompleted', [this]);
+        };
 
-            /**
-             * @namespace Common and useful DOM elements for the class instance
-             */
-            this.dom = {
-                /**
-                 * Resizing element (the one the mouse is resizing)
-                 *  @property resize
-                 *  @type     element
-                 *  @default  null
-                 */
-                "resizeCol": null,
-
-                /**
-                 * Resizing element neighbour (the column next to the one the mouse is resizing)
-                 * This is for fixed table resizing.
-                 *  @property resize
-                 *  @type     element
-                 *  @default  null
-                 */
-                "resizeColNeighbour": null,
-
-                /**
-                 *  Array of events to be restored, used for overriding existing events from other plugins for a time.
-                 *  @property restoreEvents
-                 *  @type     array
-                 *  @default  []
-                 */
-                "restoreEvents": []
+        ColResize.prototype.setupColumn = function (col) {
+            var _this = this;
+            var $th = this.$(col.nTh);
+            if (col.resizable === false)
+                return;
+
+            // listen to mousemove event for resize
+            $th.on('mousemove.ColResize', function (e) {
+                if (_this.dom.resize || col.resizable === false)
+                    return;
+
+                /* Store information about the mouse position */
+                var $thTarget = e.target.nodeName.toUpperCase() == 'TH' ? _this.$(e.target) : _this.$(e.target).closest('TH');
+                var offset = $thTarget.offset();
+                var nLength = $thTarget.innerWidth();
+
+                /* are we on the col border (if so, resize col) */
+                if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5) {
+                    $thTarget.css({ 'cursor': 'col-resize' });
+                } else
+                    $thTarget.css({ 'cursor': 'pointer' });
+            });
+
+            //Save the original width
+            col._ColResize_sWidthOrig = col.sWidthOrig;
+            col.initWidth = $th.width();
+            col.minWidthOrig = col.minWidth;
+
+            $th.on('dblclick.ColResize', function (e) {
+                _this.onDblClick(e, $th, col);
+            });
+
+            $th.off('mousedown.ColReorder');
+
+            // listen to mousedown event
+            $th.on('mousedown.ColResize', function (e) {
+                return _this.onMouseDown(e, col);
+            });
+        };
+
+        ColResize.prototype.setupFixedHeader = function () {
+            var fhSettings = this.settings.fixedHeader === true ? undefined : this.settings.fixedHeader;
+
+            //If left or right option was set to true disable resizing for the first or last column
+            if (this.$.isPlainObject(fhSettings)) {
+                var columns = this.dt.settings.aoColumns;
+                if (fhSettings.left === true)
+                    columns[0].resizable = false;
+                if (fhSettings.right === true)
+                    columns[columns.length - 1].resizable = false;
+            }
+
+            this.dom.fixedHeader = new this.$.fn.dataTable.FixedHeader(this.dt.api, fhSettings);
+            var origUpdateClones = this.dom.fixedHeader._fnUpdateClones;
+            var that = this;
+
+            //FixeHeader doesn't have any callback after updating the clones so we have to wrap the orig function
+            this.dom.fixedHeader._fnUpdateClones = function () {
+                origUpdateClones.apply(this, arguments);
+                that.memorizeFixedHeaderNodes();
             };
 
+            //As we missed the first call of _fnUpdateClones we have to call memorizeFixedHeaderNodes function manually
+            this.memorizeFixedHeaderNodes();
+        };
 
-            /* Constructor logic */
-            this.s.dt = oDTSettings.oInstance.fnSettings();
-            this.s.dt._colResize = this;
-            this._fnConstruct();
-
-            /* Add destroy callback */
-            oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColResize');
-
-            return this;
-        };
-
-
-        ColResize.prototype = {
-            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-             * Public methods
-             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-            /**
-             * Reset the column widths to the original widths that was detected on
-             * start up.
-             *  @return {this} Returns `this` for chaining.
-             *
-             *  @example
-             *    // DataTables initialisation with ColResize
-             *    var table = $('#example').dataTable( {
-             *        "sDom": 'Zlfrtip'
-             *    } );
-             *
-             *    // Add click event to a button to reset the ordering
-             *    $('#resetOrdering').click( function (e) {
-             *        e.preventDefault();
-             *        $.fn.dataTable.ColResize( table ).fnReset();
-             *    } );
-             */
-            "fnReset": function () {
-                var a = [];
-                for (var i = 0, iLen = this.s.dt.aoColumns.length; i < iLen; i++) {
-                    this.s.dt.aoColumns[i].width = this.s.dt.aoColumns[i]._ColResize_iOrigWidth;
+        ColResize.prototype.memorizeFixedHeaderNodes = function () {
+            var _this = this;
+            var fhSettings = this.dom.fixedHeader.fnGetSettings();
+            var fhCache = fhSettings.aoCache;
+            var i, col;
+            for (i = 0; i < fhCache.length; i++) {
+                var type = fhCache[i].sType;
+                var propName;
+                var selector;
+                switch (type) {
+                    case 'fixedHeader':
+                        propName = 'fhTh';
+                        selector = 'thead>tr>th';
+                        this.dt.settings.fhTHead = fhCache[i].nNode;
+                        break;
+                    case 'fixedFooter':
+                        propName = 'fhTf';
+                        selector = 'thead>tr>th';
+
+                        //prepend a cloned thead to the floating footer table so that resizing will work correctly
+                        var tfoot = this.$(fhCache[i].nNode);
+                        var thead = this.$(this.dt.settings.nTHead).clone().css({ height: 0, visibility: 'hidden' });
+                        this.$('tr', thead).css('height', 0);
+                        this.$('tr>th', thead).css({
+                            'height': 0,
+                            'padding-bottom': 0,
+                            'padding-top': 0,
+                            'border-bottom-width': 0,
+                            'border-top-width': 0,
+                            'line-height': 0
+                        });
+                        tfoot.prepend(thead);
+                        this.$('tfoot>tr>th', tfoot).css('width', '');
+                        this.dt.settings.fhTFoot = fhCache[i].nNode;
+                        break;
+                    default:
+                        continue;
                 }
 
-                this.s.dt.adjust().draw();
+                this.$(selector, fhCache[i].nNode).each(function (j, th) {
+                    col = _this.getVisibleColumn(j);
+                    col[propName] = th;
+                });
+            }
+        };
 
-                return this;
-            },
+        //zero based index
+        ColResize.prototype.getVisibleColumn = function (idx) {
+            var columns = this.dt.settings.aoColumns;
+            var currVisColIdx = -1;
+            for (var i = 0; i < columns.length; i++) {
+                if (!columns[i].bVisible)
+                    continue;
+                currVisColIdx++;
+                if (currVisColIdx == idx)
+                    return columns[i];
+            }
+            return null;
+        };
 
+        ColResize.prototype.updateTableSize = function () {
+            if (this.dom.scrollX && this.dom.scrollHeadTable.length)
+                this.tableSize = this.dom.scrollHeadTable.width();
+            else
+                this.tableSize = -1;
+        };
 
-            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-             * Private methods (they are of course public in JS, but recommended as private)
-             * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+        ColResize.prototype.proportionallyColumnSizing = function () {
+            var _this = this;
+            var prevWidths = [], newWidths = [], prevWidth, newWidth, newTableWidth, prevTableWidth, moveLength, multiplier, cWidth, i, j, delay = 500, prevTotalColWidths = 0, currTotalColWidths, columnRestWidths = [], columns = this.dt.settings.aoColumns, bodyTableColumns = this.$('thead th', this.dom.scrollBodyTable), headTableColumns = this.$('thead th', this.dom.scrollHeadTable), footTableColumns = this.dom.scrollFootTable.length ? this.$('thead th', this.dom.scrollFootTable) : [], visColumns = [];
 
-            /**
-             * Constructor logic
-             *  @method  _fnConstruct
-             *  @returns void
-             *  @private
-             */
-            "_fnConstruct": function () {
-                var that = this;
-                var iLen = that.s.dt.aoColumns.length;
-                var i;
+            for (i = 0; i < columns.length; i++) {
+                if (!columns[i].bVisible)
+                    continue;
+                visColumns.push(columns[i]);
+                columnRestWidths.push(0); //set default value
+            }
 
-                that._fnSetupMouseListeners();
+            for (i = 0; i < bodyTableColumns.length; i++) {
+                cWidth = parseFloat(bodyTableColumns[i].style.width);
+                prevTotalColWidths += cWidth;
+                prevWidths.push(cWidth);
+            }
 
-                /* Add event handlers for the resize handles */
-                for (i = 0; i < iLen; i++) {
-                    /* Mark the original column width for later reference */
-                    this.s.dt.aoColumns[i]._ColResize_iOrigWidth = this.s.dt.aoColumns[i].width;
+            for (i = 0; i < bodyTableColumns.length; i++) {
+                bodyTableColumns[i].style.width = '';
+            }
+
+            //Get the new table width calculated by the browser
+            newTableWidth = parseFloat(this.dom.scrollBodyTable.css('width'));
+
+            //Get the old table width
+            prevTableWidth = this.dom.table.preWidth;
+            moveLength = newTableWidth - prevTableWidth;
+            if (moveLength == 0) {
+                for (i = 0; i < bodyTableColumns.length; i++) {
+                    bodyTableColumns[i].style.width = prevWidths[i] + 'px';
                 }
+                return;
+            }
 
-                this._fnSetColumnIndexes();
-
-                /* State saving */
-                this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
-                    that._fnStateSave.call(that, oData);
-                }, "ColResize_State" );
-
-                // State loading
-                this._fnStateLoad();
-            },
-
-            /**
-             * @method  _fnStateSave
-             * @param   object oState DataTables state
-             * @private
-             */
-            "_fnStateSave": function (oState) {
-                this.s.dt.aoColumns.forEach(function(col, index) {
-                    oState.columns[index].width = col.sWidthOrig;
-                });
-            },
-
-            /**
-             * If state has been loaded, apply the saved widths to the columns
-             * @method  _fnStateLoad
-             * @private
-             */
-            "_fnStateLoad": function() {
-                var that = this,
-                    loadedState = this.s.dt.oLoadedState;
-                if (loadedState && loadedState.columns) {
-                    var colStates = loadedState.columns,
-                        currCols = this.s.dt.aoColumns;
-                    // Only apply the saved widths if the number of columns is the same.
-                    // Otherwise, we don't know if we're applying the width to the correct column.
-                    if (colStates.length > 0 && colStates.length === currCols.length) {
-                        colStates.forEach(function(state, index) {
-                            var col = that.s.dt.aoColumns[index];
-                            if (state.width) {
-                                col.sWidthOrig = col.sWidth = state.width;
-                            }
-                        });
+            //var tot = 0;
+            currTotalColWidths = prevTotalColWidths;
+            for (i = 0; i < visColumns.length; i++) {
+                //For each column calculate the new width
+                prevWidth = prevWidths[i];
+                multiplier = (+(prevWidth / prevTotalColWidths).toFixed(2));
+
+                //tot += multiplier;
+                newWidth = prevWidth + (moveLength * multiplier) + columnRestWidths[i];
+                currTotalColWidths -= prevWidth;
+
+                //Check whether the column can be resized to the new calculated value
+                //if not, set it to the min or max width depends on the moveLength value
+                if (!this.canResizeColumn(visColumns[i], newWidth)) {
+                    cWidth = moveLength > 0 ? this.getColumnMaxWidth(visColumns[i]) : this.getColumnMinWidth(visColumns[i]);
+                    var rest = newWidth - cWidth;
+                    newWidth = cWidth;
+
+                    for (j = (i + 1); j < visColumns.length; j++) {
+                        columnRestWidths[j] += rest * (+(visColumns[j] / currTotalColWidths).toFixed(2));
                     }
                 }
-            },
-
-            /**
-             * Remove events of type from obj add it to restoreEvents array to be restored at a later time
-             * @param until string flag when to restore the event
-             * @param obj Object to remove events from
-             * @param type type of event to remove
-             * @param namespace namespace of the event being removed
-             */
-            "_fnDelayEvents": function (until, obj, type, namespace) {
-                var that = this;
-                //Get the events for the object
-                var events = $._data($(obj).get(0), 'events');
-                $.each(events, function (i, o) {
-                    //If the event type matches
-                    if (i == type) {
-                        //Loop through the possible many events with that type
-                        $.each(o, function (k, v) {
-                            //Somehow it is possible for the event to be undefined make sure it is defined first
-                            if (v) {
-                                if (namespace) {
-                                    //Add the event to the array of events to be restored later
-                                    that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": v.namespace, "handler": v.handler});
-                                    //If the namespace matches
-                                    if (v.namespace == namespace) {
-                                        //Turn off/unbind the event
-                                        $(obj).off(type + "." + namespace);
-                                    }
-                                } else {
-                                    //Add the event to the array of events to be restored later
-                                    that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": null, "handler": v.handler});
-                                    //Turn off/unbind the event
-                                    $(obj).off(type);
-                                }
-                            }
-                        });
-                    }
-                });
-            },
-
-            /**
-             * Loop through restoreEvents array and restore the events on the elements provided
-             */
-            "_fnRestoreEvents": function (until) {
-                var that = this;
-                //Loop through the events to be restored
-                var i;
-                for (i = that.dom.restoreEvents.length; i--;) {
-                    if (that.dom.restoreEvents[i].until == undefined || that.dom.restoreEvents[i].until == null || that.dom.restoreEvents[i].until == until) {
-                        if (that.dom.restoreEvents[i].namespace) {
-                            //Turn on the event for the object provided
-                            $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace).on(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace, that.dom.restoreEvents[i].handler);
-                            that.dom.restoreEvents.splice(i, 1);
-                        } else {
-                            //Turn on the event for the object provided
-                            $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type).on(that.dom.restoreEvents[i].type, that.dom.restoreEvents[i].handler);
-                            that.dom.restoreEvents.splice(i, 1);
-                        }
-                    }
+                newWidths.push(newWidth);
+            }
+
+            //Apply the calculated column widths to the headers cells
+            var tablesWidth = this.dom.scrollBodyTable.outerWidth() + 'px';
+            for (i = 0; i < headTableColumns.length; i++) {
+                headTableColumns[i].style.width = newWidths[i] + 'px';
+            }
+            this.dom.scrollHeadTable.css('width', tablesWidth);
+            this.dom.scrollHeadInner.css('width', tablesWidth);
+
+            for (i = 0; i < bodyTableColumns.length; i++) {
+                bodyTableColumns[i].style.width = newWidths[i] + 'px';
+            }
+
+            if (this.dom.scrollFootTable.length) {
+                for (i = 0; i < footTableColumns.length; i++) {
+                    footTableColumns[i].style.width = newWidths[i] + 'px';
                 }
-            },
+                this.dom.scrollFootTable[0].style.width = tablesWidth;
+                this.dom.scrollFootInner[0].style.width = tablesWidth;
+            }
 
-            /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-             * Mouse drop and drag
-             */
+            //console.log('moveLength: ' + moveLength + ' multiplier: ' + tot);
+            //console.log(newWidths);
+            this.dom.table.preWidth = newTableWidth;
+
+            //Call afterResizing function after the window stops resizing
+            if (this.dom.winResizeTimer)
+                clearTimeout(this.dom.winResizeTimer);
+            this.dom.winResizeTimer = setTimeout(function () {
+                _this.afterResizing();
+                _this.dom.winResizeTimer = null;
+            }, delay);
+        };
 
-            "_fnSetupMouseListeners":function() {
-                var that = this;
-                $(that.s.dt.nTableWrapper).off("mouseenter.ColResize").on("mouseenter.ColResize","th",function(e) {
-                    e.preventDefault();
-                    that._fnMouseEnter.call(that, e, this);
-                });
-                $(that.s.dt.nTableWrapper).off("mouseleave.ColResize").on("mouseleave.ColResize","th",function(e) {
-                    e.preventDefault();
-                    that._fnMouseLeave.call(that, e, this);
-                });
-            },
-
-            /**
-             * Add mouse listeners to the resize handle on TH element
-             *  @method  _fnMouseListener
-             *  @param   i Column index
-             *  @param   nTh TH resize handle element clicked on
-             *  @returns void
-             *  @private
-             */
-            "_fnMouseListener": function (i, nTh) {
-                var that = this;
-                $(nTh).off('mouseenter.ColResize').on('mouseenter.ColResize', function (e) {
-                    e.preventDefault();
-                    that._fnMouseEnter.call(that, e, nTh);
-                });
-                $(nTh).off('mouseleave.ColResize').on('mouseleave.ColResize', function (e) {
-                    e.preventDefault();
-                    that._fnMouseLeave.call(that, e, nTh);
-                });
-            },
-
-            /**
-             *
-             * @param e Mouse event
-             * @param nTh TH element that the mouse is over
-             */
-            "_fnMouseEnter": function (e, nTh) {
-                var that = this;
-                if(!that.s.isMousedown) {
-                    //Once the mouse has entered the cell add mouse move event to see if the mouse is over resize handle
-                    $(nTh).off('mousemove.ColResizeHandle').on('mousemove.ColResizeHandle', function (e) {
-                        e.preventDefault();
-                        that._fnResizeHandleCheck.call(that, e, nTh);
-                    });
+        ColResize.prototype.getColumnIndex = function (col) {
+            //Get the current column position
+            var colIdx = -1;
+            for (var i = 0; i < this.dt.settings.aoColumns.length; i++) {
+                if (this.dt.settings.aoColumns[i] === col) {
+                    colIdx = i;
+                    break;
                 }
-            },
-
-            /**
-             * Clear mouse events when the mouse has left the th
-             * @param e Mouse event
-             * @param nTh TH element that the mouse has just left
-             */
-            "_fnMouseLeave": function (e, nTh) {
-                //Once the mouse has left the TH make suure to remove the mouse move listener
-                $(nTh).off('mousemove.ColResizeHandle');
-            },
-
-            /**
-             * Mouse down on a TH element in the table header
-             *  @method  _fnMouseDown
-             *  @param   event e Mouse event
-             *  @param   element nTh TH element to be resized
-             *  @returns void
-             *  @private
-             */
-            "_fnMouseDown": function (e, nTh) {
-                var that = this;
-
-                that.s.isMousedown = true;
+            }
+            return colIdx;
+        };
 
-                /* Store information about the mouse position */
-                var target = $(e.target).closest('th, td');
-                var offset = target.offset();
-
-                /* Store information about the mouse position for resize calculations in mouse move function */
-                this.s.mouse.startX = e.pageX;
-                this.s.mouse.startY = e.pageY;
-
-                //Store the indexes of the columns the mouse is down on
-                var idx = that.dom.resizeCol[0].cellIndex;
-                
-                // the last column has no 'right-side' neighbour
-                // with fixed this can make the table smaller
-               if (that.dom.resizeColNeighbour[0] === undefined){
-                    var idxNeighbour = 0;
+        ColResize.prototype.getColumnEvent = function (th, type, ns) {
+            var event;
+            var thEvents = this.$._data(th, "events");
+            this.$.each(thEvents[type] || [], function (idx, handler) {
+                if (handler.namespace === ns)
+                    event = handler;
+            });
+            return event;
+        };
+
+        ColResize.prototype.loadState = function (data) {
+            var _this = this;
+            var i, col;
+
+            var onInit = function () {
+                if (_this.settings.fixedLayout) {
+                    _this.setTablesLayout('fixed');
                 } else {
-                    var idxNeighbour = that.dom.resizeColNeighbour[0].cellIndex;
+                    _this.setTablesLayout('auto');
                 }
-                
-               
+                if (!data.colResize) {
+                    if (_this.dt.settings.oFeatures.bAutoWidthOrig)
+                        _this.dt.settings.oFeatures.bAutoWidth = true;
+                    else if (_this.dt.settings.sTableWidthOrig)
+                        _this.$(_this.dt.settings.nTable).width(_this.dt.settings.sTableWidthOrig);
+
+                    for (i = 0; i < _this.dt.settings.aoColumns.length; i++) {
+                        col = _this.dt.settings.aoColumns[i];
+                        if (col._ColResize_sWidthOrig) {
+                            col.sWidthOrig = col._ColResize_sWidthOrig;
+                        }
+                    }
+                    _this.dom.origState = true;
+                } else {
+                    var columns = data.colResize.columns || [];
+                    var wMap = {};
 
-                if (idx === undefined) {
-                    return;
-                }
+                    if (_this.dt.settings.oFeatures.bAutoWidth) {
+                        _this.dt.settings.oFeatures.bAutoWidth = false;
+                    }
 
-                this.s.mouse.targetIndex = idx;
-                this.s.mouse.targetColumn = this.s.dt.aoColumns[ idx ];
-
-                this.s.mouse.neighbourIndex = idxNeighbour;
-                this.s.mouse.neighbourColumn = this.s.dt.aoColumns[ idxNeighbour ];
-
-                /* Add event handlers to the document */
-                $(document)
-                    .off('mousemove.ColResize').on('mousemove.ColResize', function (e) {
-                        that._fnMouseMove.call(that, e);
-                    })
-                    .off('mouseup.ColResize').on('mouseup.ColResize', function (e) {
-                        that._fnMouseUp.call(that, e);
-                    });
-            },
-
-            /**
-             * Deal with a mouse move event while dragging to resize a column
-             *  @method  _fnMouseMove
-             *  @param   e Mouse event
-             *  @returns void
-             *  @private
-             */
-            "_fnMouseMove": function (e) {
-                var that = this;
-
-                var offset = $(that.s.mouse.targetColumn.nTh).offset();
-                var relativeX = (e.pageX - offset.left);
-                var distFromLeft = relativeX;
-                var distFromRight = $(that.s.mouse.targetColumn.nTh).outerWidth() - relativeX - 1;
-
-                //Change in mouse x position
-                var dx = e.pageX - that.s.mouse.startX;
-                //Get the minimum width of the column (default minimum 10px)
-                var minColumnWidth = Math.max(parseInt($(that.s.mouse.targetColumn.nTh).css('min-width')), 10);
-                //Store the previous width of the column
-                var prevWidth = $(that.s.mouse.targetColumn.nTh).width();
-                //As long as the cursor is past the handle, resize the columns
-                if ((dx > 0 && distFromRight <= 0) || (dx < 0 && distFromRight >= 0)) {
-                    if (!that.s.init.tableWidthFixed) {
-                        //As long as the width is larger than the minimum
-                        var newColWidth = Math.max(minColumnWidth, prevWidth + dx);
-                        //Get the width difference (take into account the columns minimum width)
-                        var widthDiff = newColWidth - prevWidth;
-                        var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index"));
-                        //Set datatable column widths
-                        that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px";
-                        var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='"+colResizeIdx+"']");
-                        //For each table expand the width by the same amount as the column
-                        //This accounts for other datatable plugins like FixedColumns
-                        domCols.parents("table").each(function() {
-                            if(!$(this).parent().hasClass("DTFC_LeftBodyLiner")) {
-                                var newWidth = $(this).width() + widthDiff;
-                                $(this).width(newWidth);
-                            } else {
-                                var newWidth =$(that.s.dt.nTableWrapper).find(".DTFC_LeftHeadWrapper").children("table").width();
-                                $(this).parents(".DTFC_LeftWrapper").width(newWidth);
-                                $(this).parent().width(newWidth+15);
-                                $(this).width(newWidth);
-                            }
-                        });
-                        //Apply the new width to the columns after the table has been resized
-                        domCols.width(that.s.mouse.targetColumn.width);
-                    } else {
-                        //A neighbour column must exist in order to resize a column in a table with a fixed width
-                        if (that.s.mouse.neighbourColumn) {
-                            //Get the minimum width of the neighbor column (default minimum 10px)
-                            var minColumnNeighbourWidth = Math.max(parseInt($(that.s.mouse.neighbourColumn.nTh).css('min-width')), 10);
-                            //Store the previous width of the neighbour column
-                            var prevNeighbourWidth = $(that.s.mouse.neighbourColumn.nTh).width();
-                            //As long as the width is larger than the minimum
-                            var newColWidth = Math.max(minColumnWidth, prevWidth + dx);
-                            var newColNeighbourWidth = Math.max(minColumnNeighbourWidth, prevNeighbourWidth - dx);
-                            //Get the width difference (take into account the columns minimum width)
-                            var widthDiff = newColWidth - prevWidth;
-                            var widthDiffNeighbour = newColNeighbourWidth - prevNeighbourWidth;
-                            //Get the column index for the column being changed
-                            var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index"));
-                            var neighbourColResizeIdx = parseInt(that.dom.resizeColNeighbour.attr("data-column-index"));
-                            //Set datatable column widths
-                            that.s.mouse.neighbourColumn.sWidthOrig = that.s.mouse.neighbourColumn.sWidth = that.s.mouse.neighbourColumn.width = newColNeighbourWidth + "px";
-                            that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px";
-                            //Get list of columns based on column index in all affected tables tables. This accounts for other plugins like FixedColumns
-                            var domNeighbourCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + neighbourColResizeIdx + "']");
-                            var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + colResizeIdx + "']");
-                            //If dx if positive (the width is getting larger) shrink the neighbour columns first
-                            if(dx>0) {
-                                domNeighbourCols.width(that.s.mouse.neighbourColumn.width);
-                                domCols.width(that.s.mouse.targetColumn.width);
-                            } else {
-                                //Apply the new width to the columns then to the neighbour columns
-                                domCols.width(that.s.mouse.targetColumn.width);
-                                domNeighbourCols.width(that.s.mouse.neighbourColumn.width);
-                            }
-                        }
+                    if (_this.dom.scrollX && data.colResize.tableSize > 0) {
+                        _this.dom.scrollHeadTable.width(data.colResize.tableSize);
+                        _this.dom.scrollHeadInner.width(data.colResize.tableSize);
+                        _this.dom.scrollBodyTable.width(data.colResize.tableSize);
+                        _this.dom.scrollFootTable.width(data.colResize.tableSize);
                     }
-                }
-                that.s.mouse.startX = e.pageX;
-            },
-
-            /**
-             * Check to see if the mouse is over the resize handle area
-             * @param e
-             * @param nTh
-             */
-            "_fnResizeHandleCheck": function (e, nTh) {
-                var that = this;
-
-                var offset = $(nTh).offset();
-                var relativeX = (e.pageX - offset.left);
-                var relativeY = (e.pageY - offset.top);
-                var distFromLeft = relativeX;
-                var distFromRight = $(nTh).outerWidth() - relativeX - 1;
-
-                var handleBuffer = this.s.init.handleWidth / 2;
-                var leftHandleOn = distFromLeft < handleBuffer;
-                var rightHandleOn = distFromRight < handleBuffer;
-
-                //If this is the first table cell
-                if ($(nTh).prev("th").length == 0) {
-                    if(this.s.init.rtl)
-                        rightHandleOn = false;
-                    else
-                        leftHandleOn = false;
-                }
-                //If this is the last cell and the table is fixed width don't let them expand the last cell directly
-                if ($(nTh).next("th").length == 0 && this.s.init.tableWidthFixed) {
-                    if(this.s.init.rtl)
-                        leftHandleOn = false;
-                    else
-                        rightHandleOn = false;
-                }
 
-                var resizeAvailable = leftHandleOn||rightHandleOn;
-
-                //If table is in right to left mode flip which TH is being resized
-                if (that.s.init.rtl) {
-                    //Handle is to the left
-                    if (leftHandleOn) {
-                        that.dom.resizeCol = $(nTh);
-                        that.dom.resizeColNeighbour = $(nTh).next();
-                    } else if (rightHandleOn) {
-                        that.dom.resizeCol = $(nTh).prev();
-                        that.dom.resizeColNeighbour = $(nTh);
+                    for (i = 0; i < columns.length; i++) {
+                        wMap[i] = columns[i];
                     }
-                } else {
-                    //Handle is to the right
-                    if (rightHandleOn) {
-                        that.dom.resizeCol = $(nTh);
-                        that.dom.resizeColNeighbour = $(nTh).next();
-                    } else if (leftHandleOn) {
-                        that.dom.resizeCol = $(nTh).prev();
-                        that.dom.resizeColNeighbour = $(nTh);
+                    for (i = 0; i < _this.dt.settings.aoColumns.length; i++) {
+                        col = _this.dt.settings.aoColumns[i];
+                        var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i;
+                        col.sWidth = wMap[idx];
+                        col.sWidthOrig = wMap[idx];
+                        col.nTh.style.width = columns[i];
+
+                        //Check for FixedHeader
+                        if (col.fhTh)
+                            col.fhTh.style.width = columns[i];
+                        if (col.fhTf)
+                            col.fhTf.style.width = columns[i];
                     }
+                    _this.dom.origState = false;
                 }
 
-                //If table width is fixed make sure both columns are resizable else just check the one.
-                if(this.s.init.tableWidthFixed)
-                    resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1 && this.s.init.exclude.indexOf(parseInt($(that.dom.resizeColNeighbour).attr("data-column-index"))) == -1;
-                else
-                    resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1;
-
-                $(nTh).off('mousedown.ColResize');
-                if (resizeAvailable) {
-                    $(nTh).css("cursor", "ew-resize");
-
-                    //Delay other mousedown events from the Reorder plugin
-                    that._fnDelayEvents(null, nTh, "mousedown", "ColReorder");
-                    that._fnDelayEvents("click", nTh, "click", "DT");
-
-                    $(nTh).off('mousedown.ColResize').on('mousedown.ColResize', function (e) {
-                        e.preventDefault();
-                        that._fnMouseDown.call(that, e, nTh);
-                    })
-                        .off('click.ColResize').on('click.ColResize', function (e) {
-                            that._fnClick.call(that, e);
-                        });
-                } else {
-                    $(nTh).css("cursor", "pointer");
-                    $(nTh).off('mousedown.ColResize click.ColResize');
-                    //Restore any events that were removed
-                    that._fnRestoreEvents();
-                    //This is to restore column sorting on click functionality
-                    if (!that.s.isMousedown)
-                    //Restore click event if mouse is not down
-                        this._fnRestoreEvents("click");
+                _this.dt.api.columns.adjust();
+                if (_this.dom.scrollX || _this.dom.scrollY)
+                    _this.dt.api.draw(false);
+            };
+
+            if (this.initialized) {
+                onInit();
+                return;
+            }
+            this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'colResizeInitCompleted', function () {
+                onInit();
+            }, "ColResize_Init");
+        };
+
+        ColResize.prototype.saveState = function (data) {
+            if (!this.dt.settings._bInitComplete) {
+                var oData = this.dt.settings.fnStateLoadCallback.call(this.dt.settings.oInstance, this.dt.settings);
+                if (oData && oData.colResize)
+                    data.colResize = oData.colResize;
+                return;
+            }
+            this.updateTableSize();
+            data.colResize = {
+                columns: [],
+                tableSize: this.tableSize
+            };
+
+            data.colResize.columns.length = this.dt.settings.aoColumns.length;
+            for (var i = 0; i < this.dt.settings.aoColumns.length; i++) {
+                var col = this.dt.settings.aoColumns[i];
+                var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i;
+                data.colResize.columns[idx] = col.sWidth;
+            }
+        };
+
+        ColResize.prototype.registerCallbacks = function () {
+            var _this = this;
+            /* State saving */
+            this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateSaveParams', function (oS, oData) {
+                _this.saveState(oData);
+            }, "ColResize_StateSave");
+
+            /* State loading */
+            this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateLoaded', function (oS, oData) {
+                _this.loadState(oData);
+            }, "ColResize_StateLoad");
+
+            if (this.$.fn.DataTable.models.oSettings.remoteStateInitCompleted !== undefined) {
+                //Integrate with remote state
+                this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateLoadedParams', function (s, data) {
+                    _this.loadState(data);
+                }, "ColResize_StateLoad");
+                this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateSaveParams', function (s, data) {
+                    _this.saveState(data);
+                }, "ColResize_StateSave");
+            }
+        };
+
+        ColResize.prototype.setTablesLayout = function (value) {
+            if (this.dom.scrollX || this.dom.scrollY) {
+                this.dom.scrollHeadTable.css('table-layout', value);
+                this.dom.scrollBodyTable.css('table-layout', value);
+                this.dom.scrollFootTable.css('table-layout', value);
+            } else {
+                this.$(this.dt.settings.nTable).css('table-layout', value);
+            }
+            this.dom.fixedLayout = value == 'fixed';
+        };
+
+        //only when scrollX or scrollY are enabled
+        ColResize.prototype.fixFootAndHeadTables = function (e) {
+            var _this = this;
+            if (e != null && e.target !== this.dt.settings.nTable)
+                return;
+
+            if (this.dom.scrollFootTable.length) {
+                this.$('thead', this.dom.scrollFootTable).remove();
+                this.dom.scrollFootTable.prepend(this.$('thead', this.dom.scrollBodyTable).clone());
+            }
+            this.$('tfoot', this.dom.scrollHeadTable).remove();
+            this.dom.scrollHeadTable.append(this.$('tfoot', this.dom.scrollBodyTable).clone());
+            var removeFooterWidth = function (table) {
+                _this.$('tfoot>tr>th', table).each(function (i, th) {
+                    _this.$(th).css('width', '');
+                });
+            };
+
+            //Remove all tfoot headers widths
+            removeFooterWidth(this.dom.scrollFootTable);
+            removeFooterWidth(this.dom.scrollBodyTable);
+            removeFooterWidth(this.dom.scrollHeadTable);
+        };
+
+        ColResize.prototype.onDraw = function (e) {
+            if (e != null && e.target !== this.dt.settings.nTable)
+                return;
+            if (this.dom.scrollX || this.dom.scrollY) {
+                this.fixFootAndHeadTables();
+
+                //Fix the header table padding
+                if (this.dt.settings._bInitComplete) {
+                    var borderWidth = this.dom.scrollHeadTable.outerWidth() - this.dom.scrollHeadTable.innerWidth();
+                    var paddingType = this.dt.settings.oBrowser.bScrollbarLeft ? 'padding-left' : 'padding-right';
+                    var paddingVal = parseFloat(this.dom.scrollHeadInner.css(paddingType));
+                    this.dom.scrollHeadInner.css(paddingType, (paddingVal + borderWidth) + 'px');
                 }
-            },
-
-            "_fnClick": function (e) {
-                var that = this;
-                that.s.isMousedown = false;
-                e.stopImmediatePropagation();
-            },
-
-            /**
-             * Finish off the mouse drag
-             *  @method  _fnMouseUp
-             *  @param   e Mouse event
-             *  @returns void
-             *  @private
-             */
-            "_fnMouseUp": function (e) {
-                var that = this;
-                that.s.isMousedown = false;
-
-                //Fix width of column to be the size the dom is limited to (for when user sets min-width on a column)
-                that.s.mouse.targetColumn.width = that.dom.resizeCol.width();
-
-                $(document).off('mousemove.ColResize mouseup.ColResize');
-                this.s.dt.oInstance.fnAdjustColumnSizing();
-                //Table width fix, prevents extra gaps between tables
-                var LeftWrapper = $(that.s.dt.nTableWrapper).find(".DTFC_LeftWrapper");
-                var DTFC_LeftWidth = LeftWrapper.width();
-                LeftWrapper.children(".DTFC_LeftHeadWrapper").children("table").width(DTFC_LeftWidth);
-
-                if (that.s.init.resizeCallback) {
-                    that.s.init.resizeCallback.call(that, that.s.mouse.targetColumn);
+            }
+
+            var autoWidthTypes = [];
+            if (this.settings.dblClick == 'autoMinFit' || !this.settings.fixedLayout)
+                autoWidthTypes.push('autoMinWidth');
+            if (this.settings.dblClick == 'autoFit')
+                autoWidthTypes.push('autoWidth');
+
+            //Call this only once so that the table will be cloned only one time
+            if (autoWidthTypes.length)
+                this.updateColumnsAutoWidth(autoWidthTypes);
+
+            if (!this.settings.fixedLayout) {
+                var columns = this.dt.settings.aoColumns;
+                var i;
+                for (i = 0; i < columns.length; i++) {
+                    if (!columns[i].bVisible)
+                        continue;
+                    columns[i].minWidth = Math.max((columns[i].minWidthOrig || 0), columns[i].autoMinWidth);
+
+                    //We have to resize if the current column width if is less that the column minWidth
+                    if (this.$(columns[i].nTh).width() < columns[i].minWidth)
+                        this.resize(columns[i], columns[i].minWidth);
+                }
+            } else {
+                if (!this.dom.fixedLayout) {
+                    this.setTablesLayout('fixed');
+                    this.afterResizing();
                 }
-            },
-
-            /**
-             * Clean up ColResize memory references and event handlers
-             *  @method  _fnDestroy
-             *  @returns void
-             *  @private
-             */
-            "_fnDestroy": function () {
-                var i, iLen;
-
-                for (i = 0, iLen = this.s.dt.aoDrawCallback.length; i < iLen; i++) {
-                    if (this.s.dt.aoDrawCallback[i].sName === 'ColResize_Pre') {
-                        this.s.dt.aoDrawCallback.splice(i, 1);
+            }
+        };
+
+        ColResize.prototype.getTableAutoColWidths = function (table, types) {
+            var widths = {}, i, colIdx;
+            var $table = this.$(table);
+            for (i = 0; i < types.length; i++) {
+                widths[types[i]] = [];
+            }
+            if (!types.length || !$table.length)
+                return widths;
+
+            var clnTable = $table.clone().removeAttr('id').css('table-layout', 'auto');
+
+            // Remove any assigned widths from the footer (from scrolling)
+            clnTable.find('thead th, tfoot th, tfoot td').css('width', '');
+            var container = this.$('<div />').css({
+                'position': 'absolute',
+                'width': '9999px',
+                'height': '9999px'
+            });
+            container.append(clnTable);
+            this.$(this.dt.settings.nTableWrapper).append(container);
+
+            var headerCols = this.$('thead>tr>th', clnTable);
+
+            for (i = 0; i < types.length; i++) {
+                var type = types[i];
+                var fn = '';
+                switch (type) {
+                    case 'autoMinWidth':
+                        clnTable.css('width', '1px');
+                        fn = 'width';
                         break;
+                    case 'autoWidth':
+                        clnTable.css('width', 'auto');
+                        fn = 'outerWidth';
+                        break;
+                    default:
+                        throw 'Invalid widthType ' + type;
+                }
+                for (colIdx = 0; colIdx < headerCols.length; colIdx++) {
+                    widths[type].push(this.$(headerCols[colIdx])[fn]());
+                }
+            }
+
+            container.remove();
+            return widths;
+        };
+
+        ColResize.prototype.updateColumnsAutoWidth = function (types) {
+            var columns = this.dt.settings.aoColumns;
+            var i, j, colLen, type, visColIdx = 0;
+            var widths = {};
+            if (this.dom.scrollX || this.dom.scrollY) {
+                var headWidths = this.getTableAutoColWidths(this.dom.scrollHeadTable, types);
+                var bodyWidths = this.getTableAutoColWidths(this.dom.scrollBodyTable, types);
+                var footWidths = this.getTableAutoColWidths(this.dom.scrollFootTable, types);
+
+                for (i = 0; i < types.length; i++) {
+                    type = types[i];
+                    widths[type] = [];
+                    footWidths[type].length = headWidths[type].length;
+                    colLen = headWidths[type].length;
+                    for (j = 0; j < colLen; j++) {
+                        widths[type].push(Math.max(headWidths[type][j], bodyWidths[type][j], (footWidths[type][j] || 0)));
                     }
                 }
+            } else {
+                widths = this.getTableAutoColWidths(this.dt.settings.nTable, types);
+            }
+
+            for (i = 0; i < columns.length; i++) {
+                if (!columns[i].bVisible)
+                    continue;
+                for (j = 0; j < types.length; j++) {
+                    type = types[j];
+                    columns[i][type] = widths[type][visColIdx];
+                }
+                visColIdx++;
+            }
+        };
 
-                $(this.s.dt.nTHead).find('*').off('.ColResize');
+        ColResize.prototype.overrideClickHander = function (col, $th) {
+            var dtClickEvent = this.getColumnEvent($th.get(0), 'click', 'DT');
 
-                $.each(this.s.dt.aoColumns, function (i, column) {
-                    $(column.nTh).removeAttr('data-column-index');
+            //Remove the DataTables event so that ordering will not occur
+            if (dtClickEvent) {
+                $th.off('click.DT');
+                this.$(document).one('click.ColResize', function (e) {
+                    $th.on('click.DT', dtClickEvent.handler);
                 });
+            }
+        };
 
-                this.s.dt._colResize = null;
-                this.s = null;
-            },
+        ColResize.prototype.onDblClick = function (e, $th, col) {
+            if (e.target !== $th.get(0))
+                return;
+            if ($th.css('cursor') != 'col-resize')
+                return;
+
+            var width;
+            switch (this.settings.dblClick) {
+                case 'autoMinFit':
+                    width = col.autoMinWidth;
+                    break;
+                case 'autoFit':
+                    width = col.autoWidth;
+                    break;
+                default:
+                    width = col.initWidth;
+            }
+            this.resize(col, width);
+        };
 
+        ColResize.prototype.onMouseDown = function (e, col) {
+            var _this = this;
+            if (e.target !== col.nTh && e.target !== col.fhTh)
+                return true;
 
-            /**
-             * Add a data attribute to the column headers, so we know the index of
-             * the row to be reordered. This allows fast detection of the index, and
-             * for this plug-in to work with FixedHeader which clones the nodes.
-             *  @private
-             */
-            "_fnSetColumnIndexes": function () {
-                $.each(this.s.dt.aoColumns, function (i, column) {
-                    $(column.nTh).attr('data-column-index', i);
-                });
+            var $th = e.target === col.nTh ? this.$(col.nTh) : this.$(col.fhTh);
+
+            if ($th.css('cursor') != 'col-resize' || col.resizable === false) {
+                var colReorder = this.dt.settings._colReorder;
+                if (colReorder) {
+                    colReorder._fnMouseDown.call(colReorder, e, e.target); //Here we fix the e.preventDefault() in ColReorder so that we can have working inputs in header
+                }
+                return true;
+            }
+            this.dom.mouse.startX = e.pageX;
+            this.dom.mouse.prevX = e.pageX;
+            this.dom.mouse.startWidth = $th.width();
+            this.dom.resize = true;
+
+            this.beforeResizing(col);
+
+            /* Add event handlers to the document */
+            this.$(document).on('mousemove.ColResize', function (event) {
+                _this.onMouseMove(event, col);
+            });
+            this.overrideClickHander(col, $th);
+            this.$(document).one('mouseup.ColResize', function (event) {
+                _this.onMouseUp(event, col);
+            });
+
+            return false;
+        };
+
+        ColResize.prototype.resize = function (col, width) {
+            var colWidth = this.$(col.nTh).width();
+            var moveLength = width - this.$(col.nTh).width();
+            this.beforeResizing(col);
+            var resized = this.resizeColumn(col, colWidth, moveLength, moveLength);
+            this.afterResizing();
+            return resized;
+        };
+
+        ColResize.prototype.beforeResizing = function (col) {
+            //if (this.settings.fixedLayout && !this.dom.fixedLayout)
+            //    this.setTablesLayout('fixed');
+        };
+
+        ColResize.prototype.afterResizing = function () {
+            var i;
+            var columns = this.dt.settings.aoColumns;
+            for (i = 0; i < columns.length; i++) {
+                if (!columns[i].bVisible)
+                    continue;
+                columns[i].sWidth = this.$(columns[i].nTh).css('width');
             }
+
+            //Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled
+            this.updateTableSize();
+
+            //Save the state
+            this.dt.settings.oInstance.oApi._fnSaveState(this.dt.settings);
+            this.dom.origState = false;
         };
 
+        ColResize.prototype.onMouseUp = function (e, col) {
+            this.$(document).off('mousemove.ColResize');
+            if (!this.dom.resize)
+                return;
+            this.dom.resize = false;
+            this.afterResizing();
+        };
 
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * Static parameters
-         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
-        /**
-         * ColResize default settings for initialisation
-         *  @namespace
-         *  @static
-         */
-        ColResize.defaults = {
-            /**
-             * Callback function that is fired when columns are resized
-             *  @type function():void
-             *  @default null
-             *  @static
-             */
-            "resizeCallback": null,
-
-            /**
-             * Exclude array for columns that are not resizable
-             *  @property exclude
-             *  @type     array of indexes that are excluded from resizing
-             *  @default  []
-             */
-            "exclude": [],
-
-            /**
-             * Check to see if user is using a fixed table width or dynamic
-             * if true:
-             *      -Columns will resize themselves and their neighbour
-             *      -If neighbour is excluded resize will not occur
-             * if false:
-             *      -Columns will resize themselves and increase or decrease the width of the table accordingly
-             */
-            "tableWidthFixed": true,
-
-            /**
-             * Width of the resize handle in pixels
-             *  @property handleWidth
-             *  @type     int (pixels)
-             *  @default  10
-             */
-            "handleWidth": 10,
-
-            /**
-             * Right to left support, when true flips which column they are resizing on mouse down
-             *  @property rtl
-             *  @type     bool
-             *  @default  false
-             */
-            "rtl": false
-        };
-
-
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * Constants
-         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-        /**
-         * ColResize version
-         *  @constant  version
-         *  @type      String
-         *  @default   As code
-         */
-        ColResize.version = "0.0.10";
-
-
-        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-         * DataTables interfaces
-         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-        // Expose
-        $.fn.dataTable.ColResize = ColResize;
-        $.fn.DataTable.ColResize = ColResize;
-
-
-        // Register a new feature with DataTables
-        if (typeof $.fn.dataTable == "function" &&
-            typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
-            $.fn.dataTableExt.fnVersionCheck('1.9.3')) {
-            $.fn.dataTableExt.aoFeatures.push({
-                "fnInit": function (settings) {
-                    var table = settings.oInstance;
-
-                    if (!settings._colResize) {
-                        var dtInit = settings.oInit;
-                        var opts = dtInit.colResize || dtInit.oColResize || {};
-
-                        new ColResize(settings, opts);
-                    }
-                    else {
-                        table.oApi._fnLog(settings, 1, "ColResize attempted to initialise twice. Ignoring second");
+        ColResize.prototype.canResizeColumn = function (col, newWidth) {
+            return (col.resizable === undefined || col.resizable) && this.settings.minWidth <= newWidth && (!col.minWidth || col.minWidth <= newWidth) && (!this.settings.maxWidth || this.settings.maxWidth >= newWidth) && (!col.maxWidth || col.maxWidth >= newWidth);
+        };
+
+        ColResize.prototype.getColumnMaxWidth = function (col) {
+            return col.maxWidth ? col.maxWidth : this.settings.maxWidth;
+        };
+
+        ColResize.prototype.getColumnMinWidth = function (col) {
+            return col.minWidth ? col.minWidth : this.settings.minWidth;
+        };
+
+        ColResize.prototype.getPrevResizableColumnIdx = function (col, moveLength) {
+            var columns = this.dt.settings.aoColumns;
+            var colIdx = ColResizeHelper.indexOf(columns, col);
+            for (var i = colIdx; i >= 0; i--) {
+                if (!columns[i].bVisible)
+                    continue;
+                var newWidth = this.$(columns[i].nTh).width() + moveLength;
+                if (this.canResizeColumn(columns[i], newWidth))
+                    return i;
+            }
+            return -1;
+        };
+
+        ColResize.prototype.getNextResizableColumnIdx = function (col, moveLength) {
+            var columns = this.dt.settings.aoColumns;
+            var colIdx = ColResizeHelper.indexOf(columns, col);
+            for (var i = (colIdx + 1); i < columns.length; i++) {
+                if (!columns[i].bVisible)
+                    continue;
+                var newWidth = this.$(columns[i].nTh).width() - moveLength;
+                if (this.canResizeColumn(columns[i], newWidth))
+                    return i;
+            }
+            return -1;
+        };
+
+        ColResize.prototype.resizeColumn = function (col, startWidth, moveLength, lastMoveLength) {
+            if (moveLength == 0 || lastMoveLength == 0 || col.resizable === false)
+                return false;
+            var i;
+            var columns = this.dt.settings.aoColumns;
+            var headCol = this.$(col.nTh);
+            var headColNext = headCol.next();
+            var colIdx = this.getColumnIndex(col);
+            var thWidth = startWidth + moveLength;
+            var thNextWidth;
+            var nextColIdx;
+
+            if (!this.dom.scrollX) {
+                if (lastMoveLength < 0) {
+                    thWidth = headColNext.width() - lastMoveLength;
+                    nextColIdx = this.getPrevResizableColumnIdx(col, lastMoveLength);
+                    if (nextColIdx < 0)
+                        return false;
+                    headCol = headColNext;
+                    colIdx = colIdx + 1;
+                    headColNext = this.$(columns[nextColIdx].nTh);
+                    thNextWidth = headColNext.width() + lastMoveLength;
+                } else {
+                    thWidth = headCol.width() + lastMoveLength;
+                    nextColIdx = this.getNextResizableColumnIdx(col, lastMoveLength);
+
+                    //If there is no columns that can be shrinked dont resize anymore
+                    if (nextColIdx < 0)
+                        return false;
+                    headColNext = this.$(columns[nextColIdx].nTh);
+                    thNextWidth = headColNext.width() - lastMoveLength;
+
+                    if ((this.settings.maxWidth && this.settings.maxWidth < thWidth) || col.maxWidth && col.maxWidth < thWidth)
+                        return false;
+                }
+                if (!this.canResizeColumn(columns[nextColIdx], thNextWidth) || !this.canResizeColumn(columns[colIdx], thWidth))
+                    return false;
+                headColNext.width(thNextWidth);
+
+                //If fixed header is present we have to resize the cloned column too
+                if (this.dom.fixedHeader) {
+                    this.$(columns[nextColIdx].fhTh).width(thNextWidth);
+                    this.$(columns[colIdx].fhTh).width(thWidth);
+
+                    //If fixedfooter was enabled resize that too
+                    if (columns[nextColIdx].fhTf) {
+                        this.$(columns[nextColIdx].fhTf).width(thNextWidth);
+                        this.$(columns[colIdx].fhTf).width(thWidth);
                     }
+                }
+            } else {
+                if (!this.canResizeColumn(col, thWidth))
+                    return false;
+                var tSize = this.tableSize + moveLength + 'px';
+                this.dom.scrollHeadInner.css('width', tSize);
+                this.dom.scrollHeadTable.css('width', tSize);
+                this.dom.scrollBodyTable.css('width', tSize);
+                this.dom.scrollFootTable.css('width', tSize);
+            }
+            headCol.width(thWidth);
+
+            //scrollX or scrollY enabled
+            if (this.dom.scrollBody.length) {
+                var colDomIdx = 0;
+                for (i = 0; i < this.dt.settings.aoColumns.length && i != colIdx; i++) {
+                    if (this.dt.settings.aoColumns[i].bVisible)
+                        colDomIdx++;
+                }
 
-                    return null;
-                    /* No node for DataTables to insert */
-                },
-                "cFeature": "Z",
-                "sFeature": "ColResize"
-            });
-        } else {
-            alert("Warning: ColResize requires DataTables 1.9.3 or greater - www.datatables.net/download");
-        }
+                //Get the table
+                var bodyCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollBodyTable);
+                var footCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollFootTable);
 
+                //This will happen only when scrollY is used without scrollX
+                if (!this.dom.scrollX) {
+                    var nextColDomIdx = 0;
+                    for (i = 0; i < this.dt.settings.aoColumns.length && i != nextColIdx; i++) {
+                        if (this.dt.settings.aoColumns[i].bVisible)
+                            nextColDomIdx++;
+                    }
+                    var bodyColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollBodyTable);
+                    var footColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollFootTable);
 
-// API augmentation
-        if ($.fn.dataTable.Api) {
-            $.fn.dataTable.Api.register('colResize.reset()', function () {
-                return this.iterator('table', function (ctx) {
-                    ctx._colResize.fnReset();
-                });
-            });
-        }
+                    bodyColNext.width(thNextWidth);
+                    if (thWidth > 0)
+                        bodyCol.width(thWidth);
 
-        return ColResize;
-    }; // /factory
+                    footColNext.width(thNextWidth);
+                    if (thWidth > 0)
+                        footCol.width(thWidth);
+                }
 
+                //Resize the table and the column
+                if (this.dom.scrollX && thWidth > 0) {
+                    bodyCol.width(thWidth);
+                    footCol.width(thWidth);
+                }
+            }
+            return true;
+        };
 
-// Define as an AMD module if possible
-if ( typeof define === 'function' && define.amd ) {
-    define( ['jquery', 'datatables'], factory );
-}
-else if ( typeof exports === 'object' ) {
-    // Node/CommonJS
-    factory( require('jquery'), require('datatables') );
-}
-else if (jQuery && !jQuery.fn.dataTable.ColResize) {
-    // Otherwise simply initialise as normal, stopping multiple evaluation
-    factory(jQuery, jQuery.fn.dataTable);
-}
+        ColResize.prototype.onMouseMove = function (e, col) {
+            var moveLength = e.pageX - this.dom.mouse.startX;
+            var lastMoveLength = e.pageX - this.dom.mouse.prevX;
+            this.resizeColumn(col, this.dom.mouse.startWidth, moveLength, lastMoveLength);
+            this.dom.mouse.prevX = e.pageX;
+        };
 
+        ColResize.prototype.destroy = function () {
+        };
+        ColResize.defaultSettings = {
+            minWidth: 1,
+            maxWidth: null,
+            fixedLayout: true,
+            fixedHeader: null,
+            dblClick: 'initWidth'
+        };
+        return ColResize;
+    })();
+    dt.ColResize = ColResize;
 
-})(window, document);
\ No newline at end of file
+    var ColResizeHelper = (function () {
+        function ColResizeHelper() {
+        }
+        ColResizeHelper.indexOf = function (arr, item, equalFun) {
+            if (typeof equalFun === "undefined") { equalFun = null; }
+            for (var i = 0; i < arr.length; i++) {
+                if (equalFun) {
+                    if (equalFun(arr[i], item))
+                        return i;
+                } else if (arr[i] === item)
+                    return i;
+            }
+            return -1;
+        };
+        return ColResizeHelper;
+    })();
+    dt.ColResizeHelper = ColResizeHelper;
+})(dt || (dt = {}));
+
+(function ($, window, document, undefined) {
+    //Register events
+    $.fn.DataTable.models.oSettings.colResizeInitCompleted = [];
+
+    //Register api function
+    $.fn.DataTable.Api.register('colResize.init()', function (settings) {
+        var colResize = new dt.ColResize($, this, settings);
+        if (this.settings()[0]._bInitComplete)
+            colResize.initialize();
+        else
+            this.one('init.dt', function () {
+                colResize.initialize();
+            });
+        return null;
+    });
+
+    $.fn.DataTable.Api.register('column().resize()', function (width) {
+        var oSettings = this.settings()[0];
+        var colResize = oSettings.colResize;
+        return colResize.resize(oSettings.aoColumns[this[0][0]], width);
+    });
+
+    //Add as feature
+    $.fn.dataTable.ext.feature.push({
+        "fnInit": function (oSettings) {
+            return oSettings.oInstance.api().colResize.init(oSettings.oInit.colResize);
+        },
+        "cFeature": "J",
+        "sFeature": "ColResize"
+    });
+}(jQuery, window, document, undefined));
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css
new file mode 100644
index 00000000..4001ab12
--- /dev/null
+++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css
@@ -0,0 +1,4 @@
+div.FixedHeader_Cloned th,
+div.FixedHeader_Cloned td {
+	background-color: white !important;
+}
diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js
new file mode 100644
index 00000000..c1f962c4
--- /dev/null
+++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js
@@ -0,0 +1,1027 @@
+/*! FixedHeader 2.1.2
+ * ©2010-2014 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary     FixedHeader
+ * @description Fix a table's header or footer, so it is always visible while
+ *              Scrolling
+ * @version     2.1.2
+ * @file        dataTables.fixedHeader.js
+ * @author      SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact     www.sprymedia.co.uk/contact
+ * @copyright   Copyright 2009-2014 SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ *   MIT license - http://datatables.net/license/mit
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/* Global scope for FixedColumns for backwards compatibility - will be removed
+ * in future. Not documented in 1.1.x.
+ */
+
+/* Global scope for FixedColumns */
+var FixedHeader;
+
+(function(window, document, undefined) {
+
+
+var factory = function( $, DataTable ) {
+"use strict";
+
+/*
+ * Function: FixedHeader
+ * Purpose:  Provide 'fixed' header, footer and columns for a DataTable
+ * Returns:  object:FixedHeader - must be called with 'new'
+ * Inputs:   mixed:mTable - target table
+ *  @param {object} dt DataTables instance or HTML table node. With DataTables
+ *    1.10 this can also be a jQuery collection (with just a single table in its
+ *    result set), a jQuery selector, DataTables API instance or settings
+ *    object.
+ *  @param {object} [oInit] initialisation settings, with the following
+ *    properties (each optional)
+ *    * bool:top -    fix the header (default true)
+ *    * bool:bottom - fix the footer (default false)
+ *    * int:left -    fix the left column(s) (default 0)
+ *    * int:right -   fix the right column(s) (default 0)
+ *    * int:zTop -    fixed header zIndex
+ *    * int:zBottom - fixed footer zIndex
+ *    * int:zLeft -   fixed left zIndex
+ *    * int:zRight -  fixed right zIndex
+ */
+FixedHeader = function ( mTable, oInit ) {
+	/* Sanity check - you just know it will happen */
+	if ( ! this instanceof FixedHeader )
+	{
+		alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." );
+		return;
+	}
+
+	var that = this;
+	var oSettings = {
+		"aoCache": [],
+		"oSides": {
+			"top": true,
+			"bottom": false,
+			"left": 0,
+			"right": 0
+		},
+		"oZIndexes": {
+			"top": 104,
+			"bottom": 103,
+			"left": 102,
+			"right": 101
+		},
+		"oCloneOnDraw": {
+			"top": false,
+			"bottom": false,
+			"left": true,
+			"right": true
+		},
+		"oMes": {
+			"iTableWidth": 0,
+			"iTableHeight": 0,
+			"iTableLeft": 0,
+			"iTableRight": 0, /* note this is left+width, not actually "right" */
+			"iTableTop": 0,
+			"iTableBottom": 0 /* note this is top+height, not actually "bottom" */
+		},
+		"oOffset": {
+			"top": 0
+		},
+		"nTable": null,
+		"bFooter": false,
+		"bInitComplete": false
+	};
+
+	/*
+	 * Function: fnGetSettings
+	 * Purpose:  Get the settings for this object
+	 * Returns:  object: - settings object
+	 * Inputs:   -
+	 */
+	this.fnGetSettings = function () {
+		return oSettings;
+	};
+
+	/*
+	 * Function: fnUpdate
+	 * Purpose:  Update the positioning and copies of the fixed elements
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	this.fnUpdate = function () {
+		this._fnUpdateClones();
+		this._fnUpdatePositions();
+	};
+
+	/*
+	 * Function: fnPosition
+	 * Purpose:  Update the positioning of the fixed elements
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	this.fnPosition = function () {
+		this._fnUpdatePositions();
+	};
+
+
+	var dt = $.fn.dataTable.Api ?
+		new $.fn.dataTable.Api( mTable ).settings()[0] :
+		mTable.fnSettings();
+
+	dt._oPluginFixedHeader = this;
+
+	/* Let's do it */
+	this.fnInit( dt, oInit );
+
+};
+
+
+/*
+ * Variable: FixedHeader
+ * Purpose:  Prototype for FixedHeader
+ * Scope:    global
+ */
+FixedHeader.prototype = {
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Initialisation
+	 */
+
+	/*
+	 * Function: fnInit
+	 * Purpose:  The "constructor"
+	 * Returns:  -
+	 * Inputs:   {as FixedHeader function}
+	 */
+	fnInit: function ( oDtSettings, oInit )
+	{
+		var s = this.fnGetSettings();
+		var that = this;
+
+		/* Record the user definable settings */
+		this.fnInitSettings( s, oInit );
+
+		if ( oDtSettings.oScroll.sX !== "" || oDtSettings.oScroll.sY !== "" )
+		{
+			alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" );
+			return;
+		}
+
+		s.nTable = oDtSettings.nTable;
+		oDtSettings.aoDrawCallback.unshift( {
+			"fn": function () {
+				FixedHeader.fnMeasure();
+				that._fnUpdateClones.call(that);
+				that._fnUpdatePositions.call(that);
+			},
+			"sName": "FixedHeader"
+		} );
+
+		s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false;
+
+		/* Add the 'sides' that are fixed */
+		if ( s.oSides.top )
+		{
+			s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) );
+		}
+		if ( s.oSides.bottom )
+		{
+			s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) );
+		}
+		if ( s.oSides.left )
+		{
+			s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft, s.oSides.left ) );
+		}
+		if ( s.oSides.right )
+		{
+			s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight, s.oSides.right ) );
+		}
+
+		/* Event listeners for window movement */
+		FixedHeader.afnScroll.push( function () {
+			that._fnUpdatePositions.call(that);
+		} );
+
+		$(window).resize( function () {
+			FixedHeader.fnMeasure();
+			that._fnUpdateClones.call(that);
+			that._fnUpdatePositions.call(that);
+		} );
+
+		$(s.nTable)
+			.on('column-reorder.dt', function () {
+				FixedHeader.fnMeasure();
+				that._fnUpdateClones( true );
+				that._fnUpdatePositions();
+			} )
+			.on('column-visibility.dt', function () {
+				FixedHeader.fnMeasure();
+				that._fnUpdateClones( true );
+				that._fnUpdatePositions();
+			} );
+
+		/* Get things right to start with */
+		FixedHeader.fnMeasure();
+		that._fnUpdateClones();
+		that._fnUpdatePositions();
+
+		s.bInitComplete = true;
+	},
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Support functions
+	 */
+
+	/*
+	 * Function: fnInitSettings
+	 * Purpose:  Take the user's settings and copy them to our local store
+	 * Returns:  -
+	 * Inputs:   object:s - the local settings object
+	 *           object:oInit - the user's settings object
+	 */
+	fnInitSettings: function ( s, oInit )
+	{
+		if ( oInit !== undefined )
+		{
+			if ( oInit.top !== undefined ) {
+				s.oSides.top = oInit.top;
+			}
+			if ( oInit.bottom !== undefined ) {
+				s.oSides.bottom = oInit.bottom;
+			}
+			if ( typeof oInit.left == 'boolean' ) {
+				s.oSides.left = oInit.left ? 1 : 0;
+			}
+			else if ( oInit.left !== undefined ) {
+				s.oSides.left = oInit.left;
+			}
+			if ( typeof oInit.right == 'boolean' ) {
+				s.oSides.right = oInit.right ? 1 : 0;
+			}
+			else if ( oInit.right !== undefined ) {
+				s.oSides.right = oInit.right;
+			}
+
+			if ( oInit.zTop !== undefined ) {
+				s.oZIndexes.top = oInit.zTop;
+			}
+			if ( oInit.zBottom !== undefined ) {
+				s.oZIndexes.bottom = oInit.zBottom;
+			}
+			if ( oInit.zLeft !== undefined ) {
+				s.oZIndexes.left = oInit.zLeft;
+			}
+			if ( oInit.zRight !== undefined ) {
+				s.oZIndexes.right = oInit.zRight;
+			}
+
+			if ( oInit.offsetTop !== undefined ) {
+				s.oOffset.top = oInit.offsetTop;
+			}
+			if ( oInit.alwaysCloneTop !== undefined ) {
+				s.oCloneOnDraw.top = oInit.alwaysCloneTop;
+			}
+			if ( oInit.alwaysCloneBottom !== undefined ) {
+				s.oCloneOnDraw.bottom = oInit.alwaysCloneBottom;
+			}
+			if ( oInit.alwaysCloneLeft !== undefined ) {
+				s.oCloneOnDraw.left = oInit.alwaysCloneLeft;
+			}
+			if ( oInit.alwaysCloneRight !== undefined ) {
+				s.oCloneOnDraw.right = oInit.alwaysCloneRight;
+			}
+		}
+	},
+
+	/*
+	 * Function: _fnCloneTable
+	 * Purpose:  Clone the table node and do basic initialisation
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	_fnCloneTable: function ( sType, sClass, fnClone, iCells )
+	{
+		var s = this.fnGetSettings();
+		var nCTable;
+
+		/* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how
+		 * DataTables works. Therefore, we can set this to be relatively position (if it is not
+		 * alreadu absolute, and use this as the base point for the cloned header
+		 */
+		if ( $(s.nTable.parentNode).css('position') != "absolute" )
+		{
+			s.nTable.parentNode.style.position = "relative";
+		}
+
+		/* Just a shallow clone will do - we only want the table node */
+		nCTable = s.nTable.cloneNode( false );
+		nCTable.removeAttribute( 'id' );
+
+		var nDiv = document.createElement( 'div' );
+		nDiv.style.position = "absolute";
+		nDiv.style.top = "0px";
+		nDiv.style.left = "0px";
+		nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass;
+
+		/* Set the zIndexes */
+		if ( sType == "fixedHeader" )
+		{
+			nDiv.style.zIndex = s.oZIndexes.top;
+		}
+		if ( sType == "fixedFooter" )
+		{
+			nDiv.style.zIndex = s.oZIndexes.bottom;
+		}
+		if ( sType == "fixedLeft" )
+		{
+			nDiv.style.zIndex = s.oZIndexes.left;
+		}
+		else if ( sType == "fixedRight" )
+		{
+			nDiv.style.zIndex = s.oZIndexes.right;
+		}
+
+		/* remove margins since we are going to position it absolutely */
+		nCTable.style.margin = "0";
+
+		/* Insert the newly cloned table into the DOM, on top of the "real" header */
+		nDiv.appendChild( nCTable );
+		document.body.appendChild( nDiv );
+
+		return {
+			"nNode": nCTable,
+			"nWrapper": nDiv,
+			"sType": sType,
+			"sPosition": "",
+			"sTop": "",
+			"sLeft": "",
+			"fnClone": fnClone,
+			"iCells": iCells
+		};
+	},
+
+	/*
+	 * Function: _fnMeasure
+	 * Purpose:  Get the current positioning of the table in the DOM
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	_fnMeasure: function ()
+	{
+		var
+			s = this.fnGetSettings(),
+			m = s.oMes,
+			jqTable = $(s.nTable),
+			oOffset = jqTable.offset(),
+			iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ),
+			iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' );
+
+		m.iTableWidth = jqTable.outerWidth();
+		m.iTableHeight = jqTable.outerHeight();
+		m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft;
+		m.iTableTop = oOffset.top + iParentScrollTop;
+		m.iTableRight = m.iTableLeft + m.iTableWidth;
+		m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth;
+		m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight;
+	},
+
+	/*
+	 * Function: _fnSumScroll
+	 * Purpose:  Sum node parameters all the way to the top
+	 * Returns:  int: sum
+	 * Inputs:   node:n - node to consider
+	 *           string:side - scrollTop or scrollLeft
+	 */
+	_fnSumScroll: function ( n, side )
+	{
+		var i = n[side];
+		while ( n = n.parentNode )
+		{
+			if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' )
+			{
+				break;
+			}
+			i = n[side];
+		}
+		return i;
+	},
+
+	/*
+	 * Function: _fnUpdatePositions
+	 * Purpose:  Loop over the fixed elements for this table and update their positions
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	_fnUpdatePositions: function ()
+	{
+		var s = this.fnGetSettings();
+		this._fnMeasure();
+
+		for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ )
+		{
+			if ( s.aoCache[i].sType == "fixedHeader" )
+			{
+				this._fnScrollFixedHeader( s.aoCache[i] );
+			}
+			else if ( s.aoCache[i].sType == "fixedFooter" )
+			{
+				this._fnScrollFixedFooter( s.aoCache[i] );
+			}
+			else if ( s.aoCache[i].sType == "fixedLeft" )
+			{
+				this._fnScrollHorizontalLeft( s.aoCache[i] );
+			}
+			else
+			{
+				this._fnScrollHorizontalRight( s.aoCache[i] );
+			}
+		}
+	},
+
+	/*
+	 * Function: _fnUpdateClones
+	 * Purpose:  Loop over the fixed elements for this table and call their cloning functions
+	 * Returns:  -
+	 * Inputs:   -
+	 */
+	_fnUpdateClones: function ( full )
+	{
+		var s = this.fnGetSettings();
+
+		if ( full ) {
+			// This is a little bit of a hack to force a full clone draw. When
+			// `full` is set to true, we want to reclone the source elements,
+			// regardless of the clone-on-draw settings
+			s.bInitComplete = false;
+		}
+
+		for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ )
+		{
+			s.aoCache[i].fnClone.call( this, s.aoCache[i] );
+		}
+
+		if ( full ) {
+			s.bInitComplete = true;
+		}
+	},
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Scrolling functions
+	 */
+
+	/*
+	 * Function: _fnScrollHorizontalLeft
+	 * Purpose:  Update the positioning of the scrolling elements
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnScrollHorizontalRight: function ( oCache )
+	{
+		var
+			s = this.fnGetSettings(),
+			oMes = s.oMes,
+			oWin = FixedHeader.oWin,
+			oDoc = FixedHeader.oDoc,
+			nTable = oCache.nWrapper,
+			iFixedWidth = $(nTable).outerWidth();
+
+		if ( oWin.iScrollRight < oMes.iTableRight )
+		{
+			/* Fully right aligned */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iFixedWidth)+"px", 'left', nTable.style );
+		}
+		else if ( oMes.iTableLeft < oDoc.iWidth-oWin.iScrollRight-iFixedWidth )
+		{
+			/* Middle */
+			this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', (oWin.iWidth-iFixedWidth)+"px", 'left', nTable.style );
+		}
+		else
+		{
+			/* Fully left aligned */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+	},
+
+	/*
+	 * Function: _fnScrollHorizontalLeft
+	 * Purpose:  Update the positioning of the scrolling elements
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnScrollHorizontalLeft: function ( oCache )
+	{
+		var
+			s = this.fnGetSettings(),
+			oMes = s.oMes,
+			oWin = FixedHeader.oWin,
+			oDoc = FixedHeader.oDoc,
+			nTable = oCache.nWrapper,
+			iCellWidth = $(nTable).outerWidth();
+
+		if ( oWin.iScrollLeft < oMes.iTableLeft )
+		{
+			/* Fully left align */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+		else if ( oWin.iScrollLeft < oMes.iTableLeft+oMes.iTableWidth-iCellWidth )
+		{
+			this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', "0px", 'left', nTable.style );
+		}
+		else
+		{
+			/* Fully right align */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iCellWidth)+"px", 'left', nTable.style );
+		}
+	},
+
+	/*
+	 * Function: _fnScrollFixedFooter
+	 * Purpose:  Update the positioning of the scrolling elements
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnScrollFixedFooter: function ( oCache )
+	{
+		var
+			s = this.fnGetSettings(),
+			oMes = s.oMes,
+			oWin = FixedHeader.oWin,
+			oDoc = FixedHeader.oDoc,
+			nTable = oCache.nWrapper,
+			iTheadHeight = $("thead", s.nTable).outerHeight(),
+			iCellHeight = $(nTable).outerHeight();
+
+		if ( oWin.iScrollBottom < oMes.iTableBottom )
+		{
+			/* Below */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+oMes.iTableHeight-iCellHeight)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+		else if ( oWin.iScrollBottom < oMes.iTableBottom+oMes.iTableHeight-iCellHeight-iTheadHeight )
+		{
+			this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oWin.iHeight-iCellHeight)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
+		}
+		else
+		{
+			/* Above */
+			this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iCellHeight)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+	},
+
+	/*
+	 * Function: _fnScrollFixedHeader
+	 * Purpose:  Update the positioning of the scrolling elements
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnScrollFixedHeader: function ( oCache )
+	{
+		var
+			s = this.fnGetSettings(),
+			oMes = s.oMes,
+			oWin = FixedHeader.oWin,
+			oDoc = FixedHeader.oDoc,
+			nTable = oCache.nWrapper,
+			iTbodyHeight = 0,
+			anTbodies = s.nTable.getElementsByTagName('tbody');
+
+		for (var i = 0; i < anTbodies.length; ++i) {
+			iTbodyHeight += anTbodies[i].offsetHeight;
+		}
+
+		if ( oMes.iTableTop > oWin.iScrollTop + s.oOffset.top )
+		{
+			/* Above the table */
+			this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+		else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight )
+		{
+			/* At the bottom of the table */
+			this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+		}
+		else
+		{
+			/* In the middle of the table */
+			this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
+			this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style );
+			this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
+		}
+	},
+
+	/*
+	 * Function: _fnUpdateCache
+	 * Purpose:  Check the cache and update cache and value if needed
+	 * Returns:  -
+	 * Inputs:   object:oCache - local cache object
+	 *           string:sCache - cache property
+	 *           string:sSet - value to set
+	 *           string:sProperty - object property to set
+	 *           object:oObj - object to update
+	 */
+	_fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj )
+	{
+		if ( oCache[sCache] != sSet )
+		{
+			oObj[sProperty] = sSet;
+			oCache[sCache] = sSet;
+		}
+	},
+
+
+
+	/**
+	 * Copy the classes of all child nodes from one element to another. This implies
+	 * that the two have identical structure - no error checking is performed to that
+	 * fact.
+	 *  @param {element} source Node to copy classes from
+	 *  @param {element} dest Node to copy classes too
+	 */
+	_fnClassUpdate: function ( source, dest )
+	{
+		var that = this;
+
+		if ( source.nodeName.toUpperCase() === "TR" || source.nodeName.toUpperCase() === "TH" ||
+			 source.nodeName.toUpperCase() === "TD" || source.nodeName.toUpperCase() === "SPAN" )
+		{
+			dest.className = source.className;
+		}
+
+		$(source).children().each( function (i) {
+			that._fnClassUpdate( $(source).children()[i], $(dest).children()[i] );
+		} );
+	},
+
+
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Cloning functions
+	 */
+
+	/*
+	 * Function: _fnCloneThead
+	 * Purpose:  Clone the thead element
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnCloneThead: function ( oCache )
+	{
+		var s = this.fnGetSettings();
+		var nTable = oCache.nNode;
+
+		if ( s.bInitComplete && !s.oCloneOnDraw.top )
+		{
+			this._fnClassUpdate( $('thead', s.nTable)[0], $('thead', nTable)[0] );
+			return;
+		}
+
+		/* Set the wrapper width to match that of the cloned table */
+		var iDtWidth = $(s.nTable).outerWidth();
+		oCache.nWrapper.style.width = iDtWidth+"px";
+		nTable.style.width = iDtWidth+"px";
+
+		/* Remove any children the cloned table has */
+		while ( nTable.childNodes.length > 0 )
+		{
+			$('thead th', nTable).unbind( 'click' );
+			nTable.removeChild( nTable.childNodes[0] );
+		}
+
+		/* Clone the DataTables header */
+		var nThead = $('thead', s.nTable).clone(true)[0];
+		nTable.appendChild( nThead );
+
+		/* Copy the widths across - apparently a clone isn't good enough for this */
+		var a = [];
+		var b = [];
+
+		$("thead>tr th", s.nTable).each( function (i) {
+			a.push( $(this).width() );
+		} );
+
+		$("thead>tr td", s.nTable).each( function (i) {
+			b.push( $(this).width() );
+		} );
+
+		$("thead>tr th", s.nTable).each( function (i) {
+			$("thead>tr th:eq("+i+")", nTable).width( a[i] );
+			$(this).width( a[i] );
+		} );
+
+		$("thead>tr td", s.nTable).each( function (i) {
+			$("thead>tr td:eq("+i+")", nTable).width( b[i] );
+			$(this).width( b[i] );
+		} );
+
+		// Stop DataTables 1.9 from putting a focus ring on the headers when
+		// clicked to sort
+		$('th.sorting, th.sorting_desc, th.sorting_asc', nTable).bind( 'click', function () {
+			this.blur();
+		} );
+	},
+
+	/*
+	 * Function: _fnCloneTfoot
+	 * Purpose:  Clone the tfoot element
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnCloneTfoot: function ( oCache )
+	{
+		var s = this.fnGetSettings();
+		var nTable = oCache.nNode;
+
+		/* Set the wrapper width to match that of the cloned table */
+		oCache.nWrapper.style.width = $(s.nTable).outerWidth()+"px";
+
+		/* Remove any children the cloned table has */
+		while ( nTable.childNodes.length > 0 )
+		{
+			nTable.removeChild( nTable.childNodes[0] );
+		}
+
+		/* Clone the DataTables footer */
+		var nTfoot = $('tfoot', s.nTable).clone(true)[0];
+		nTable.appendChild( nTfoot );
+
+		/* Copy the widths across - apparently a clone isn't good enough for this */
+		$("tfoot:eq(0)>tr th", s.nTable).each( function (i) {
+			$("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( $(this).width() );
+		} );
+
+		$("tfoot:eq(0)>tr td", s.nTable).each( function (i) {
+			$("tfoot:eq(0)>tr td:eq("+i+")", nTable).width( $(this).width() );
+		} );
+	},
+
+	/*
+	 * Function: _fnCloneTLeft
+	 * Purpose:  Clone the left column(s)
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnCloneTLeft: function ( oCache )
+	{
+		var s = this.fnGetSettings();
+		var nTable = oCache.nNode;
+		var nBody = $('tbody', s.nTable)[0];
+
+		/* Remove any children the cloned table has */
+		while ( nTable.childNodes.length > 0 )
+		{
+			nTable.removeChild( nTable.childNodes[0] );
+		}
+
+		/* Is this the most efficient way to do this - it looks horrible... */
+		nTable.appendChild( $("thead", s.nTable).clone(true)[0] );
+		nTable.appendChild( $("tbody", s.nTable).clone(true)[0] );
+		if ( s.bFooter )
+		{
+			nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] );
+		}
+
+		/* Remove unneeded cells */
+		var sSelector = 'gt(' + (oCache.iCells - 1) + ')';
+		$('thead tr', nTable).each( function (k) {
+			$('th:' + sSelector, this).remove();
+		} );
+
+		$('tfoot tr', nTable).each( function (k) {
+			$('th:' + sSelector, this).remove();
+		} );
+
+		$('tbody tr', nTable).each( function (k) {
+			$('td:' + sSelector, this).remove();
+		} );
+
+		this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable );
+		this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
+		this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable );
+
+		var iWidth = 0;
+		for (var i = 0; i < oCache.iCells; i++) {
+			iWidth += $('thead tr th:eq(' + i + ')', s.nTable).outerWidth();
+		}
+		nTable.style.width = iWidth+"px";
+		oCache.nWrapper.style.width = iWidth+"px";
+	},
+
+	/*
+	 * Function: _fnCloneTRight
+	 * Purpose:  Clone the right most column(s)
+	 * Returns:  -
+	 * Inputs:   object:oCache - the cached values for this fixed element
+	 */
+	_fnCloneTRight: function ( oCache )
+	{
+		var s = this.fnGetSettings();
+		var nBody = $('tbody', s.nTable)[0];
+		var nTable = oCache.nNode;
+		var iCols = $('tbody tr:eq(0) td', s.nTable).length;
+
+		/* Remove any children the cloned table has */
+		while ( nTable.childNodes.length > 0 )
+		{
+			nTable.removeChild( nTable.childNodes[0] );
+		}
+
+		/* Is this the most efficient way to do this - it looks horrible... */
+		nTable.appendChild( $("thead", s.nTable).clone(true)[0] );
+		nTable.appendChild( $("tbody", s.nTable).clone(true)[0] );
+		if ( s.bFooter )
+		{
+			nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] );
+		}
+		$('thead tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove();
+		$('tfoot tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove();
+
+		/* Remove unneeded cells */
+		$('tbody tr', nTable).each( function (k) {
+			$('td:lt('+(iCols-oCache.iCells)+')', this).remove();
+		} );
+
+		this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable );
+		this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
+		this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable );
+
+		var iWidth = 0;
+		for (var i = 0; i < oCache.iCells; i++) {
+			iWidth += $('thead tr th:eq('+(iCols-1-i)+')', s.nTable).outerWidth();
+		}
+		nTable.style.width = iWidth+"px";
+		oCache.nWrapper.style.width = iWidth+"px";
+	},
+
+
+	/**
+	 * Equalise the heights of the rows in a given table node in a cross browser way. Note that this
+	 * is more or less lifted as is from FixedColumns
+	 *  @method  fnEqualiseHeights
+	 *  @returns void
+	 *  @param   {string} parent Node type - thead, tbody or tfoot
+	 *  @param   {element} original Original node to take the heights from
+	 *  @param   {element} clone Copy the heights to
+	 *  @private
+	 */
+	"fnEqualiseHeights": function ( parent, original, clone )
+	{
+		var that = this;
+		var originals = $(parent +' tr', original);
+		var height;
+
+		$(parent+' tr', clone).each( function (k) {
+			height = originals.eq( k ).css('height');
+
+			// This is nasty :-(. IE has a sub-pixel error even when setting
+			// the height below (the Firefox fix) which causes the fixed column
+			// to go out of alignment. Need to add a pixel before the assignment
+			// Can this be feature detected? Not sure how...
+			if ( navigator.appName == 'Microsoft Internet Explorer' ) {
+				height = parseInt( height, 10 ) + 1;
+			}
+
+			$(this).css( 'height', height );
+
+			// For Firefox to work, we need to also set the height of the
+			// original row, to the value that we read from it! Otherwise there
+			// is a sub-pixel rounding error
+			originals.eq( k ).css( 'height', height );
+		} );
+	}
+};
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Static properties and methods
+ *   We use these for speed! This information is common to all instances of FixedHeader, so no
+ * point if having them calculated and stored for each different instance.
+ */
+
+/*
+ * Variable: oWin
+ * Purpose:  Store information about the window positioning
+ * Scope:    FixedHeader
+ */
+FixedHeader.oWin = {
+	"iScrollTop": 0,
+	"iScrollRight": 0,
+	"iScrollBottom": 0,
+	"iScrollLeft": 0,
+	"iHeight": 0,
+	"iWidth": 0
+};
+
+/*
+ * Variable: oDoc
+ * Purpose:  Store information about the document size
+ * Scope:    FixedHeader
+ */
+FixedHeader.oDoc = {
+	"iHeight": 0,
+	"iWidth": 0
+};
+
+/*
+ * Variable: afnScroll
+ * Purpose:  Array of functions that are to be used for the scrolling components
+ * Scope:    FixedHeader
+ */
+FixedHeader.afnScroll = [];
+
+/*
+ * Function: fnMeasure
+ * Purpose:  Update the measurements for the window and document
+ * Returns:  -
+ * Inputs:   -
+ */
+FixedHeader.fnMeasure = function ()
+{
+	var
+		jqWin = $(window),
+		jqDoc = $(document),
+		oWin = FixedHeader.oWin,
+		oDoc = FixedHeader.oDoc;
+
+	oDoc.iHeight = jqDoc.height();
+	oDoc.iWidth = jqDoc.width();
+
+	oWin.iHeight = jqWin.height();
+	oWin.iWidth = jqWin.width();
+	oWin.iScrollTop = jqWin.scrollTop();
+	oWin.iScrollLeft = jqWin.scrollLeft();
+	oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth;
+	oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight;
+};
+
+
+FixedHeader.version = "2.1.2";
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Global processing
+ */
+
+/*
+ * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is
+ * done as an optimisation, to reduce calculation and proagation time
+ */
+$(window).scroll( function () {
+	FixedHeader.fnMeasure();
+
+	for ( var i=0, iLen=FixedHeader.afnScroll.length ; i<iLen ; i++ ) {
+		FixedHeader.afnScroll[i]();
+	}
+} );
+
+
+$.fn.dataTable.FixedHeader = FixedHeader;
+$.fn.DataTable.FixedHeader = FixedHeader;
+
+
+return FixedHeader;
+}; // /factory
+
+
+// Define as an AMD module if possible
+if ( typeof define === 'function' && define.amd ) {
+	define( ['jquery', 'datatables'], factory );
+}
+else if ( typeof exports === 'object' ) {
+    // Node/CommonJS
+    factory( require('jquery'), require('datatables') );
+}
+else if ( jQuery && !jQuery.fn.dataTable.FixedHeader ) {
+	// Otherwise simply initialise as normal, stopping multiple evaluation
+	factory( jQuery, jQuery.fn.dataTable );
+}
+
+
+})(window, document);
diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html
index b60b4ea9..d53f930d 100755
--- a/wqflask/wqflask/templates/correlation_page.html
+++ b/wqflask/wqflask/templates/correlation_page.html
@@ -144,6 +144,7 @@
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script>
     <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script>
@@ -228,15 +229,14 @@
                     { "type": "natural" },
                     { "type": "natural" }
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
-                "scrollY": "600px",
-                "scrollX": true,
-                "scrollCollapse": true,
+                "scrollY": "700px",
+                "scrollCollapse": false,
                 "colResize": {
                     "tableWidthFixed": false
                 },
@@ -257,15 +257,14 @@
                     { "type": "natural" },
                     { "type": "natural" }
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
-                "scrollY": "600px",
-                "scrollX": true,
-                "scrollCollapse": true,
+                "scrollY": "700px",
+                "scrollCollapse": false,
                 "colResize": {
                     "tableWidthFixed": false
                 },
@@ -281,15 +280,14 @@
                     { "type": "natural" },
                     { "type": "natural" }
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
-                "scrollY": "600px",
-                "scrollX": true,
-                "scrollCollapse": true,
+                "scrollY": "700px",
+                "scrollCollapse": false,
                 "colResize": {
                     "tableWidthFixed": false
                 },
@@ -298,11 +296,6 @@
             {% endif %}
             console.timeEnd("Creating table");
 
-            var table = $('#corr_results').DataTable();
-            //new $.fn.dataTable.FixedHeader( table );
-            new $.fn.dataTable.FixedColumns( table );
-
-
         });
     </script>
 {% endblock %}
diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 1ae2a25a..7c8bdb1b 100755
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -4,7 +4,7 @@
     <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" />
     <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" />
     <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" />
-    <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css" >
+    <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css" >
     <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css">
 {% endblock %}
 {% block content %}
@@ -47,7 +47,7 @@
             <button class="btn btn-primary"><span class="glyphicon glyphicon-download"></span> Download Table</button>
             <br />
             <br />
-            <table class="table table-hover table-striped" id='trait_table' {% if dataset.type == 'Geno' %} width="400px" style="float: left;"{% endif %}>
+            <table class="table table-hover table-striped" id='trait_table' {% if dataset.type == 'Geno' %}width="400px"{% endif %} style="float: left;">
                 <thead>
                     <tr>
                     {% for header in header_fields %}
@@ -119,11 +119,11 @@
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script>
+    <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script>
-    <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script>
-    <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script>
-
 	
     <script type="text/javascript" charset="utf-8">
         function getValue(x) {
@@ -173,28 +173,33 @@
 
             console.time("Creating table");
             {% if dataset.type == 'ProbeSet' %}
-            $('#trait_table').dataTable( {
+            $('#trait_table').DataTable( {
                 "columns": [
                     { "type": "natural" },
                     { "type": "natural" },
                     { "type": "natural" },
-                    { "type": "natural", "width": "35%"},
-                    { "type": "natural", "width": "15%"},
                     { "type": "natural" },
-                    { "type": "natural", "width": "8%"},
-                    { "type": "natural", "width": "15%"},
-                    { "type": "natural", "width": "7%"}
+                    { "type": "natural" },
+                    { "type": "natural" },
+                    { "type": "natural" },
+                    { "type": "natural" },
+                    { "type": "natural" }
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
+                "scrollY": "700px",
+                "scrollCollapse": false,
+                "colResize": {
+                    "tableWidthFixed": false,
+                },
                 "paging": false
             } );
             {% elif dataset.type == 'Publish' %}
-            $('#trait_table').dataTable( {
+            $('#trait_table').DataTable( {
                 "columns": [
                     { "type": "natural" },
                     { "type": "natural" },
@@ -205,36 +210,46 @@
                     { "type": "natural", "width": "15%"},
                     { "type": "natural" }
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
+                "scrollY": "700px",
+                "scrollCollapse": false,
+                "colResize": {
+                    "tableWidthFixed": false,
+                },
                 "paging": false
             } );
             {% elif dataset.type == 'Geno' %}
-            $('#trait_table').dataTable( {
+            $('#trait_table').DataTable( {
                 "columns": [
                     { "type": "natural" },
                     { "type": "natural" },
                     { "type": "natural", "width": "40%"}
                 ],
-                "sDom": "Ztir",
+                "sDom": "RJtir",
                 "iDisplayLength": -1,
                 "autoWidth": true,
                 "bLengthChange": true,
                 "bDeferRender": true,
                 "bSortClasses": false,
+                "scrollY": "700px",
+                "scrollCollapse": false,
+                "colResize": {
+                    "tableWidthFixed": false,
+                },
                 "paging": false
             } );
             {% endif %}
             console.timeEnd("Creating table");
-
-            var table = $('#trait_table').DataTable();
-            new $.fn.dataTable.FixedHeader( table );
-            new $.fn.dataTable.FixedColumns( table );
          
+            //var table = $('#trait_table').DataTable();
+            //new $.fn.dataTable.FixedHeader( table );
+            //new $.fn.dataTable.FixedColumns( table );
+
         });
     </script>
 {% endblock %}
diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html
index cdde5d9d..b4d6b85b 100755
--- a/wqflask/wqflask/templates/show_trait.html
+++ b/wqflask/wqflask/templates/show_trait.html
@@ -13,6 +13,8 @@
     <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" />
     <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" />
     <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" />
+    <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css" >
+    <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css">
 
 {% endblock %}
 {% block content %} <!-- Start of body -->
@@ -146,6 +148,10 @@
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.scientific.js"></script>
     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script>
+    <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script>
+    <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script>
     <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script>
     <script type="text/javascript" charset="utf-8">
@@ -195,68 +201,79 @@
                 });
 
                 console.time("Creating table");
-                
-                {% if sample_groups[0].se_exists() %}
-                    $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'yellow')
-                    $('#samples_primary, #samples_other').dataTable( {
-                        //"sDom": "<<'span3'l><'span3'T><'span4'f>'row-fluid'r>t<'row-fluid'<'span6'i><'span6'p>>",
-                        "aoColumns": [
-                            { "sType": "natural" },
-                            null,
-                            { "sType": "cust-txt" },
-                            { "bSortable": false },
-                            { "sType": "cust-txt" }
+
+                $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'yellow')
+                {% if sample_groups[0].se_exists() %} 
+                $('#samples_primary, #samples_other').DataTable( {
+                    "columns": [
+                        { "type": "natural" },
+                        { "type": "natural" },
+                        { "type": "cust-txt" },
+                        { "bSortable": false },
+                        { "type": "cust-txt" }
+                        ],
+                    "sDom": "RJtir",
+                    "oTableTools": {
+                        "aButtons": [
+                            "copy",
+                            "print",
+                            {
+                                "sExtends":    "collection",
+                                "sButtonText": 'Save <span class="caret" />',
+                                "aButtons":    [ "csv", "xls", "pdf" ]
+                            }
                         ],
-                        "sDom": "ftr",
-                        "oTableTools": {
-                            "aButtons": [
-                                "copy",
-                                "print",
-                                {
-                                    "sExtends":    "collection",
-                                    "sButtonText": 'Save <span class="caret" />',
-                                    "aButtons":    [ "csv", "xls", "pdf" ]
-                                }
-                            ],
-                            "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf"
-                        },
-                        "bPaginate": false,
-                        "bLengthChange": true,
-                        "bDeferRender": true,
-                        "bSortClasses": false
-                    } );
-                    console.timeEnd("Creating table");
+                        "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf"
+                    },
+                    "iDisplayLength": -1,
+                    "autoWidth": true,
+                    "bLengthChange": true,
+                    "bDeferRender": true,
+                    "bSortClasses": false,
+                    "scrollY": "600px",
+                    "scrollCollapse": false,
+                    "colResize": {
+                        "tableWidthFixed": false
+                    },
+                    "paging": false
+                } );
+                console.timeEnd("Creating table");
 
                 {% else %}
-        
-            
-                    console.time("Creating table");
+                console.time("Creating table");
                     
-                    $('#samples_primary, #samples_other').dataTable( {
-                        //"sDom": "<<'span3'l><'span3'T><'span4'f>'row-fluid'r>t<'row-fluid'<'span6'i><'span6'p>>",
-                        "aoColumns": [
-                            { "sType": "natural" },
-                            null,
-                            { "sType": "cust-txt" }
+                $('#samples_primary, #samples_other').DataTable( {
+                    "columns": [
+                        { "type": "natural" },
+                        null,
+                        { "type": "cust-txt" }
+                    ],
+                    "sDom": "RJtir",
+                    "oTableTools": {
+                        "aButtons": [
+                            "copy",
+                            "print",
+                            {
+                                "sExtends":    "collection",
+                                "sButtonText": 'Save <span class="caret" />',
+                                "aButtons":    [ "csv", "xls", "pdf" ]
+                            }
                         ],
-                        "sDom": "ftr",
-                        "oTableTools": {
-                            "aButtons": [
-                                "copy",
-                                "print",
-                                {
-                                    "sExtends":    "collection",
-                                    "sButtonText": 'Save <span class="caret" />',
-                                    "aButtons":    [ "csv", "xls", "pdf" ]
-                                }
-                            ],
-                            "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf"
-                        },
-                        "bPaginate": false,
-                        "bLengthChange": true,
-                        "bDeferRender": true,
-                        "bSortClasses": false
-                    } );
+                        "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf"
+                    },
+                    "iDisplayLength": -1,
+                    "autoWidth": true,
+                    "bLengthChange": true,
+                    "bDeferRender": true,
+                    "bSortClasses": false,
+                    "scrollY": "600px",
+                    "scrollX": true,
+                    "scrollCollapse": false,
+                    "colResize": {
+                        "tableWidthFixed": false
+                    },
+                    "paging": false
+                } );
                 {% endif %}
             });
     </script>
diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html
index a02dc409..8c919ee0 100755
--- a/wqflask/wqflask/templates/show_trait_edit_data.html
+++ b/wqflask/wqflask/templates/show_trait_edit_data.html
@@ -73,26 +73,25 @@
     <br>
 
 
-    <div id="edit_sample_lists">
+    <!--<div id="edit_sample_lists">-->
     {% for sample_type in sample_groups %}
-        <div class="sample_group">
+        <!--<div class="sample_group">-->
             <h3>{{ sample_type.header }}</h3>
 
-            <table cellpadding="0" cellspacing="0" border="0" class="table table-hover table-striped table-bordered"
-                   id="samples_{{ sample_type.sample_group_type }}">
+            <table class="table table-hover table-striped" id="samples_{{ sample_type.sample_group_type }}" style="float: left;">
                 <thead>
                     <tr>
-                        <td>Index</td>
-                        <td>Sample</td>
-                        <td>Value</td>
+                        <th>Index</td>
+                        <th>Sample</td>
+                        <th>Value</td>
                         {% if sample_type.se_exists() %}
-                        <td>&nbsp;</td>
-                        <td>SE</td>
+                        <th>&nbsp;</td>
+                        <th>SE</td>
                         {% endif %}
                         {% for attribute in sample_type.attributes|sort() %}
-                        <td>
+                        <th>
                             {{ sample_type.attributes[attribute].name }}
-                        </td>
+                        </th>
                         {% endfor %}
                     </tr>
                 </thead>
@@ -148,9 +147,9 @@
                     {% endfor %}
                 </tbody>
             </table>
-        </div>
+        <!--</div>-->
         {% endfor %}
-    </div>
+    <!--</div>-->
 
 
     <input type="hidden" name="Default_Name">