src/pyams_skin/resources/js/ext/jquery-dataTables-colReorderWithResize.js
changeset 0 bb4aabe07487
equal deleted inserted replaced
-1:000000000000 0:bb4aabe07487
       
     1 /*
       
     2  * File:        ColReorderWithResize.js
       
     3  * Version:     1.0.7
       
     4  * CVS:         $Id$
       
     5  * Description: Allow columns to be reordered in a DataTable
       
     6  * Author:      Allan Jardine (www.sprymedia.co.uk)
       
     7  * Author:      Christophe Battarel (www.altairis.fr)
       
     8  * Created:     Wed Sep 15 18:23:29 BST 2010
       
     9  * Modified:    July 2011 by Christophe Battarel - christophe.battarel@altairis.fr (columns resizable)
       
    10  * Modified:    February 2012 by Martin Marchetta - martin.marchetta@gmail.com
       
    11  *  1. Made the "hot area" for resizing a little wider (it was a little difficult to hit the exact border of a column for resizing)
       
    12  *  2. Resizing didn't work at all when using scroller (that plugin splits the table into 2 different tables: one for the header and another one for the body, so when you resized the header, the data columns didn't follow)
       
    13  *  3. Fixed collateral effects of sorting feature
       
    14  *  4. If sScrollX is enabled (i.e. horizontal scrolling), when resizing a column the width of the other columns is not changed, but the whole
       
    15  *     table is resized to give an Excel-like behavior (good suggestion by Allan)
       
    16  * Modified:    February 2012 by Christophe Battarel - christophe.battarel@altairis.fr (ColReorder v1.0.5 adaptation)
       
    17  * Modified:    September 16th 2012 by Hassan Kamara - h@phrmc.com
       
    18  * Language:    Javascript
       
    19  * License:     GPL v2 or BSD 3 point style
       
    20  * Project:     DataTables
       
    21  * Contact:     www.sprymedia.co.uk/contact
       
    22  * 
       
    23  * Copyright 2010-2011 Allan Jardine, all rights reserved.
       
    24  *
       
    25  * This source file is free software, under either the GPL v2 license or a
       
    26  * BSD style license, available at:
       
    27  *   http://datatables.net/license_gpl2
       
    28  *   http://datatables.net/license_bsd
       
    29  *
       
    30  */
       
    31 
       
    32 
       
    33 (function ($, window, document) {
       
    34 
       
    35 
       
    36 	/**
       
    37 	 * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
       
    38 	 * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
       
    39 	 *  @method  fnInvertKeyValues
       
    40 	 *  @param   array aIn Array to switch around
       
    41 	 *  @returns array
       
    42 	 */
       
    43 	function fnInvertKeyValues(aIn) {
       
    44 		var aRet = [];
       
    45 		for (var i = 0, iLen = aIn.length; i < iLen; i++) {
       
    46 			aRet[ aIn[i] ] = i;
       
    47 		}
       
    48 		return aRet;
       
    49 	}
       
    50 
       
    51 
       
    52 	/**
       
    53 	 * Modify an array by switching the position of two elements
       
    54 	 *  @method  fnArraySwitch
       
    55 	 *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)
       
    56 	 *  @param   int iFrom From point
       
    57 	 *  @param   int iTo Insert point
       
    58 	 *  @returns void
       
    59 	 */
       
    60 	function fnArraySwitch(aArray, iFrom, iTo) {
       
    61 		var mStore = aArray.splice(iFrom, 1)[0];
       
    62 		aArray.splice(iTo, 0, mStore);
       
    63 	}
       
    64 
       
    65 
       
    66 	/**
       
    67 	 * Switch the positions of nodes in a parent node (note this is specifically designed for
       
    68 	 * table rows). Note this function considers all element nodes under the parent!
       
    69 	 *  @method  fnDomSwitch
       
    70 	 *  @param   string sTag Tag to consider
       
    71 	 *  @param   int iFrom Element to move
       
    72 	 *  @param   int Point to element the element to (before this point), can be null for append
       
    73 	 *  @returns void
       
    74 	 */
       
    75 	function fnDomSwitch(nParent, iFrom, iTo) {
       
    76 		var anTags = [];
       
    77 		for (var i = 0, iLen = nParent.childNodes.length; i < iLen; i++) {
       
    78 			if (nParent.childNodes[i].nodeType == 1) {
       
    79 				anTags.push(nParent.childNodes[i]);
       
    80 			}
       
    81 		}
       
    82 		var nStore = anTags[ iFrom ];
       
    83 
       
    84 		if (iTo !== null) {
       
    85 			nParent.insertBefore(nStore, anTags[iTo]);
       
    86 		}
       
    87 		else {
       
    88 			nParent.appendChild(nStore);
       
    89 		}
       
    90 	}
       
    91 
       
    92 
       
    93 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
    94 	 * DataTables plug-in API functions
       
    95 	 *
       
    96 	 * This are required by ColReorder in order to perform the tasks required, and also keep this
       
    97 	 * code portable, to be used for other column reordering projects with DataTables, if needed.
       
    98 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
    99 
       
   100 
       
   101 	/**
       
   102 	 * Plug-in for DataTables which will reorder the internal column structure by taking the column
       
   103 	 * from one position (iFrom) and insert it into a given point (iTo).
       
   104 	 *  @method  $.fn.dataTableExt.oApi.fnColReorder
       
   105 	 *  @param   object oSettings DataTables settings object - automatically added by DataTables!
       
   106 	 *  @param   int iFrom Take the column to be repositioned from this point
       
   107 	 *  @param   int iTo and insert it into this point
       
   108 	 *  @returns void
       
   109 	 */
       
   110 	$.fn.dataTableExt.oApi.fnColReorder = function (oSettings, iFrom, iTo) {
       
   111 		var i, iLen, j, jLen, iCols = oSettings.aoColumns.length, nTrs, oCol;
       
   112 
       
   113 		/* Sanity check in the input */
       
   114 		if (iFrom == iTo) {
       
   115 			/* Pointless reorder */
       
   116 			return;
       
   117 		}
       
   118 
       
   119 		if (iFrom < 0 || iFrom >= iCols) {
       
   120 			this.oApi._fnLog(oSettings, 1, "ColReorder 'from' index is out of bounds: " + iFrom);
       
   121 			return;
       
   122 		}
       
   123 
       
   124 		if (iTo < 0 || iTo >= iCols) {
       
   125 			this.oApi._fnLog(oSettings, 1, "ColReorder 'to' index is out of bounds: " + iTo);
       
   126 			return;
       
   127 		}
       
   128 
       
   129 		/*
       
   130 		 * Calculate the new column array index, so we have a mapping between the old and new
       
   131 		 */
       
   132 		var aiMapping = [];
       
   133 		for (i = 0, iLen = iCols; i < iLen; i++) {
       
   134 			aiMapping[i] = i;
       
   135 		}
       
   136 		fnArraySwitch(aiMapping, iFrom, iTo);
       
   137 		var aiInvertMapping = fnInvertKeyValues(aiMapping);
       
   138 
       
   139 
       
   140 		/*
       
   141 		 * Convert all internal indexing to the new column order indexes
       
   142 		 */
       
   143 		/* Sorting */
       
   144 		for (i = 0, iLen = oSettings.aaSorting.length; i < iLen; i++) {
       
   145 			oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
       
   146 		}
       
   147 
       
   148 		/* Fixed sorting */
       
   149 		if (oSettings.aaSortingFixed !== null) {
       
   150 			for (i = 0, iLen = oSettings.aaSortingFixed.length; i < iLen; i++) {
       
   151 				oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
       
   152 			}
       
   153 		}
       
   154 
       
   155 		/* Data column sorting (the column which the sort for a given column should take place on) */
       
   156 		for (i = 0, iLen = iCols; i < iLen; i++) {
       
   157 			oCol = oSettings.aoColumns[i];
       
   158 			for (j = 0, jLen = oCol.aDataSort.length; j < jLen; j++) {
       
   159 				oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
       
   160 			}
       
   161 		}
       
   162 
       
   163 		/* Update the Get and Set functions for each column */
       
   164 		for (i = 0, iLen = iCols; i < iLen; i++) {
       
   165 			oCol = oSettings.aoColumns[i];
       
   166 			if (typeof oCol.mData == 'number') {
       
   167 				oCol.mData = aiInvertMapping[ oCol.mData ];
       
   168 				oCol.fnGetData = oSettings.oApi._fnGetObjectDataFn(oCol.mData);
       
   169 				oCol.fnSetData = oSettings.oApi._fnSetObjectDataFn(oCol.mData);
       
   170 			}
       
   171 		}
       
   172 
       
   173 
       
   174 		/*
       
   175 		 * Move the DOM elements
       
   176 		 */
       
   177 		if (oSettings.aoColumns[iFrom].bVisible) {
       
   178 			/* Calculate the current visible index and the point to insert the node before. The insert
       
   179 			 * before needs to take into account that there might not be an element to insert before,
       
   180 			 * in which case it will be null, and an appendChild should be used
       
   181 			 */
       
   182 			var iVisibleIndex = this.oApi._fnColumnIndexToVisible(oSettings, iFrom);
       
   183 			var iInsertBeforeIndex = null;
       
   184 
       
   185 			i = iTo < iFrom ? iTo : iTo + 1;
       
   186 			while (iInsertBeforeIndex === null && i < iCols) {
       
   187 				iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible(oSettings, i);
       
   188 				i++;
       
   189 			}
       
   190 
       
   191 			/* Header */
       
   192 			nTrs = oSettings.nTHead.getElementsByTagName('tr');
       
   193 			for (i = 0, iLen = nTrs.length; i < iLen; i++) {
       
   194 				fnDomSwitch(nTrs[i], iVisibleIndex, iInsertBeforeIndex);
       
   195 			}
       
   196 
       
   197 			/* Footer */
       
   198 			if (oSettings.nTFoot !== null) {
       
   199 				nTrs = oSettings.nTFoot.getElementsByTagName('tr');
       
   200 				for (i = 0, iLen = nTrs.length; i < iLen; i++) {
       
   201 					fnDomSwitch(nTrs[i], iVisibleIndex, iInsertBeforeIndex);
       
   202 				}
       
   203 			}
       
   204 
       
   205 			/* Body */
       
   206 			for (i = 0, iLen = oSettings.aoData.length; i < iLen; i++) {
       
   207 				if (oSettings.aoData[i].nTr !== null) {
       
   208 					fnDomSwitch(oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex);
       
   209 				}
       
   210 			}
       
   211 		}
       
   212 
       
   213 
       
   214 		/*
       
   215 		 * Move the internal array elements
       
   216 		 */
       
   217 		/* Columns */
       
   218 		fnArraySwitch(oSettings.aoColumns, iFrom, iTo);
       
   219 
       
   220 		/* Search columns */
       
   221 		fnArraySwitch(oSettings.aoPreSearchCols, iFrom, iTo);
       
   222 
       
   223 		/* Array array - internal data anodes cache */
       
   224 		for (i = 0, iLen = oSettings.aoData.length; i < iLen; i++) {
       
   225 			if ($.isArray(oSettings.aoData[i]._aData)) {
       
   226 				fnArraySwitch(oSettings.aoData[i]._aData, iFrom, iTo);
       
   227 			}
       
   228 			fnArraySwitch(oSettings.aoData[i]._anHidden, iFrom, iTo);
       
   229 		}
       
   230 
       
   231 		/* Reposition the header elements in the header layout array */
       
   232 		for (i = 0, iLen = oSettings.aoHeader.length; i < iLen; i++) {
       
   233 			fnArraySwitch(oSettings.aoHeader[i], iFrom, iTo);
       
   234 		}
       
   235 
       
   236 		if (oSettings.aoFooter !== null) {
       
   237 			for (i = 0, iLen = oSettings.aoFooter.length; i < iLen; i++) {
       
   238 				fnArraySwitch(oSettings.aoFooter[i], iFrom, iTo);
       
   239 			}
       
   240 		}
       
   241 
       
   242 
       
   243 		/*
       
   244 		 * Update DataTables' event handlers
       
   245 		 */
       
   246 
       
   247 		/* Sort listener */
       
   248 		for (i = 0, iLen = iCols; i < iLen; i++) {
       
   249 			//Martin Marchetta:
       
   250 			//Update this field which is the one used by DataTables for getting the column's data for sorting.
       
   251 			oSettings.aoColumns[i].aDataSort = [i];
       
   252 			//Update the internal column index, since columns are actually being re-ordered in the internal structure
       
   253 			oSettings.aoColumns[i]._ColReorder_iOrigCol = i;
       
   254 			///////////////////////////////////
       
   255 			$(oSettings.aoColumns[i].nTh).unbind('click');
       
   256 			this.oApi._fnSortAttachListener(oSettings, oSettings.aoColumns[i].nTh, i);
       
   257 		}
       
   258 
       
   259 
       
   260 		/*
       
   261 		 * Any extra operations for the other plug-ins
       
   262 		 */
       
   263 		if (typeof ColVis != 'undefined') {
       
   264 			ColVis.fnRebuild(oSettings.oInstance);
       
   265 		}
       
   266 
       
   267 		/* Fire an event so other plug-ins can update */
       
   268 		$(oSettings.oInstance).trigger('column-reorder', [ oSettings, {
       
   269 			"iFrom": iFrom,
       
   270 			"iTo": iTo,
       
   271 			"aiInvertMapping": aiInvertMapping
       
   272 		} ]);
       
   273 
       
   274 		if (typeof oSettings.oInstance._oPluginFixedHeader != 'undefined') {
       
   275 			oSettings.oInstance._oPluginFixedHeader.fnUpdate();
       
   276 		}
       
   277 	};
       
   278 
       
   279 
       
   280 	/**
       
   281 	 * ColReorder provides column visiblity control for DataTables
       
   282 	 * @class ColReorder
       
   283 	 * @constructor
       
   284 	 * @param {object} DataTables settings object
       
   285 	 * @param {object} ColReorder options
       
   286 	 */
       
   287 	ColReorder = function (oDTSettings, oOpts) {
       
   288 		/* Santiy check that we are a new instance */
       
   289 		if (!this.CLASS || this.CLASS != "ColReorder") {
       
   290 			alert("Warning: ColReorder must be initialised with the keyword 'new'");
       
   291 		}
       
   292 
       
   293 		if (typeof oOpts == 'undefined') {
       
   294 			oOpts = {};
       
   295 		}
       
   296 
       
   297 
       
   298 		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   299 		 * Public class variables
       
   300 		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   301 
       
   302 		/**
       
   303 		 * @namespace Settings object which contains customisable information for ColReorder instance
       
   304 		 */
       
   305 		this.s = {
       
   306 			/**
       
   307 			 * DataTables settings object
       
   308 			 *  @property dt
       
   309 			 *  @type     Object
       
   310 			 *  @default  null
       
   311 			 */
       
   312 			"dt": null,
       
   313 
       
   314 			/**
       
   315 			 * Initialisation object used for this instance
       
   316 			 *  @property init
       
   317 			 *  @type     object
       
   318 			 *  @default  {}
       
   319 			 */
       
   320 			"init": oOpts,
       
   321 
       
   322 			/**
       
   323 			 * Allow Reorder functionnality
       
   324 			 *  @property allowReorder
       
   325 			 *  @type     boolean
       
   326 			 *  @default  true
       
   327 			 */
       
   328 			"allowReorder": true,
       
   329 
       
   330 			/**
       
   331 			 * Allow Resize functionnality
       
   332 			 *  @property allowResize
       
   333 			 *  @type     boolean
       
   334 			 *  @default  true
       
   335 			 */
       
   336 			"allowResize": true,
       
   337 
       
   338 			/**
       
   339 			 * Number of columns to fix (not allow to be reordered)
       
   340 			 *  @property fixed
       
   341 			 *  @type     int
       
   342 			 *  @default  0
       
   343 			 */
       
   344 			"fixed": 0,
       
   345 
       
   346 			/**
       
   347 			 * Callback function for once the reorder has been done
       
   348 			 *  @property dropcallback
       
   349 			 *  @type     function
       
   350 			 *  @default  null
       
   351 			 */
       
   352 			"dropCallback": null,
       
   353 
       
   354 			/**
       
   355 			 * @namespace Information used for the mouse drag
       
   356 			 */
       
   357 			"mouse": {
       
   358 				"startX": -1,
       
   359 				"startY": -1,
       
   360 				"offsetX": -1,
       
   361 				"offsetY": -1,
       
   362 				"target": -1,
       
   363 				"targetIndex": -1,
       
   364 				"fromIndex": -1
       
   365 			},
       
   366 
       
   367 			/**
       
   368 			 * Information which is used for positioning the insert cusor and knowing where to do the
       
   369 			 * insert. Array of objects with the properties:
       
   370 			 *   x: x-axis position
       
   371 			 *   to: insert point
       
   372 			 *  @property aoTargets
       
   373 			 *  @type     array
       
   374 			 *  @default  []
       
   375 			 */
       
   376 			"aoTargets": []
       
   377 		};
       
   378 
       
   379 
       
   380 		/**
       
   381 		 * @namespace Common and useful DOM elements for the class instance
       
   382 		 */
       
   383 		this.dom = {
       
   384 			/**
       
   385 			 * Dragging element (the one the mouse is moving)
       
   386 			 *  @property drag
       
   387 			 *  @type     element
       
   388 			 *  @default  null
       
   389 			 */
       
   390 			"drag": null,
       
   391 
       
   392 			/**
       
   393 			 * Resizing a column
       
   394 			 *  @property drag
       
   395 			 *  @type     element
       
   396 			 *  @default  null
       
   397 			 */
       
   398 			"resize": null,
       
   399 
       
   400 			/**
       
   401 			 * The insert cursor
       
   402 			 *  @property pointer
       
   403 			 *  @type     element
       
   404 			 *  @default  null
       
   405 			 */
       
   406 			"pointer": null
       
   407 		};
       
   408 
       
   409 		/////////////////
       
   410 		//Martin Marchetta: keep the current table's size in order to resize it if columns are resized and scrollX is enabled
       
   411 		this.table_size = -1;
       
   412 		/////////////////
       
   413 
       
   414 		/* Constructor logic */
       
   415 		this.s.dt = oDTSettings.oInstance.fnSettings();
       
   416 		this._fnConstruct();
       
   417 
       
   418 		/* Add destroy callback */
       
   419 		oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', jQuery.proxy(this._fnDestroy, this), 'ColReorder');
       
   420 
       
   421 		/* Store the instance for later use */
       
   422 		ColReorder.aoInstances.push(this);
       
   423 		return this;
       
   424 	};
       
   425 
       
   426 
       
   427 	ColReorder.prototype = {
       
   428 		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   429 		 * Public methods
       
   430 		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   431 
       
   432 		"fnReset": function () {
       
   433 			var a = [];
       
   434 			for (var i = 0, iLen = this.s.dt.aoColumns.length; i < iLen; i++) {
       
   435 				a.push(this.s.dt.aoColumns[i]._ColReorder_iOrigCol);
       
   436 			}
       
   437 
       
   438 			this._fnOrderColumns(a);
       
   439 		},
       
   440 
       
   441 
       
   442 		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   443 		 * Private methods (they are of course public in JS, but recommended as private)
       
   444 		 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   445 
       
   446 		/**
       
   447 		 * Constructor logic
       
   448 		 *  @method  _fnConstruct
       
   449 		 *  @returns void
       
   450 		 *  @private
       
   451 		 */
       
   452 		"_fnConstruct": function () {
       
   453 			var that = this;
       
   454 			var i, iLen;
       
   455 
       
   456 			/* allow reorder */
       
   457 			if (typeof this.s.init.allowReorder != 'undefined') {
       
   458 				this.s.allowReorder = this.s.init.allowReorder;
       
   459 			}
       
   460 
       
   461 			/* allow resize */
       
   462 			if (typeof this.s.init.allowResize != 'undefined') {
       
   463 				this.s.allowResize = this.s.init.allowResize;
       
   464 			}
       
   465 
       
   466 			/* Columns discounted from reordering - counting left to right */
       
   467 			if (typeof this.s.init.iFixedColumns != 'undefined') {
       
   468 				this.s.fixed = this.s.init.iFixedColumns;
       
   469 			}
       
   470 
       
   471 			/* Drop callback initialisation option */
       
   472 			if (typeof this.s.init.fnReorderCallback != 'undefined') {
       
   473 				this.s.dropCallback = this.s.init.fnReorderCallback;
       
   474 			}
       
   475 
       
   476 			/* Add event handlers for the drag and drop, and also mark the original column order */
       
   477 			for (i = 0, iLen = this.s.dt.aoColumns.length; i < iLen; i++) {
       
   478 				if (i > this.s.fixed - 1) {
       
   479 					this._fnMouseListener(i, this.s.dt.aoColumns[i].nTh);
       
   480 				}
       
   481 
       
   482 				/* Mark the original column order for later reference */
       
   483 				this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
       
   484 			}
       
   485 
       
   486 			/* State saving */
       
   487 			this.s.dt.oApi._fnCallbackReg(this.s.dt, 'aoStateSaveParams', function (oS, oData) {
       
   488 				that._fnStateSave.call(that, oData);
       
   489 			}, "ColReorder_State");
       
   490 
       
   491 			/* An initial column order has been specified */
       
   492 			var aiOrder = null;
       
   493 			if (typeof this.s.init.aiOrder != 'undefined') {
       
   494 				aiOrder = this.s.init.aiOrder.slice();
       
   495 			}
       
   496 
       
   497 			/* State loading, overrides the column order given */
       
   498 			if (this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
       
   499 				this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length) {
       
   500 				aiOrder = this.s.dt.oLoadedState.ColReorder;
       
   501 			}
       
   502 
       
   503 			/* If we have an order to apply - do so */
       
   504 			if (aiOrder) {
       
   505 				/* We might be called during or after the DataTables initialisation. If before, then we need
       
   506 				 * to wait until the draw is done, if after, then do what we need to do right away
       
   507 				 */
       
   508 				if (!that.s.dt._bInitComplete) {
       
   509 					var bDone = false;
       
   510 					this.s.dt.aoDrawCallback.push({
       
   511 													  "fn": function () {
       
   512 														  if (!that.s.dt._bInitComplete && !bDone) {
       
   513 															  bDone = true;
       
   514 															  var resort = fnInvertKeyValues(aiOrder);
       
   515 															  that._fnOrderColumns.call(that, resort);
       
   516 														  }
       
   517 													  },
       
   518 													  "sName": "ColReorder_Pre"
       
   519 												  });
       
   520 				}
       
   521 				else {
       
   522 					var resort = fnInvertKeyValues(aiOrder);
       
   523 					that._fnOrderColumns.call(that, resort);
       
   524 				}
       
   525 			}
       
   526 		},
       
   527 
       
   528 
       
   529 		/**
       
   530 		 * Set the column order from an array
       
   531 		 *  @method  _fnOrderColumns
       
   532 		 *  @param   array a An array of integers which dictate the column order that should be applied
       
   533 		 *  @returns void
       
   534 		 *  @private
       
   535 		 */
       
   536 		"_fnOrderColumns": function (a) {
       
   537 			if (a.length != this.s.dt.aoColumns.length) {
       
   538 				this.s.dt.oInstance.oApi._fnLog(oDTSettings, 1, "ColReorder - array reorder does not " +
       
   539 					"match known number of columns. Skipping.");
       
   540 				return;
       
   541 			}
       
   542 
       
   543 			for (var i = 0, iLen = a.length; i < iLen; i++) {
       
   544 				var currIndex = $.inArray(i, a);
       
   545 				if (i != currIndex) {
       
   546 					/* Reorder our switching array */
       
   547 					fnArraySwitch(a, currIndex, i);
       
   548 
       
   549 					/* Do the column reorder in the table */
       
   550 					this.s.dt.oInstance.fnColReorder(currIndex, i);
       
   551 				}
       
   552 			}
       
   553 
       
   554 			/* When scrolling we need to recalculate the column sizes to allow for the shift */
       
   555 			if (this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "") {
       
   556 				this.s.dt.oInstance.fnAdjustColumnSizing();
       
   557 			}
       
   558 
       
   559 			/* Save the state */
       
   560 			this.s.dt.oInstance.oApi._fnSaveState(this.s.dt);
       
   561 		},
       
   562 
       
   563 
       
   564 		/**
       
   565 		 * Because we change the indexes of columns in the table, relative to their starting point
       
   566 		 * we need to reorder the state columns to what they are at the starting point so we can
       
   567 		 * then rearrange them again on state load!
       
   568 		 *  @method  _fnStateSave
       
   569 		 *  @param   object oState DataTables state
       
   570 		 *  @returns string JSON encoded cookie string for DataTables
       
   571 		 *  @private
       
   572 		 */
       
   573 		"_fnStateSave": function (oState) {
       
   574 			var i, iLen, aCopy, iOrigColumn;
       
   575 			var oSettings = this.s.dt;
       
   576 
       
   577 			/* Sorting */
       
   578 			for (i = 0; i < oState.aaSorting.length; i++) {
       
   579 				oState.aaSorting[i][0] = oSettings.aoColumns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
       
   580 			}
       
   581 
       
   582 			aSearchCopy = $.extend(true, [], oState.aoSearchCols);
       
   583 			oState.ColReorder = [];
       
   584 
       
   585 			for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) {
       
   586 				iOrigColumn = oSettings.aoColumns[i]._ColReorder_iOrigCol;
       
   587 
       
   588 				/* Column filter */
       
   589 				oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
       
   590 
       
   591 				/* Visibility */
       
   592 				oState.abVisCols[ iOrigColumn ] = oSettings.aoColumns[i].bVisible;
       
   593 
       
   594 				/* Column reordering */
       
   595 				oState.ColReorder.push(iOrigColumn);
       
   596 			}
       
   597 		},
       
   598 
       
   599 
       
   600 		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   601 		 * Mouse drop and drag
       
   602 		 */
       
   603 
       
   604 		/**
       
   605 		 * Add a mouse down listener to a particluar TH element
       
   606 		 *  @method  _fnMouseListener
       
   607 		 *  @param   int i Column index
       
   608 		 *  @param   element nTh TH element clicked on
       
   609 		 *  @returns void
       
   610 		 *  @private
       
   611 		 */
       
   612 		"_fnMouseListener": function (i, nTh) {
       
   613 			var that = this;
       
   614 
       
   615 			//Martin Marchetta (rebind events since after column re-order they use wrong column indices)
       
   616 			$(nTh).unbind('mousemove.ColReorder');
       
   617 			$(nTh).unbind('mousedown.ColReorder');
       
   618 			////////////////
       
   619 
       
   620 			// listen to mousemove event for resize
       
   621 			if (this.s.allowResize) {
       
   622 				$(nTh).bind('mousemove.ColReorder', function (e) {
       
   623 					if (that.dom.drag === null && that.dom.resize === null) {
       
   624 						/* Store information about the mouse position */
       
   625 						var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
       
   626 						var offset = $(nThTarget).offset();
       
   627 						var nLength = $(nThTarget).innerWidth();
       
   628 
       
   629 						/* are we on the col border (if so, resize col) */
       
   630 						if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5) {
       
   631 							$(nThTarget).css({'cursor': 'col-resize'});
       
   632 						}
       
   633 						else
       
   634 							$(nThTarget).css({'cursor': 'pointer'});
       
   635 					}
       
   636 				});
       
   637 			}
       
   638 
       
   639 			// listen to mousedown event
       
   640 			$(nTh).bind('mousedown.ColReorder', function (e) {
       
   641 				that._fnMouseDown.call(that, e, nTh, i); //Martin Marchetta: added the index of the column dragged or resized
       
   642 				return false;
       
   643 			});
       
   644 		},
       
   645 
       
   646 
       
   647 		/**
       
   648 		 * Mouse down on a TH element in the table header
       
   649 		 *  @method  _fnMouseDown
       
   650 		 *  @param   event e Mouse event
       
   651 		 *  @param   element nTh TH element to be dragged
       
   652 		 *  @param     i The column that's resized/dragged
       
   653 		 *  @returns void
       
   654 		 *  @private
       
   655 		 */
       
   656 		"_fnMouseDown": function (e, nTh, i) {
       
   657 			var
       
   658 				that = this,
       
   659 				aoColumns = this.s.dt.aoColumns;
       
   660 
       
   661 			/* are we resizing a column ? */
       
   662 			if ($(nTh).css('cursor') == 'col-resize') {
       
   663 				this.s.mouse.startX = e.pageX;
       
   664 				this.s.mouse.startWidth = $(nTh).width();
       
   665 				this.s.mouse.resizeElem = $(nTh);
       
   666 				var nThNext = $(nTh).next();
       
   667 				this.s.mouse.nextStartWidth = $(nThNext).width();
       
   668 				that.dom.resize = true;
       
   669 				////////////////////
       
   670 				//Martin Marchetta
       
   671 				//a. Disable column sorting so as to avoid issues when finishing column resizing
       
   672 				this.s.dt.aoColumns[i].bSortable = false;
       
   673 				//b. Disable Autowidth feature (now the user is in charge of setting column width so keeping this enabled looses changes after operations)
       
   674 				this.s.dt.oFeatures.bAutoWidth = false;
       
   675 				////////////////////
       
   676 			}
       
   677 			else if (this.s.allowReorder) {
       
   678 				that.dom.resize = null;
       
   679 				/* Store information about the mouse position */
       
   680 				var nThTarget = e.target.nodeName == "TH" ? e.target : $(e.target).parents('TH')[0];
       
   681 				var offset = $(nThTarget).offset();
       
   682 				this.s.mouse.startX = e.pageX;
       
   683 				this.s.mouse.startY = e.pageY;
       
   684 				this.s.mouse.offsetX = e.pageX - offset.left;
       
   685 				this.s.mouse.offsetY = e.pageY - offset.top;
       
   686 				this.s.mouse.target = nTh;
       
   687 				this.s.mouse.targetIndex = $('th', nTh.parentNode).index(nTh);
       
   688 				this.s.mouse.fromIndex = this.s.dt.oInstance.oApi._fnVisibleToColumnIndex(this.s.dt,
       
   689 																						  this.s.mouse.targetIndex);
       
   690 
       
   691 				/* Calculate a cached array with the points of the column inserts, and the 'to' points */
       
   692 				this.s.aoTargets.splice(0, this.s.aoTargets.length);
       
   693 
       
   694 				this.s.aoTargets.push({
       
   695 										  "x": $(this.s.dt.nTable).offset().left,
       
   696 										  "to": 0
       
   697 									  });
       
   698 
       
   699 				var iToPoint = 0;
       
   700 				for (var i = 0, iLen = aoColumns.length; i < iLen; i++) {
       
   701 					/* For the column / header in question, we want it's position to remain the same if the
       
   702 					 * position is just to it's immediate left or right, so we only incremement the counter for
       
   703 					 * other columns
       
   704 					 */
       
   705 					if (i != this.s.mouse.fromIndex) {
       
   706 						iToPoint++;
       
   707 					}
       
   708 
       
   709 					if (aoColumns[i].bVisible) {
       
   710 						this.s.aoTargets.push({
       
   711 												  "x": $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
       
   712 												  "to": iToPoint
       
   713 											  });
       
   714 					}
       
   715 				}
       
   716 
       
   717 				/* Disallow columns for being reordered by drag and drop, counting left to right */
       
   718 				if (this.s.fixed !== 0) {
       
   719 					this.s.aoTargets.splice(0, this.s.fixed);
       
   720 				}
       
   721 			}
       
   722 
       
   723 			/* Add event handlers to the document */
       
   724 			$(document).bind('mousemove.ColReorder', function (e) {
       
   725 				that._fnMouseMove.call(that, e, i); //Martin Marchetta: Added index of the call being dragged or resized
       
   726 			});
       
   727 
       
   728 			$(document).bind('mouseup.ColReorder', function (e) {
       
   729 				//Martin Marcheta: Added this small delay in order to prevent collision with column sort feature (there must be a better
       
   730 				//way of doing this, but I don't have more time to digg into it)
       
   731 				setTimeout(function () {
       
   732 					that._fnMouseUp.call(that, e, i);  //Martin Marchetta: Added index of the call being dragged or resized
       
   733 				}, 10);
       
   734 			});
       
   735 		},
       
   736 
       
   737 
       
   738 		/**
       
   739 		 * Deal with a mouse move event while dragging a node
       
   740 		 *  @method  _fnMouseMove
       
   741 		 *  @param   event e Mouse event
       
   742 		 *  @param   colResized Index of the column that's being dragged or resized (index within the internal model, not the visible order)
       
   743 		 *  @returns void
       
   744 		 *  @private
       
   745 		 */
       
   746 		"_fnMouseMove": function (e, colResized) {
       
   747 			var that = this;
       
   748 
       
   749 			////////////////////
       
   750 			//Martin Marchetta: Determine if ScrollX is enabled
       
   751 			var scrollXEnabled;
       
   752 
       
   753 			scrollXEnabled = this.s.dt.oInit.sScrollX === "" ? false : true;
       
   754 
       
   755 			//Keep the current table's width (used in case sScrollX is enabled to resize the whole table, giving an Excel-like behavior)
       
   756 			if (this.table_size < 0 && scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined) {
       
   757 				if ($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
       
   758 					this.table_size = $($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width();
       
   759 			}
       
   760 			////////////////////
       
   761 
       
   762 			/* are we resizing a column ? */
       
   763 			if (this.dom.resize) {
       
   764 				var nTh = this.s.mouse.resizeElem;
       
   765 				var nThNext = $(nTh).next();
       
   766 				var moveLength = e.pageX - this.s.mouse.startX;
       
   767 				if (moveLength != 0 && !scrollXEnabled)
       
   768 					$(nThNext).width(this.s.mouse.nextStartWidth - moveLength);
       
   769 				$(nTh).width(this.s.mouse.startWidth + moveLength);
       
   770 
       
   771 				//Martin Marchetta: Resize the header too (if sScrollX is enabled)
       
   772 				if (scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined) {
       
   773 					if ($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
       
   774 						$($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width(this.table_size + moveLength);
       
   775 				}
       
   776 
       
   777 				////////////////////////
       
   778 				//Martin Marchetta: Fixed col resizing when the scroller is enabled.
       
   779 				var visibleColumnIndex;
       
   780 				//First determine if this plugin is being used along with the smart scroller...
       
   781 				if ($('div.dataTables_scrollBody') != null) {
       
   782 					//...if so, when resizing the header, also resize the table's body (when enabling the Scroller, the table's header and
       
   783 					//body are split into different tables, so the column resizing doesn't work anymore)
       
   784 					if ($('div.dataTables_scrollBody').length > 0) {
       
   785 						//Since some columns might have been hidden, find the correct one to resize in the table's body
       
   786 						var currentColumnIndex;
       
   787 						visibleColumnIndex = -1;
       
   788 						for (currentColumnIndex = -1; currentColumnIndex < this.s.dt.aoColumns.length - 1 && currentColumnIndex != colResized; currentColumnIndex++) {
       
   789 							if (this.s.dt.aoColumns[currentColumnIndex + 1].bVisible)
       
   790 								visibleColumnIndex++;
       
   791 						}
       
   792 
       
   793 						//Get the scroller's div
       
   794 						tableScroller = $('div.dataTables_scrollBody', this.s.dt.nTableWrapper)[0];
       
   795 
       
   796 						//Get the table
       
   797 						scrollingTableHead = $(tableScroller)[0].childNodes[0].childNodes[0].childNodes[0];
       
   798 
       
   799 						//Resize the columns
       
   800 						if (moveLength != 0 && !scrollXEnabled) {
       
   801 							$($(scrollingTableHead)[0].childNodes[visibleColumnIndex + 1]).width(this.s.mouse.nextStartWidth - moveLength);
       
   802 						}
       
   803 						$($(scrollingTableHead)[0].childNodes[visibleColumnIndex]).width(this.s.mouse.startWidth + moveLength);
       
   804 
       
   805 						//Resize the table too
       
   806 						if (scrollXEnabled)
       
   807 							$($(tableScroller)[0].childNodes[0]).width(this.table_size + moveLength);
       
   808 					}
       
   809 				}
       
   810 				////////////////////////
       
   811 
       
   812 				return;
       
   813 			}
       
   814 			else if (this.s.allowReorder) {
       
   815 				if (this.dom.drag === null) {
       
   816 					/* Only create the drag element if the mouse has moved a specific distance from the start
       
   817 					 * point - this allows the user to make small mouse movements when sorting and not have a
       
   818 					 * possibly confusing drag element showing up
       
   819 					 */
       
   820 					if (Math.pow(
       
   821 						Math.pow(e.pageX - this.s.mouse.startX, 2) +
       
   822 							Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5) < 5) {
       
   823 						return;
       
   824 					}
       
   825 					this._fnCreateDragNode();
       
   826 				}
       
   827 
       
   828 				/* Position the element - we respect where in the element the click occured */
       
   829 				this.dom.drag.style.left = (e.pageX - this.s.mouse.offsetX) + "px";
       
   830 				this.dom.drag.style.top = (e.pageY - this.s.mouse.offsetY) + "px";
       
   831 
       
   832 				/* Based on the current mouse position, calculate where the insert should go */
       
   833 				var bSet = false;
       
   834 				for (var i = 1, iLen = this.s.aoTargets.length; i < iLen; i++) {
       
   835 					if (e.pageX < this.s.aoTargets[i - 1].x + ((this.s.aoTargets[i].x - this.s.aoTargets[i - 1].x) / 2)) {
       
   836 						this.dom.pointer.style.left = this.s.aoTargets[i - 1].x + "px";
       
   837 						this.s.mouse.toIndex = this.s.aoTargets[i - 1].to;
       
   838 						bSet = true;
       
   839 						break;
       
   840 					}
       
   841 				}
       
   842 
       
   843 				/* The insert element wasn't positioned in the array (less than operator), so we put it at
       
   844 				 * the end
       
   845 				 */
       
   846 				if (!bSet) {
       
   847 					this.dom.pointer.style.left = this.s.aoTargets[this.s.aoTargets.length - 1].x + "px";
       
   848 					this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length - 1].to;
       
   849 				}
       
   850 			}
       
   851 		},
       
   852 
       
   853 
       
   854 		/**
       
   855 		 * Finish off the mouse drag and insert the column where needed
       
   856 		 *  @method  _fnMouseUp
       
   857 		 *  @param   event e Mouse event
       
   858 		 *  @param colResized The index of the column that was just dragged or resized (index within the internal model, not the visible order).
       
   859 		 *  @returns void
       
   860 		 *  @private
       
   861 		 */
       
   862 		"_fnMouseUp": function (e, colResized) {
       
   863 			var that = this;
       
   864 
       
   865 			$(document).unbind('mousemove.ColReorder');
       
   866 			$(document).unbind('mouseup.ColReorder');
       
   867 
       
   868 			if (this.dom.drag !== null) {
       
   869 				/* Remove the guide elements */
       
   870 				document.body.removeChild(this.dom.drag);
       
   871 				document.body.removeChild(this.dom.pointer);
       
   872 				this.dom.drag = null;
       
   873 				this.dom.pointer = null;
       
   874 
       
   875 				/* Actually do the reorder */
       
   876 				this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex, this.s.mouse.toIndex);
       
   877 
       
   878 				/* When scrolling we need to recalculate the column sizes to allow for the shift */
       
   879 				if (this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "") {
       
   880 					this.s.dt.oInstance.fnAdjustColumnSizing();
       
   881 				}
       
   882 
       
   883 				if (this.s.dropCallback !== null) {
       
   884 					this.s.dropCallback.call(this);
       
   885 				}
       
   886 
       
   887 				////////////
       
   888 				//Martin Marchetta: Re-initialize so as to register the new column order
       
   889 				//(otherwise the events remain bound to the original column indices)
       
   890 				this._fnConstruct();
       
   891 				///////////
       
   892 
       
   893 				/* Save the state */
       
   894 				this.s.dt.oInstance.oApi._fnSaveState(this.s.dt);
       
   895 			}
       
   896 			///////////////////////////////////////////////////////
       
   897 			//Martin Marchetta
       
   898 			else if (this.dom.resize !== null) {
       
   899 				var i;
       
   900 				var j;
       
   901 				var currentColumn;
       
   902 				var nextVisibleColumnIndex;
       
   903 				var previousVisibleColumnIndex;
       
   904 				var scrollXEnabled;
       
   905 
       
   906 				//Re-enable column sorting
       
   907 				this.s.dt.aoColumns[colResized].bSortable = true;
       
   908 
       
   909 				//Save the new resized column's width
       
   910 				this.s.dt.aoColumns[colResized].sWidth = $(this.s.mouse.resizeElem).innerWidth() + "px";
       
   911 
       
   912 				//If other columns might have changed their size, save their size too
       
   913 				scrollXEnabled = this.s.dt.oInit.sScrollX === "" ? false : true;
       
   914 				if (!scrollXEnabled) {
       
   915 					//The colResized index (internal model) here might not match the visible index since some columns might have been hidden
       
   916 					for (nextVisibleColumnIndex = colResized + 1; nextVisibleColumnIndex < this.s.dt.aoColumns.length; nextVisibleColumnIndex++) {
       
   917 						if (this.s.dt.aoColumns[nextVisibleColumnIndex].bVisible)
       
   918 							break;
       
   919 					}
       
   920 
       
   921 					for (previousVisibleColumnIndex = colResized - 1; previousVisibleColumnIndex >= 0; previousVisibleColumnIndex--) {
       
   922 						if (this.s.dt.aoColumns[previousVisibleColumnIndex].bVisible)
       
   923 							break;
       
   924 					}
       
   925 
       
   926 					if (this.s.dt.aoColumns.length > nextVisibleColumnIndex)
       
   927 						this.s.dt.aoColumns[nextVisibleColumnIndex].sWidth = $(this.s.mouse.resizeElem).next().innerWidth() + "px";
       
   928 					else { //The column resized is the right-most, so save the sizes of all the columns at the left
       
   929 						currentColumn = this.s.mouse.resizeElem;
       
   930 						for (i = previousVisibleColumnIndex; i > 0; i--) {
       
   931 							if (this.s.dt.aoColumns[i].bVisible) {
       
   932 								currentColumn = $(currentColumn).prev();
       
   933 								this.s.dt.aoColumns[i].sWidth = $(currentColumn).innerWidth() + "px";
       
   934 							}
       
   935 						}
       
   936 					}
       
   937 				}
       
   938 
       
   939 				//Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled
       
   940 				if (scrollXEnabled && $('div.dataTables_scrollHead', this.s.dt.nTableWrapper) != undefined) {
       
   941 					if ($('div.dataTables_scrollHead', this.s.dt.nTableWrapper).length > 0)
       
   942 						this.table_size = $($('div.dataTables_scrollHead', this.s.dt.nTableWrapper)[0].childNodes[0].childNodes[0]).width();
       
   943 				}
       
   944 
       
   945 				//Save the state
       
   946 				this.s.dt.oInstance.oApi._fnSaveState(this.s.dt);
       
   947 			}
       
   948 			///////////////////////////////////////////////////////
       
   949 
       
   950 			this.dom.resize = null;
       
   951 		},
       
   952 
       
   953 
       
   954 		/**
       
   955 		 * Copy the TH element that is being drags so the user has the idea that they are actually
       
   956 		 * moving it around the page.
       
   957 		 *  @method  _fnCreateDragNode
       
   958 		 *  @returns void
       
   959 		 *  @private
       
   960 		 */
       
   961 		"_fnCreateDragNode": function () {
       
   962 			var that = this;
       
   963 
       
   964 			this.dom.drag = $(this.s.dt.nTHead.parentNode).clone(true)[0];
       
   965 			this.dom.drag.className += " DTCR_clonedTable";
       
   966 			while (this.dom.drag.getElementsByTagName('caption').length > 0) {
       
   967 				this.dom.drag.removeChild(this.dom.drag.getElementsByTagName('caption')[0]);
       
   968 			}
       
   969 			while (this.dom.drag.getElementsByTagName('tbody').length > 0) {
       
   970 				this.dom.drag.removeChild(this.dom.drag.getElementsByTagName('tbody')[0]);
       
   971 			}
       
   972 			while (this.dom.drag.getElementsByTagName('tfoot').length > 0) {
       
   973 				this.dom.drag.removeChild(this.dom.drag.getElementsByTagName('tfoot')[0]);
       
   974 			}
       
   975 
       
   976 			$('thead tr:eq(0)', this.dom.drag).each(function () {
       
   977 				$('th:not(:eq(' + that.s.mouse.targetIndex + '))', this).remove();
       
   978 			});
       
   979 			$('tr', this.dom.drag).height($('tr:eq(0)', that.s.dt.nTHead).height());
       
   980 
       
   981 			$('thead tr:gt(0)', this.dom.drag).remove();
       
   982 
       
   983 			$('thead th:eq(0)', this.dom.drag).each(function (i) {
       
   984 				this.style.width = $('th:eq(' + that.s.mouse.targetIndex + ')', that.s.dt.nTHead).width() + "px";
       
   985 			});
       
   986 
       
   987 			this.dom.drag.style.position = "absolute";
       
   988 			this.dom.drag.style.zIndex = 1200;
       
   989 			this.dom.drag.style.top = "0px";
       
   990 			this.dom.drag.style.left = "0px";
       
   991 			this.dom.drag.style.width = $('th:eq(' + that.s.mouse.targetIndex + ')', that.s.dt.nTHead).outerWidth() + "px";
       
   992 
       
   993 
       
   994 			this.dom.pointer = document.createElement('div');
       
   995 			this.dom.pointer.className = "DTCR_pointer";
       
   996 			this.dom.pointer.style.position = "absolute";
       
   997 
       
   998 			if (this.s.dt.oScroll.sX === "" && this.s.dt.oScroll.sY === "") {
       
   999 				this.dom.pointer.style.top = $(this.s.dt.nTable).offset().top + "px";
       
  1000 				this.dom.pointer.style.height = $(this.s.dt.nTable).height() + "px";
       
  1001 			}
       
  1002 			else {
       
  1003 				this.dom.pointer.style.top = $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top + "px";
       
  1004 				this.dom.pointer.style.height = $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() + "px";
       
  1005 			}
       
  1006 
       
  1007 			document.body.appendChild(this.dom.pointer);
       
  1008 			document.body.appendChild(this.dom.drag);
       
  1009 		},
       
  1010 
       
  1011 		/**
       
  1012 		 * Clean up ColReorder memory references and event handlers
       
  1013 		 *  @method  _fnDestroy
       
  1014 		 *  @returns void
       
  1015 		 *  @private
       
  1016 		 */
       
  1017 		"_fnDestroy": function () {
       
  1018 			for (var i = 0, iLen = ColReorder.aoInstances.length; i < iLen; i++) {
       
  1019 				if (ColReorder.aoInstances[i] === this) {
       
  1020 					ColReorder.aoInstances.splice(i, 1);
       
  1021 					break;
       
  1022 				}
       
  1023 			}
       
  1024 
       
  1025 			$(this.s.dt.nTHead).find('*').unbind('.ColReorder');
       
  1026 
       
  1027 			this.s.dt.oInstance._oPluginColReorder = null;
       
  1028 			this.s = null;
       
  1029 		}
       
  1030 	};
       
  1031 
       
  1032 
       
  1033 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1034 	 * Static parameters
       
  1035 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  1036 
       
  1037 	/**
       
  1038 	 * Array of all ColReorder instances for later reference
       
  1039 	 *  @property ColReorder.aoInstances
       
  1040 	 *  @type     array
       
  1041 	 *  @default  []
       
  1042 	 *  @static
       
  1043 	 */
       
  1044 	ColReorder.aoInstances = [];
       
  1045 
       
  1046 
       
  1047 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1048 	 * Static functions
       
  1049 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  1050 
       
  1051 	/**
       
  1052 	 * Reset the column ordering for a DataTables instance
       
  1053 	 *  @method  ColReorder.fnReset
       
  1054 	 *  @param   object oTable DataTables instance to consider
       
  1055 	 *  @returns void
       
  1056 	 *  @static
       
  1057 	 */
       
  1058 	ColReorder.fnReset = function (oTable) {
       
  1059 		for (var i = 0, iLen = ColReorder.aoInstances.length; i < iLen; i++) {
       
  1060 			if (ColReorder.aoInstances[i].s.dt.oInstance == oTable) {
       
  1061 				ColReorder.aoInstances[i].fnReset();
       
  1062 			}
       
  1063 		}
       
  1064 	};
       
  1065 
       
  1066 
       
  1067 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1068 	 * Constants
       
  1069 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  1070 
       
  1071 	/**
       
  1072 	 * Name of this class
       
  1073 	 *  @constant CLASS
       
  1074 	 *  @type     String
       
  1075 	 *  @default  ColReorder
       
  1076 	 */
       
  1077 	ColReorder.prototype.CLASS = "ColReorder";
       
  1078 
       
  1079 
       
  1080 	/**
       
  1081 	 * ColReorder version
       
  1082 	 *  @constant  VERSION
       
  1083 	 *  @type      String
       
  1084 	 *  @default   As code
       
  1085 	 */
       
  1086 	ColReorder.VERSION = "1.0.7";
       
  1087 	ColReorder.prototype.VERSION = ColReorder.VERSION;
       
  1088 
       
  1089 
       
  1090 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1091 	 * Initialisation
       
  1092 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  1093 
       
  1094 	/*
       
  1095 	 * Register a new feature with DataTables
       
  1096 	 */
       
  1097 	if (typeof $.fn.dataTable == "function" &&
       
  1098 		typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
       
  1099 		$.fn.dataTableExt.fnVersionCheck('1.9.3')) {
       
  1100 		$.fn.dataTableExt.aoFeatures.push({
       
  1101 											  "fnInit": function (oDTSettings) {
       
  1102 												  var oTable = oDTSettings.oInstance;
       
  1103 												  if (typeof oTable._oPluginColReorder == 'undefined') {
       
  1104 													  var opts = typeof oDTSettings.oInit.oColReorder != 'undefined' ?
       
  1105 														  oDTSettings.oInit.oColReorder : {};
       
  1106 													  oTable._oPluginColReorder = new ColReorder(oDTSettings, opts);
       
  1107 												  } else {
       
  1108 													  oTable.oApi._fnLog(oDTSettings, 1, "ColReorder attempted to initialise twice. Ignoring second");
       
  1109 												  }
       
  1110 
       
  1111 												  return null;
       
  1112 												  /* No node to insert */
       
  1113 											  },
       
  1114 											  "cFeature": "R",
       
  1115 											  "sFeature": "ColReorder"
       
  1116 										  });
       
  1117 	}
       
  1118 	else {
       
  1119 		alert("Warning: ColReorder requires DataTables 1.9.3 or greater - www.datatables.net/download");
       
  1120 	}
       
  1121 
       
  1122 })(jQuery, window, document);