dataTables.colReorder.js 36 KB

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