datatables.net-colreorder
Advanced tools
Comparing version 1.7.0 to 2.0.0
@@ -1,2 +0,2 @@ | ||
/*! ColReorder 1.7.0 | ||
/*! ColReorder 2.0.0-dev | ||
* © SpryMedia Ltd - datatables.net/license | ||
@@ -46,3 +46,3 @@ */ | ||
} | ||
}(function( $, window, document, undefined ) { | ||
}(function( $, window, document ) { | ||
'use strict'; | ||
@@ -53,1468 +53,976 @@ var DataTable = $.fn.dataTable; | ||
(function( factory ){ | ||
if ( typeof define === 'function' && define.amd ) { | ||
// AMD | ||
define( ['jquery', 'datatables.net'], function ( $ ) { | ||
return factory( $, window, document ); | ||
} ); | ||
} | ||
else if ( typeof exports === 'object' ) { | ||
// CommonJS | ||
var jq = require('jquery'); | ||
var cjsRequires = function (root, $) { | ||
if ( ! $.fn.dataTable ) { | ||
require('datatables.net')(root, $); | ||
} | ||
}; | ||
if (typeof window === 'undefined') { | ||
module.exports = function (root, $) { | ||
if ( ! root ) { | ||
// CommonJS environments without a window global must pass a | ||
// root. This will give an error otherwise | ||
root = window; | ||
} | ||
if ( ! $ ) { | ||
$ = jq( root ); | ||
} | ||
cjsRequires( root, $ ); | ||
return factory( $, root, root.document ); | ||
}; | ||
} | ||
else { | ||
cjsRequires( window, jq ); | ||
module.exports = factory( jq, window, window.document ); | ||
} | ||
} | ||
else { | ||
// Browser | ||
factory( jQuery, window, document ); | ||
} | ||
}(function( $, window, document ) { | ||
'use strict'; | ||
var DataTable = $.fn.dataTable; | ||
/** | ||
* @summary ColReorder | ||
* @description Provide the ability to reorder columns in a DataTable | ||
* @version 1.7.0 | ||
* @author SpryMedia Ltd | ||
* @contact datatables.net | ||
* @copyright SpryMedia Ltd. | ||
* Mutate an array, moving a set of elements into a new index position | ||
* | ||
* This source file is free software, available under the following license: | ||
* MIT license - http://datatables.net/license/mit | ||
* @param arr Array to modify | ||
* @param from Start move index | ||
* @param count Number of elements to move | ||
* @param to Index where the start element will move to | ||
*/ | ||
function arrayMove(arr, from, count, to) { | ||
var movers = arr.splice(from, count); | ||
// Add delete and start to the array, so we can use it for the `apply` | ||
movers.unshift(0); // splice delete param | ||
movers.unshift(to < from ? to : to - count + 1); // splice start param | ||
arr.splice.apply(arr, movers); | ||
} | ||
/** | ||
* Run finishing activities after one or more columns have been reordered. | ||
* | ||
* This source file is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. | ||
* @param dt DataTable being operated on - must be a single table instance | ||
*/ | ||
function finalise(dt) { | ||
// Cache invalidation. Always read from the data object rather | ||
// than reading back from the DOM since it could have been | ||
// changed by a renderer | ||
dt.rows().invalidate('data'); | ||
// Redraw the header / footer. Its a little bit of a hack this, as DT | ||
// doesn't expose the header draw as an API method. It calls state | ||
// saving, so we don't need to here. | ||
dt.column(0).visible(dt.column(0).visible()); | ||
dt.columns.adjust(); | ||
// Fire an event so other plug-ins can update | ||
var order = dt.colReorder.order(); | ||
dt.trigger('columns-reordered', [ | ||
{ | ||
order: order, | ||
mapping: invertKeyValues(order) | ||
} | ||
]); | ||
} | ||
/** | ||
* Get the original indexes in their current order | ||
* | ||
* For details please refer to: http://www.datatables.net | ||
* @param dt DataTable being operated on - must be a single table instance | ||
* @returns Original indexes in current order | ||
*/ | ||
function getOrder(dt) { | ||
return dt.settings()[0].aoColumns.map(function (col) { | ||
return col._crOriginalIdx; | ||
}); | ||
} | ||
/** | ||
* Manipulate a header / footer array in DataTables settings to reorder | ||
* the columns. | ||
*/ | ||
function headerUpdate(structure, map, from, to) { | ||
var done = []; | ||
for (var i = 0; i < structure.length; i++) { | ||
var headerRow = structure[i]; | ||
arrayMove(headerRow, from[0], from.length, to); | ||
for (var j = 0; j < headerRow.length; j++) { | ||
var cell = headerRow[j].cell; | ||
// Only work on a DOM element once, otherwise we risk remapping a | ||
// remapped value (etc). | ||
if (done.includes(cell)) { | ||
continue; | ||
} | ||
var indexes = cell.getAttribute('data-dt-column').split(','); | ||
var mapped = indexes | ||
.map(function (idx) { | ||
return map[idx]; | ||
}) | ||
.join(','); | ||
// Update data attributes for the new column position | ||
cell.setAttribute('data-dt-column', mapped); | ||
done.push(cell); | ||
} | ||
} | ||
} | ||
/** | ||
* Setup for ColReorder API operations | ||
* | ||
* @param dt DataTable(s) being operated on - might have multiple tables! | ||
*/ | ||
function init(api) { | ||
// Assign the original column index to a parameter that we can lookup. | ||
// On the first pass (i.e. when the parameter hasn't yet been set), the | ||
// index order will be the original order, so this is quite a simple | ||
// assignment. | ||
api.columns().iterator('column', function (s, idx) { | ||
var columns = s.aoColumns; | ||
if (columns[idx]._crOriginalIdx === undefined) { | ||
columns[idx]._crOriginalIdx = idx; | ||
} | ||
}); | ||
} | ||
/** | ||
* Switch the key value pairing of an index array to be value key (i.e. the old value is now the | ||
* key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ]. | ||
* @method fnInvertKeyValues | ||
* @param array aIn Array to switch around | ||
* @returns array | ||
* | ||
* @param array arr Array to switch around | ||
*/ | ||
function fnInvertKeyValues( aIn ) | ||
{ | ||
var aRet=[]; | ||
for ( var i=0, iLen=aIn.length ; i<iLen ; i++ ) | ||
{ | ||
aRet[ aIn[i] ] = i; | ||
} | ||
return aRet; | ||
function invertKeyValues(arr) { | ||
var result = []; | ||
for (var i = 0; i < arr.length; i++) { | ||
result[arr[i]] = i; | ||
} | ||
return result; | ||
} | ||
/** | ||
* Modify an array by switching the position of two elements | ||
* @method fnArraySwitch | ||
* @param array aArray Array to consider, will be modified by reference (i.e. no return) | ||
* @param int iFrom From point | ||
* @param int iTo Insert point | ||
* @returns void | ||
* Move one or more columns from one index to another. | ||
* | ||
* This method has a lot of knowledge about how DataTables works internally. | ||
* If DataTables changes how it handles cells, columns, etc, then this | ||
* method would need to be updated accordingly. | ||
* | ||
* @param dt DataTable being operated on - must be a single table instance | ||
* @param from Column indexes to move | ||
* @param to Destination index (starting if multiple) | ||
*/ | ||
function fnArraySwitch( aArray, iFrom, iTo ) | ||
{ | ||
var mStore = aArray.splice( iFrom, 1 )[0]; | ||
aArray.splice( iTo, 0, mStore ); | ||
function move(dt, from, to) { | ||
var i, j; | ||
var settings = dt.settings()[0]; | ||
var columns = settings.aoColumns; | ||
var newOrder = columns.map(function (col, idx) { | ||
return idx; | ||
}); | ||
// The to column in already inside the from column(s) (might be the same) | ||
// no change required | ||
if (from.includes(to)) { | ||
return; | ||
} | ||
// A reverse index array so we can look up new indexes from old | ||
arrayMove(newOrder, from[0], from.length, to); | ||
var reverseIndexes = invertKeyValues(newOrder); | ||
// Main column | ||
arrayMove(columns, from[0], from.length, to); | ||
// Per row manipulations | ||
for (i = 0; i < settings.aoData.length; i++) { | ||
var data = settings.aoData[i]; | ||
var cells = data.anCells; | ||
if (cells) { | ||
// Array of cells | ||
arrayMove(cells, from[0], from.length, to); | ||
for (j = 0; j < cells.length; j++) { | ||
// Reinsert into the document in the new order | ||
if (data.nTr && cells[j] && columns[j].bVisible) { | ||
data.nTr.appendChild(cells[j]); | ||
} | ||
// Update lookup index | ||
if (cells[j] && cells[j]._DT_CellIndex) { | ||
cells[j]._DT_CellIndex.column = j; | ||
} | ||
} | ||
} | ||
} | ||
// Per column manipulation | ||
for (i = 0; i < columns.length; i++) { | ||
var column = columns[i]; | ||
// Data column sorting | ||
for (j = 0; j < column.aDataSort.length; j++) { | ||
column.aDataSort[j] = reverseIndexes[column.aDataSort[j]]; | ||
} | ||
// Update the column indexes | ||
column.idx = reverseIndexes[column.idx]; | ||
// Reorder the colgroup > col elements for the new order | ||
if (column.bVisible) { | ||
settings.colgroup.append(column.colEl); | ||
} | ||
} | ||
// Header and footer | ||
headerUpdate(settings.aoHeader, reverseIndexes, from, to); | ||
headerUpdate(settings.aoFooter, reverseIndexes, from, to); | ||
// Search - columns | ||
arrayMove(settings.aoPreSearchCols, from[0], from.length, to); | ||
// Ordering indexes update - note that the sort listener on the | ||
// header works out the index to apply on each draw, so it doesn't | ||
// need to be updated here. | ||
orderingIndexes(reverseIndexes, settings.aaSorting); | ||
if (Array.isArray(settings.aaSortingFixed)) { | ||
orderingIndexes(reverseIndexes, settings.aaSortingFixed); | ||
} | ||
else if (settings.aaSortingFixed.pre) { | ||
orderingIndexes(reverseIndexes, settings.aaSortingFixed.pre); | ||
} | ||
else if (settings.aaSortingFixed.post) { | ||
orderingIndexes(reverseIndexes, settings.aaSortingFixed.pre); | ||
} | ||
settings.aLastSort.forEach(function (el) { | ||
el.src = reverseIndexes[el.src]; | ||
}); | ||
// Fire an event so other plug-ins can update | ||
dt.trigger('column-reorder', [ | ||
dt.settings()[0], | ||
{ | ||
from: from, | ||
to: to, | ||
mapping: reverseIndexes | ||
} | ||
]); | ||
} | ||
/** | ||
* Switch the positions of nodes in a parent node (note this is specifically designed for | ||
* table rows). Note this function considers all element nodes under the parent! | ||
* @method fnDomSwitch | ||
* @param string sTag Tag to consider | ||
* @param int iFrom Element to move | ||
* @param int Point to element the element to (before this point), can be null for append | ||
* @returns void | ||
* Update the indexing for ordering arrays | ||
* | ||
* @param map Reverse index map | ||
* @param order Array to update | ||
*/ | ||
function fnDomSwitch( nParent, iFrom, iTo ) | ||
{ | ||
var anTags = []; | ||
for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ ) | ||
{ | ||
if ( nParent.childNodes[i].nodeType == 1 ) | ||
{ | ||
anTags.push( nParent.childNodes[i] ); | ||
} | ||
} | ||
var nStore = anTags[ iFrom ]; | ||
if ( iTo !== null ) | ||
{ | ||
nParent.insertBefore( nStore, anTags[iTo] ); | ||
} | ||
else | ||
{ | ||
nParent.appendChild( nStore ); | ||
} | ||
function orderingIndexes(map, order) { | ||
for (var i = 0; i < order.length; i++) { | ||
var el = order[i]; | ||
if (typeof el === 'number') { | ||
// Just a number | ||
order[i] = map[el]; | ||
} | ||
else if ($.isPlainObject(el) && el.idx !== undefined) { | ||
// New index in an object style | ||
el.idx = map[el.idx]; | ||
} | ||
else if (Array.isArray(el) && typeof el[0] === 'number') { | ||
// The good old fixes length array | ||
el[0] = map[el[0]]; | ||
} | ||
// No need to update if in object + .name style | ||
} | ||
} | ||
/** | ||
* Plug-in for DataTables which will reorder the internal column structure by taking the column | ||
* from one position (iFrom) and insert it into a given point (iTo). | ||
* @method $.fn.dataTableExt.oApi.fnColReorder | ||
* @param object oSettings DataTables settings object - automatically added by DataTables! | ||
* @param int iFrom Take the column to be repositioned from this point | ||
* @param int iTo and insert it into this point | ||
* @param bool drop Indicate if the reorder is the final one (i.e. a drop) | ||
* not a live reorder | ||
* @param bool invalidateRows speeds up processing if false passed | ||
* @returns void | ||
* Take an index array for the current positioned, reordered to what you want | ||
* them to be. | ||
* | ||
* @param dt DataTable being operated on - must be a single table instance | ||
* @param order Indexes from current order, positioned as you want them to be | ||
*/ | ||
$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows ) | ||
{ | ||
var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol; | ||
var attrMap = function ( obj, prop, mapping ) { | ||
if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) { | ||
return; | ||
} | ||
var a = obj[ prop ].split('.'); | ||
var num = a.shift(); | ||
if ( isNaN( num*1 ) ) { | ||
return; | ||
} | ||
obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.'); | ||
}; | ||
/* Sanity check in the input */ | ||
if ( iFrom == iTo ) | ||
{ | ||
/* Pointless reorder */ | ||
return; | ||
} | ||
if ( iFrom < 0 || iFrom >= iCols ) | ||
{ | ||
this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); | ||
return; | ||
} | ||
if ( iTo < 0 || iTo >= iCols ) | ||
{ | ||
this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); | ||
return; | ||
} | ||
/* | ||
* Calculate the new column array index, so we have a mapping between the old and new | ||
*/ | ||
var aiMapping = []; | ||
for ( i=0, iLen=iCols ; i<iLen ; i++ ) | ||
{ | ||
aiMapping[i] = i; | ||
} | ||
fnArraySwitch( aiMapping, iFrom, iTo ); | ||
var aiInvertMapping = fnInvertKeyValues( aiMapping ); | ||
/* | ||
* Convert all internal indexing to the new column order indexes | ||
*/ | ||
/* Sorting */ | ||
for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ ) | ||
{ | ||
oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ]; | ||
} | ||
/* Fixed sorting */ | ||
if ( oSettings.aaSortingFixed !== null ) | ||
{ | ||
for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ ) | ||
{ | ||
oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ]; | ||
} | ||
} | ||
/* Data column sorting (the column which the sort for a given column should take place on) */ | ||
for ( i=0, iLen=iCols ; i<iLen ; i++ ) | ||
{ | ||
oCol = oSettings.aoColumns[i]; | ||
for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ ) | ||
{ | ||
oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ]; | ||
} | ||
// Update the column indexes | ||
oCol.idx = aiInvertMapping[ oCol.idx ]; | ||
} | ||
// Update 1.10 optimised sort class removal variable | ||
$.each( oSettings.aLastSort, function (i, val) { | ||
oSettings.aLastSort[i].src = aiInvertMapping[ val.src ]; | ||
} ); | ||
/* Update the Get and Set functions for each column */ | ||
for ( i=0, iLen=iCols ; i<iLen ; i++ ) | ||
{ | ||
oCol = oSettings.aoColumns[i]; | ||
if ( typeof oCol.mData == 'number' ) { | ||
oCol.mData = aiInvertMapping[ oCol.mData ]; | ||
} | ||
else if ( $.isPlainObject( oCol.mData ) ) { | ||
// HTML5 data sourced | ||
attrMap( oCol.mData, '_', aiInvertMapping ); | ||
attrMap( oCol.mData, 'filter', aiInvertMapping ); | ||
attrMap( oCol.mData, 'sort', aiInvertMapping ); | ||
attrMap( oCol.mData, 'type', aiInvertMapping ); | ||
} | ||
} | ||
/* | ||
* Move the DOM elements | ||
*/ | ||
if ( oSettings.aoColumns[iFrom].bVisible ) | ||
{ | ||
/* Calculate the current visible index and the point to insert the node before. The insert | ||
* before needs to take into account that there might not be an element to insert before, | ||
* in which case it will be null, and an appendChild should be used | ||
*/ | ||
var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom ); | ||
var iInsertBeforeIndex = null; | ||
i = iTo < iFrom ? iTo : iTo + 1; | ||
while ( iInsertBeforeIndex === null && i < iCols ) | ||
{ | ||
iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i ); | ||
i++; | ||
} | ||
/* Header */ | ||
nTrs = oSettings.nTHead.getElementsByTagName('tr'); | ||
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | ||
{ | ||
fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex ); | ||
} | ||
/* Footer */ | ||
if ( oSettings.nTFoot !== null ) | ||
{ | ||
nTrs = oSettings.nTFoot.getElementsByTagName('tr'); | ||
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | ||
{ | ||
fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex ); | ||
} | ||
} | ||
/* Body */ | ||
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) | ||
{ | ||
if ( oSettings.aoData[i].nTr !== null ) | ||
{ | ||
fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex ); | ||
} | ||
} | ||
} | ||
/* | ||
* Move the internal array elements | ||
*/ | ||
/* Columns */ | ||
fnArraySwitch( oSettings.aoColumns, iFrom, iTo ); | ||
// regenerate the get / set functions | ||
for ( i=0, iLen=iCols ; i<iLen ; i++ ) { | ||
oSettings.oApi._fnColumnOptions( oSettings, i, {} ); | ||
} | ||
/* Search columns */ | ||
fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo ); | ||
/* Array array - internal data anodes cache */ | ||
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) | ||
{ | ||
var data = oSettings.aoData[i]; | ||
var cells = data.anCells; | ||
if ( cells ) { | ||
fnArraySwitch( cells, iFrom, iTo ); | ||
// Longer term, should this be moved into the DataTables' invalidate | ||
// methods? | ||
for ( j=0, jen=cells.length ; j<jen ; j++ ) { | ||
if ( cells[j] && cells[j]._DT_CellIndex ) { | ||
cells[j]._DT_CellIndex.column = j; | ||
} | ||
} | ||
} | ||
// Swap around array sourced data (object based is left as is) | ||
if ( Array.isArray( data._aData ) ) { | ||
fnArraySwitch( data._aData, iFrom, iTo ); | ||
} | ||
} | ||
/* Reposition the header elements in the header layout array */ | ||
for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ ) | ||
{ | ||
fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo ); | ||
} | ||
if ( oSettings.aoFooter !== null ) | ||
{ | ||
for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ ) | ||
{ | ||
fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo ); | ||
} | ||
} | ||
if ( invalidateRows || invalidateRows === undefined ) | ||
{ | ||
// Always read from the data object rather than reading back from the DOM | ||
// since it could have been changed by a renderer | ||
$.fn.dataTable.Api( oSettings ).rows().invalidate('data'); | ||
} | ||
/* | ||
* Update DataTables' event handlers | ||
*/ | ||
/* Sort listener */ | ||
for ( i=0, iLen=iCols ; i<iLen ; i++ ) | ||
{ | ||
$(oSettings.aoColumns[i].nTh).off('.DT'); | ||
this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); | ||
} | ||
/* Fire an event so other plug-ins can update */ | ||
$(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, { | ||
from: iFrom, | ||
to: iTo, | ||
mapping: aiInvertMapping, | ||
drop: drop, | ||
// Old style parameters for compatibility | ||
iFrom: iFrom, | ||
iTo: iTo, | ||
aiInvertMapping: aiInvertMapping | ||
} ] ); | ||
}; | ||
function setOrder(dt, order, original) { | ||
var changed = false; | ||
var i; | ||
if (order.length !== dt.columns().count()) { | ||
dt.error('ColReorder - column count mismatch'); | ||
return; | ||
} | ||
// The order given is based on the original indexes, rather than the | ||
// existing ones, so we need to translate from the original to current | ||
// before then doing the order | ||
if (original) { | ||
order = transpose(dt, order, 'toCurrent'); | ||
} | ||
// The API is array index as the desired position, but our algorithm below is | ||
// for array index as the current position. So we need to invert for it to work. | ||
var setOrder = invertKeyValues(order); | ||
// Move columns, one by one with validation disabled! | ||
for (i = 0; i < setOrder.length; i++) { | ||
var currentIndex = setOrder.indexOf(i); | ||
if (i !== currentIndex) { | ||
// Reorder our switching error | ||
arrayMove(setOrder, currentIndex, 1, i); | ||
// Do the reorder | ||
move(dt, [currentIndex], i); | ||
changed = true; | ||
} | ||
} | ||
// Reorder complete | ||
if (changed) { | ||
finalise(dt); | ||
} | ||
} | ||
/** | ||
* ColReorder provides column visibility control for DataTables | ||
* @class ColReorder | ||
* @constructor | ||
* @param {object} dt DataTables settings object | ||
* @param {object} opts ColReorder options | ||
* Convert the DataTables header structure array into a 2D array where each | ||
* element has a reference to its TH/TD cell (regardless of spanning). | ||
* | ||
* @param structure Header / footer structure object | ||
* @returns 2D array of header cells | ||
*/ | ||
var ColReorder = function( dt, opts ) | ||
{ | ||
var settings = new $.fn.dataTable.Api( dt ).settings()[0]; | ||
// Ensure that we can't initialise on the same table twice | ||
if ( settings._colReorder ) { | ||
return settings._colReorder; | ||
} | ||
// Allow the options to be a boolean for defaults | ||
if ( opts === true ) { | ||
opts = {}; | ||
} | ||
// Convert from camelCase to Hungarian, just as DataTables does | ||
var camelToHungarian = $.fn.dataTable.camelToHungarian; | ||
if ( camelToHungarian ) { | ||
camelToHungarian( ColReorder.defaults, ColReorder.defaults, true ); | ||
camelToHungarian( ColReorder.defaults, opts || {} ); | ||
} | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Public class variables | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
/** | ||
* @namespace Settings object which contains customisable information for ColReorder instance | ||
*/ | ||
this.s = { | ||
/** | ||
* DataTables settings object | ||
* @property dt | ||
* @type Object | ||
* @default null | ||
*/ | ||
"dt": null, | ||
/** | ||
* Enable flag | ||
* @property dt | ||
* @type Object | ||
* @default null | ||
*/ | ||
"enable": null, | ||
/** | ||
* Initialisation object used for this instance | ||
* @property init | ||
* @type object | ||
* @default {} | ||
*/ | ||
"init": $.extend( true, {}, ColReorder.defaults, opts ), | ||
/** | ||
* Number of columns to fix (not allow to be reordered) | ||
* @property fixed | ||
* @type int | ||
* @default 0 | ||
*/ | ||
"fixed": 0, | ||
/** | ||
* Number of columns to fix counting from right (not allow to be reordered) | ||
* @property fixedRight | ||
* @type int | ||
* @default 0 | ||
*/ | ||
"fixedRight": 0, | ||
/** | ||
* Callback function for once the reorder has been done | ||
* @property reorderCallback | ||
* @type function | ||
* @default null | ||
*/ | ||
"reorderCallback": null, | ||
/** | ||
* @namespace Information used for the mouse drag | ||
*/ | ||
"mouse": { | ||
"startX": -1, | ||
"startY": -1, | ||
"offsetX": -1, | ||
"offsetY": -1, | ||
"target": -1, | ||
"targetIndex": -1, | ||
"fromIndex": -1 | ||
}, | ||
/** | ||
* Information which is used for positioning the insert cusor and knowing where to do the | ||
* insert. Array of objects with the properties: | ||
* x: x-axis position | ||
* to: insert point | ||
* @property aoTargets | ||
* @type array | ||
* @default [] | ||
*/ | ||
"aoTargets": [] | ||
}; | ||
/** | ||
* @namespace Common and useful DOM elements for the class instance | ||
*/ | ||
this.dom = { | ||
/** | ||
* Dragging element (the one the mouse is moving) | ||
* @property drag | ||
* @type element | ||
* @default null | ||
*/ | ||
"drag": null, | ||
/** | ||
* The insert cursor | ||
* @property pointer | ||
* @type element | ||
* @default null | ||
*/ | ||
"pointer": null | ||
}; | ||
/* Constructor logic */ | ||
this.s.enable = this.s.init.bEnable; | ||
this.s.dt = settings; | ||
this.s.dt._colReorder = this; | ||
this._fnConstruct(); | ||
return this; | ||
}; | ||
$.extend( ColReorder.prototype, { | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Public methods | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
/** | ||
* Enable / disable end user interaction | ||
*/ | ||
fnEnable: function ( flag ) | ||
{ | ||
if ( flag === false ) { | ||
return this.fnDisable(); | ||
} | ||
this.s.enable = true; | ||
}, | ||
/** | ||
* Disable end user interaction | ||
*/ | ||
fnDisable: function () | ||
{ | ||
this.s.enable = false; | ||
}, | ||
/** | ||
* Reset the column ordering to the original ordering that was detected on | ||
* start up. | ||
* @return {this} Returns `this` for chaining. | ||
* | ||
* @example | ||
* // DataTables initialisation with ColReorder | ||
* var table = $('#example').dataTable( { | ||
* "sDom": 'Rlfrtip' | ||
* } ); | ||
* | ||
* // Add click event to a button to reset the ordering | ||
* $('#resetOrdering').click( function (e) { | ||
* e.preventDefault(); | ||
* $.fn.dataTable.ColReorder( table ).fnReset(); | ||
* } ); | ||
*/ | ||
"fnReset": function () | ||
{ | ||
this._fnOrderColumns( this.fnOrder() ); | ||
return this; | ||
}, | ||
/** | ||
* `Deprecated` - Get the current order of the columns, as an array. | ||
* @return {array} Array of column identifiers | ||
* @deprecated `fnOrder` should be used in preference to this method. | ||
* `fnOrder` acts as a getter/setter. | ||
*/ | ||
"fnGetCurrentOrder": function () | ||
{ | ||
return this.fnOrder(); | ||
}, | ||
/** | ||
* Get the current order of the columns, as an array. Note that the values | ||
* given in the array are unique identifiers for each column. Currently | ||
* these are the original ordering of the columns that was detected on | ||
* start up, but this could potentially change in future. | ||
* @return {array} Array of column identifiers | ||
* | ||
* @example | ||
* // Get column ordering for the table | ||
* var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder(); | ||
*//** | ||
* Set the order of the columns, from the positions identified in the | ||
* ordering array given. Note that ColReorder takes a brute force approach | ||
* to reordering, so it is possible multiple reordering events will occur | ||
* before the final order is settled upon. | ||
* @param {array} [set] Array of column identifiers in the new order. Note | ||
* that every column must be included, uniquely, in this array. | ||
* @return {this} Returns `this` for chaining. | ||
* | ||
* @example | ||
* // Swap the first and second columns | ||
* $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] ); | ||
* | ||
* @example | ||
* // Move the first column to the end for the table `#example` | ||
* var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder(); | ||
* var first = curr.shift(); | ||
* curr.push( first ); | ||
* $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr ); | ||
* | ||
* @example | ||
* // Reverse the table's order | ||
* $.fn.dataTable.ColReorder( '#example' ).fnOrder( | ||
* $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse() | ||
* ); | ||
*/ | ||
"fnOrder": function ( set, original ) | ||
{ | ||
var a = [], i, ien, j, jen; | ||
var columns = this.s.dt.aoColumns; | ||
if ( set === undefined ){ | ||
for ( i=0, ien=columns.length ; i<ien ; i++ ) { | ||
a.push( columns[i]._ColReorder_iOrigCol ); | ||
} | ||
return a; | ||
} | ||
// The order given is based on the original indexes, rather than the | ||
// existing ones, so we need to translate from the original to current | ||
// before then doing the order | ||
if ( original ) { | ||
var order = this.fnOrder(); | ||
for ( i=0, ien=set.length ; i<ien ; i++ ) { | ||
a.push( $.inArray( set[i], order ) ); | ||
} | ||
set = a; | ||
} | ||
this._fnOrderColumns( fnInvertKeyValues( set ) ); | ||
return this; | ||
}, | ||
/** | ||
* Convert from the original column index, to the original | ||
* | ||
* @param {int|array} idx Index(es) to convert | ||
* @param {string} dir Transpose direction - `fromOriginal` / `toCurrent` | ||
* or `'toOriginal` / `fromCurrent` | ||
* @return {int|array} Converted values | ||
*/ | ||
fnTranspose: function ( idx, dir ) | ||
{ | ||
if ( ! dir ) { | ||
dir = 'toCurrent'; | ||
} | ||
var order = this.fnOrder(); | ||
var columns = this.s.dt.aoColumns; | ||
if ( dir === 'toCurrent' ) { | ||
// Given an original index, want the current | ||
return ! Array.isArray( idx ) ? | ||
$.inArray( idx, order ) : | ||
$.map( idx, function ( index ) { | ||
return $.inArray( index, order ); | ||
} ); | ||
} | ||
else { | ||
// Given a current index, want the original | ||
return ! Array.isArray( idx ) ? | ||
columns[idx]._ColReorder_iOrigCol : | ||
$.map( idx, function ( index ) { | ||
return columns[index]._ColReorder_iOrigCol; | ||
} ); | ||
} | ||
}, | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Private methods (they are of course public in JS, but recommended as private) | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
/** | ||
* Constructor logic | ||
* @method _fnConstruct | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnConstruct": function () | ||
{ | ||
var that = this; | ||
var iLen = this.s.dt.aoColumns.length; | ||
var table = this.s.dt.nTable; | ||
var i; | ||
/* Columns discounted from reordering - counting left to right */ | ||
if ( this.s.init.iFixedColumns ) | ||
{ | ||
this.s.fixed = this.s.init.iFixedColumns; | ||
} | ||
if ( this.s.init.iFixedColumnsLeft ) | ||
{ | ||
this.s.fixed = this.s.init.iFixedColumnsLeft; | ||
} | ||
/* Columns discounted from reordering - counting right to left */ | ||
this.s.fixedRight = this.s.init.iFixedColumnsRight ? | ||
this.s.init.iFixedColumnsRight : | ||
0; | ||
/* Drop callback initialisation option */ | ||
if ( this.s.init.fnReorderCallback ) | ||
{ | ||
this.s.reorderCallback = this.s.init.fnReorderCallback; | ||
} | ||
/* Add event handlers for the drag and drop, and also mark the original column order */ | ||
for ( i = 0; i < iLen; i++ ) | ||
{ | ||
if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight ) | ||
{ | ||
this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh ); | ||
} | ||
/* Mark the original column order for later reference */ | ||
this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; | ||
} | ||
/* State saving */ | ||
this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { | ||
that._fnStateSave.call( that, oData ); | ||
}, "ColReorder_State" ); | ||
this.s.dt.oApi._fnCallbackReg(this.s.dt, 'aoStateLoadParams', function(oS, oData) { | ||
that.s.dt._colReorder.fnOrder(oData.ColReorder, true); | ||
}) | ||
/* An initial column order has been specified */ | ||
var aiOrder = null; | ||
if ( this.s.init.aiOrder ) | ||
{ | ||
aiOrder = this.s.init.aiOrder.slice(); | ||
} | ||
/* State loading, overrides the column order given */ | ||
if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && | ||
this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) | ||
{ | ||
aiOrder = this.s.dt.oLoadedState.ColReorder; | ||
} | ||
/* If we have an order to apply - do so */ | ||
if ( aiOrder ) | ||
{ | ||
/* We might be called during or after the DataTables initialisation. If before, then we need | ||
* to wait until the draw is done, if after, then do what we need to do right away | ||
*/ | ||
if ( !that.s.dt._bInitComplete ) | ||
{ | ||
var bDone = false; | ||
$(table).on( 'draw.dt.colReorder', function () { | ||
if ( !that.s.dt._bInitComplete && !bDone ) | ||
{ | ||
bDone = true; | ||
var resort = fnInvertKeyValues( aiOrder ); | ||
that._fnOrderColumns.call( that, resort ); | ||
} | ||
} ); | ||
} | ||
else | ||
{ | ||
var resort = fnInvertKeyValues( aiOrder ); | ||
that._fnOrderColumns.call( that, resort ); | ||
} | ||
} | ||
else { | ||
this._fnSetColumnIndexes(); | ||
} | ||
// Destroy clean up | ||
$(table).on( 'destroy.dt.colReorder', function () { | ||
// Restore table to original order from when it was loaded | ||
that.fnReset(); | ||
$(table).off( 'destroy.dt.colReorder draw.dt.colReorder' ); | ||
$.each( that.s.dt.aoColumns, function (i, column) { | ||
$(column.nTh).off('.ColReorder'); | ||
$(column.nTh).removeAttr('data-column-index'); | ||
} ); | ||
that.s.dt._colReorder = null; | ||
that.s = null; | ||
} ); | ||
}, | ||
/** | ||
* Set the column order from an array | ||
* @method _fnOrderColumns | ||
* @param array a An array of integers which dictate the column order that should be applied | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnOrderColumns": function ( a ) | ||
{ | ||
var changed = false; | ||
if ( a.length != this.s.dt.aoColumns.length ) | ||
{ | ||
this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+ | ||
"match known number of columns. Skipping." ); | ||
return; | ||
} | ||
for ( var i=0, iLen=a.length ; i<iLen ; i++ ) | ||
{ | ||
var currIndex = $.inArray( i, a ); | ||
if ( i != currIndex ) | ||
{ | ||
/* Reorder our switching array */ | ||
fnArraySwitch( a, currIndex, i ); | ||
/* Do the column reorder in the table */ | ||
this.s.dt.oInstance.fnColReorder( currIndex, i, true, false ); | ||
changed = true; | ||
} | ||
} | ||
this._fnSetColumnIndexes(); | ||
// Has anything actually changed? If not, then nothing else to do | ||
if ( ! changed ) { | ||
return; | ||
} | ||
$.fn.dataTable.Api( this.s.dt ).rows().invalidate('data'); | ||
/* When scrolling we need to recalculate the column sizes to allow for the shift */ | ||
if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) | ||
{ | ||
this.s.dt.oInstance.fnAdjustColumnSizing( false ); | ||
} | ||
/* Save the state */ | ||
this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); | ||
if ( this.s.reorderCallback !== null ) | ||
{ | ||
this.s.reorderCallback.call( this ); | ||
} | ||
}, | ||
/** | ||
* Because we change the indexes of columns in the table, relative to their starting point | ||
* we need to reorder the state columns to what they are at the starting point so we can | ||
* then rearrange them again on state load! | ||
* @method _fnStateSave | ||
* @param object oState DataTables state | ||
* @returns string JSON encoded cookie string for DataTables | ||
* @private | ||
*/ | ||
"_fnStateSave": function ( oState ) | ||
{ | ||
if(this.s === null) { | ||
return; | ||
} | ||
var i, iLen, aCopy, iOrigColumn; | ||
var oSettings = this.s.dt; | ||
var columns = oSettings.aoColumns; | ||
oState.ColReorder = []; | ||
/* Sorting */ | ||
if ( oState.aaSorting ) { | ||
// 1.10.0- | ||
for ( i=0 ; i<oState.aaSorting.length ; i++ ) { | ||
oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol; | ||
} | ||
var aSearchCopy = $.extend( true, [], oState.aoSearchCols ); | ||
for ( i=0, iLen=columns.length ; i<iLen ; i++ ) | ||
{ | ||
iOrigColumn = columns[i]._ColReorder_iOrigCol; | ||
/* Column filter */ | ||
oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i]; | ||
/* Visibility */ | ||
oState.abVisCols[ iOrigColumn ] = columns[i].bVisible; | ||
/* Column reordering */ | ||
oState.ColReorder.push( iOrigColumn ); | ||
} | ||
} | ||
else if ( oState.order ) { | ||
// 1.10.1+ | ||
for ( i=0 ; i<oState.order.length ; i++ ) { | ||
oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol; | ||
} | ||
var stateColumnsCopy = $.extend( true, [], oState.columns ); | ||
for ( i=0, iLen=columns.length ; i<iLen ; i++ ) | ||
{ | ||
iOrigColumn = columns[i]._ColReorder_iOrigCol; | ||
/* Columns */ | ||
oState.columns[ iOrigColumn ] = stateColumnsCopy[i]; | ||
/* Column reordering */ | ||
oState.ColReorder.push( iOrigColumn ); | ||
} | ||
} | ||
}, | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Mouse drop and drag | ||
*/ | ||
/** | ||
* Add a mouse down listener to a particluar TH element | ||
* @method _fnMouseListener | ||
* @param int i Column index | ||
* @param element nTh TH element clicked on | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnMouseListener": function ( i, nTh ) | ||
{ | ||
var that = this; | ||
$(nTh) | ||
.on( 'mousedown.ColReorder', function (e) { | ||
if ( that.s.enable && e.which === 1 ) { | ||
that._fnMouseDown.call( that, e, nTh ); | ||
} | ||
} ) | ||
.on( 'touchstart.ColReorder', function (e) { | ||
if ( that.s.enable ) { | ||
that._fnMouseDown.call( that, e, nTh ); | ||
} | ||
} ); | ||
}, | ||
/** | ||
* Mouse down on a TH element in the table header | ||
* @method _fnMouseDown | ||
* @param event e Mouse event | ||
* @param element nTh TH element to be dragged | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnMouseDown": function ( e, nTh ) | ||
{ | ||
var that = this; | ||
/* Store information about the mouse position */ | ||
var target = $(e.target).closest('th, td'); | ||
var offset = target.offset(); | ||
var idx = parseInt( $(nTh).attr('data-column-index'), 10 ); | ||
if ( idx === undefined ) { | ||
return; | ||
} | ||
this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' ); | ||
this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' ); | ||
this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left; | ||
this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top; | ||
this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0]; | ||
this.s.mouse.targetIndex = idx; | ||
this.s.mouse.fromIndex = idx; | ||
this._fnRegions(); | ||
/* Add event handlers to the document */ | ||
$(document) | ||
.on( 'mousemove.ColReorder touchmove.ColReorder', function (e) { | ||
that._fnMouseMove.call( that, e ); | ||
} ) | ||
.on( 'mouseup.ColReorder touchend.ColReorder', function (e) { | ||
that._fnMouseUp.call( that, e ); | ||
} ); | ||
}, | ||
/** | ||
* Deal with a mouse move event while dragging a node | ||
* @method _fnMouseMove | ||
* @param event e Mouse event | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnMouseMove": function ( e ) | ||
{ | ||
var that = this; | ||
if ( this.dom.drag === null ) | ||
{ | ||
/* Only create the drag element if the mouse has moved a specific distance from the start | ||
* point - this allows the user to make small mouse movements when sorting and not have a | ||
* possibly confusing drag element showing up | ||
*/ | ||
if ( Math.pow( | ||
Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) + | ||
Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 ) | ||
{ | ||
return; | ||
} | ||
this._fnCreateDragNode(); | ||
} | ||
/* Position the element - we respect where in the element the click occured */ | ||
this.dom.drag.css( { | ||
left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX, | ||
top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY | ||
} ); | ||
/* Based on the current mouse position, calculate where the insert should go */ | ||
var target; | ||
var lastToIndex = this.s.mouse.toIndex; | ||
var cursorXPosiotion = this._fnCursorPosition(e, 'pageX'); | ||
var targetsPrev = function (i) { | ||
while (i >= 0) { | ||
i--; | ||
if (i <= 0) { | ||
return null; | ||
} | ||
if (that.s.aoTargets[i+1].x !== that.s.aoTargets[i].x) { | ||
return that.s.aoTargets[i]; | ||
} | ||
} | ||
}; | ||
var firstNotHidden = function () { | ||
for (var i=0 ; i<that.s.aoTargets.length-1 ; i++) { | ||
if (that.s.aoTargets[i].x !== that.s.aoTargets[i+1].x) { | ||
return that.s.aoTargets[i]; | ||
} | ||
} | ||
}; | ||
var lastNotHidden = function () { | ||
for (var i=that.s.aoTargets.length-1 ; i>0 ; i--) { | ||
if (that.s.aoTargets[i].x !== that.s.aoTargets[i-1].x) { | ||
return that.s.aoTargets[i]; | ||
} | ||
} | ||
}; | ||
for (var i = 1; i < this.s.aoTargets.length; i++) { | ||
var prevTarget = targetsPrev(i); | ||
if (! prevTarget) { | ||
prevTarget = firstNotHidden(); | ||
} | ||
var prevTargetMiddle = prevTarget.x + (this.s.aoTargets[i].x - prevTarget.x) / 2; | ||
if (this._fnIsLtr()) { | ||
if (cursorXPosiotion < prevTargetMiddle ) { | ||
target = prevTarget; | ||
break; | ||
function structureFill(structure) { | ||
var filledIn = []; | ||
for (var row = 0; row < structure.length; row++) { | ||
filledIn.push([]); | ||
for (var col = 0; col < structure[row].length; col++) { | ||
var cell = structure[row][col]; | ||
if (cell) { | ||
for (var rowInner = 0; rowInner < cell.rowspan; rowInner++) { | ||
for (var colInner = 0; colInner < cell.colspan; colInner++) { | ||
filledIn[row + rowInner][col + colInner] = cell.cell; | ||
} | ||
} | ||
} | ||
else { | ||
if (cursorXPosiotion > prevTargetMiddle) { | ||
target = prevTarget; | ||
break; | ||
} | ||
} | ||
} | ||
return filledIn; | ||
} | ||
/** | ||
* Convert the index type | ||
* | ||
* @param dt DataTable to work on | ||
* @param idx Index to transform | ||
* @param dir Transform direction | ||
* @returns Converted number(s) | ||
*/ | ||
function transpose(dt, idx, dir) { | ||
var order = dt.colReorder.order(); | ||
var columns = dt.settings()[0].aoColumns; | ||
if (dir === 'toCurrent' || dir === 'fromOriginal') { | ||
// Given an original index, want the current | ||
return !Array.isArray(idx) | ||
? order.indexOf(idx) | ||
: idx.map(function (index) { | ||
return order.indexOf(index); | ||
}); | ||
} | ||
// Given a current index, want the original | ||
return !Array.isArray(idx) | ||
? columns[idx]._crOriginalIdx | ||
: idx.map(function (index) { | ||
return columns[index]._crOriginalIdx; | ||
}); | ||
} | ||
/** | ||
* Validate that a requested move is okay. This includes bound checking | ||
* and that it won't split colspan'ed cells. | ||
* | ||
* @param table API instance | ||
* @param from Column indexes to move | ||
* @param to Destination index (starting if multiple) | ||
* @returns Validation result | ||
*/ | ||
function validateMove(table, from, to) { | ||
var columns = table.columns().count(); | ||
// Sanity and bound checking | ||
if (from[0] < to && to < from[from.length]) { | ||
return false; | ||
} | ||
if (from[0] < 0 && from[from.length - 1] > columns) { | ||
return false; | ||
} | ||
if (to < 0 && to > columns) { | ||
return false; | ||
} | ||
// No change - it's valid | ||
if (from.includes(to)) { | ||
return true; | ||
} | ||
if (!validateStructureMove(table.table().header.structure(), from, to)) { | ||
return false; | ||
} | ||
if (!validateStructureMove(table.table().footer.structure(), from, to)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
/** | ||
* For a given structure check that the move is valid. | ||
* @param structure | ||
* @param from | ||
* @param to | ||
* @returns | ||
*/ | ||
function validateStructureMove(structure, from, to) { | ||
var header = structureFill(structure); | ||
var i; | ||
// Shuffle the header cells around | ||
for (i = 0; i < header.length; i++) { | ||
arrayMove(header[i], from[0], from.length, to); | ||
} | ||
// Sanity check that the headers are next to each other | ||
for (i = 0; i < header.length; i++) { | ||
var seen = []; | ||
for (var j = 0; j < header[i].length; j++) { | ||
var cell = header[i][j]; | ||
if (!seen.includes(cell)) { | ||
// Hasn't been seen before | ||
seen.push(cell); | ||
} | ||
} | ||
else if (seen[seen.length - 1] !== cell) { | ||
// Has been seen before and is not the previous cell - validation failed | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
if (target) { | ||
this.dom.pointer.css('left', target.x); | ||
this.s.mouse.toIndex = target.to; | ||
/** | ||
* This is one possible UI for column reordering in DataTables. In this case | ||
* columns are reordered by clicking and dragging a column header. It calculates | ||
* where columns can be dropped based on the column header used to start the drag | ||
* and then `colReorder.move()` method to alter the DataTable. | ||
*/ | ||
var ColReorder = /** @class */ (function () { | ||
function ColReorder(dt, opts) { | ||
this.dom = { | ||
drag: null | ||
}; | ||
this.c = { | ||
columns: null, | ||
enable: null, | ||
order: null | ||
}; | ||
this.s = { | ||
dropZones: [], | ||
mouse: { | ||
absLeft: -1, | ||
offset: { | ||
x: -1, | ||
y: -1 | ||
}, | ||
start: { | ||
x: -1, | ||
y: -1 | ||
}, | ||
target: null, | ||
targets: [] | ||
}, | ||
scrollInterval: null | ||
}; | ||
var that = this; | ||
var ctx = dt.settings()[0]; | ||
// Check if ColReorder already has been initialised on this DataTable - only | ||
// one can exist. | ||
if (ctx._colReorder) { | ||
return; | ||
} | ||
else { | ||
// The insert element wasn't positioned in the array (less than | ||
// operator), so we put it at the end | ||
this.dom.pointer.css( 'left', lastNotHidden().x ); | ||
this.s.mouse.toIndex = lastNotHidden().to; | ||
} | ||
// Perform reordering if realtime updating is on and the column has moved | ||
if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) { | ||
this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex ); | ||
this.s.mouse.fromIndex = this.s.mouse.toIndex; | ||
// Not great for performance, but required to keep everything in alignment | ||
if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) | ||
{ | ||
this.s.dt.oInstance.fnAdjustColumnSizing( false ); | ||
} | ||
this._fnRegions(); | ||
} | ||
}, | ||
/** | ||
* Finish off the mouse drag and insert the column where needed | ||
* @method _fnMouseUp | ||
* @param event e Mouse event | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnMouseUp": function ( e ) | ||
{ | ||
var that = this; | ||
$(document).off( '.ColReorder' ); | ||
if ( this.dom.drag !== null ) | ||
{ | ||
/* Remove the guide elements */ | ||
this.dom.drag.remove(); | ||
this.dom.pointer.remove(); | ||
this.dom.drag = null; | ||
this.dom.pointer = null; | ||
/* Actually do the reorder */ | ||
this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true ); | ||
this._fnSetColumnIndexes(); | ||
/* When scrolling we need to recalculate the column sizes to allow for the shift */ | ||
if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) | ||
{ | ||
this.s.dt.oInstance.fnAdjustColumnSizing( false ); | ||
} | ||
/* Save the state */ | ||
this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); | ||
if ( this.s.reorderCallback !== null ) | ||
{ | ||
this.s.reorderCallback.call( this ); | ||
} | ||
} | ||
}, | ||
/** | ||
* Calculate a cached array with the points of the column inserts, and the | ||
* 'to' points | ||
* @method _fnRegions | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnRegions": function () | ||
{ | ||
var aoColumns = this.s.dt.aoColumns; | ||
var isLTR = this._fnIsLtr(); | ||
this.s.aoTargets.splice(0, this.s.aoTargets.length); | ||
var lastBound = $(this.s.dt.nTable).offset().left; | ||
var aoColumnBounds = []; | ||
$.each(aoColumns, function (i, column) { | ||
if (column.bVisible && column.nTh.style.display !== 'none') { | ||
var nth = $(column.nTh); | ||
var bound = nth.offset().left; | ||
if (isLTR) { | ||
bound += nth.outerWidth(); | ||
dt.settings()[0]._colReorder = this; | ||
this.dt = dt; | ||
$.extend(this.c, ColReorder.defaults, opts); | ||
init(dt); | ||
dt.on('stateSaveParams', function (e, s, d) { | ||
d.colReorder = getOrder(dt); | ||
}); | ||
dt.on('destroy', function () { | ||
dt.off('.colReorder'); | ||
dt.colReorder.reset(); | ||
}); | ||
// Initial ordering / state restoring | ||
var loaded = dt.state.loaded(); | ||
var order = this.c.order; | ||
if (loaded && loaded.colReorder) { | ||
order = loaded.colReorder; | ||
} | ||
if (order) { | ||
dt.ready(function () { | ||
setOrder(dt, order, true); | ||
}); | ||
} | ||
dt.table() | ||
.header.structure() | ||
.forEach(function (row) { | ||
for (var i = 0; i < row.length; i++) { | ||
if (row[i] && row[i].cell) { | ||
that._addListener(row[i].cell); | ||
} | ||
aoColumnBounds.push({ | ||
index: i, | ||
bound: bound | ||
}); | ||
lastBound = bound; | ||
} | ||
else { | ||
aoColumnBounds.push({ | ||
index: i, | ||
bound: lastBound | ||
} | ||
}); | ||
} | ||
ColReorder.prototype.disable = function () { | ||
this.c.enable = false; | ||
return this; | ||
}; | ||
ColReorder.prototype.enable = function (flag) { | ||
if (flag === void 0) { flag = true; } | ||
if (flag === false) { | ||
return this.disable(); | ||
} | ||
this.c.enable = true; | ||
return this; | ||
}; | ||
/** | ||
* Attach the mouse down listener to an element to start a column reorder action | ||
* | ||
* @param el | ||
*/ | ||
ColReorder.prototype._addListener = function (el) { | ||
var that = this; | ||
$(el) | ||
.on('selectstart.colReorder', function () { | ||
return false; | ||
}) | ||
.on('mousedown.colReorder touchstart.colReorder', function (e) { | ||
// Ignore middle and right click | ||
if (e.type === 'mousedown' && e.which !== 1) { | ||
return; | ||
} | ||
// Ignore if disabled | ||
if (!that.c.enable) { | ||
return; | ||
} | ||
that._mouseDown(e, this); | ||
}); | ||
}; | ||
/** | ||
* Create the element that is dragged around the page | ||
*/ | ||
ColReorder.prototype._createDragNode = function () { | ||
var origCell = this.s.mouse.target; | ||
var origTr = origCell.parent(); | ||
var origThead = origTr.parent(); | ||
var origTable = origThead.parent(); | ||
var cloneCell = origCell.clone(); | ||
// This is a slightly odd combination of jQuery and DOM, but it is the | ||
// fastest and least resource intensive way I could think of cloning | ||
// the table with just a single header cell in it. | ||
this.dom.drag = $(origTable[0].cloneNode(false)) | ||
.addClass('dtcr-cloned') | ||
.append($(origThead[0].cloneNode(false)).append($(origTr[0].cloneNode(false)).append(cloneCell[0])) // Not sure why it doesn't want to append a jQuery node | ||
) | ||
.css({ | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
width: $(origCell).outerWidth(), | ||
height: $(origCell).outerHeight() | ||
}) | ||
.appendTo('body'); | ||
}; | ||
/** | ||
* Get cursor position regardless of mouse or touch input | ||
* | ||
* @param e Event | ||
* @param prop Property name to get | ||
* @returns Value - assuming a number here | ||
*/ | ||
ColReorder.prototype._cursorPosition = function (e, prop) { | ||
return e.type.indexOf('touch') !== -1 ? e.originalEvent.touches[0][prop] : e[prop]; | ||
}; | ||
/** | ||
* Cache values at start | ||
* | ||
* @param e Triggering event | ||
* @param cell Cell that the action started on | ||
* @returns | ||
*/ | ||
ColReorder.prototype._mouseDown = function (e, cell) { | ||
var _this = this; | ||
var target = $(e.target).closest('th, td'); | ||
var offset = target.offset(); | ||
var moveableColumns = this.dt.columns(this.c.columns).indexes().toArray(); | ||
var moveColumnIndexes = $(cell) | ||
.attr('data-dt-column') | ||
.split(',') | ||
.map(function (val) { | ||
return parseInt(val, 10); | ||
}); | ||
// Don't do anything for columns which are not selected as moveable | ||
for (var j = 0; j < moveColumnIndexes.length; j++) { | ||
if (!moveableColumns.includes(moveColumnIndexes[j])) { | ||
return false; | ||
} | ||
} | ||
this.s.mouse.start.x = this._cursorPosition(e, 'pageX'); | ||
this.s.mouse.start.y = this._cursorPosition(e, 'pageY'); | ||
this.s.mouse.offset.x = this._cursorPosition(e, 'pageX') - offset.left; | ||
this.s.mouse.offset.y = this._cursorPosition(e, 'pageY') - offset.top; | ||
this.s.mouse.target = target; | ||
this.s.mouse.targets = moveColumnIndexes; | ||
// Classes to highlight the columns being moved | ||
for (var i = 0; i < moveColumnIndexes.length; i++) { | ||
var cells = this.dt | ||
.cells(null, moveColumnIndexes[i], { page: 'current' }) | ||
.nodes() | ||
.to$(); | ||
var klass = 'dtcr-moving'; | ||
if (i === 0) { | ||
klass += ' dtcr-moving-first'; | ||
} | ||
if (i === moveColumnIndexes.length - 1) { | ||
klass += ' dtcr-moving-last'; | ||
} | ||
cells.addClass(klass); | ||
} | ||
this._regions(moveColumnIndexes); | ||
this._scrollRegions(); | ||
/* Add event handlers to the document */ | ||
$(document) | ||
.on('mousemove.colReorder touchmove.colReorder', function (e) { | ||
_this._mouseMove(e); | ||
}) | ||
.on('mouseup.colReorder touchend.colReorder', function (e) { | ||
_this._mouseUp(e); | ||
}); | ||
}; | ||
ColReorder.prototype._mouseMove = function (e) { | ||
if (this.dom.drag === null) { | ||
// Only create the drag element if the mouse has moved a specific distance from the start | ||
// point - this allows the user to make small mouse movements when sorting and not have a | ||
// possibly confusing drag element showing up | ||
if (Math.pow(Math.pow(this._cursorPosition(e, 'pageX') - this.s.mouse.start.x, 2) + | ||
Math.pow(this._cursorPosition(e, 'pageY') - this.s.mouse.start.y, 2), 0.5) < 5) { | ||
return; | ||
} | ||
$(document.body).addClass('dtcr-dragging'); | ||
this._createDragNode(); | ||
} | ||
// Position the element - we respect where in the element the click occurred | ||
this.dom.drag.css({ | ||
left: this._cursorPosition(e, 'pageX') - this.s.mouse.offset.x, | ||
top: this._cursorPosition(e, 'pageY') - this.s.mouse.offset.y | ||
}); | ||
// Find cursor's left position relative to the table | ||
var tableOffset = $(this.dt.table().node()).offset().left; | ||
var cursorMouseLeft = this._cursorPosition(e, 'pageX') - tableOffset; | ||
var dropZone = this.s.dropZones.find(function (zone) { | ||
if (zone.left <= cursorMouseLeft && cursorMouseLeft <= zone.left + zone.width) { | ||
return true; | ||
} | ||
return false; | ||
}); | ||
this.s.mouse.absLeft = this._cursorPosition(e, 'pageX'); | ||
if (!dropZone) { | ||
return; | ||
} | ||
if (!dropZone.self) { | ||
this._move(dropZone, cursorMouseLeft); | ||
} | ||
}; | ||
ColReorder.prototype._mouseUp = function (e) { | ||
$(document).off('.colReorder'); | ||
$(document.body).removeClass('dtcr-dragging'); | ||
if (this.dom.drag) { | ||
this.dom.drag.remove(); | ||
this.dom.drag = null; | ||
} | ||
if (this.s.scrollInterval) { | ||
clearInterval(this.s.scrollInterval); | ||
} | ||
this.dt.cells('.dtcr-moving').nodes().to$().removeClass('dtcr-moving dtcr-moving-first dtcr-moving-last'); | ||
}; | ||
/** | ||
* Shift columns around | ||
* | ||
* @param dropZone Where to move to | ||
* @param cursorMouseLeft Cursor position, relative to the left of the table | ||
*/ | ||
ColReorder.prototype._move = function (dropZone, cursorMouseLeft) { | ||
var that = this; | ||
this.dt.colReorder.move(this.s.mouse.targets, dropZone.colIdx); | ||
// Update the targets | ||
this.s.mouse.targets = $(this.s.mouse.target) | ||
.attr('data-dt-column') | ||
.split(',') | ||
.map(function (val) { | ||
return parseInt(val, 10); | ||
}); | ||
this._regions(this.s.mouse.targets); | ||
// If the column being moved is smaller than the column it is replacing, | ||
// the drop zones might need a correction to allow for this since, otherwise | ||
// we might immediately be changing the column order as soon as it was placed. | ||
// Find the drop zone for the first in the list of targets - is its | ||
// left greater than the mouse position. If so, it needs correcting | ||
var dz = this.s.dropZones.find(function (zone) { | ||
return zone.colIdx === that.s.mouse.targets[0]; | ||
}); | ||
var dzIdx = this.s.dropZones.indexOf(dz); | ||
if (dz.left > cursorMouseLeft) { | ||
var previousDiff = dz.left - cursorMouseLeft; | ||
var previousDz = this.s.dropZones[dzIdx - 1]; | ||
dz.left -= previousDiff; | ||
dz.width += previousDiff; | ||
if (previousDz) { | ||
previousDz.width -= previousDiff; | ||
} | ||
} | ||
// And for the last in the list | ||
dz = this.s.dropZones.find(function (zone) { | ||
return zone.colIdx === that.s.mouse.targets[that.s.mouse.targets.length - 1]; | ||
}); | ||
if (dz.left + dz.width < cursorMouseLeft) { | ||
var nextDiff = cursorMouseLeft - (dz.left + dz.width); | ||
var nextDz = this.s.dropZones[dzIdx + 1]; | ||
dz.width += nextDiff; | ||
if (nextDz) { | ||
nextDz.left += nextDiff; | ||
nextDz.width -= nextDiff; | ||
} | ||
} | ||
}; | ||
/** | ||
* Determine the boundaries for where drops can happen and where they would | ||
* insert into. | ||
*/ | ||
ColReorder.prototype._regions = function (moveColumns) { | ||
var that = this; | ||
var dropZones = []; | ||
var totalWidth = 0; | ||
var negativeCorrect = 0; | ||
var allowedColumns = this.dt.columns(this.c.columns).indexes().toArray(); | ||
var widths = this.dt.columns().widths(); | ||
// Each column is a drop zone | ||
this.dt.columns().every(function (colIdx, tabIdx, i) { | ||
if (!this.visible()) { | ||
return; | ||
} | ||
var columnWidth = widths[colIdx]; | ||
// Check that we are allowed to move into this column - if not, need | ||
// to offset the widths | ||
if (!allowedColumns.includes(colIdx)) { | ||
totalWidth += columnWidth; | ||
return; | ||
} | ||
var valid = validateMove(that.dt, moveColumns, colIdx); | ||
if (valid) { | ||
// New drop zone. Note that it might have it's offset moved | ||
// by the final condition in this logic set | ||
dropZones.push({ | ||
colIdx: colIdx, | ||
left: totalWidth - negativeCorrect, | ||
self: moveColumns[0] <= colIdx && colIdx <= moveColumns[moveColumns.length - 1], | ||
width: columnWidth + negativeCorrect | ||
}); | ||
} | ||
}); | ||
var firstColumn = aoColumnBounds[0]; | ||
var firstColumnWidth = $(aoColumns[firstColumn.index].nTh).outerWidth(); | ||
this.s.aoTargets.push({ | ||
to: 0, | ||
x: firstColumn.bound - firstColumnWidth | ||
} | ||
else if (colIdx < moveColumns[0]) { | ||
// Not valid and before the column(s) to be moved - the drop | ||
// zone for the previous valid drop point is extended | ||
if (dropZones.length) { | ||
dropZones[dropZones.length - 1].width += columnWidth; | ||
} | ||
} | ||
else if (colIdx > moveColumns[moveColumns.length - 1]) { | ||
// Not valid and after the column(s) to be moved - the next | ||
// drop zone to be created will be extended | ||
negativeCorrect += columnWidth; | ||
} | ||
totalWidth += columnWidth; | ||
}); | ||
for (var i = 0; i < aoColumnBounds.length; i++) { | ||
var columnBound = aoColumnBounds[i]; | ||
var iToPoint = columnBound.index; | ||
/* For the column / header in question, we want it's position to remain the same if the | ||
* position is just to it's immediate left or right, so we only increment the counter for | ||
* other columns | ||
*/ | ||
if (columnBound.index < this.s.mouse.fromIndex) { | ||
iToPoint++; | ||
this.s.dropZones = dropZones; | ||
// this._drawDropZones(); | ||
}; | ||
/** | ||
* Check if the table is scrolling or not. It is it the `table` isn't the same for | ||
* the header and body parents. | ||
* | ||
* @returns | ||
*/ | ||
ColReorder.prototype._isScrolling = function () { | ||
return this.dt.table().body().parentNode !== this.dt.table().header().parentNode; | ||
}; | ||
/** | ||
* Set an interval clock that will check to see if the scrolling of the table body should be moved | ||
* as the mouse moves on the scroll (allowing a drag and drop to columns which aren't yet visible) | ||
*/ | ||
ColReorder.prototype._scrollRegions = function () { | ||
if (!this._isScrolling()) { | ||
// Not scrolling - nothing to do | ||
return; | ||
} | ||
var that = this; | ||
var tableLeft = $(this.dt.table().container()).position().left; | ||
var tableWidth = $(this.dt.table().container()).outerWidth(); | ||
var mouseBuffer = 75; | ||
var scrollContainer = this.dt.table().body().parentElement.parentElement; | ||
this.s.scrollInterval = setInterval(function () { | ||
var mouseLeft = that.s.mouse.absLeft; | ||
if (mouseLeft < tableLeft + mouseBuffer && scrollContainer.scrollLeft) { | ||
scrollContainer.scrollLeft -= 5; | ||
} | ||
else if (mouseLeft > tableLeft + tableWidth - mouseBuffer && | ||
scrollContainer.scrollLeft < scrollContainer.scrollWidth) { | ||
scrollContainer.scrollLeft += 5; | ||
} | ||
}, 25); | ||
}; | ||
// This is handy for debugging where the drop zones actually are! | ||
// private _drawDropZones () { | ||
// let dropZones = this.s.dropZones; | ||
// $('div.allan').remove(); | ||
// for (let i=0 ; i<dropZones.length ; i++) { | ||
// let zone = dropZones[i]; | ||
// $(this.dt.table().container()).append( | ||
// $('<div>') | ||
// .addClass('allan') | ||
// .css({ | ||
// position: 'absolute', | ||
// top: 0, | ||
// width: zone.width - 4, | ||
// height: 20, | ||
// left: zone.left + 2, | ||
// border: '1px solid red', | ||
// }) | ||
// ); | ||
// } | ||
// } | ||
ColReorder.defaults = { | ||
columns: '', | ||
enable: true, | ||
order: null | ||
}; | ||
ColReorder.version = '2.0.0-dev'; | ||
return ColReorder; | ||
}()); | ||
this.s.aoTargets.push({ | ||
to: iToPoint, | ||
x: columnBound.bound | ||
}); | ||
} | ||
/* Disallow columns for being reordered by drag and drop, counting right to left */ | ||
if ( this.s.fixedRight !== 0 ) | ||
{ | ||
this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight ); | ||
} | ||
/* Disallow columns for being reordered by drag and drop, counting left to right */ | ||
if ( this.s.fixed !== 0 ) | ||
{ | ||
this.s.aoTargets.splice( 0, this.s.fixed ); | ||
} | ||
}, | ||
/** | ||
* Copy the TH element that is being drags so the user has the idea that they are actually | ||
* moving it around the page. | ||
* @method _fnCreateDragNode | ||
* @returns void | ||
* @private | ||
*/ | ||
"_fnCreateDragNode": function () | ||
{ | ||
var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== ""; | ||
var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh; | ||
var origTr = origCell.parentNode; | ||
var origThead = origTr.parentNode; | ||
var origTable = origThead.parentNode; | ||
var cloneCell = $(origCell).clone(); | ||
// This is a slightly odd combination of jQuery and DOM, but it is the | ||
// fastest and least resource intensive way I could think of cloning | ||
// the table with just a single header cell in it. | ||
this.dom.drag = $(origTable.cloneNode(false)) | ||
.addClass( 'DTCR_clonedTable' ) | ||
.append( | ||
$(origThead.cloneNode(false)).append( | ||
$(origTr.cloneNode(false)).append( | ||
cloneCell[0] | ||
) | ||
) | ||
) | ||
.css( { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
width: $(origCell).outerWidth(), | ||
height: $(origCell).outerHeight() | ||
} ) | ||
.appendTo( 'body' ); | ||
this.dom.pointer = $('<div></div>') | ||
.addClass( 'DTCR_pointer' ) | ||
.css( { | ||
position: 'absolute', | ||
top: scrolling ? | ||
$($(this.s.dt.nScrollBody).parent()).offset().top : | ||
$(this.s.dt.nTable).offset().top, | ||
height : scrolling ? | ||
$($(this.s.dt.nScrollBody).parent()).height() : | ||
$(this.s.dt.nTable).height() | ||
} ) | ||
.appendTo( 'body' ); | ||
}, | ||
/** | ||
* Add a data attribute to the column headers, so we know the index of | ||
* the row to be reordered. This allows fast detection of the index, and | ||
* for this plug-in to work with FixedHeader which clones the nodes. | ||
* @private | ||
*/ | ||
"_fnSetColumnIndexes": function () | ||
{ | ||
$.each( this.s.dt.aoColumns, function (i, column) { | ||
$(column.nTh).attr('data-column-index', i); | ||
} ); | ||
}, | ||
/** | ||
* Get cursor position regardless of mouse or touch input | ||
* @param {Event} e jQuery Event | ||
* @param {string} prop Property to get | ||
* @return {number} Value | ||
*/ | ||
_fnCursorPosition: function ( e, prop ) { | ||
if ( e.type.indexOf('touch') !== -1 ) { | ||
return e.originalEvent.touches[0][ prop ]; | ||
} | ||
return e[ prop ]; | ||
}, | ||
_fnIsLtr: function () { | ||
return $(this.s.dt.nTable).css('direction') !== "rtl"; | ||
} | ||
} ); | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Static parameters | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
/*! ColReorder 2.0.0-dev | ||
* © SpryMedia Ltd - datatables.net/license | ||
*/ | ||
/** | ||
* ColReorder default settings for initialisation | ||
* @namespace | ||
* @static | ||
* @summary ColReorder | ||
* @description Provide the ability to reorder columns in a DataTable | ||
* @version 2.0.0-dev | ||
* @author SpryMedia Ltd | ||
* @contact datatables.net | ||
* @copyright SpryMedia Ltd. | ||
* | ||
* This source file is free software, available under the following license: | ||
* MIT license - http://datatables.net/license/mit | ||
* | ||
* This source file is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. | ||
* | ||
* For details please refer to: http://www.datatables.net | ||
*/ | ||
ColReorder.defaults = { | ||
/** | ||
* Predefined ordering for the columns that will be applied automatically | ||
* on initialisation. If not specified then the order that the columns are | ||
* found to be in the HTML is the order used. | ||
* @type array | ||
* @default null | ||
* @static | ||
*/ | ||
aiOrder: null, | ||
/** | ||
* ColReorder enable on initialisation | ||
* @type boolean | ||
* @default true | ||
* @static | ||
*/ | ||
bEnable: true, | ||
/** | ||
* Redraw the table's column ordering as the end user draws the column | ||
* (`true`) or wait until the mouse is released (`false` - default). Note | ||
* that this will perform a redraw on each reordering, which involves an | ||
* Ajax request each time if you are using server-side processing in | ||
* DataTables. | ||
* @type boolean | ||
* @default false | ||
* @static | ||
*/ | ||
bRealtime: true, | ||
/** | ||
* Indicate how many columns should be fixed in position (counting from the | ||
* left). This will typically be 1 if used, but can be as high as you like. | ||
* @type int | ||
* @default 0 | ||
* @static | ||
*/ | ||
iFixedColumnsLeft: 0, | ||
/** | ||
* As `iFixedColumnsRight` but counting from the right. | ||
* @type int | ||
* @default 0 | ||
* @static | ||
*/ | ||
iFixedColumnsRight: 0, | ||
/** | ||
* Callback function that is fired when columns are reordered. The `column- | ||
* reorder` event is preferred over this callback | ||
* @type function():void | ||
* @default null | ||
* @static | ||
*/ | ||
fnReorderCallback: null | ||
}; | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* Constants | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
// declare var DataTable: any; | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* UI interaction class | ||
*/ | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* DataTables API integration | ||
*/ | ||
/** Enable mouse column reordering */ | ||
DataTable.Api.register('colReorder.enable()', function (flag) { | ||
return this.iterator('table', function (ctx) { | ||
if (ctx._colReorder) { | ||
ctx._colReorder.enable(flag); | ||
} | ||
}); | ||
}); | ||
/** Disable mouse column reordering */ | ||
DataTable.Api.register('colReorder.disable()', function () { | ||
return this.iterator('table', function (ctx) { | ||
if (ctx._colReorder) { | ||
ctx._colReorder.disable(); | ||
} | ||
}); | ||
}); | ||
/** | ||
* ColReorder version | ||
* @constant version | ||
* @type String | ||
* @default As code | ||
* Change the ordering of the columns in the DataTable. | ||
*/ | ||
ColReorder.version = "1.7.0"; | ||
DataTable.Api.register('colReorder.move()', function (from, to) { | ||
init(this); | ||
if (!Array.isArray(from)) { | ||
from = [from]; | ||
} | ||
if (!validateMove(this, from, to)) { | ||
this.error('ColReorder - invalid move'); | ||
return this; | ||
} | ||
return this.tables().every(function () { | ||
move(this, from, to); | ||
finalise(this); | ||
}); | ||
}); | ||
DataTable.Api.register('colReorder.order()', function (set, original) { | ||
init(this); | ||
if (!set) { | ||
return this.context.length ? getOrder(this) : null; | ||
} | ||
return this.tables().every(function () { | ||
setOrder(this, set, original); | ||
}); | ||
}); | ||
DataTable.Api.register('colReorder.reset()', function () { | ||
init(this); | ||
return this.tables().every(function () { | ||
var order = this.columns() | ||
.every(function (i) { | ||
return i; | ||
}) | ||
.flatten() | ||
.toArray(); | ||
setOrder(this, order, true); | ||
}); | ||
}); | ||
DataTable.Api.register('colReorder.transpose()', function (idx, dir) { | ||
init(this); | ||
if (!dir) { | ||
dir = 'toCurrent'; | ||
} | ||
return transpose(this, idx, dir); | ||
}); | ||
DataTable.ColReorder = ColReorder; | ||
// Called when DataTables is going to load a state. That might be | ||
// before the table is ready (state saving) or after (state restoring). | ||
// Also note that it happens _before_ preInit (below). | ||
$(document).on('stateLoadInit.dt', function (e, settings, state) { | ||
if (e.namespace !== 'dt') { | ||
return; | ||
} | ||
var dt = new DataTable.Api(settings); | ||
if (state.colReorder) { | ||
if (dt.ready()) { | ||
// Table is fully loaded - do the column reordering here | ||
// so that the stored indexes are in the correct place | ||
// e.g. column visibility | ||
setOrder(dt, state.colReorder, true); | ||
} | ||
else { | ||
// If the table is not ready, column reordering is done | ||
// after it becomes fully ready. That means that saved | ||
// column indexes need to be updated for where those columns | ||
// currently are. | ||
var map = invertKeyValues(state.colReorder); | ||
// State's ordering indexes | ||
orderingIndexes(map, state.order); | ||
// State's columns array - sort by restore index | ||
for (var i = 0; i < state.columns.length; i++) { | ||
state.columns[i]._cr_sort = state.colReorder[i]; | ||
} | ||
state.columns.sort(function (a, b) { | ||
return a._cr_sort - b._cr_sort; | ||
}); | ||
} | ||
} | ||
}); | ||
$(document).on('preInit.dt', function (e, settings) { | ||
if (e.namespace !== 'dt') { | ||
return; | ||
} | ||
var init = settings.oInit.colReorder; | ||
var defaults = DataTable.defaults.colReorder; | ||
if (init || defaults) { | ||
var opts = $.extend({}, defaults, init); | ||
if (init !== false) { | ||
var dt = new DataTable.Api(settings); | ||
new ColReorder(dt, opts); | ||
} | ||
} | ||
}); | ||
return DataTable; | ||
})); | ||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
* DataTables interfaces | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
// Expose | ||
$.fn.dataTable.ColReorder = ColReorder; | ||
$.fn.DataTable.ColReorder = ColReorder; | ||
// Register a new feature with DataTables | ||
if ( typeof $.fn.dataTable == "function" && | ||
typeof $.fn.dataTableExt.fnVersionCheck == "function" && | ||
$.fn.dataTableExt.fnVersionCheck('1.10.8') ) | ||
{ | ||
$.fn.dataTableExt.aoFeatures.push( { | ||
"fnInit": function( settings ) { | ||
var table = settings.oInstance; | ||
if ( ! settings._colReorder ) { | ||
var dtInit = settings.oInit; | ||
var opts = dtInit.colReorder || dtInit.oColReorder || {}; | ||
new ColReorder( settings, opts ); | ||
} | ||
else { | ||
table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" ); | ||
} | ||
return null; /* No node for DataTables to insert */ | ||
}, | ||
"cFeature": "R", | ||
"sFeature": "ColReorder" | ||
} ); | ||
} | ||
else { | ||
alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download"); | ||
} | ||
// Attach a listener to the document which listens for DataTables initialisation | ||
// events so we can automatically initialise | ||
$(document).on( 'preInit.dt.colReorder', function (e, settings) { | ||
if ( e.namespace !== 'dt' ) { | ||
return; | ||
} | ||
var init = settings.oInit.colReorder; | ||
var defaults = DataTable.defaults.colReorder; | ||
if ( init || defaults ) { | ||
var opts = $.extend( {}, init, defaults ); | ||
if ( init !== false ) { | ||
new ColReorder( settings, opts ); | ||
} | ||
} | ||
} ); | ||
// API augmentation | ||
$.fn.dataTable.Api.register( 'colReorder.reset()', function () { | ||
return this.iterator( 'table', function ( ctx ) { | ||
ctx._colReorder.fnReset(); | ||
} ); | ||
} ); | ||
$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) { | ||
if ( set ) { | ||
return this.iterator( 'table', function ( ctx ) { | ||
ctx._colReorder.fnOrder( set, original ); | ||
} ); | ||
} | ||
return this.context.length ? | ||
this.context[0]._colReorder.fnOrder() : | ||
null; | ||
} ); | ||
$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) { | ||
return this.context.length && this.context[0]._colReorder ? | ||
this.context[0]._colReorder.fnTranspose( idx, dir ) : | ||
idx; | ||
} ); | ||
$.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) { | ||
if (this.context.length) { | ||
this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows ); | ||
this.context[0]._colReorder._fnSetColumnIndexes(); | ||
} | ||
return this; | ||
} ); | ||
$.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) { | ||
return this.iterator( 'table', function ( ctx ) { | ||
if ( ctx._colReorder ) { | ||
ctx._colReorder.fnEnable( flag ); | ||
} | ||
} ); | ||
} ); | ||
$.fn.dataTable.Api.register( 'colReorder.disable()', function() { | ||
return this.iterator( 'table', function ( ctx ) { | ||
if ( ctx._colReorder ) { | ||
ctx._colReorder.fnDisable(); | ||
} | ||
} ); | ||
} ); | ||
return DataTable; | ||
})); |
@@ -1,4 +0,7 @@ | ||
/*! ColReorder 1.7.0 | ||
/*! ColReorder 2.0.0-dev | ||
* © SpryMedia Ltd - datatables.net/license | ||
*/ | ||
!function(o){var n,s;"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return o(t,window,document)}):"object"==typeof exports?(n=require("jquery"),s=function(t,e){e.fn.dataTable||require("datatables.net")(t,e)},"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||n(t),s(t,e),o(e,0,t.document)}:(s(window,n),module.exports=o(n,window,window.document))):o(jQuery,window,document)}(function(R,t,s,b){"use strict";var n=R.fn.dataTable;function T(t){for(var e=[],o=0,n=t.length;o<n;o++)e[t[o]]=o;return e}function v(t,e,o){e=t.splice(e,1)[0];t.splice(o,0,e)}function S(t,e,o){for(var n=[],s=0,r=t.childNodes.length;s<r;s++)1==t.childNodes[s].nodeType&&n.push(t.childNodes[s]);e=n[e];null!==o?t.insertBefore(e,n[o]):t.appendChild(e)}R.fn.dataTableExt.oApi.fnColReorder=function(o,t,e,n,s){function r(t,e,o){var n,s;t[e]&&"function"!=typeof t[e]&&(s=(n=t[e].split(".")).shift(),isNaN(+s)||(t[e]=o[+s]+"."+n.join(".")))}var i,a,l,d,f,u,h=o.aoColumns.length;if(t!=e)if(t<0||h<=t)this.oApi._fnLog(o,1,"ColReorder 'from' index is out of bounds: "+t);else if(e<0||h<=e)this.oApi._fnLog(o,1,"ColReorder 'to' index is out of bounds: "+e);else{var c=[];for(p=0,i=h;p<i;p++)c[p]=p;v(c,t,e);var g=T(c);for(p=0,i=o.aaSorting.length;p<i;p++)o.aaSorting[p][0]=g[o.aaSorting[p][0]];if(null!==o.aaSortingFixed)for(p=0,i=o.aaSortingFixed.length;p<i;p++)o.aaSortingFixed[p][0]=g[o.aaSortingFixed[p][0]];for(p=0,i=h;p<i;p++){for(a=0,l=(u=o.aoColumns[p]).aDataSort.length;a<l;a++)u.aDataSort[a]=g[u.aDataSort[a]];u.idx=g[u.idx]}for(R.each(o.aLastSort,function(t,e){o.aLastSort[t].src=g[e.src]}),p=0,i=h;p<i;p++)"number"==typeof(u=o.aoColumns[p]).mData?u.mData=g[u.mData]:R.isPlainObject(u.mData)&&(r(u.mData,"_",g),r(u.mData,"filter",g),r(u.mData,"sort",g),r(u.mData,"type",g));if(o.aoColumns[t].bVisible){for(var m=this.oApi._fnColumnIndexToVisible(o,t),C=null,p=e<t?e:e+1;null===C&&p<h;)C=this.oApi._fnColumnIndexToVisible(o,p),p++;for(p=0,i=(f=o.nTHead.getElementsByTagName("tr")).length;p<i;p++)S(f[p],m,C);if(null!==o.nTFoot)for(p=0,i=(f=o.nTFoot.getElementsByTagName("tr")).length;p<i;p++)S(f[p],m,C);for(p=0,i=o.aoData.length;p<i;p++)null!==o.aoData[p].nTr&&S(o.aoData[p].nTr,m,C)}for(v(o.aoColumns,t,e),p=0,i=h;p<i;p++)o.oApi._fnColumnOptions(o,p,{});for(v(o.aoPreSearchCols,t,e),p=0,i=o.aoData.length;p<i;p++){var _=o.aoData[p],x=_.anCells;if(x)for(v(x,t,e),a=0,d=x.length;a<d;a++)x[a]&&x[a]._DT_CellIndex&&(x[a]._DT_CellIndex.column=a);Array.isArray(_._aData)&&v(_._aData,t,e)}for(p=0,i=o.aoHeader.length;p<i;p++)v(o.aoHeader[p],t,e);if(null!==o.aoFooter)for(p=0,i=o.aoFooter.length;p<i;p++)v(o.aoFooter[p],t,e);for(!s&&s!==b||R.fn.dataTable.Api(o).rows().invalidate("data"),p=0,i=h;p<i;p++)R(o.aoColumns[p].nTh).off(".DT"),this.oApi._fnSortAttachListener(o,o.aoColumns[p].nTh,p);R(o.oInstance).trigger("column-reorder.dt",[o,{from:t,to:e,mapping:g,drop:n,iFrom:t,iTo:e,aiInvertMapping:g}])}};function r(t,e){if((t=new R.fn.dataTable.Api(t).settings()[0])._colReorder)return t._colReorder;!0===e&&(e={});var o=R.fn.dataTable.camelToHungarian;return o&&(o(r.defaults,r.defaults,!0),o(r.defaults,e||{})),this.s={dt:null,enable:null,init:R.extend(!0,{},r.defaults,e),fixed:0,fixedRight:0,reorderCallback:null,mouse:{startX:-1,startY:-1,offsetX:-1,offsetY:-1,target:-1,targetIndex:-1,fromIndex:-1},aoTargets:[]},this.dom={drag:null,pointer:null},this.s.enable=this.s.init.bEnable,this.s.dt=t,(this.s.dt._colReorder=this)._fnConstruct(),this}return R.extend(r.prototype,{fnEnable:function(t){if(!1===t)return this.fnDisable();this.s.enable=!0},fnDisable:function(){this.s.enable=!1},fnReset:function(){return this._fnOrderColumns(this.fnOrder()),this},fnGetCurrentOrder:function(){return this.fnOrder()},fnOrder:function(t,e){var o=[],n=this.s.dt.aoColumns;if(t===b){for(r=0,i=n.length;r<i;r++)o.push(n[r]._ColReorder_iOrigCol);return o}if(e){for(var s=this.fnOrder(),r=0,i=t.length;r<i;r++)o.push(R.inArray(t[r],s));t=o}return this._fnOrderColumns(T(t)),this},fnTranspose:function(t,e){e=e||"toCurrent";var o=this.fnOrder(),n=this.s.dt.aoColumns;return"toCurrent"===e?Array.isArray(t)?R.map(t,function(t){return R.inArray(t,o)}):R.inArray(t,o):Array.isArray(t)?R.map(t,function(t){return n[t]._ColReorder_iOrigCol}):n[t]._ColReorder_iOrigCol},_fnConstruct:function(){var t,o=this,e=this.s.dt.aoColumns.length,n=this.s.dt.nTable;for(this.s.init.iFixedColumns&&(this.s.fixed=this.s.init.iFixedColumns),this.s.init.iFixedColumnsLeft&&(this.s.fixed=this.s.init.iFixedColumnsLeft),this.s.fixedRight=this.s.init.iFixedColumnsRight||0,this.s.init.fnReorderCallback&&(this.s.reorderCallback=this.s.init.fnReorderCallback),t=0;t<e;t++)t>this.s.fixed-1&&t<e-this.s.fixedRight&&this._fnMouseListener(t,this.s.dt.aoColumns[t].nTh),this.s.dt.aoColumns[t]._ColReorder_iOrigCol=t;this.s.dt.oApi._fnCallbackReg(this.s.dt,"aoStateSaveParams",function(t,e){o._fnStateSave.call(o,e)},"ColReorder_State"),this.s.dt.oApi._fnCallbackReg(this.s.dt,"aoStateLoadParams",function(t,e){o.s.dt._colReorder.fnOrder(e.ColReorder,!0)});var s,r,i=null;this.s.init.aiOrder&&(i=this.s.init.aiOrder.slice()),(i=this.s.dt.oLoadedState&&void 0!==this.s.dt.oLoadedState.ColReorder&&this.s.dt.oLoadedState.ColReorder.length==this.s.dt.aoColumns.length?this.s.dt.oLoadedState.ColReorder:i)?o.s.dt._bInitComplete?(s=T(i),o._fnOrderColumns.call(o,s)):(r=!1,R(n).on("draw.dt.colReorder",function(){var t;o.s.dt._bInitComplete||r||(r=!0,t=T(i),o._fnOrderColumns.call(o,t))})):this._fnSetColumnIndexes(),R(n).on("destroy.dt.colReorder",function(){o.fnReset(),R(n).off("destroy.dt.colReorder draw.dt.colReorder"),R.each(o.s.dt.aoColumns,function(t,e){R(e.nTh).off(".ColReorder"),R(e.nTh).removeAttr("data-column-index")}),o.s.dt._colReorder=null,o.s=null})},_fnOrderColumns:function(t){var e=!1;if(t.length!=this.s.dt.aoColumns.length)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"ColReorder - array reorder does not match known number of columns. Skipping.");else{for(var o=0,n=t.length;o<n;o++){var s=R.inArray(o,t);o!=s&&(v(t,s,o),this.s.dt.oInstance.fnColReorder(s,o,!0,!1),e=!0)}this._fnSetColumnIndexes(),e&&(R.fn.dataTable.Api(this.s.dt).rows().invalidate("data"),""===this.s.dt.oScroll.sX&&""===this.s.dt.oScroll.sY||this.s.dt.oInstance.fnAdjustColumnSizing(!1),this.s.dt.oInstance.oApi._fnSaveState(this.s.dt),null!==this.s.reorderCallback&&this.s.reorderCallback.call(this))}},_fnStateSave:function(t){if(null!==this.s){var e,o=this.s.dt.aoColumns;if(t.ColReorder=[],t.aaSorting){for(s=0;s<t.aaSorting.length;s++)t.aaSorting[s][0]=o[t.aaSorting[s][0]]._ColReorder_iOrigCol;for(var n=R.extend(!0,[],t.aoSearchCols),s=0,r=o.length;s<r;s++)e=o[s]._ColReorder_iOrigCol,t.aoSearchCols[e]=n[s],t.abVisCols[e]=o[s].bVisible,t.ColReorder.push(e)}else if(t.order){for(s=0;s<t.order.length;s++)t.order[s][0]=o[t.order[s][0]]._ColReorder_iOrigCol;var i=R.extend(!0,[],t.columns);for(s=0,r=o.length;s<r;s++)e=o[s]._ColReorder_iOrigCol,t.columns[e]=i[s],t.ColReorder.push(e)}}},_fnMouseListener:function(t,e){var o=this;R(e).on("mousedown.ColReorder",function(t){o.s.enable&&1===t.which&&o._fnMouseDown.call(o,t,e)}).on("touchstart.ColReorder",function(t){o.s.enable&&o._fnMouseDown.call(o,t,e)})},_fnMouseDown:function(t,e){var o=this,n=R(t.target).closest("th, td").offset(),e=parseInt(R(e).attr("data-column-index"),10);e!==b&&(this.s.mouse.startX=this._fnCursorPosition(t,"pageX"),this.s.mouse.startY=this._fnCursorPosition(t,"pageY"),this.s.mouse.offsetX=this._fnCursorPosition(t,"pageX")-n.left,this.s.mouse.offsetY=this._fnCursorPosition(t,"pageY")-n.top,this.s.mouse.target=this.s.dt.aoColumns[e].nTh,this.s.mouse.targetIndex=e,this.s.mouse.fromIndex=e,this._fnRegions(),R(s).on("mousemove.ColReorder touchmove.ColReorder",function(t){o._fnMouseMove.call(o,t)}).on("mouseup.ColReorder touchend.ColReorder",function(t){o._fnMouseUp.call(o,t)}))},_fnMouseMove:function(t){var e,o=this;if(null===this.dom.drag){if(Math.pow(Math.pow(this._fnCursorPosition(t,"pageX")-this.s.mouse.startX,2)+Math.pow(this._fnCursorPosition(t,"pageY")-this.s.mouse.startY,2),.5)<5)return;this._fnCreateDragNode()}this.dom.drag.css({left:this._fnCursorPosition(t,"pageX")-this.s.mouse.offsetX,top:this._fnCursorPosition(t,"pageY")-this.s.mouse.offsetY});for(var n=this.s.mouse.toIndex,s=this._fnCursorPosition(t,"pageX"),t=function(){for(var t=o.s.aoTargets.length-1;0<t;t--)if(o.s.aoTargets[t].x!==o.s.aoTargets[t-1].x)return o.s.aoTargets[t]},r=1;r<this.s.aoTargets.length;r++){var i=function(t){for(;0<=t;){if(--t<=0)return null;if(o.s.aoTargets[t+1].x!==o.s.aoTargets[t].x)return o.s.aoTargets[t]}}(r),a=(i=i||function(){for(var t=0;t<o.s.aoTargets.length-1;t++)if(o.s.aoTargets[t].x!==o.s.aoTargets[t+1].x)return o.s.aoTargets[t]}()).x+(this.s.aoTargets[r].x-i.x)/2;if(this._fnIsLtr()){if(s<a){e=i;break}}else if(a<s){e=i;break}}e?(this.dom.pointer.css("left",e.x),this.s.mouse.toIndex=e.to):(this.dom.pointer.css("left",t().x),this.s.mouse.toIndex=t().to),this.s.init.bRealtime&&n!==this.s.mouse.toIndex&&(this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex),this.s.mouse.fromIndex=this.s.mouse.toIndex,""===this.s.dt.oScroll.sX&&""===this.s.dt.oScroll.sY||this.s.dt.oInstance.fnAdjustColumnSizing(!1),this._fnRegions())},_fnMouseUp:function(t){R(s).off(".ColReorder"),null!==this.dom.drag&&(this.dom.drag.remove(),this.dom.pointer.remove(),this.dom.drag=null,this.dom.pointer=null,this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex,!0),this._fnSetColumnIndexes(),""===this.s.dt.oScroll.sX&&""===this.s.dt.oScroll.sY||this.s.dt.oInstance.fnAdjustColumnSizing(!1),this.s.dt.oInstance.oApi._fnSaveState(this.s.dt),null!==this.s.reorderCallback&&this.s.reorderCallback.call(this))},_fnRegions:function(){var t=this.s.dt.aoColumns,n=this._fnIsLtr(),s=(this.s.aoTargets.splice(0,this.s.aoTargets.length),R(this.s.dt.nTable).offset().left),r=[],e=(R.each(t,function(t,e){var o;e.bVisible&&"none"!==e.nTh.style.display?(o=(e=R(e.nTh)).offset().left,n&&(o+=e.outerWidth()),r.push({index:t,bound:o}),s=o):r.push({index:t,bound:s})}),r[0]),t=R(t[e.index].nTh).outerWidth();this.s.aoTargets.push({to:0,x:e.bound-t});for(var o=0;o<r.length;o++){var i=r[o],a=i.index;i.index<this.s.mouse.fromIndex&&a++,this.s.aoTargets.push({to:a,x:i.bound})}0!==this.s.fixedRight&&this.s.aoTargets.splice(this.s.aoTargets.length-this.s.fixedRight),0!==this.s.fixed&&this.s.aoTargets.splice(0,this.s.fixed)},_fnCreateDragNode:function(){var t=""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY,e=this.s.dt.aoColumns[this.s.mouse.targetIndex].nTh,o=e.parentNode,n=o.parentNode,s=n.parentNode,r=R(e).clone();this.dom.drag=R(s.cloneNode(!1)).addClass("DTCR_clonedTable").append(R(n.cloneNode(!1)).append(R(o.cloneNode(!1)).append(r[0]))).css({position:"absolute",top:0,left:0,width:R(e).outerWidth(),height:R(e).outerHeight()}).appendTo("body"),this.dom.pointer=R("<div></div>").addClass("DTCR_pointer").css({position:"absolute",top:R(t?R(this.s.dt.nScrollBody).parent():this.s.dt.nTable).offset().top,height:R(t?R(this.s.dt.nScrollBody).parent():this.s.dt.nTable).height()}).appendTo("body")},_fnSetColumnIndexes:function(){R.each(this.s.dt.aoColumns,function(t,e){R(e.nTh).attr("data-column-index",t)})},_fnCursorPosition:function(t,e){return(-1!==t.type.indexOf("touch")?t.originalEvent.touches[0]:t)[e]},_fnIsLtr:function(){return"rtl"!==R(this.s.dt.nTable).css("direction")}}),r.defaults={aiOrder:null,bEnable:!0,bRealtime:!0,iFixedColumnsLeft:0,iFixedColumnsRight:0,fnReorderCallback:null},r.version="1.7.0",R.fn.dataTable.ColReorder=r,R.fn.DataTable.ColReorder=r,"function"==typeof R.fn.dataTable&&"function"==typeof R.fn.dataTableExt.fnVersionCheck&&R.fn.dataTableExt.fnVersionCheck("1.10.8")?R.fn.dataTableExt.aoFeatures.push({fnInit:function(t){var e=t.oInstance;return t._colReorder?e.oApi._fnLog(t,1,"ColReorder attempted to initialise twice. Ignoring second"):(e=(e=t.oInit).colReorder||e.oColReorder||{},new r(t,e)),null},cFeature:"R",sFeature:"ColReorder"}):alert("Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download"),R(s).on("preInit.dt.colReorder",function(t,e){var o;"dt"===t.namespace&&(t=e.oInit.colReorder,o=n.defaults.colReorder,(t||o)&&(o=R.extend({},t,o),!1!==t&&new r(e,o)))}),R.fn.dataTable.Api.register("colReorder.reset()",function(){return this.iterator("table",function(t){t._colReorder.fnReset()})}),R.fn.dataTable.Api.register("colReorder.order()",function(e,o){return e?this.iterator("table",function(t){t._colReorder.fnOrder(e,o)}):this.context.length?this.context[0]._colReorder.fnOrder():null}),R.fn.dataTable.Api.register("colReorder.transpose()",function(t,e){return this.context.length&&this.context[0]._colReorder?this.context[0]._colReorder.fnTranspose(t,e):t}),R.fn.dataTable.Api.register("colReorder.move()",function(t,e,o,n){return this.context.length&&(this.context[0]._colReorder.s.dt.oInstance.fnColReorder(t,e,o,n),this.context[0]._colReorder._fnSetColumnIndexes()),this}),R.fn.dataTable.Api.register("colReorder.enable()",function(e){return this.iterator("table",function(t){t._colReorder&&t._colReorder.fnEnable(e)})}),R.fn.dataTable.Api.register("colReorder.disable()",function(){return this.iterator("table",function(t){t._colReorder&&t._colReorder.fnDisable()})}),n}); | ||
!function(o){var r,n;"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return o(t,window,document)}):"object"==typeof exports?(r=require("jquery"),n=function(t,e){e.fn.dataTable||require("datatables.net")(t,e)},"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||r(t),n(t,e),o(e,t,t.document)}:(n(window,r),module.exports=o(r,window,window.document))):o(jQuery,window,document)}(function(t,o,e){"use strict";var r,n,s,t=t.fn.dataTable;return r=function(c,t,f){var n=c.fn.dataTable;function h(t,e,o,r){var n=t.splice(e,o);n.unshift(0),n.unshift(r<e?r:r-o+1),t.splice.apply(t,n)}function a(t){t.rows().invalidate("data"),t.column(0).visible(t.column(0).visible()),t.columns.adjust();var e=t.colReorder.order();t.trigger("columns-reordered",[{order:e,mapping:g(e)}])}function s(t){return t.settings()[0].aoColumns.map(function(t){return t._crOriginalIdx})}function p(t,e,o,r){for(var n=[],s=0;s<t.length;s++){var i=t[s];h(i,o[0],o.length,r);for(var a=0;a<i.length;a++){var l,u=i[a].cell;n.includes(u)||(l=u.getAttribute("data-dt-column").split(",").map(function(t){return e[t]}).join(","),u.setAttribute("data-dt-column",l),n.push(u))}}}function i(t){t.columns().iterator("column",function(t,e){t=t.aoColumns;void 0===t[e]._crOriginalIdx&&(t[e]._crOriginalIdx=e)})}function g(t){for(var e=[],o=0;o<t.length;o++)e[t[o]]=o;return e}function l(t,e,o){var r,n=t.settings()[0],s=n.aoColumns,i=s.map(function(t,e){return e});if(!e.includes(o)){h(i,e[0],e.length,o);var a=g(i);for(h(s,e[0],e.length,o),r=0;r<n.aoData.length;r++){var l=n.aoData[r],u=l.anCells;if(u)for(h(u,e[0],e.length,o),c=0;c<u.length;c++)l.nTr&&u[c]&&s[c].bVisible&&l.nTr.appendChild(u[c]),u[c]&&u[c]._DT_CellIndex&&(u[c]._DT_CellIndex.column=c)}for(r=0;r<s.length;r++){for(var d=s[r],c=0;c<d.aDataSort.length;c++)d.aDataSort[c]=a[d.aDataSort[c]];d.idx=a[d.idx],d.bVisible&&n.colgroup.append(d.colEl)}p(n.aoHeader,a,e,o),p(n.aoFooter,a,e,o),h(n.aoPreSearchCols,e[0],e.length,o),m(a,n.aaSorting),Array.isArray(n.aaSortingFixed)?m(a,n.aaSortingFixed):(n.aaSortingFixed.pre||n.aaSortingFixed.post)&&m(a,n.aaSortingFixed.pre),n.aLastSort.forEach(function(t){t.src=a[t.src]}),t.trigger("column-reorder",[t.settings()[0],{from:e,to:o,mapping:a}])}}function m(t,e){for(var o=0;o<e.length;o++){var r=e[o];"number"==typeof r?e[o]=t[r]:c.isPlainObject(r)&&void 0!==r.idx?r.idx=t[r.idx]:Array.isArray(r)&&"number"==typeof r[0]&&(r[0]=t[r[0]])}}function u(t,e,o){var r=!1;if(e.length!==t.columns().count())t.error("ColReorder - column count mismatch");else{for(var n=g(e=o?d(t,e,"toCurrent"):e),s=0;s<n.length;s++){var i=n.indexOf(s);s!==i&&(h(n,i,1,s),l(t,[i],s),r=!0)}r&&a(t)}}function d(t,e,o){var r=t.colReorder.order(),n=t.settings()[0].aoColumns;return"toCurrent"===o||"fromOriginal"===o?Array.isArray(e)?e.map(function(t){return r.indexOf(t)}):r.indexOf(e):Array.isArray(e)?e.map(function(t){return n[t]._crOriginalIdx}):n[e]._crOriginalIdx}function v(t,e,o){var r=t.columns().count();return!(e[0]<o&&o<e[e.length]||e[0]<0&&e[e.length-1]>r||o<0&&r<o||!e.includes(o)&&(!y(t.table().header.structure(),e,o)||!y(t.table().footer.structure(),e,o)))}function y(t,e,o){for(var r=function(t){for(var e=[],o=0;o<t.length;o++){e.push([]);for(var r=0;r<t[o].length;r++){var n=t[o][r];if(n)for(var s=0;s<n.rowspan;s++)for(var i=0;i<n.colspan;i++)e[o+s][r+i]=n.cell}}return e}(t),n=0;n<r.length;n++)h(r[n],e[0],e.length,o);for(n=0;n<r.length;n++)for(var s=[],i=0;i<r[n].length;i++){var a=r[n][i];if(s.includes(a)){if(s[s.length-1]!==a)return}else s.push(a)}return 1}_.prototype.disable=function(){return this.c.enable=!1,this},_.prototype.enable=function(t){return!1===(t=void 0===t?!0:t)?this.disable():(this.c.enable=!0,this)},_.prototype._addListener=function(t){var e=this;c(t).on("selectstart.colReorder",function(){return!1}).on("mousedown.colReorder touchstart.colReorder",function(t){"mousedown"===t.type&&1!==t.which||e.c.enable&&e._mouseDown(t,this)})},_.prototype._createDragNode=function(){var t=this.s.mouse.target,e=t.parent(),o=e.parent(),r=o.parent(),n=t.clone();this.dom.drag=c(r[0].cloneNode(!1)).addClass("dtcr-cloned").append(c(o[0].cloneNode(!1)).append(c(e[0].cloneNode(!1)).append(n[0]))).css({position:"absolute",top:0,left:0,width:c(t).outerWidth(),height:c(t).outerHeight()}).appendTo("body")},_.prototype._cursorPosition=function(t,e){return(-1!==t.type.indexOf("touch")?t.originalEvent.touches[0]:t)[e]},_.prototype._mouseDown=function(t,e){for(var o=this,r=c(t.target).closest("th, td"),n=r.offset(),s=this.dt.columns(this.c.columns).indexes().toArray(),i=c(e).attr("data-dt-column").split(",").map(function(t){return parseInt(t,10)}),a=0;a<i.length;a++)if(!s.includes(i[a]))return!1;this.s.mouse.start.x=this._cursorPosition(t,"pageX"),this.s.mouse.start.y=this._cursorPosition(t,"pageY"),this.s.mouse.offset.x=this._cursorPosition(t,"pageX")-n.left,this.s.mouse.offset.y=this._cursorPosition(t,"pageY")-n.top,this.s.mouse.target=r,this.s.mouse.targets=i;for(var l=0;l<i.length;l++){var u=this.dt.cells(null,i[l],{page:"current"}).nodes().to$(),d="dtcr-moving";0===l&&(d+=" dtcr-moving-first"),l===i.length-1&&(d+=" dtcr-moving-last"),u.addClass(d)}this._regions(i),this._scrollRegions(),c(f).on("mousemove.colReorder touchmove.colReorder",function(t){o._mouseMove(t)}).on("mouseup.colReorder touchend.colReorder",function(t){o._mouseUp(t)})},_.prototype._mouseMove=function(t){if(null===this.dom.drag){if(Math.pow(Math.pow(this._cursorPosition(t,"pageX")-this.s.mouse.start.x,2)+Math.pow(this._cursorPosition(t,"pageY")-this.s.mouse.start.y,2),.5)<5)return;c(f.body).addClass("dtcr-dragging"),this._createDragNode()}this.dom.drag.css({left:this._cursorPosition(t,"pageX")-this.s.mouse.offset.x,top:this._cursorPosition(t,"pageY")-this.s.mouse.offset.y});var e=c(this.dt.table().node()).offset().left,o=this._cursorPosition(t,"pageX")-e,e=this.s.dropZones.find(function(t){return t.left<=o&&o<=t.left+t.width});this.s.mouse.absLeft=this._cursorPosition(t,"pageX"),e&&!e.self&&this._move(e,o)},_.prototype._mouseUp=function(t){c(f).off(".colReorder"),c(f.body).removeClass("dtcr-dragging"),this.dom.drag&&(this.dom.drag.remove(),this.dom.drag=null),this.s.scrollInterval&&clearInterval(this.s.scrollInterval),this.dt.cells(".dtcr-moving").nodes().to$().removeClass("dtcr-moving dtcr-moving-first dtcr-moving-last")},_.prototype._move=function(t,e){var o,r,n=this,t=(this.dt.colReorder.move(this.s.mouse.targets,t.colIdx),this.s.mouse.targets=c(this.s.mouse.target).attr("data-dt-column").split(",").map(function(t){return parseInt(t,10)}),this._regions(this.s.mouse.targets),this.s.dropZones.find(function(t){return t.colIdx===n.s.mouse.targets[0]})),s=this.s.dropZones.indexOf(t);t.left>e&&(r=t.left-e,o=this.s.dropZones[s-1],t.left-=r,t.width+=r,o)&&(o.width-=r),(t=this.s.dropZones.find(function(t){return t.colIdx===n.s.mouse.targets[n.s.mouse.targets.length-1]})).left+t.width<e&&(o=e-(t.left+t.width),r=this.s.dropZones[s+1],t.width+=o,r)&&(r.left+=o,r.width-=o)},_.prototype._regions=function(n){var s=this,i=[],a=0,l=0,u=this.dt.columns(this.c.columns).indexes().toArray(),d=this.dt.columns().widths();this.dt.columns().every(function(t,e,o){var r;this.visible()&&(r=d[t],u.includes(t)&&(v(s.dt,n,t)?i.push({colIdx:t,left:a-l,self:n[0]<=t&&t<=n[n.length-1],width:r+l}):t<n[0]?i.length&&(i[i.length-1].width+=r):t>n[n.length-1]&&(l+=r)),a+=r)}),this.s.dropZones=i},_.prototype._isScrolling=function(){return this.dt.table().body().parentNode!==this.dt.table().header().parentNode},_.prototype._scrollRegions=function(){var e,o,r,n;this._isScrolling()&&(o=c((e=this).dt.table().container()).position().left,r=c(this.dt.table().container()).outerWidth(),n=this.dt.table().body().parentElement.parentElement,this.s.scrollInterval=setInterval(function(){var t=e.s.mouse.absLeft;t<o+75&&n.scrollLeft?n.scrollLeft-=5:o+r-75<t&&n.scrollLeft<n.scrollWidth&&(n.scrollLeft+=5)},25))},_.defaults={columns:"",enable:!0,order:null},_.version="2.0.0-dev"; | ||
/*! ColReorder 2.0.0-dev | ||
* © SpryMedia Ltd - datatables.net/license | ||
*/var b=_;function _(r,t){this.dom={drag:null},this.c={columns:null,enable:null,order:null},this.s={dropZones:[],mouse:{absLeft:-1,offset:{x:-1,y:-1},start:{x:-1,y:-1},target:null,targets:[]},scrollInterval:null};var e,o=this;r.settings()[0]._colReorder||((r.settings()[0]._colReorder=this).dt=r,c.extend(this.c,_.defaults,t),i(r),r.on("stateSaveParams",function(t,e,o){o.colReorder=s(r)}),r.on("destroy",function(){r.off(".colReorder"),r.colReorder.reset()}),t=r.state.loaded(),e=this.c.order,(e=t&&t.colReorder?t.colReorder:e)&&r.ready(function(){u(r,e,!0)}),r.table().header.structure().forEach(function(t){for(var e=0;e<t.length;e++)t[e]&&t[e].cell&&o._addListener(t[e].cell)}))}return n.Api.register("colReorder.enable()",function(e){return this.iterator("table",function(t){t._colReorder&&t._colReorder.enable(e)})}),n.Api.register("colReorder.disable()",function(){return this.iterator("table",function(t){t._colReorder&&t._colReorder.disable()})}),n.Api.register("colReorder.move()",function(t,e){return i(this),v(this,t=Array.isArray(t)?t:[t],e)?this.tables().every(function(){l(this,t,e),a(this)}):(this.error("ColReorder - invalid move"),this)}),n.Api.register("colReorder.order()",function(t,e){return i(this),t?this.tables().every(function(){u(this,t,e)}):this.context.length?s(this):null}),n.Api.register("colReorder.reset()",function(){return i(this),this.tables().every(function(){var t=this.columns().every(function(t){return t}).flatten().toArray();u(this,t,!0)})}),n.Api.register("colReorder.transpose()",function(t,e){return i(this),d(this,t,e=e||"toCurrent")}),n.ColReorder=b,c(f).on("stateLoadInit.dt",function(t,e,o){if("dt"===t.namespace){t=new n.Api(e);if(o.colReorder)if(t.ready())u(t,o.colReorder,!0);else{m(g(o.colReorder),o.order);for(var r=0;r<o.columns.length;r++)o.columns[r]._cr_sort=o.colReorder[r];o.columns.sort(function(t,e){return t._cr_sort-e._cr_sort})}}}),c(f).on("preInit.dt",function(t,e){var o,r;"dt"===t.namespace&&(t=e.oInit.colReorder,r=n.defaults.colReorder,t||r)&&(o=c.extend({},r,t),!1!==t)&&(r=new n.Api(e),new b(r,o))}),n},"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return r(t,0,e)}):"object"==typeof exports?(n=require("jquery"),s=function(t,e){e.fn.dataTable||require("datatables.net")(t,e)},void 0===o?module.exports=function(t,e){return t=t||o,e=e||n(t),s(t,e),r(e,0,t.document)}:(s(o,n),module.exports=r(n,0,o.document))):r(jQuery,0,e),t}); |
@@ -7,3 +7,3 @@ { | ||
"types": "./types/types.d.ts", | ||
"version": "1.7.0", | ||
"version": "2.0.0", | ||
"files": [ | ||
@@ -24,3 +24,3 @@ "js/**/*.js", | ||
"dependencies": { | ||
"datatables.net": ">=1.13.4", | ||
"datatables.net": ">=2.0.0", | ||
"jquery": ">=1.7" | ||
@@ -27,0 +27,0 @@ }, |
@@ -10,3 +10,3 @@ // Type definitions for DataTables ColReorder | ||
import DataTables, {Api} from 'datatables.net'; | ||
import DataTables, {Api, ColumnSelector} from 'datatables.net'; | ||
@@ -36,3 +36,3 @@ export default DataTables; | ||
interface ApiStatic { | ||
interface DataTablesStatic { | ||
/** | ||
@@ -45,3 +45,3 @@ * ColReorder class | ||
*/ | ||
new (dt: Api<any>, settings: boolean | ConfigColReorder); | ||
new (dt: Api<any>, settings: boolean | ConfigColReorder): DataTablesStatic['ColReorder']; | ||
@@ -68,30 +68,15 @@ /** | ||
/** | ||
* Initial enablement state of ColReorder - Since 1.5.0 | ||
* Columns to allow reordering on via the UI. | ||
*/ | ||
enable?: boolean; | ||
columns?: ColumnSelector; | ||
/** | ||
* Number of columns (counting from the left) to disallow reordering of, '0' in default | ||
* Initial enablement state of ColReorder - Since 1.5.0 | ||
*/ | ||
fixedColumnsLeft?: number; | ||
enable?: boolean; | ||
/** | ||
* Number of columns (counting from the right) to disallow reordering of, '0' in default | ||
*/ | ||
fixedColumnsRight?: number; | ||
/** | ||
* Set a default order for the columns in the table | ||
*/ | ||
order?: number[]; | ||
/** | ||
* Enable / disable live reordering of columns during a drag, 'true' in default | ||
*/ | ||
realtime?: boolean; | ||
/** | ||
* Callback after reorder | ||
*/ | ||
reorderCallback?: () => void; | ||
} | ||
@@ -98,0 +83,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
0
97820
2170
Updateddatatables.net@>=2.0.0