dataTables.colReorder.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372
  1. /*! ColReorder 1.1.3
  2. * ©2010-2014 SpryMedia Ltd - datatables.net/license
  3. */
  4. /**
  5. * @summary ColReorder
  6. * @description Provide the ability to reorder columns in a DataTable
  7. * @version 1.1.3
  8. * @file dataTables.colReorder.js
  9. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  10. * @contact www.sprymedia.co.uk/contact
  11. * @copyright Copyright 2010-2014 SpryMedia Ltd.
  12. *
  13. * This source file is free software, available under the following license:
  14. * MIT license - http://datatables.net/license/mit
  15. *
  16. * This source file is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19. *
  20. * For details please refer to: http://www.datatables.net
  21. */
  22. (function(window, document, undefined) {
  23. /**
  24. * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
  25. * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
  26. * @method fnInvertKeyValues
  27. * @param array aIn Array to switch around
  28. * @returns array
  29. */
  30. function fnInvertKeyValues( aIn )
  31. {
  32. var aRet=[];
  33. for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
  34. {
  35. aRet[ aIn[i] ] = i;
  36. }
  37. return aRet;
  38. }
  39. /**
  40. * Modify an array by switching the position of two elements
  41. * @method fnArraySwitch
  42. * @param array aArray Array to consider, will be modified by reference (i.e. no return)
  43. * @param int iFrom From point
  44. * @param int iTo Insert point
  45. * @returns void
  46. */
  47. function fnArraySwitch( aArray, iFrom, iTo )
  48. {
  49. var mStore = aArray.splice( iFrom, 1 )[0];
  50. aArray.splice( iTo, 0, mStore );
  51. }
  52. /**
  53. * Switch the positions of nodes in a parent node (note this is specifically designed for
  54. * table rows). Note this function considers all element nodes under the parent!
  55. * @method fnDomSwitch
  56. * @param string sTag Tag to consider
  57. * @param int iFrom Element to move
  58. * @param int Point to element the element to (before this point), can be null for append
  59. * @returns void
  60. */
  61. function fnDomSwitch( nParent, iFrom, iTo )
  62. {
  63. var anTags = [];
  64. for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
  65. {
  66. if ( nParent.childNodes[i].nodeType == 1 )
  67. {
  68. anTags.push( nParent.childNodes[i] );
  69. }
  70. }
  71. var nStore = anTags[ iFrom ];
  72. if ( iTo !== null )
  73. {
  74. nParent.insertBefore( nStore, anTags[iTo] );
  75. }
  76. else
  77. {
  78. nParent.appendChild( nStore );
  79. }
  80. }
  81. var factory = function( $, DataTable ) {
  82. "use strict";
  83. /**
  84. * Plug-in for DataTables which will reorder the internal column structure by taking the column
  85. * from one position (iFrom) and insert it into a given point (iTo).
  86. * @method $.fn.dataTableExt.oApi.fnColReorder
  87. * @param object oSettings DataTables settings object - automatically added by DataTables!
  88. * @param int iFrom Take the column to be repositioned from this point
  89. * @param int iTo and insert it into this point
  90. * @returns void
  91. */
  92. $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo )
  93. {
  94. var v110 = $.fn.dataTable.Api ? true : false;
  95. var i, iLen, j, jLen, iCols=oSettings.aoColumns.length, nTrs, oCol;
  96. var attrMap = function ( obj, prop, mapping ) {
  97. if ( ! obj[ prop ] ) {
  98. return;
  99. }
  100. var a = obj[ prop ].split('.');
  101. var num = a.shift();
  102. if ( isNaN( num*1 ) ) {
  103. return;
  104. }
  105. obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
  106. };
  107. /* Sanity check in the input */
  108. if ( iFrom == iTo )
  109. {
  110. /* Pointless reorder */
  111. return;
  112. }
  113. if ( iFrom < 0 || iFrom >= iCols )
  114. {
  115. this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
  116. return;
  117. }
  118. if ( iTo < 0 || iTo >= iCols )
  119. {
  120. this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
  121. return;
  122. }
  123. /*
  124. * Calculate the new column array index, so we have a mapping between the old and new
  125. */
  126. var aiMapping = [];
  127. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  128. {
  129. aiMapping[i] = i;
  130. }
  131. fnArraySwitch( aiMapping, iFrom, iTo );
  132. var aiInvertMapping = fnInvertKeyValues( aiMapping );
  133. /*
  134. * Convert all internal indexing to the new column order indexes
  135. */
  136. /* Sorting */
  137. for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
  138. {
  139. oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
  140. }
  141. /* Fixed sorting */
  142. if ( oSettings.aaSortingFixed !== null )
  143. {
  144. for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
  145. {
  146. oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
  147. }
  148. }
  149. /* Data column sorting (the column which the sort for a given column should take place on) */
  150. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  151. {
  152. oCol = oSettings.aoColumns[i];
  153. for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
  154. {
  155. oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
  156. }
  157. // Update the column indexes
  158. if ( v110 ) {
  159. oCol.idx = aiInvertMapping[ oCol.idx ];
  160. }
  161. }
  162. if ( v110 ) {
  163. // Update 1.10 optimised sort class removal variable
  164. $.each( oSettings.aLastSort, function (i, val) {
  165. oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
  166. } );
  167. }
  168. /* Update the Get and Set functions for each column */
  169. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  170. {
  171. oCol = oSettings.aoColumns[i];
  172. if ( typeof oCol.mData == 'number' ) {
  173. oCol.mData = aiInvertMapping[ oCol.mData ];
  174. // regenerate the get / set functions
  175. oSettings.oApi._fnColumnOptions( oSettings, i, {} );
  176. }
  177. else if ( $.isPlainObject( oCol.mData ) ) {
  178. // HTML5 data sourced
  179. attrMap( oCol.mData, '_', aiInvertMapping );
  180. attrMap( oCol.mData, 'filter', aiInvertMapping );
  181. attrMap( oCol.mData, 'sort', aiInvertMapping );
  182. attrMap( oCol.mData, 'type', aiInvertMapping );
  183. // regenerate the get / set functions
  184. oSettings.oApi._fnColumnOptions( oSettings, i, {} );
  185. }
  186. }
  187. /*
  188. * Move the DOM elements
  189. */
  190. if ( oSettings.aoColumns[iFrom].bVisible )
  191. {
  192. /* Calculate the current visible index and the point to insert the node before. The insert
  193. * before needs to take into account that there might not be an element to insert before,
  194. * in which case it will be null, and an appendChild should be used
  195. */
  196. var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
  197. var iInsertBeforeIndex = null;
  198. i = iTo < iFrom ? iTo : iTo + 1;
  199. while ( iInsertBeforeIndex === null && i < iCols )
  200. {
  201. iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
  202. i++;
  203. }
  204. /* Header */
  205. nTrs = oSettings.nTHead.getElementsByTagName('tr');
  206. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  207. {
  208. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  209. }
  210. /* Footer */
  211. if ( oSettings.nTFoot !== null )
  212. {
  213. nTrs = oSettings.nTFoot.getElementsByTagName('tr');
  214. for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
  215. {
  216. fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
  217. }
  218. }
  219. /* Body */
  220. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  221. {
  222. if ( oSettings.aoData[i].nTr !== null )
  223. {
  224. fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
  225. }
  226. }
  227. }
  228. /*
  229. * Move the internal array elements
  230. */
  231. /* Columns */
  232. fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
  233. /* Search columns */
  234. fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
  235. /* Array array - internal data anodes cache */
  236. for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
  237. {
  238. var data = oSettings.aoData[i];
  239. if ( v110 ) {
  240. // DataTables 1.10+
  241. if ( data.anCells ) {
  242. fnArraySwitch( data.anCells, iFrom, iTo );
  243. }
  244. // For DOM sourced data, the invalidate will reread the cell into
  245. // the data array, but for data sources as an array, they need to
  246. // be flipped
  247. if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
  248. fnArraySwitch( data._aData, iFrom, iTo );
  249. }
  250. }
  251. else {
  252. // DataTables 1.9-
  253. if ( $.isArray( data._aData ) ) {
  254. fnArraySwitch( data._aData, iFrom, iTo );
  255. }
  256. fnArraySwitch( data._anHidden, iFrom, iTo );
  257. }
  258. }
  259. /* Reposition the header elements in the header layout array */
  260. for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
  261. {
  262. fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
  263. }
  264. if ( oSettings.aoFooter !== null )
  265. {
  266. for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
  267. {
  268. fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
  269. }
  270. }
  271. // In 1.10 we need to invalidate row cached data for sorting, filtering etc
  272. if ( v110 ) {
  273. var api = new $.fn.dataTable.Api( oSettings );
  274. api.rows().invalidate();
  275. }
  276. /*
  277. * Update DataTables' event handlers
  278. */
  279. /* Sort listener */
  280. for ( i=0, iLen=iCols ; i<iLen ; i++ )
  281. {
  282. $(oSettings.aoColumns[i].nTh).off('click.DT');
  283. this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
  284. }
  285. /* Fire an event so other plug-ins can update */
  286. $(oSettings.oInstance).trigger( 'column-reorder', [ oSettings, {
  287. "iFrom": iFrom,
  288. "iTo": iTo,
  289. "aiInvertMapping": aiInvertMapping
  290. } ] );
  291. };
  292. /**
  293. * ColReorder provides column visibility control for DataTables
  294. * @class ColReorder
  295. * @constructor
  296. * @param {object} dt DataTables settings object
  297. * @param {object} opts ColReorder options
  298. */
  299. var ColReorder = function( dt, opts )
  300. {
  301. var oDTSettings;
  302. if ( $.fn.dataTable.Api ) {
  303. oDTSettings = new $.fn.dataTable.Api( dt ).settings()[0];
  304. }
  305. // 1.9 compatibility
  306. else if ( dt.fnSettings ) {
  307. // DataTables object, convert to the settings object
  308. oDTSettings = dt.fnSettings();
  309. }
  310. else if ( typeof dt === 'string' ) {
  311. // jQuery selector
  312. if ( $.fn.dataTable.fnIsDataTable( $(dt)[0] ) ) {
  313. oDTSettings = $(dt).eq(0).dataTable().fnSettings();
  314. }
  315. }
  316. else if ( dt.nodeName && dt.nodeName.toLowerCase() === 'table' ) {
  317. // Table node
  318. if ( $.fn.dataTable.fnIsDataTable( dt.nodeName ) ) {
  319. oDTSettings = $(dt.nodeName).dataTable().fnSettings();
  320. }
  321. }
  322. else if ( dt instanceof jQuery ) {
  323. // jQuery object
  324. if ( $.fn.dataTable.fnIsDataTable( dt[0] ) ) {
  325. oDTSettings = dt.eq(0).dataTable().fnSettings();
  326. }
  327. }
  328. else {
  329. // DataTables settings object
  330. oDTSettings = dt;
  331. }
  332. // Ensure that we can't initialise on the same table twice
  333. if ( oDTSettings._colReorder ) {
  334. throw "ColReorder already initialised on table #"+oDTSettings.nTable.id;
  335. }
  336. // Convert from camelCase to Hungarian, just as DataTables does
  337. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  338. if ( camelToHungarian ) {
  339. camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
  340. camelToHungarian( ColReorder.defaults, opts || {} );
  341. }
  342. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  343. * Public class variables
  344. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  345. /**
  346. * @namespace Settings object which contains customisable information for ColReorder instance
  347. */
  348. this.s = {
  349. /**
  350. * DataTables settings object
  351. * @property dt
  352. * @type Object
  353. * @default null
  354. */
  355. "dt": null,
  356. /**
  357. * Initialisation object used for this instance
  358. * @property init
  359. * @type object
  360. * @default {}
  361. */
  362. "init": $.extend( true, {}, ColReorder.defaults, opts ),
  363. /**
  364. * Number of columns to fix (not allow to be reordered)
  365. * @property fixed
  366. * @type int
  367. * @default 0
  368. */
  369. "fixed": 0,
  370. /**
  371. * Number of columns to fix counting from right (not allow to be reordered)
  372. * @property fixedRight
  373. * @type int
  374. * @default 0
  375. */
  376. "fixedRight": 0,
  377. /**
  378. * Callback function for once the reorder has been done
  379. * @property reorderCallback
  380. * @type function
  381. * @default null
  382. */
  383. "reorderCallback": null,
  384. /**
  385. * @namespace Information used for the mouse drag
  386. */
  387. "mouse": {
  388. "startX": -1,
  389. "startY": -1,
  390. "offsetX": -1,
  391. "offsetY": -1,
  392. "target": -1,
  393. "targetIndex": -1,
  394. "fromIndex": -1
  395. },
  396. /**
  397. * Information which is used for positioning the insert cusor and knowing where to do the
  398. * insert. Array of objects with the properties:
  399. * x: x-axis position
  400. * to: insert point
  401. * @property aoTargets
  402. * @type array
  403. * @default []
  404. */
  405. "aoTargets": []
  406. };
  407. /**
  408. * @namespace Common and useful DOM elements for the class instance
  409. */
  410. this.dom = {
  411. /**
  412. * Dragging element (the one the mouse is moving)
  413. * @property drag
  414. * @type element
  415. * @default null
  416. */
  417. "drag": null,
  418. /**
  419. * The insert cursor
  420. * @property pointer
  421. * @type element
  422. * @default null
  423. */
  424. "pointer": null
  425. };
  426. /* Constructor logic */
  427. this.s.dt = oDTSettings;
  428. this.s.dt._colReorder = this;
  429. this._fnConstruct();
  430. /* Add destroy callback */
  431. oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColReorder');
  432. return this;
  433. };
  434. ColReorder.prototype = {
  435. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  436. * Public methods
  437. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  438. /**
  439. * Reset the column ordering to the original ordering that was detected on
  440. * start up.
  441. * @return {this} Returns `this` for chaining.
  442. *
  443. * @example
  444. * // DataTables initialisation with ColReorder
  445. * var table = $('#example').dataTable( {
  446. * "sDom": 'Rlfrtip'
  447. * } );
  448. *
  449. * // Add click event to a button to reset the ordering
  450. * $('#resetOrdering').click( function (e) {
  451. * e.preventDefault();
  452. * $.fn.dataTable.ColReorder( table ).fnReset();
  453. * } );
  454. */
  455. "fnReset": function ()
  456. {
  457. var a = [];
  458. for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
  459. {
  460. a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
  461. }
  462. this._fnOrderColumns( a );
  463. return this;
  464. },
  465. /**
  466. * `Deprecated` - Get the current order of the columns, as an array.
  467. * @return {array} Array of column identifiers
  468. * @deprecated `fnOrder` should be used in preference to this method.
  469. * `fnOrder` acts as a getter/setter.
  470. */
  471. "fnGetCurrentOrder": function ()
  472. {
  473. return this.fnOrder();
  474. },
  475. /**
  476. * Get the current order of the columns, as an array. Note that the values
  477. * given in the array are unique identifiers for each column. Currently
  478. * these are the original ordering of the columns that was detected on
  479. * start up, but this could potentially change in future.
  480. * @return {array} Array of column identifiers
  481. *
  482. * @example
  483. * // Get column ordering for the table
  484. * var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
  485. *//**
  486. * Set the order of the columns, from the positions identified in the
  487. * ordering array given. Note that ColReorder takes a brute force approach
  488. * to reordering, so it is possible multiple reordering events will occur
  489. * before the final order is settled upon.
  490. * @param {array} [set] Array of column identifiers in the new order. Note
  491. * that every column must be included, uniquely, in this array.
  492. * @return {this} Returns `this` for chaining.
  493. *
  494. * @example
  495. * // Swap the first and second columns
  496. * $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
  497. *
  498. * @example
  499. * // Move the first column to the end for the table `#example`
  500. * var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
  501. * var first = curr.shift();
  502. * curr.push( first );
  503. * $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
  504. *
  505. * @example
  506. * // Reverse the table's order
  507. * $.fn.dataTable.ColReorder( '#example' ).fnOrder(
  508. * $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
  509. * );
  510. */
  511. "fnOrder": function ( set )
  512. {
  513. if ( set === undefined )
  514. {
  515. var a = [];
  516. for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
  517. {
  518. a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol );
  519. }
  520. return a;
  521. }
  522. this._fnOrderColumns( fnInvertKeyValues( set ) );
  523. return this;
  524. },
  525. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  526. * Private methods (they are of course public in JS, but recommended as private)
  527. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  528. /**
  529. * Constructor logic
  530. * @method _fnConstruct
  531. * @returns void
  532. * @private
  533. */
  534. "_fnConstruct": function ()
  535. {
  536. var that = this;
  537. var iLen = this.s.dt.aoColumns.length;
  538. var i;
  539. /* Columns discounted from reordering - counting left to right */
  540. if ( this.s.init.iFixedColumns )
  541. {
  542. this.s.fixed = this.s.init.iFixedColumns;
  543. }
  544. /* Columns discounted from reordering - counting right to left */
  545. this.s.fixedRight = this.s.init.iFixedColumnsRight ?
  546. this.s.init.iFixedColumnsRight :
  547. 0;
  548. /* Drop callback initialisation option */
  549. if ( this.s.init.fnReorderCallback )
  550. {
  551. this.s.reorderCallback = this.s.init.fnReorderCallback;
  552. }
  553. /* Add event handlers for the drag and drop, and also mark the original column order */
  554. for ( i = 0; i < iLen; i++ )
  555. {
  556. if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
  557. {
  558. this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
  559. }
  560. /* Mark the original column order for later reference */
  561. this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
  562. }
  563. /* State saving */
  564. this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
  565. that._fnStateSave.call( that, oData );
  566. }, "ColReorder_State" );
  567. /* An initial column order has been specified */
  568. var aiOrder = null;
  569. if ( this.s.init.aiOrder )
  570. {
  571. aiOrder = this.s.init.aiOrder.slice();
  572. }
  573. /* State loading, overrides the column order given */
  574. if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
  575. this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
  576. {
  577. aiOrder = this.s.dt.oLoadedState.ColReorder;
  578. }
  579. /* If we have an order to apply - do so */
  580. if ( aiOrder )
  581. {
  582. /* We might be called during or after the DataTables initialisation. If before, then we need
  583. * to wait until the draw is done, if after, then do what we need to do right away
  584. */
  585. if ( !that.s.dt._bInitComplete )
  586. {
  587. var bDone = false;
  588. this.s.dt.aoDrawCallback.push( {
  589. "fn": function () {
  590. if ( !that.s.dt._bInitComplete && !bDone )
  591. {
  592. bDone = true;
  593. var resort = fnInvertKeyValues( aiOrder );
  594. that._fnOrderColumns.call( that, resort );
  595. }
  596. },
  597. "sName": "ColReorder_Pre"
  598. } );
  599. }
  600. else
  601. {
  602. var resort = fnInvertKeyValues( aiOrder );
  603. that._fnOrderColumns.call( that, resort );
  604. }
  605. }
  606. else {
  607. this._fnSetColumnIndexes();
  608. }
  609. },
  610. /**
  611. * Set the column order from an array
  612. * @method _fnOrderColumns
  613. * @param array a An array of integers which dictate the column order that should be applied
  614. * @returns void
  615. * @private
  616. */
  617. "_fnOrderColumns": function ( a )
  618. {
  619. if ( a.length != this.s.dt.aoColumns.length )
  620. {
  621. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
  622. "match known number of columns. Skipping." );
  623. return;
  624. }
  625. for ( var i=0, iLen=a.length ; i<iLen ; i++ )
  626. {
  627. var currIndex = $.inArray( i, a );
  628. if ( i != currIndex )
  629. {
  630. /* Reorder our switching array */
  631. fnArraySwitch( a, currIndex, i );
  632. /* Do the column reorder in the table */
  633. this.s.dt.oInstance.fnColReorder( currIndex, i );
  634. }
  635. }
  636. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  637. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  638. {
  639. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  640. }
  641. /* Save the state */
  642. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  643. this._fnSetColumnIndexes();
  644. if ( this.s.reorderCallback !== null )
  645. {
  646. this.s.reorderCallback.call( this );
  647. }
  648. },
  649. /**
  650. * Because we change the indexes of columns in the table, relative to their starting point
  651. * we need to reorder the state columns to what they are at the starting point so we can
  652. * then rearrange them again on state load!
  653. * @method _fnStateSave
  654. * @param object oState DataTables state
  655. * @returns string JSON encoded cookie string for DataTables
  656. * @private
  657. */
  658. "_fnStateSave": function ( oState )
  659. {
  660. var i, iLen, aCopy, iOrigColumn;
  661. var oSettings = this.s.dt;
  662. var columns = oSettings.aoColumns;
  663. oState.ColReorder = [];
  664. /* Sorting */
  665. if ( oState.aaSorting ) {
  666. // 1.10.0-
  667. for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
  668. oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
  669. }
  670. var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
  671. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  672. {
  673. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  674. /* Column filter */
  675. oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
  676. /* Visibility */
  677. oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
  678. /* Column reordering */
  679. oState.ColReorder.push( iOrigColumn );
  680. }
  681. }
  682. else if ( oState.order ) {
  683. // 1.10.1+
  684. for ( i=0 ; i<oState.order.length ; i++ ) {
  685. oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
  686. }
  687. var stateColumnsCopy = $.extend( true, [], oState.columns );
  688. for ( i=0, iLen=columns.length ; i<iLen ; i++ )
  689. {
  690. iOrigColumn = columns[i]._ColReorder_iOrigCol;
  691. /* Columns */
  692. oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
  693. /* Column reordering */
  694. oState.ColReorder.push( iOrigColumn );
  695. }
  696. }
  697. },
  698. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  699. * Mouse drop and drag
  700. */
  701. /**
  702. * Add a mouse down listener to a particluar TH element
  703. * @method _fnMouseListener
  704. * @param int i Column index
  705. * @param element nTh TH element clicked on
  706. * @returns void
  707. * @private
  708. */
  709. "_fnMouseListener": function ( i, nTh )
  710. {
  711. var that = this;
  712. $(nTh).on( 'mousedown.ColReorder', function (e) {
  713. e.preventDefault();
  714. that._fnMouseDown.call( that, e, nTh );
  715. } );
  716. },
  717. /**
  718. * Mouse down on a TH element in the table header
  719. * @method _fnMouseDown
  720. * @param event e Mouse event
  721. * @param element nTh TH element to be dragged
  722. * @returns void
  723. * @private
  724. */
  725. "_fnMouseDown": function ( e, nTh )
  726. {
  727. var that = this;
  728. /* Store information about the mouse position */
  729. var target = $(e.target).closest('th, td');
  730. var offset = target.offset();
  731. var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
  732. if ( idx === undefined ) {
  733. return;
  734. }
  735. this.s.mouse.startX = e.pageX;
  736. this.s.mouse.startY = e.pageY;
  737. this.s.mouse.offsetX = e.pageX - offset.left;
  738. this.s.mouse.offsetY = e.pageY - offset.top;
  739. this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
  740. this.s.mouse.targetIndex = idx;
  741. this.s.mouse.fromIndex = idx;
  742. this._fnRegions();
  743. /* Add event handlers to the document */
  744. $(document)
  745. .on( 'mousemove.ColReorder', function (e) {
  746. that._fnMouseMove.call( that, e );
  747. } )
  748. .on( 'mouseup.ColReorder', function (e) {
  749. that._fnMouseUp.call( that, e );
  750. } );
  751. },
  752. /**
  753. * Deal with a mouse move event while dragging a node
  754. * @method _fnMouseMove
  755. * @param event e Mouse event
  756. * @returns void
  757. * @private
  758. */
  759. "_fnMouseMove": function ( e )
  760. {
  761. var that = this;
  762. if ( this.dom.drag === null )
  763. {
  764. /* Only create the drag element if the mouse has moved a specific distance from the start
  765. * point - this allows the user to make small mouse movements when sorting and not have a
  766. * possibly confusing drag element showing up
  767. */
  768. if ( Math.pow(
  769. Math.pow(e.pageX - this.s.mouse.startX, 2) +
  770. Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 )
  771. {
  772. return;
  773. }
  774. this._fnCreateDragNode();
  775. }
  776. /* Position the element - we respect where in the element the click occured */
  777. this.dom.drag.css( {
  778. left: e.pageX - this.s.mouse.offsetX,
  779. top: e.pageY - this.s.mouse.offsetY
  780. } );
  781. /* Based on the current mouse position, calculate where the insert should go */
  782. var bSet = false;
  783. var lastToIndex = this.s.mouse.toIndex;
  784. for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
  785. {
  786. if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
  787. {
  788. this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );
  789. this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
  790. bSet = true;
  791. break;
  792. }
  793. }
  794. // The insert element wasn't positioned in the array (less than
  795. // operator), so we put it at the end
  796. if ( !bSet )
  797. {
  798. this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );
  799. this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
  800. }
  801. // Perform reordering if realtime updating is on and the column has moved
  802. if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
  803. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
  804. this.s.mouse.fromIndex = this.s.mouse.toIndex;
  805. this._fnRegions();
  806. }
  807. },
  808. /**
  809. * Finish off the mouse drag and insert the column where needed
  810. * @method _fnMouseUp
  811. * @param event e Mouse event
  812. * @returns void
  813. * @private
  814. */
  815. "_fnMouseUp": function ( e )
  816. {
  817. var that = this;
  818. $(document).off( 'mousemove.ColReorder mouseup.ColReorder' );
  819. if ( this.dom.drag !== null )
  820. {
  821. /* Remove the guide elements */
  822. this.dom.drag.remove();
  823. this.dom.pointer.remove();
  824. this.dom.drag = null;
  825. this.dom.pointer = null;
  826. /* Actually do the reorder */
  827. this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );
  828. this._fnSetColumnIndexes();
  829. /* When scrolling we need to recalculate the column sizes to allow for the shift */
  830. if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
  831. {
  832. this.s.dt.oInstance.fnAdjustColumnSizing( false );
  833. }
  834. /* Save the state */
  835. this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
  836. if ( this.s.reorderCallback !== null )
  837. {
  838. this.s.reorderCallback.call( this );
  839. }
  840. }
  841. },
  842. /**
  843. * Calculate a cached array with the points of the column inserts, and the
  844. * 'to' points
  845. * @method _fnRegions
  846. * @returns void
  847. * @private
  848. */
  849. "_fnRegions": function ()
  850. {
  851. var aoColumns = this.s.dt.aoColumns;
  852. this.s.aoTargets.splice( 0, this.s.aoTargets.length );
  853. this.s.aoTargets.push( {
  854. "x": $(this.s.dt.nTable).offset().left,
  855. "to": 0
  856. } );
  857. var iToPoint = 0;
  858. for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
  859. {
  860. /* For the column / header in question, we want it's position to remain the same if the
  861. * position is just to it's immediate left or right, so we only incremement the counter for
  862. * other columns
  863. */
  864. if ( i != this.s.mouse.fromIndex )
  865. {
  866. iToPoint++;
  867. }
  868. if ( aoColumns[i].bVisible )
  869. {
  870. this.s.aoTargets.push( {
  871. "x": $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(),
  872. "to": iToPoint
  873. } );
  874. }
  875. }
  876. /* Disallow columns for being reordered by drag and drop, counting right to left */
  877. if ( this.s.fixedRight !== 0 )
  878. {
  879. this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
  880. }
  881. /* Disallow columns for being reordered by drag and drop, counting left to right */
  882. if ( this.s.fixed !== 0 )
  883. {
  884. this.s.aoTargets.splice( 0, this.s.fixed );
  885. }
  886. },
  887. /**
  888. * Copy the TH element that is being drags so the user has the idea that they are actually
  889. * moving it around the page.
  890. * @method _fnCreateDragNode
  891. * @returns void
  892. * @private
  893. */
  894. "_fnCreateDragNode": function ()
  895. {
  896. var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
  897. var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
  898. var origTr = origCell.parentNode;
  899. var origThead = origTr.parentNode;
  900. var origTable = origThead.parentNode;
  901. var cloneCell = $(origCell).clone();
  902. // This is a slightly odd combination of jQuery and DOM, but it is the
  903. // fastest and least resource intensive way I could think of cloning
  904. // the table with just a single header cell in it.
  905. this.dom.drag = $(origTable.cloneNode(false))
  906. .addClass( 'DTCR_clonedTable' )
  907. .append(
  908. $(origThead.cloneNode(false)).append(
  909. $(origTr.cloneNode(false)).append(
  910. cloneCell[0]
  911. )
  912. )
  913. )
  914. .css( {
  915. position: 'absolute',
  916. top: 0,
  917. left: 0,
  918. width: $(origCell).outerWidth(),
  919. height: $(origCell).outerHeight()
  920. } )
  921. .appendTo( 'body' );
  922. this.dom.pointer = $('<div></div>')
  923. .addClass( 'DTCR_pointer' )
  924. .css( {
  925. position: 'absolute',
  926. top: scrolling ?
  927. $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
  928. $(this.s.dt.nTable).offset().top,
  929. height : scrolling ?
  930. $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
  931. $(this.s.dt.nTable).height()
  932. } )
  933. .appendTo( 'body' );
  934. },
  935. /**
  936. * Clean up ColReorder memory references and event handlers
  937. * @method _fnDestroy
  938. * @returns void
  939. * @private
  940. */
  941. "_fnDestroy": function ()
  942. {
  943. var i, iLen;
  944. for ( i=0, iLen=this.s.dt.aoDrawCallback.length ; i<iLen ; i++ )
  945. {
  946. if ( this.s.dt.aoDrawCallback[i].sName === 'ColReorder_Pre' )
  947. {
  948. this.s.dt.aoDrawCallback.splice( i, 1 );
  949. break;
  950. }
  951. }
  952. $(this.s.dt.nTHead).find( '*' ).off( '.ColReorder' );
  953. $.each( this.s.dt.aoColumns, function (i, column) {
  954. $(column.nTh).removeAttr('data-column-index');
  955. } );
  956. this.s.dt._colReorder = null;
  957. this.s = null;
  958. },
  959. /**
  960. * Add a data attribute to the column headers, so we know the index of
  961. * the row to be reordered. This allows fast detection of the index, and
  962. * for this plug-in to work with FixedHeader which clones the nodes.
  963. * @private
  964. */
  965. "_fnSetColumnIndexes": function ()
  966. {
  967. $.each( this.s.dt.aoColumns, function (i, column) {
  968. $(column.nTh).attr('data-column-index', i);
  969. } );
  970. }
  971. };
  972. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  973. * Static parameters
  974. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  975. /**
  976. * ColReorder default settings for initialisation
  977. * @namespace
  978. * @static
  979. */
  980. ColReorder.defaults = {
  981. /**
  982. * Predefined ordering for the columns that will be applied automatically
  983. * on initialisation. If not specified then the order that the columns are
  984. * found to be in the HTML is the order used.
  985. * @type array
  986. * @default null
  987. * @static
  988. * @example
  989. * // Using the `oColReorder` option in the DataTables options object
  990. * $('#example').dataTable( {
  991. * "sDom": 'Rlfrtip',
  992. * "oColReorder": {
  993. * "aiOrder": [ 4, 3, 2, 1, 0 ]
  994. * }
  995. * } );
  996. *
  997. * @example
  998. * // Using `new` constructor
  999. * $('#example').dataTable()
  1000. *
  1001. * new $.fn.dataTable.ColReorder( '#example', {
  1002. * "aiOrder": [ 4, 3, 2, 1, 0 ]
  1003. * } );
  1004. */
  1005. aiOrder: null,
  1006. /**
  1007. * Redraw the table's column ordering as the end user draws the column
  1008. * (`true`) or wait until the mouse is released (`false` - default). Note
  1009. * that this will perform a redraw on each reordering, which involves an
  1010. * Ajax request each time if you are using server-side processing in
  1011. * DataTables.
  1012. * @type boolean
  1013. * @default false
  1014. * @static
  1015. * @example
  1016. * // Using the `oColReorder` option in the DataTables options object
  1017. * $('#example').dataTable( {
  1018. * "sDom": 'Rlfrtip',
  1019. * "oColReorder": {
  1020. * "bRealtime": true
  1021. * }
  1022. * } );
  1023. *
  1024. * @example
  1025. * // Using `new` constructor
  1026. * $('#example').dataTable()
  1027. *
  1028. * new $.fn.dataTable.ColReorder( '#example', {
  1029. * "bRealtime": true
  1030. * } );
  1031. */
  1032. bRealtime: false,
  1033. /**
  1034. * Indicate how many columns should be fixed in position (counting from the
  1035. * left). This will typically be 1 if used, but can be as high as you like.
  1036. * @type int
  1037. * @default 0
  1038. * @static
  1039. * @example
  1040. * // Using the `oColReorder` option in the DataTables options object
  1041. * $('#example').dataTable( {
  1042. * "sDom": 'Rlfrtip',
  1043. * "oColReorder": {
  1044. * "iFixedColumns": 1
  1045. * }
  1046. * } );
  1047. *
  1048. * @example
  1049. * // Using `new` constructor
  1050. * $('#example').dataTable()
  1051. *
  1052. * new $.fn.dataTable.ColReorder( '#example', {
  1053. * "iFixedColumns": 1
  1054. * } );
  1055. */
  1056. iFixedColumns: 0,
  1057. /**
  1058. * As `iFixedColumnsRight` but counting from the right.
  1059. * @type int
  1060. * @default 0
  1061. * @static
  1062. * @example
  1063. * // Using the `oColReorder` option in the DataTables options object
  1064. * $('#example').dataTable( {
  1065. * "sDom": 'Rlfrtip',
  1066. * "oColReorder": {
  1067. * "iFixedColumnsRight": 1
  1068. * }
  1069. * } );
  1070. *
  1071. * @example
  1072. * // Using `new` constructor
  1073. * $('#example').dataTable()
  1074. *
  1075. * new $.fn.dataTable.ColReorder( '#example', {
  1076. * "iFixedColumnsRight": 1
  1077. * } );
  1078. */
  1079. iFixedColumnsRight: 0,
  1080. /**
  1081. * Callback function that is fired when columns are reordered
  1082. * @type function():void
  1083. * @default null
  1084. * @static
  1085. * @example
  1086. * // Using the `oColReorder` option in the DataTables options object
  1087. * $('#example').dataTable( {
  1088. * "sDom": 'Rlfrtip',
  1089. * "oColReorder": {
  1090. * "fnReorderCallback": function () {
  1091. * alert( 'Columns reordered' );
  1092. * }
  1093. * }
  1094. * } );
  1095. *
  1096. * @example
  1097. * // Using `new` constructor
  1098. * $('#example').dataTable()
  1099. *
  1100. * new $.fn.dataTable.ColReorder( '#example', {
  1101. * "fnReorderCallback": function () {
  1102. * alert( 'Columns reordered' );
  1103. * }
  1104. * } );
  1105. */
  1106. fnReorderCallback: null
  1107. };
  1108. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1109. * Constants
  1110. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1111. /**
  1112. * ColReorder version
  1113. * @constant version
  1114. * @type String
  1115. * @default As code
  1116. */
  1117. ColReorder.version = "1.1.3";
  1118. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1119. * DataTables interfaces
  1120. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1121. // Expose
  1122. $.fn.dataTable.ColReorder = ColReorder;
  1123. $.fn.DataTable.ColReorder = ColReorder;
  1124. // Register a new feature with DataTables
  1125. if ( typeof $.fn.dataTable == "function" &&
  1126. typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
  1127. $.fn.dataTableExt.fnVersionCheck('1.9.3') )
  1128. {
  1129. $.fn.dataTableExt.aoFeatures.push( {
  1130. "fnInit": function( settings ) {
  1131. var table = settings.oInstance;
  1132. if ( ! settings._colReorder ) {
  1133. var dtInit = settings.oInit;
  1134. var opts = dtInit.colReorder || dtInit.oColReorder || {};
  1135. new ColReorder( settings, opts );
  1136. }
  1137. else {
  1138. table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
  1139. }
  1140. return null; /* No node for DataTables to insert */
  1141. },
  1142. "cFeature": "R",
  1143. "sFeature": "ColReorder"
  1144. } );
  1145. }
  1146. else {
  1147. alert( "Warning: ColReorder requires DataTables 1.9.3 or greater - www.datatables.net/download");
  1148. }
  1149. // API augmentation
  1150. if ( $.fn.dataTable.Api ) {
  1151. $.fn.dataTable.Api.register( 'colReorder.reset()', function () {
  1152. return this.iterator( 'table', function ( ctx ) {
  1153. ctx._colReorder.fnReset();
  1154. } );
  1155. } );
  1156. $.fn.dataTable.Api.register( 'colReorder.order()', function ( set ) {
  1157. if ( set ) {
  1158. return this.iterator( 'table', function ( ctx ) {
  1159. ctx._colReorder.fnOrder( set );
  1160. } );
  1161. }
  1162. return this.context.length ?
  1163. this.context[0]._colReorder.fnOrder() :
  1164. null;
  1165. } );
  1166. }
  1167. return ColReorder;
  1168. }; // /factory
  1169. // Define as an AMD module if possible
  1170. if ( typeof define === 'function' && define.amd ) {
  1171. define( ['jquery', 'datatables'], factory );
  1172. }
  1173. else if ( typeof exports === 'object' ) {
  1174. // Node/CommonJS
  1175. factory( require('jquery'), require('datatables') );
  1176. }
  1177. else if ( jQuery && !jQuery.fn.dataTable.ColReorder ) {
  1178. // Otherwise simply initialise as normal, stopping multiple evaluation
  1179. factory( jQuery, jQuery.fn.dataTable );
  1180. }
  1181. })(window, document);