/** * @license * File: ColReorderWithResize.js * Version: 3.0 * CVS: $Id$ * Description: Allow columns to be reordered in a DataTable * Author: Allan Jardine (www.sprymedia.co.uk) * Author: Christophe Battarel (www.altairis.fr) * Created: Wed Sep 15 18:23:29 BST 2010 * Modified: July 2011 by Christophe Battarel - christophe.battarel@altairis.fr (columns resizable) * Modified: February 2012 by Martin Marchetta - martin.marchetta@gmail.com * 1. Made the "hot area" for resizing a little wider (it was a little difficult to hit the exact border of a column for resizing) * 2. Resizing didn't work at all when using scroller (that plugin splits the table into 2 different tables: one for the header and another one for the body, so when you resized the header, the data columns didn't follow) * 3. Fixed collateral effects of sorting feature * 4. If sScrollX is enabled (i.e. horizontal scrolling), when resizing a column the width of the other columns is not changed, but the whole * table is resized to give an Excel-like behavior (good suggestion by Allan) * Modified: February 2012 by Christophe Battarel - christophe.battarel@altairis.fr (ColReorder v1.0.5 adaptation) * Modified: September 16th 2012 by Hassan Kamara - h@phrmc.com * Modified: June 2017 by Jeff Walter - jeffreydwalter@gmail.com * 1. ColReorder v1.3.3 adaptation. * 2. Fixed issues with column width calculations which allowed column headers to become misaligned with table body when using scroller plugin. * Modified: June 2018 by Jeff Walter - jeffreydwalter@gmail.com * 1. Took a second stab at this plugin. Made things work for both scroller and non-scroller tables. * Language: Javascript * License: MIT * Project: DataTables * */ (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD define( ['jquery', 'datatables.net'], function ( $ ) { return factory( $, window, document ); } ); } else if ( typeof exports === 'object' ) { // CommonJS module.exports = function (root, $) { if ( ! root ) { root = window; } if ( ! $ || ! $.fn.dataTable ) { $ = require('datatables.net')(root, $).$; } return factory( $, root, root.document ); }; } else { // Browser factory( jQuery, window, document ); } }(function( $, window, document, undefined ) { 'use strict'; var DataTable = $.fn.dataTable; /** * 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 */ function fnInvertKeyValues( aIn ) { var aRet=[]; for ( var i=0, iLen=aIn.length ; i= 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 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" ); /* 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 () { $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' ); $(that.s.dt.nTHead).find( '*' ).off( '.ColReorder' ); $.each( that.s.dt.aoColumns, function (i, column) { $(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= minNThWidth) { $nTh.width(nThWidth); } else { $nTh.width(minNThWidth); } } else { // Hack to calculate the minimum width of the column based on contents. $nThNext.width('1%'); var minNThNextWidth = $nThNext.width(); $nThNext.width(this.s.mouse.nextStartWidth); if(nThNextInnerWidth <= minNThNextWidth) { return; } $nTh.width(nThWidth); } } // Smart scrolling is enabled. else { // Keep the current table's width (used in case sScrollX is enabled to resize the whole table, giving an Excel-like behavior) var $scrollHead = $(this.s.dt.nScrollHead); var $scrollBody = $(this.s.dt.nScrollBody); // Keep the current table's width (used in case sScrollX is enabled to resize the whole table, giving an Excel-like behavior) // if(scrollXEnabled) { // var $scrollHeadInner = $scrollHead.find('div.dataTables_scrollHeadInner'); // var $scrollHeadTableWrapper = $(this.s.dt.nTableWrapper); // // //** begin commentato oscar // // if((this.table_size === undefined || this.table_size < 0) && $scrollHeadTableWrapper.length > 0) { // this.table_size = $($scrollHead[0].childNodes[0].childNodes[0]).width(); // } // if(this.table_size + moveLength > $scrollHeadTableWrapper.width()) { // Resize the header too (if sScrollX is enabled). // if($scrollHeadTableWrapper.length) { // $($scrollHeadTableWrapper[0].childNodes[0].childNodes[0]).width(this.table_size + moveLength); // } // $($scrollHeadInner).width(this.table_size + moveLength); // Resize the table too (if sScrollX is enabled). // var new_table_size = this.table_size; // if(this.table_size + moveLength > $scrollHeadTableWrapper.width()) { // new_table_size += moveLength; // } // if(moveLength >= 0) { // $scrollBody.closest('.dataTables_scroll').find('.dataTables_scrollHead table').first().width(new_table_size); // $scrollBody.closest('.dataTables_scroll').find('.dataTables_scrollBody table').first().width(new_table_size); // } // ** end commentato oscar // } // } // When resizing the header, also resize the table's body (when enabling the Scroller, the table's header and // body are split into different tables, so the column resizing doesn't work anymore). // Since some columns might have been hidden, find the correct one to resize in the table's body // Get the first row in the scrollBody thead. var $scrollBodyTheadTr = $scrollBody.find('thead').first('tr'); var $scrollBodyNTh = $scrollBodyTheadTr.find('th:nth-child('+visibleColumnIndex+')'); var $scrollBodyNThNext = $scrollBodyTheadTr.find('th:nth-child('+(visibleColumnIndex+1)+')'); var $scrollBodyThSizing = $scrollBodyNTh.find('.dataTables_sizing'); var $scrollBodyThNextSizing = $scrollBodyNThNext.find('.dataTables_sizing'); // Get the first row in the scrollBody tbody. var $scrollBodyTbodyTr = $scrollBody.find('tbody').first('tr'); var $scrollBodyNTd = $scrollBodyTbodyTr.find('td:nth-child('+visibleColumnIndex+')'); var $scrollBodyNTdNext = $scrollBodyTbodyTr.find('td:nth-child('+(visibleColumnIndex+1)+')'); //** begin commentato oscar // if(moveLength < 0) { // // Hack to calculate the minimum width of the column based on contents. // $scrollBodyNTh.width('1%'); // var minNThWidth = $scrollBodyNTh.width(); // $scrollBodyNTh.width(this.s.mouse.startWidth); // // if(nThWidth >= minNThWidth) { // $nTh.width(nThWidth); // $scrollBodyNTh.width(nThWidth); // } // else { // $nTh.width(minNThWidth); // $scrollBodyNTh.width(minNThWidth); // } // } // else { // // Hack to calculate the minimum width of the column based on contents. // $scrollBodyNThNext.width('1%'); // var minNThNextWidth = $scrollBodyNThNext.width(); // $scrollBodyNThNext.width(this.s.mouse.nextStartWidth); // // if($scrollBodyNThNext.width() <= minNThNextWidth) { return; } // // $nTh.width(nThWidth); // $scrollBodyNTh.width(nThWidth); // } // ** end commentato oscar //** begin oscar added $scrollBody.closest('.dataTables_scroll').find('table th:nth-child('+visibleColumnIndex+')').each(function(){ $(this).css('width',nThWidth+'px'); $(this).css('min-width',nThWidth+'px'); $(this).css('max-width',nThWidth+'px'); }); $scrollBody.closest('.dataTables_scroll').find('table td:nth-child('+visibleColumnIndex+')').each(function(){ $(this).css('width',nThWidth+'px'); $(this).css('min-width',nThWidth+'px'); $(this).css('max-width',nThWidth+'px'); }); //** end oscar } } else if(this.s.allowReorder) { 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 bSet = false; var lastToIndex = this.s.mouse.toIndex; for ( var i=1, iLen=this.s.aoTargets.length ; i