You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1492 lines
38KB

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