diff options
8 files changed, 3417 insertions, 893 deletions
diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js new file mode 100644 index 00000000..58e7656e --- /dev/null +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js @@ -0,0 +1,1372 @@ +/*! ColReorder 1.1.3 + * ©2010-2014 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary ColReorder + * @description Provide the ability to reorder columns in a DataTable + * @version 1.1.3 + * @file dataTables.colReorder.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2010-2014 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 + */ + +(function(window, document, undefined) { + + +/** + * 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<iLen ; i++ ) + { + aRet[ aIn[i] ] = i; + } + return aRet; +} + + +/** + * 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 + */ +function fnArraySwitch( aArray, iFrom, iTo ) +{ + var mStore = aArray.splice( iFrom, 1 )[0]; + aArray.splice( iTo, 0, mStore ); +} + + +/** + * 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 + */ +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 ); + } +} + + + +var factory = function( $, DataTable ) { +"use strict"; + +/** + * 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 + * @returns void + */ +$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo ) +{ + var v110 = $.fn.dataTable.Api ? true : false; + var i, iLen, j, jLen, iCols=oSettings.aoColumns.length, nTrs, oCol; + var attrMap = function ( obj, prop, mapping ) { + if ( ! obj[ prop ] ) { + 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 + if ( v110 ) { + oCol.idx = aiInvertMapping[ oCol.idx ]; + } + } + + if ( v110 ) { + // 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 ]; + + // regenerate the get / set functions + oSettings.oApi._fnColumnOptions( oSettings, i, {} ); + } + 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 ); + + // regenerate the get / set functions + oSettings.oApi._fnColumnOptions( oSettings, i, {} ); + } + } + + + /* + * 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 ); + + /* 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]; + + if ( v110 ) { + // DataTables 1.10+ + if ( data.anCells ) { + fnArraySwitch( data.anCells, iFrom, iTo ); + } + + // For DOM sourced data, the invalidate will reread the cell into + // the data array, but for data sources as an array, they need to + // be flipped + if ( data.src !== 'dom' && $.isArray( data._aData ) ) { + fnArraySwitch( data._aData, iFrom, iTo ); + } + } + else { + // DataTables 1.9- + if ( $.isArray( data._aData ) ) { + fnArraySwitch( data._aData, iFrom, iTo ); + } + fnArraySwitch( data._anHidden, 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 ); + } + } + + // In 1.10 we need to invalidate row cached data for sorting, filtering etc + if ( v110 ) { + var api = new $.fn.dataTable.Api( oSettings ); + api.rows().invalidate(); + } + + /* + * Update DataTables' event handlers + */ + + /* Sort listener */ + for ( i=0, iLen=iCols ; i<iLen ; i++ ) + { + $(oSettings.aoColumns[i].nTh).off('click.DT'); + this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); + } + + + /* Fire an event so other plug-ins can update */ + $(oSettings.oInstance).trigger( 'column-reorder', [ oSettings, { + "iFrom": iFrom, + "iTo": iTo, + "aiInvertMapping": aiInvertMapping + } ] ); +}; + + +/** + * ColReorder provides column visibility control for DataTables + * @class ColReorder + * @constructor + * @param {object} dt DataTables settings object + * @param {object} opts ColReorder options + */ +var ColReorder = function( dt, opts ) +{ + var oDTSettings; + + if ( $.fn.dataTable.Api ) { + oDTSettings = new $.fn.dataTable.Api( dt ).settings()[0]; + } + // 1.9 compatibility + else if ( dt.fnSettings ) { + // DataTables object, convert to the settings object + oDTSettings = dt.fnSettings(); + } + else if ( typeof dt === 'string' ) { + // jQuery selector + if ( $.fn.dataTable.fnIsDataTable( $(dt)[0] ) ) { + oDTSettings = $(dt).eq(0).dataTable().fnSettings(); + } + } + else if ( dt.nodeName && dt.nodeName.toLowerCase() === 'table' ) { + // Table node + if ( $.fn.dataTable.fnIsDataTable( dt.nodeName ) ) { + oDTSettings = $(dt.nodeName).dataTable().fnSettings(); + } + } + else if ( dt instanceof jQuery ) { + // jQuery object + if ( $.fn.dataTable.fnIsDataTable( dt[0] ) ) { + oDTSettings = dt.eq(0).dataTable().fnSettings(); + } + } + else { + // DataTables settings object + oDTSettings = dt; + } + + // Ensure that we can't initialise on the same table twice + if ( oDTSettings._colReorder ) { + throw "ColReorder already initialised on table #"+oDTSettings.nTable.id; + } + + // 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, + + /** + * 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.dt = oDTSettings; + this.s.dt._colReorder = this; + this._fnConstruct(); + + /* Add destroy callback */ + oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColReorder'); + + return this; +}; + + + +ColReorder.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * 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 () + { + var a = []; + for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ ) + { + a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol ); + } + + this._fnOrderColumns( a ); + + 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 ) + { + if ( set === undefined ) + { + var a = []; + for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ ) + { + a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol ); + } + return a; + } + + this._fnOrderColumns( fnInvertKeyValues( set ) ); + + return this; + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 i; + + /* Columns discounted from reordering - counting left to right */ + if ( this.s.init.iFixedColumns ) + { + this.s.fixed = this.s.init.iFixedColumns; + } + + /* 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" ); + + /* 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; + this.s.dt.aoDrawCallback.push( { + "fn": function () { + if ( !that.s.dt._bInitComplete && !bDone ) + { + bDone = true; + var resort = fnInvertKeyValues( aiOrder ); + that._fnOrderColumns.call( that, resort ); + } + }, + "sName": "ColReorder_Pre" + } ); + } + else + { + var resort = fnInvertKeyValues( aiOrder ); + that._fnOrderColumns.call( that, resort ); + } + } + else { + this._fnSetColumnIndexes(); + } + }, + + + /** + * 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 ) + { + 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 ); + } + } + + /* 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 ); + + this._fnSetColumnIndexes(); + + 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 ) + { + 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) { + e.preventDefault(); + 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 = e.pageX; + this.s.mouse.startY = e.pageY; + this.s.mouse.offsetX = e.pageX - offset.left; + this.s.mouse.offsetY = 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', function (e) { + that._fnMouseMove.call( that, e ); + } ) + .on( 'mouseup.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(e.pageX - this.s.mouse.startX, 2) + + Math.pow(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: e.pageX - this.s.mouse.offsetX, + top: 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<iLen ; i++ ) + { + if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) ) + { + this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x ); + this.s.mouse.toIndex = this.s.aoTargets[i-1].to; + bSet = true; + break; + } + } + + // The insert element wasn't positioned in the array (less than + // operator), so we put it at the end + if ( !bSet ) + { + this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x ); + this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].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; + 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( 'mousemove.ColReorder mouseup.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 ); + 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; + + this.s.aoTargets.splice( 0, this.s.aoTargets.length ); + + this.s.aoTargets.push( { + "x": $(this.s.dt.nTable).offset().left, + "to": 0 + } ); + + var iToPoint = 0; + for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ ) + { + /* 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 incremement the counter for + * other columns + */ + if ( i != this.s.mouse.fromIndex ) + { + iToPoint++; + } + + if ( aoColumns[i].bVisible ) + { + this.s.aoTargets.push( { + "x": $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(), + "to": iToPoint + } ); + } + } + + /* 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 ? + $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top : + $(this.s.dt.nTable).offset().top, + height : scrolling ? + $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() : + $(this.s.dt.nTable).height() + } ) + .appendTo( 'body' ); + }, + + /** + * Clean up ColReorder memory references and event handlers + * @method _fnDestroy + * @returns void + * @private + */ + "_fnDestroy": function () + { + var i, iLen; + + for ( i=0, iLen=this.s.dt.aoDrawCallback.length ; i<iLen ; i++ ) + { + if ( this.s.dt.aoDrawCallback[i].sName === 'ColReorder_Pre' ) + { + this.s.dt.aoDrawCallback.splice( i, 1 ); + break; + } + } + + $(this.s.dt.nTHead).find( '*' ).off( '.ColReorder' ); + + $.each( this.s.dt.aoColumns, function (i, column) { + $(column.nTh).removeAttr('data-column-index'); + } ); + + this.s.dt._colReorder = null; + this.s = null; + }, + + + /** + * 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); + } ); + } +}; + + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Static parameters + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * ColReorder default settings for initialisation + * @namespace + * @static + */ +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 + * @example + * // Using the `oColReorder` option in the DataTables options object + * $('#example').dataTable( { + * "sDom": 'Rlfrtip', + * "oColReorder": { + * "aiOrder": [ 4, 3, 2, 1, 0 ] + * } + * } ); + * + * @example + * // Using `new` constructor + * $('#example').dataTable() + * + * new $.fn.dataTable.ColReorder( '#example', { + * "aiOrder": [ 4, 3, 2, 1, 0 ] + * } ); + */ + aiOrder: null, + + /** + * 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 + * @example + * // Using the `oColReorder` option in the DataTables options object + * $('#example').dataTable( { + * "sDom": 'Rlfrtip', + * "oColReorder": { + * "bRealtime": true + * } + * } ); + * + * @example + * // Using `new` constructor + * $('#example').dataTable() + * + * new $.fn.dataTable.ColReorder( '#example', { + * "bRealtime": true + * } ); + */ + bRealtime: false, + + /** + * 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 + * @example + * // Using the `oColReorder` option in the DataTables options object + * $('#example').dataTable( { + * "sDom": 'Rlfrtip', + * "oColReorder": { + * "iFixedColumns": 1 + * } + * } ); + * + * @example + * // Using `new` constructor + * $('#example').dataTable() + * + * new $.fn.dataTable.ColReorder( '#example', { + * "iFixedColumns": 1 + * } ); + */ + iFixedColumns: 0, + + /** + * As `iFixedColumnsRight` but counting from the right. + * @type int + * @default 0 + * @static + * @example + * // Using the `oColReorder` option in the DataTables options object + * $('#example').dataTable( { + * "sDom": 'Rlfrtip', + * "oColReorder": { + * "iFixedColumnsRight": 1 + * } + * } ); + * + * @example + * // Using `new` constructor + * $('#example').dataTable() + * + * new $.fn.dataTable.ColReorder( '#example', { + * "iFixedColumnsRight": 1 + * } ); + */ + iFixedColumnsRight: 0, + + /** + * Callback function that is fired when columns are reordered + * @type function():void + * @default null + * @static + * @example + * // Using the `oColReorder` option in the DataTables options object + * $('#example').dataTable( { + * "sDom": 'Rlfrtip', + * "oColReorder": { + * "fnReorderCallback": function () { + * alert( 'Columns reordered' ); + * } + * } + * } ); + * + * @example + * // Using `new` constructor + * $('#example').dataTable() + * + * new $.fn.dataTable.ColReorder( '#example', { + * "fnReorderCallback": function () { + * alert( 'Columns reordered' ); + * } + * } ); + */ + fnReorderCallback: null +}; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Constants + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/** + * ColReorder version + * @constant version + * @type String + * @default As code + */ +ColReorder.version = "1.1.3"; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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.9.3') ) +{ + $.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.9.3 or greater - www.datatables.net/download"); +} + + +// API augmentation +if ( $.fn.dataTable.Api ) { + $.fn.dataTable.Api.register( 'colReorder.reset()', function () { + return this.iterator( 'table', function ( ctx ) { + ctx._colReorder.fnReset(); + } ); + } ); + + $.fn.dataTable.Api.register( 'colReorder.order()', function ( set ) { + if ( set ) { + return this.iterator( 'table', function ( ctx ) { + ctx._colReorder.fnOrder( set ); + } ); + } + + return this.context.length ? + this.context[0]._colReorder.fnOrder() : + null; + } ); +} + +return ColReorder; +}; // /factory + + +// Define as an AMD module if possible +if ( typeof define === 'function' && define.amd ) { + define( ['jquery', 'datatables'], factory ); +} +else if ( typeof exports === 'object' ) { + // Node/CommonJS + factory( require('jquery'), require('datatables') ); +} +else if ( jQuery && !jQuery.fn.dataTable.ColReorder ) { + // Otherwise simply initialise as normal, stopping multiple evaluation + factory( jQuery, jQuery.fn.dataTable ); +} + + +})(window, document);
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js index 2712750a..6ef9907a 100644 --- a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colResize.js @@ -1,846 +1,943 @@ -/*! ColResize 0.0.10 - */ - -/** - * @summary ColResize - * @description Provide the ability to resize columns in a DataTable - * @version 0.0.10 - * @file dataTables.colResize.js - * @author Silvacom Ltd. - * - * For details please refer to: http://www.datatables.net - * - * Special thank to everyone who has contributed to this plug in - * - dykstrad - * - tdillan (for 0.0.3 and 0.0.5 bug fixes) - * - kylealonius (for 0.0.8 bug fix) - * - the86freak (for 0.0.9 bug fix) - */ - -(function (window, document, undefined) { - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables plug-in API functions test - * - * This are required by ColResize in order to perform the tasks required, and also keep this - * code portable, to be used for other column resize projects with DataTables, if needed. - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - var factory = function ($, DataTable) { - "use strict"; - - /** - * Plug-in for DataTables which will resize the columns depending on the handle clicked - * @method $.fn.dataTableExt.oApi.fnColResize - * @param object oSettings DataTables settings object - automatically added by DataTables! - * @param int iCol Take the column to be resized - * @returns void - */ - $.fn.dataTableExt.oApi.fnColResize = function (oSettings, iCol) { - var v110 = $.fn.dataTable.Api ? true : false; - - /* - * Update DataTables' event handlers - */ - - /* Fire an event so other plug-ins can update */ - $(oSettings.oInstance).trigger('column-resize', [ oSettings, { - "iCol": iCol - } ]); - }; - - /** - * ColResize provides column resize control for DataTables - * @class ColResize - * @constructor - * @param {object} dt DataTables settings object - * @param {object} opts ColResize options - */ - var ColResize = function (dt, opts) { - var oDTSettings; - - if ($.fn.dataTable.Api) { - oDTSettings = new $.fn.dataTable.Api(dt).settings()[0]; - } - // 1.9 compatibility - else if (dt.fnSettings) { - // DataTables object, convert to the settings object - oDTSettings = dt.fnSettings(); - } - else if (typeof dt === 'string') { - // jQuery selector - if ($.fn.dataTable.fnIsDataTable($(dt)[0])) { - oDTSettings = $(dt).eq(0).dataTable().fnSettings(); - } +var dt; +(function (dt) { + var ColResize = (function () { + function ColResize($, api, settings) { + this.$ = $; + this.tableSize = -1; + this.initialized = false; + this.dt = {}; + this.dom = { + fixedLayout: false, + fixedHeader: null, + winResizeTimer: null, + mouse: { + startX: -1, + startWidth: null + }, + table: { + prevWidth: null + }, + origState: true, + resize: false, + scrollHead: null, + scrollHeadTable: null, + scrollFoot: null, + scrollFootTable: null, + scrollFootInner: null, + scrollBody: null, + scrollBodyTable: null, + scrollX: false, + scrollY: false + }; + this.settings = this.$.extend(true, {}, dt.ColResize.defaultSettings, settings); + this.dt.settings = api.settings()[0]; + this.dt.api = api; + this.dt.settings.colResize = this; + this.registerCallbacks(); + } + ColResize.prototype.initialize = function () { + var _this = this; + this.$.each(this.dt.settings.aoColumns, function (i, col) { + return _this.setupColumn(col); + }); + + //Initialize fixedHeader if specified + if (this.settings.fixedHeader) + this.setupFixedHeader(); + + //Save scroll head and body if found + this.dom.scrollHead = this.$('div.' + this.dt.settings.oClasses.sScrollHead, this.dt.settings.nTableWrapper); + this.dom.scrollHeadInner = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner, this.dom.scrollHead); + this.dom.scrollHeadTable = this.$('div.' + this.dt.settings.oClasses.sScrollHeadInner + ' > table', this.dom.scrollHead); + + this.dom.scrollFoot = this.$('div.' + this.dt.settings.oClasses.sScrollFoot, this.dt.settings.nTableWrapper); + this.dom.scrollFootInner = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner, this.dom.scrollFoot); + this.dom.scrollFootTable = this.$('div.' + this.dt.settings.oClasses.sScrollFootInner + ' > table', this.dom.scrollFoot); + + this.dom.scrollBody = this.$('div.' + this.dt.settings.oClasses.sScrollBody, this.dt.settings.nTableWrapper); + this.dom.scrollBodyTable = this.$('> table', this.dom.scrollBody); + this.dt.api.on('draw.dt', this.onDraw.bind(this)); + if (this.dom.scrollFootTable) { + this.dt.api.on('colPinFcDraw.dt', function (e, colPin, data) { + if (data.leftClone.header) + _this.$('tfoot', data.leftClone.header).remove(); + if (data.leftClone.footer) + _this.$('thead', data.leftClone.footer).remove(); + if (data.rightClone.header) + _this.$('tfoot', data.rightClone.header).remove(); + if (data.rightClone.footer) + _this.$('thead', data.rightClone.footer).remove(); + }); } - else if (dt.nodeName && dt.nodeName.toLowerCase() === 'table') { - // Table node - if ($.fn.dataTable.fnIsDataTable(dt.nodeName)) { - oDTSettings = $(dt.nodeName).dataTable().fnSettings(); - } + + this.dom.scrollX = this.dt.settings.oInit.sScrollX === undefined ? false : true; + this.dom.scrollY = this.dt.settings.oInit.sScrollY === undefined ? false : true; + + //SaveTableWidth + this.dt.settings.sTableWidthOrig = this.$(this.dt.settings.nTable).width(); + this.updateTableSize(); + + this.dt.settings.oFeatures.bAutoWidthOrig = this.dt.settings.oFeatures.bAutoWidth; + this.dt.settings.oFeatures.bAutoWidth = false; + + if (this.dt.settings.oInit.bStateSave && this.dt.settings.oLoadedState) { + this.loadState(this.dt.settings.oLoadedState); } - else if (dt instanceof jQuery) { - // jQuery object - if ($.fn.dataTable.fnIsDataTable(dt[0])) { - oDTSettings = dt.eq(0).dataTable().fnSettings(); - } + + this.onDraw(); + this.dom.table.preWidth = parseFloat(this.dom.scrollBodyTable.css('width')); + + if (!this.dom.scrollX && this.dom.scrollY && this.settings.fixedLayout && this.dt.settings._reszEvt) { + //We have to manually resize columns on window resize + var eventName = 'resize.DT-' + this.dt.settings.sInstance; + this.$(window).off(eventName); + this.$(window).on(eventName, function () { + _this.proportionallyColumnSizing(); + //api._fnAdjustColumnSizing(this.dt.settings); + }); } - else { - // DataTables settings object - oDTSettings = dt; - } - - // Convert from camelCase to Hungarian, just as DataTables does - if ($.fn.dataTable.camelToHungarian) { - $.fn.dataTable.camelToHungarian(ColResize.defaults, opts || {}); - } - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Public class variables - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * @namespace Settings object which contains customizable information for ColResize instance - */ - this.s = { - /** - * DataTables settings object - * @property dt - * @type Object - * @default null - */ - "dt": null, - - /** - * Initialisation object used for this instance - * @property init - * @type object - * @default {} - */ - "init": $.extend(true, {}, ColResize.defaults, opts), - - /** - * @namespace Information used for the mouse drag - */ - "mouse": { - "startX": -1, - "startY": -1, - "targetIndex": -1, - "targetColumn": -1, - "neighbourIndex": -1, - "neighbourColumn": -1 - }, - /** - * Status variable keeping track of mouse down status - * @property isMousedown - * @type boolean - * @default false - */ - "isMousedown": false - }; + if (this.dom.scrollX || this.dom.scrollY) { + this.dt.api.on('column-sizing.dt', this.fixFootAndHeadTables.bind(this)); + this.dt.api.on('column-visibility.dt', this.fixFootAndHeadTables.bind(this)); + } + this.initialized = true; + this.dt.settings.oApi._fnCallbackFire(this.dt.settings, 'colResizeInitCompleted', 'colResizeInitCompleted', [this]); + }; - /** - * @namespace Common and useful DOM elements for the class instance - */ - this.dom = { - /** - * Resizing element (the one the mouse is resizing) - * @property resize - * @type element - * @default null - */ - "resizeCol": null, - - /** - * Resizing element neighbour (the column next to the one the mouse is resizing) - * This is for fixed table resizing. - * @property resize - * @type element - * @default null - */ - "resizeColNeighbour": null, - - /** - * Array of events to be restored, used for overriding existing events from other plugins for a time. - * @property restoreEvents - * @type array - * @default [] - */ - "restoreEvents": [] + ColResize.prototype.setupColumn = function (col) { + var _this = this; + var $th = this.$(col.nTh); + if (col.resizable === false) + return; + + // listen to mousemove event for resize + $th.on('mousemove.ColResize', function (e) { + if (_this.dom.resize || col.resizable === false) + return; + + /* Store information about the mouse position */ + var $thTarget = e.target.nodeName.toUpperCase() == 'TH' ? _this.$(e.target) : _this.$(e.target).closest('TH'); + var offset = $thTarget.offset(); + var nLength = $thTarget.innerWidth(); + + /* are we on the col border (if so, resize col) */ + if (Math.abs(e.pageX - Math.round(offset.left + nLength)) <= 5) { + $thTarget.css({ 'cursor': 'col-resize' }); + } else + $thTarget.css({ 'cursor': 'pointer' }); + }); + + //Save the original width + col._ColResize_sWidthOrig = col.sWidthOrig; + col.initWidth = $th.width(); + col.minWidthOrig = col.minWidth; + + $th.on('dblclick.ColResize', function (e) { + _this.onDblClick(e, $th, col); + }); + + $th.off('mousedown.ColReorder'); + + // listen to mousedown event + $th.on('mousedown.ColResize', function (e) { + return _this.onMouseDown(e, col); + }); + }; + + ColResize.prototype.setupFixedHeader = function () { + var fhSettings = this.settings.fixedHeader === true ? undefined : this.settings.fixedHeader; + + //If left or right option was set to true disable resizing for the first or last column + if (this.$.isPlainObject(fhSettings)) { + var columns = this.dt.settings.aoColumns; + if (fhSettings.left === true) + columns[0].resizable = false; + if (fhSettings.right === true) + columns[columns.length - 1].resizable = false; + } + + this.dom.fixedHeader = new this.$.fn.dataTable.FixedHeader(this.dt.api, fhSettings); + var origUpdateClones = this.dom.fixedHeader._fnUpdateClones; + var that = this; + + //FixeHeader doesn't have any callback after updating the clones so we have to wrap the orig function + this.dom.fixedHeader._fnUpdateClones = function () { + origUpdateClones.apply(this, arguments); + that.memorizeFixedHeaderNodes(); }; + //As we missed the first call of _fnUpdateClones we have to call memorizeFixedHeaderNodes function manually + this.memorizeFixedHeaderNodes(); + }; - /* Constructor logic */ - this.s.dt = oDTSettings.oInstance.fnSettings(); - this.s.dt._colResize = this; - this._fnConstruct(); - - /* Add destroy callback */ - oDTSettings.oApi._fnCallbackReg(oDTSettings, 'aoDestroyCallback', $.proxy(this._fnDestroy, this), 'ColResize'); - - return this; - }; - - - ColResize.prototype = { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Public methods - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Reset the column widths to the original widths that was detected on - * start up. - * @return {this} Returns `this` for chaining. - * - * @example - * // DataTables initialisation with ColResize - * var table = $('#example').dataTable( { - * "sDom": 'Zlfrtip' - * } ); - * - * // Add click event to a button to reset the ordering - * $('#resetOrdering').click( function (e) { - * e.preventDefault(); - * $.fn.dataTable.ColResize( table ).fnReset(); - * } ); - */ - "fnReset": function () { - var a = []; - for (var i = 0, iLen = this.s.dt.aoColumns.length; i < iLen; i++) { - this.s.dt.aoColumns[i].width = this.s.dt.aoColumns[i]._ColResize_iOrigWidth; + ColResize.prototype.memorizeFixedHeaderNodes = function () { + var _this = this; + var fhSettings = this.dom.fixedHeader.fnGetSettings(); + var fhCache = fhSettings.aoCache; + var i, col; + for (i = 0; i < fhCache.length; i++) { + var type = fhCache[i].sType; + var propName; + var selector; + switch (type) { + case 'fixedHeader': + propName = 'fhTh'; + selector = 'thead>tr>th'; + this.dt.settings.fhTHead = fhCache[i].nNode; + break; + case 'fixedFooter': + propName = 'fhTf'; + selector = 'thead>tr>th'; + + //prepend a cloned thead to the floating footer table so that resizing will work correctly + var tfoot = this.$(fhCache[i].nNode); + var thead = this.$(this.dt.settings.nTHead).clone().css({ height: 0, visibility: 'hidden' }); + this.$('tr', thead).css('height', 0); + this.$('tr>th', thead).css({ + 'height': 0, + 'padding-bottom': 0, + 'padding-top': 0, + 'border-bottom-width': 0, + 'border-top-width': 0, + 'line-height': 0 + }); + tfoot.prepend(thead); + this.$('tfoot>tr>th', tfoot).css('width', ''); + this.dt.settings.fhTFoot = fhCache[i].nNode; + break; + default: + continue; } - this.s.dt.adjust().draw(); + this.$(selector, fhCache[i].nNode).each(function (j, th) { + col = _this.getVisibleColumn(j); + col[propName] = th; + }); + } + }; - return this; - }, + //zero based index + ColResize.prototype.getVisibleColumn = function (idx) { + var columns = this.dt.settings.aoColumns; + var currVisColIdx = -1; + for (var i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + currVisColIdx++; + if (currVisColIdx == idx) + return columns[i]; + } + return null; + }; + ColResize.prototype.updateTableSize = function () { + if (this.dom.scrollX && this.dom.scrollHeadTable.length) + this.tableSize = this.dom.scrollHeadTable.width(); + else + this.tableSize = -1; + }; - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods (they are of course public in JS, but recommended as private) - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + ColResize.prototype.proportionallyColumnSizing = function () { + var _this = this; + var prevWidths = [], newWidths = [], prevWidth, newWidth, newTableWidth, prevTableWidth, moveLength, multiplier, cWidth, i, j, delay = 500, prevTotalColWidths = 0, currTotalColWidths, columnRestWidths = [], columns = this.dt.settings.aoColumns, bodyTableColumns = this.$('thead th', this.dom.scrollBodyTable), headTableColumns = this.$('thead th', this.dom.scrollHeadTable), footTableColumns = this.dom.scrollFootTable.length ? this.$('thead th', this.dom.scrollFootTable) : [], visColumns = []; - /** - * Constructor logic - * @method _fnConstruct - * @returns void - * @private - */ - "_fnConstruct": function () { - var that = this; - var iLen = that.s.dt.aoColumns.length; - var i; + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + visColumns.push(columns[i]); + columnRestWidths.push(0); //set default value + } - that._fnSetupMouseListeners(); + for (i = 0; i < bodyTableColumns.length; i++) { + cWidth = parseFloat(bodyTableColumns[i].style.width); + prevTotalColWidths += cWidth; + prevWidths.push(cWidth); + } - /* Add event handlers for the resize handles */ - for (i = 0; i < iLen; i++) { - /* Mark the original column width for later reference */ - this.s.dt.aoColumns[i]._ColResize_iOrigWidth = this.s.dt.aoColumns[i].width; + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = ''; + } + + //Get the new table width calculated by the browser + newTableWidth = parseFloat(this.dom.scrollBodyTable.css('width')); + + //Get the old table width + prevTableWidth = this.dom.table.preWidth; + moveLength = newTableWidth - prevTableWidth; + if (moveLength == 0) { + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = prevWidths[i] + 'px'; } + return; + } - this._fnSetColumnIndexes(); - - /* State saving */ - this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { - that._fnStateSave.call(that, oData); - }, "ColResize_State" ); - - // State loading - this._fnStateLoad(); - }, - - /** - * @method _fnStateSave - * @param object oState DataTables state - * @private - */ - "_fnStateSave": function (oState) { - this.s.dt.aoColumns.forEach(function(col, index) { - oState.columns[index].width = col.sWidthOrig; - }); - }, - - /** - * If state has been loaded, apply the saved widths to the columns - * @method _fnStateLoad - * @private - */ - "_fnStateLoad": function() { - var that = this, - loadedState = this.s.dt.oLoadedState; - if (loadedState && loadedState.columns) { - var colStates = loadedState.columns, - currCols = this.s.dt.aoColumns; - // Only apply the saved widths if the number of columns is the same. - // Otherwise, we don't know if we're applying the width to the correct column. - if (colStates.length > 0 && colStates.length === currCols.length) { - colStates.forEach(function(state, index) { - var col = that.s.dt.aoColumns[index]; - if (state.width) { - col.sWidthOrig = col.sWidth = state.width; - } - }); + //var tot = 0; + currTotalColWidths = prevTotalColWidths; + for (i = 0; i < visColumns.length; i++) { + //For each column calculate the new width + prevWidth = prevWidths[i]; + multiplier = (+(prevWidth / prevTotalColWidths).toFixed(2)); + + //tot += multiplier; + newWidth = prevWidth + (moveLength * multiplier) + columnRestWidths[i]; + currTotalColWidths -= prevWidth; + + //Check whether the column can be resized to the new calculated value + //if not, set it to the min or max width depends on the moveLength value + if (!this.canResizeColumn(visColumns[i], newWidth)) { + cWidth = moveLength > 0 ? this.getColumnMaxWidth(visColumns[i]) : this.getColumnMinWidth(visColumns[i]); + var rest = newWidth - cWidth; + newWidth = cWidth; + + for (j = (i + 1); j < visColumns.length; j++) { + columnRestWidths[j] += rest * (+(visColumns[j] / currTotalColWidths).toFixed(2)); } } - }, - - /** - * Remove events of type from obj add it to restoreEvents array to be restored at a later time - * @param until string flag when to restore the event - * @param obj Object to remove events from - * @param type type of event to remove - * @param namespace namespace of the event being removed - */ - "_fnDelayEvents": function (until, obj, type, namespace) { - var that = this; - //Get the events for the object - var events = $._data($(obj).get(0), 'events'); - $.each(events, function (i, o) { - //If the event type matches - if (i == type) { - //Loop through the possible many events with that type - $.each(o, function (k, v) { - //Somehow it is possible for the event to be undefined make sure it is defined first - if (v) { - if (namespace) { - //Add the event to the array of events to be restored later - that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": v.namespace, "handler": v.handler}); - //If the namespace matches - if (v.namespace == namespace) { - //Turn off/unbind the event - $(obj).off(type + "." + namespace); - } - } else { - //Add the event to the array of events to be restored later - that.dom.restoreEvents.push({"until": until, "obj": obj, "type": v.type, "namespace": null, "handler": v.handler}); - //Turn off/unbind the event - $(obj).off(type); - } - } - }); - } - }); - }, - - /** - * Loop through restoreEvents array and restore the events on the elements provided - */ - "_fnRestoreEvents": function (until) { - var that = this; - //Loop through the events to be restored - var i; - for (i = that.dom.restoreEvents.length; i--;) { - if (that.dom.restoreEvents[i].until == undefined || that.dom.restoreEvents[i].until == null || that.dom.restoreEvents[i].until == until) { - if (that.dom.restoreEvents[i].namespace) { - //Turn on the event for the object provided - $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace).on(that.dom.restoreEvents[i].type + "." + that.dom.restoreEvents[i].namespace, that.dom.restoreEvents[i].handler); - that.dom.restoreEvents.splice(i, 1); - } else { - //Turn on the event for the object provided - $(that.dom.restoreEvents[i].obj).off(that.dom.restoreEvents[i].type).on(that.dom.restoreEvents[i].type, that.dom.restoreEvents[i].handler); - that.dom.restoreEvents.splice(i, 1); - } - } + newWidths.push(newWidth); + } + + //Apply the calculated column widths to the headers cells + var tablesWidth = this.dom.scrollBodyTable.outerWidth() + 'px'; + for (i = 0; i < headTableColumns.length; i++) { + headTableColumns[i].style.width = newWidths[i] + 'px'; + } + this.dom.scrollHeadTable.css('width', tablesWidth); + this.dom.scrollHeadInner.css('width', tablesWidth); + + for (i = 0; i < bodyTableColumns.length; i++) { + bodyTableColumns[i].style.width = newWidths[i] + 'px'; + } + + if (this.dom.scrollFootTable.length) { + for (i = 0; i < footTableColumns.length; i++) { + footTableColumns[i].style.width = newWidths[i] + 'px'; } - }, + this.dom.scrollFootTable[0].style.width = tablesWidth; + this.dom.scrollFootInner[0].style.width = tablesWidth; + } - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Mouse drop and drag - */ + //console.log('moveLength: ' + moveLength + ' multiplier: ' + tot); + //console.log(newWidths); + this.dom.table.preWidth = newTableWidth; + + //Call afterResizing function after the window stops resizing + if (this.dom.winResizeTimer) + clearTimeout(this.dom.winResizeTimer); + this.dom.winResizeTimer = setTimeout(function () { + _this.afterResizing(); + _this.dom.winResizeTimer = null; + }, delay); + }; - "_fnSetupMouseListeners":function() { - var that = this; - $(that.s.dt.nTableWrapper).off("mouseenter.ColResize").on("mouseenter.ColResize","th",function(e) { - e.preventDefault(); - that._fnMouseEnter.call(that, e, this); - }); - $(that.s.dt.nTableWrapper).off("mouseleave.ColResize").on("mouseleave.ColResize","th",function(e) { - e.preventDefault(); - that._fnMouseLeave.call(that, e, this); - }); - }, - - /** - * Add mouse listeners to the resize handle on TH element - * @method _fnMouseListener - * @param i Column index - * @param nTh TH resize handle element clicked on - * @returns void - * @private - */ - "_fnMouseListener": function (i, nTh) { - var that = this; - $(nTh).off('mouseenter.ColResize').on('mouseenter.ColResize', function (e) { - e.preventDefault(); - that._fnMouseEnter.call(that, e, nTh); - }); - $(nTh).off('mouseleave.ColResize').on('mouseleave.ColResize', function (e) { - e.preventDefault(); - that._fnMouseLeave.call(that, e, nTh); - }); - }, - - /** - * - * @param e Mouse event - * @param nTh TH element that the mouse is over - */ - "_fnMouseEnter": function (e, nTh) { - var that = this; - if(!that.s.isMousedown) { - //Once the mouse has entered the cell add mouse move event to see if the mouse is over resize handle - $(nTh).off('mousemove.ColResizeHandle').on('mousemove.ColResizeHandle', function (e) { - e.preventDefault(); - that._fnResizeHandleCheck.call(that, e, nTh); - }); + ColResize.prototype.getColumnIndex = function (col) { + //Get the current column position + var colIdx = -1; + for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { + if (this.dt.settings.aoColumns[i] === col) { + colIdx = i; + break; } - }, - - /** - * Clear mouse events when the mouse has left the th - * @param e Mouse event - * @param nTh TH element that the mouse has just left - */ - "_fnMouseLeave": function (e, nTh) { - //Once the mouse has left the TH make suure to remove the mouse move listener - $(nTh).off('mousemove.ColResizeHandle'); - }, - - /** - * Mouse down on a TH element in the table header - * @method _fnMouseDown - * @param event e Mouse event - * @param element nTh TH element to be resized - * @returns void - * @private - */ - "_fnMouseDown": function (e, nTh) { - var that = this; - - that.s.isMousedown = true; + } + return colIdx; + }; - /* Store information about the mouse position */ - var target = $(e.target).closest('th, td'); - var offset = target.offset(); - - /* Store information about the mouse position for resize calculations in mouse move function */ - this.s.mouse.startX = e.pageX; - this.s.mouse.startY = e.pageY; - - //Store the indexes of the columns the mouse is down on - var idx = that.dom.resizeCol[0].cellIndex; - - // the last column has no 'right-side' neighbour - // with fixed this can make the table smaller - if (that.dom.resizeColNeighbour[0] === undefined){ - var idxNeighbour = 0; + ColResize.prototype.getColumnEvent = function (th, type, ns) { + var event; + var thEvents = this.$._data(th, "events"); + this.$.each(thEvents[type] || [], function (idx, handler) { + if (handler.namespace === ns) + event = handler; + }); + return event; + }; + + ColResize.prototype.loadState = function (data) { + var _this = this; + var i, col; + + var onInit = function () { + if (_this.settings.fixedLayout) { + _this.setTablesLayout('fixed'); } else { - var idxNeighbour = that.dom.resizeColNeighbour[0].cellIndex; + _this.setTablesLayout('auto'); } - - + if (!data.colResize) { + if (_this.dt.settings.oFeatures.bAutoWidthOrig) + _this.dt.settings.oFeatures.bAutoWidth = true; + else if (_this.dt.settings.sTableWidthOrig) + _this.$(_this.dt.settings.nTable).width(_this.dt.settings.sTableWidthOrig); + + for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { + col = _this.dt.settings.aoColumns[i]; + if (col._ColResize_sWidthOrig) { + col.sWidthOrig = col._ColResize_sWidthOrig; + } + } + _this.dom.origState = true; + } else { + var columns = data.colResize.columns || []; + var wMap = {}; - if (idx === undefined) { - return; - } + if (_this.dt.settings.oFeatures.bAutoWidth) { + _this.dt.settings.oFeatures.bAutoWidth = false; + } - this.s.mouse.targetIndex = idx; - this.s.mouse.targetColumn = this.s.dt.aoColumns[ idx ]; - - this.s.mouse.neighbourIndex = idxNeighbour; - this.s.mouse.neighbourColumn = this.s.dt.aoColumns[ idxNeighbour ]; - - /* Add event handlers to the document */ - $(document) - .off('mousemove.ColResize').on('mousemove.ColResize', function (e) { - that._fnMouseMove.call(that, e); - }) - .off('mouseup.ColResize').on('mouseup.ColResize', function (e) { - that._fnMouseUp.call(that, e); - }); - }, - - /** - * Deal with a mouse move event while dragging to resize a column - * @method _fnMouseMove - * @param e Mouse event - * @returns void - * @private - */ - "_fnMouseMove": function (e) { - var that = this; - - var offset = $(that.s.mouse.targetColumn.nTh).offset(); - var relativeX = (e.pageX - offset.left); - var distFromLeft = relativeX; - var distFromRight = $(that.s.mouse.targetColumn.nTh).outerWidth() - relativeX - 1; - - //Change in mouse x position - var dx = e.pageX - that.s.mouse.startX; - //Get the minimum width of the column (default minimum 10px) - var minColumnWidth = Math.max(parseInt($(that.s.mouse.targetColumn.nTh).css('min-width')), 10); - //Store the previous width of the column - var prevWidth = $(that.s.mouse.targetColumn.nTh).width(); - //As long as the cursor is past the handle, resize the columns - if ((dx > 0 && distFromRight <= 0) || (dx < 0 && distFromRight >= 0)) { - if (!that.s.init.tableWidthFixed) { - //As long as the width is larger than the minimum - var newColWidth = Math.max(minColumnWidth, prevWidth + dx); - //Get the width difference (take into account the columns minimum width) - var widthDiff = newColWidth - prevWidth; - var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index")); - //Set datatable column widths - that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px"; - var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='"+colResizeIdx+"']"); - //For each table expand the width by the same amount as the column - //This accounts for other datatable plugins like FixedColumns - domCols.parents("table").each(function() { - if(!$(this).parent().hasClass("DTFC_LeftBodyLiner")) { - var newWidth = $(this).width() + widthDiff; - $(this).width(newWidth); - } else { - var newWidth =$(that.s.dt.nTableWrapper).find(".DTFC_LeftHeadWrapper").children("table").width(); - $(this).parents(".DTFC_LeftWrapper").width(newWidth); - $(this).parent().width(newWidth+15); - $(this).width(newWidth); - } - }); - //Apply the new width to the columns after the table has been resized - domCols.width(that.s.mouse.targetColumn.width); - } else { - //A neighbour column must exist in order to resize a column in a table with a fixed width - if (that.s.mouse.neighbourColumn) { - //Get the minimum width of the neighbor column (default minimum 10px) - var minColumnNeighbourWidth = Math.max(parseInt($(that.s.mouse.neighbourColumn.nTh).css('min-width')), 10); - //Store the previous width of the neighbour column - var prevNeighbourWidth = $(that.s.mouse.neighbourColumn.nTh).width(); - //As long as the width is larger than the minimum - var newColWidth = Math.max(minColumnWidth, prevWidth + dx); - var newColNeighbourWidth = Math.max(minColumnNeighbourWidth, prevNeighbourWidth - dx); - //Get the width difference (take into account the columns minimum width) - var widthDiff = newColWidth - prevWidth; - var widthDiffNeighbour = newColNeighbourWidth - prevNeighbourWidth; - //Get the column index for the column being changed - var colResizeIdx = parseInt(that.dom.resizeCol.attr("data-column-index")); - var neighbourColResizeIdx = parseInt(that.dom.resizeColNeighbour.attr("data-column-index")); - //Set datatable column widths - that.s.mouse.neighbourColumn.sWidthOrig = that.s.mouse.neighbourColumn.sWidth = that.s.mouse.neighbourColumn.width = newColNeighbourWidth + "px"; - that.s.mouse.targetColumn.sWidthOrig = that.s.mouse.targetColumn.sWidth = that.s.mouse.targetColumn.width = newColWidth + "px"; - //Get list of columns based on column index in all affected tables tables. This accounts for other plugins like FixedColumns - var domNeighbourCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + neighbourColResizeIdx + "']"); - var domCols = $(that.s.dt.nTableWrapper).find("th[data-column-index='" + colResizeIdx + "']"); - //If dx if positive (the width is getting larger) shrink the neighbour columns first - if(dx>0) { - domNeighbourCols.width(that.s.mouse.neighbourColumn.width); - domCols.width(that.s.mouse.targetColumn.width); - } else { - //Apply the new width to the columns then to the neighbour columns - domCols.width(that.s.mouse.targetColumn.width); - domNeighbourCols.width(that.s.mouse.neighbourColumn.width); - } - } + if (_this.dom.scrollX && data.colResize.tableSize > 0) { + _this.dom.scrollHeadTable.width(data.colResize.tableSize); + _this.dom.scrollHeadInner.width(data.colResize.tableSize); + _this.dom.scrollBodyTable.width(data.colResize.tableSize); + _this.dom.scrollFootTable.width(data.colResize.tableSize); } - } - that.s.mouse.startX = e.pageX; - }, - - /** - * Check to see if the mouse is over the resize handle area - * @param e - * @param nTh - */ - "_fnResizeHandleCheck": function (e, nTh) { - var that = this; - - var offset = $(nTh).offset(); - var relativeX = (e.pageX - offset.left); - var relativeY = (e.pageY - offset.top); - var distFromLeft = relativeX; - var distFromRight = $(nTh).outerWidth() - relativeX - 1; - - var handleBuffer = this.s.init.handleWidth / 2; - var leftHandleOn = distFromLeft < handleBuffer; - var rightHandleOn = distFromRight < handleBuffer; - - //If this is the first table cell - if ($(nTh).prev("th").length == 0) { - if(this.s.init.rtl) - rightHandleOn = false; - else - leftHandleOn = false; - } - //If this is the last cell and the table is fixed width don't let them expand the last cell directly - if ($(nTh).next("th").length == 0 && this.s.init.tableWidthFixed) { - if(this.s.init.rtl) - leftHandleOn = false; - else - rightHandleOn = false; - } - var resizeAvailable = leftHandleOn||rightHandleOn; - - //If table is in right to left mode flip which TH is being resized - if (that.s.init.rtl) { - //Handle is to the left - if (leftHandleOn) { - that.dom.resizeCol = $(nTh); - that.dom.resizeColNeighbour = $(nTh).next(); - } else if (rightHandleOn) { - that.dom.resizeCol = $(nTh).prev(); - that.dom.resizeColNeighbour = $(nTh); + for (i = 0; i < columns.length; i++) { + wMap[i] = columns[i]; } - } else { - //Handle is to the right - if (rightHandleOn) { - that.dom.resizeCol = $(nTh); - that.dom.resizeColNeighbour = $(nTh).next(); - } else if (leftHandleOn) { - that.dom.resizeCol = $(nTh).prev(); - that.dom.resizeColNeighbour = $(nTh); + for (i = 0; i < _this.dt.settings.aoColumns.length; i++) { + col = _this.dt.settings.aoColumns[i]; + var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; + col.sWidth = wMap[idx]; + col.sWidthOrig = wMap[idx]; + col.nTh.style.width = columns[i]; + + //Check for FixedHeader + if (col.fhTh) + col.fhTh.style.width = columns[i]; + if (col.fhTf) + col.fhTf.style.width = columns[i]; } + _this.dom.origState = false; } - //If table width is fixed make sure both columns are resizable else just check the one. - if(this.s.init.tableWidthFixed) - resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1 && this.s.init.exclude.indexOf(parseInt($(that.dom.resizeColNeighbour).attr("data-column-index"))) == -1; - else - resizeAvailable &= this.s.init.exclude.indexOf(parseInt($(that.dom.resizeCol).attr("data-column-index"))) == -1; - - $(nTh).off('mousedown.ColResize'); - if (resizeAvailable) { - $(nTh).css("cursor", "ew-resize"); - - //Delay other mousedown events from the Reorder plugin - that._fnDelayEvents(null, nTh, "mousedown", "ColReorder"); - that._fnDelayEvents("click", nTh, "click", "DT"); - - $(nTh).off('mousedown.ColResize').on('mousedown.ColResize', function (e) { - e.preventDefault(); - that._fnMouseDown.call(that, e, nTh); - }) - .off('click.ColResize').on('click.ColResize', function (e) { - that._fnClick.call(that, e); - }); - } else { - $(nTh).css("cursor", "pointer"); - $(nTh).off('mousedown.ColResize click.ColResize'); - //Restore any events that were removed - that._fnRestoreEvents(); - //This is to restore column sorting on click functionality - if (!that.s.isMousedown) - //Restore click event if mouse is not down - this._fnRestoreEvents("click"); + _this.dt.api.columns.adjust(); + if (_this.dom.scrollX || _this.dom.scrollY) + _this.dt.api.draw(false); + }; + + if (this.initialized) { + onInit(); + return; + } + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'colResizeInitCompleted', function () { + onInit(); + }, "ColResize_Init"); + }; + + ColResize.prototype.saveState = function (data) { + if (!this.dt.settings._bInitComplete) { + var oData = this.dt.settings.fnStateLoadCallback.call(this.dt.settings.oInstance, this.dt.settings); + if (oData && oData.colResize) + data.colResize = oData.colResize; + return; + } + this.updateTableSize(); + data.colResize = { + columns: [], + tableSize: this.tableSize + }; + + data.colResize.columns.length = this.dt.settings.aoColumns.length; + for (var i = 0; i < this.dt.settings.aoColumns.length; i++) { + var col = this.dt.settings.aoColumns[i]; + var idx = col._ColReorder_iOrigCol != null ? col._ColReorder_iOrigCol : i; + data.colResize.columns[idx] = col.sWidth; + } + }; + + ColResize.prototype.registerCallbacks = function () { + var _this = this; + /* State saving */ + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateSaveParams', function (oS, oData) { + _this.saveState(oData); + }, "ColResize_StateSave"); + + /* State loading */ + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'aoStateLoaded', function (oS, oData) { + _this.loadState(oData); + }, "ColResize_StateLoad"); + + if (this.$.fn.DataTable.models.oSettings.remoteStateInitCompleted !== undefined) { + //Integrate with remote state + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateLoadedParams', function (s, data) { + _this.loadState(data); + }, "ColResize_StateLoad"); + this.dt.settings.oApi._fnCallbackReg(this.dt.settings, 'remoteStateSaveParams', function (s, data) { + _this.saveState(data); + }, "ColResize_StateSave"); + } + }; + + ColResize.prototype.setTablesLayout = function (value) { + if (this.dom.scrollX || this.dom.scrollY) { + this.dom.scrollHeadTable.css('table-layout', value); + this.dom.scrollBodyTable.css('table-layout', value); + this.dom.scrollFootTable.css('table-layout', value); + } else { + this.$(this.dt.settings.nTable).css('table-layout', value); + } + this.dom.fixedLayout = value == 'fixed'; + }; + + //only when scrollX or scrollY are enabled + ColResize.prototype.fixFootAndHeadTables = function (e) { + var _this = this; + if (e != null && e.target !== this.dt.settings.nTable) + return; + + if (this.dom.scrollFootTable.length) { + this.$('thead', this.dom.scrollFootTable).remove(); + this.dom.scrollFootTable.prepend(this.$('thead', this.dom.scrollBodyTable).clone()); + } + this.$('tfoot', this.dom.scrollHeadTable).remove(); + this.dom.scrollHeadTable.append(this.$('tfoot', this.dom.scrollBodyTable).clone()); + var removeFooterWidth = function (table) { + _this.$('tfoot>tr>th', table).each(function (i, th) { + _this.$(th).css('width', ''); + }); + }; + + //Remove all tfoot headers widths + removeFooterWidth(this.dom.scrollFootTable); + removeFooterWidth(this.dom.scrollBodyTable); + removeFooterWidth(this.dom.scrollHeadTable); + }; + + ColResize.prototype.onDraw = function (e) { + if (e != null && e.target !== this.dt.settings.nTable) + return; + if (this.dom.scrollX || this.dom.scrollY) { + this.fixFootAndHeadTables(); + + //Fix the header table padding + if (this.dt.settings._bInitComplete) { + var borderWidth = this.dom.scrollHeadTable.outerWidth() - this.dom.scrollHeadTable.innerWidth(); + var paddingType = this.dt.settings.oBrowser.bScrollbarLeft ? 'padding-left' : 'padding-right'; + var paddingVal = parseFloat(this.dom.scrollHeadInner.css(paddingType)); + this.dom.scrollHeadInner.css(paddingType, (paddingVal + borderWidth) + 'px'); } - }, - - "_fnClick": function (e) { - var that = this; - that.s.isMousedown = false; - e.stopImmediatePropagation(); - }, - - /** - * Finish off the mouse drag - * @method _fnMouseUp - * @param e Mouse event - * @returns void - * @private - */ - "_fnMouseUp": function (e) { - var that = this; - that.s.isMousedown = false; - - //Fix width of column to be the size the dom is limited to (for when user sets min-width on a column) - that.s.mouse.targetColumn.width = that.dom.resizeCol.width(); - - $(document).off('mousemove.ColResize mouseup.ColResize'); - this.s.dt.oInstance.fnAdjustColumnSizing(); - //Table width fix, prevents extra gaps between tables - var LeftWrapper = $(that.s.dt.nTableWrapper).find(".DTFC_LeftWrapper"); - var DTFC_LeftWidth = LeftWrapper.width(); - LeftWrapper.children(".DTFC_LeftHeadWrapper").children("table").width(DTFC_LeftWidth); - - if (that.s.init.resizeCallback) { - that.s.init.resizeCallback.call(that, that.s.mouse.targetColumn); + } + + var autoWidthTypes = []; + if (this.settings.dblClick == 'autoMinFit' || !this.settings.fixedLayout) + autoWidthTypes.push('autoMinWidth'); + if (this.settings.dblClick == 'autoFit') + autoWidthTypes.push('autoWidth'); + + //Call this only once so that the table will be cloned only one time + if (autoWidthTypes.length) + this.updateColumnsAutoWidth(autoWidthTypes); + + if (!this.settings.fixedLayout) { + var columns = this.dt.settings.aoColumns; + var i; + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + columns[i].minWidth = Math.max((columns[i].minWidthOrig || 0), columns[i].autoMinWidth); + + //We have to resize if the current column width if is less that the column minWidth + if (this.$(columns[i].nTh).width() < columns[i].minWidth) + this.resize(columns[i], columns[i].minWidth); + } + } else { + if (!this.dom.fixedLayout) { + this.setTablesLayout('fixed'); + this.afterResizing(); } - }, - - /** - * Clean up ColResize memory references and event handlers - * @method _fnDestroy - * @returns void - * @private - */ - "_fnDestroy": function () { - var i, iLen; - - for (i = 0, iLen = this.s.dt.aoDrawCallback.length; i < iLen; i++) { - if (this.s.dt.aoDrawCallback[i].sName === 'ColResize_Pre') { - this.s.dt.aoDrawCallback.splice(i, 1); + } + }; + + ColResize.prototype.getTableAutoColWidths = function (table, types) { + var widths = {}, i, colIdx; + var $table = this.$(table); + for (i = 0; i < types.length; i++) { + widths[types[i]] = []; + } + if (!types.length || !$table.length) + return widths; + + var clnTable = $table.clone().removeAttr('id').css('table-layout', 'auto'); + + // Remove any assigned widths from the footer (from scrolling) + clnTable.find('thead th, tfoot th, tfoot td').css('width', ''); + var container = this.$('<div />').css({ + 'position': 'absolute', + 'width': '9999px', + 'height': '9999px' + }); + container.append(clnTable); + this.$(this.dt.settings.nTableWrapper).append(container); + + var headerCols = this.$('thead>tr>th', clnTable); + + for (i = 0; i < types.length; i++) { + var type = types[i]; + var fn = ''; + switch (type) { + case 'autoMinWidth': + clnTable.css('width', '1px'); + fn = 'width'; break; + case 'autoWidth': + clnTable.css('width', 'auto'); + fn = 'outerWidth'; + break; + default: + throw 'Invalid widthType ' + type; + } + for (colIdx = 0; colIdx < headerCols.length; colIdx++) { + widths[type].push(this.$(headerCols[colIdx])[fn]()); + } + } + + container.remove(); + return widths; + }; + + ColResize.prototype.updateColumnsAutoWidth = function (types) { + var columns = this.dt.settings.aoColumns; + var i, j, colLen, type, visColIdx = 0; + var widths = {}; + if (this.dom.scrollX || this.dom.scrollY) { + var headWidths = this.getTableAutoColWidths(this.dom.scrollHeadTable, types); + var bodyWidths = this.getTableAutoColWidths(this.dom.scrollBodyTable, types); + var footWidths = this.getTableAutoColWidths(this.dom.scrollFootTable, types); + + for (i = 0; i < types.length; i++) { + type = types[i]; + widths[type] = []; + footWidths[type].length = headWidths[type].length; + colLen = headWidths[type].length; + for (j = 0; j < colLen; j++) { + widths[type].push(Math.max(headWidths[type][j], bodyWidths[type][j], (footWidths[type][j] || 0))); } } + } else { + widths = this.getTableAutoColWidths(this.dt.settings.nTable, types); + } + + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + for (j = 0; j < types.length; j++) { + type = types[j]; + columns[i][type] = widths[type][visColIdx]; + } + visColIdx++; + } + }; - $(this.s.dt.nTHead).find('*').off('.ColResize'); + ColResize.prototype.overrideClickHander = function (col, $th) { + var dtClickEvent = this.getColumnEvent($th.get(0), 'click', 'DT'); - $.each(this.s.dt.aoColumns, function (i, column) { - $(column.nTh).removeAttr('data-column-index'); + //Remove the DataTables event so that ordering will not occur + if (dtClickEvent) { + $th.off('click.DT'); + this.$(document).one('click.ColResize', function (e) { + $th.on('click.DT', dtClickEvent.handler); }); + } + }; - this.s.dt._colResize = null; - this.s = null; - }, + ColResize.prototype.onDblClick = function (e, $th, col) { + if (e.target !== $th.get(0)) + return; + if ($th.css('cursor') != 'col-resize') + return; + + var width; + switch (this.settings.dblClick) { + case 'autoMinFit': + width = col.autoMinWidth; + break; + case 'autoFit': + width = col.autoWidth; + break; + default: + width = col.initWidth; + } + this.resize(col, width); + }; + ColResize.prototype.onMouseDown = function (e, col) { + var _this = this; + if (e.target !== col.nTh && e.target !== col.fhTh) + return true; - /** - * 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); - }); + var $th = e.target === col.nTh ? this.$(col.nTh) : this.$(col.fhTh); + + if ($th.css('cursor') != 'col-resize' || col.resizable === false) { + var colReorder = this.dt.settings._colReorder; + if (colReorder) { + colReorder._fnMouseDown.call(colReorder, e, e.target); //Here we fix the e.preventDefault() in ColReorder so that we can have working inputs in header + } + return true; + } + this.dom.mouse.startX = e.pageX; + this.dom.mouse.prevX = e.pageX; + this.dom.mouse.startWidth = $th.width(); + this.dom.resize = true; + + this.beforeResizing(col); + + /* Add event handlers to the document */ + this.$(document).on('mousemove.ColResize', function (event) { + _this.onMouseMove(event, col); + }); + this.overrideClickHander(col, $th); + this.$(document).one('mouseup.ColResize', function (event) { + _this.onMouseUp(event, col); + }); + + return false; + }; + + ColResize.prototype.resize = function (col, width) { + var colWidth = this.$(col.nTh).width(); + var moveLength = width - this.$(col.nTh).width(); + this.beforeResizing(col); + var resized = this.resizeColumn(col, colWidth, moveLength, moveLength); + this.afterResizing(); + return resized; + }; + + ColResize.prototype.beforeResizing = function (col) { + //if (this.settings.fixedLayout && !this.dom.fixedLayout) + // this.setTablesLayout('fixed'); + }; + + ColResize.prototype.afterResizing = function () { + var i; + var columns = this.dt.settings.aoColumns; + for (i = 0; i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + columns[i].sWidth = this.$(columns[i].nTh).css('width'); } + + //Update the internal storage of the table's width (in case we changed it because the user resized some column and scrollX was enabled + this.updateTableSize(); + + //Save the state + this.dt.settings.oInstance.oApi._fnSaveState(this.dt.settings); + this.dom.origState = false; }; + ColResize.prototype.onMouseUp = function (e, col) { + this.$(document).off('mousemove.ColResize'); + if (!this.dom.resize) + return; + this.dom.resize = false; + this.afterResizing(); + }; - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Static parameters - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - - /** - * ColResize default settings for initialisation - * @namespace - * @static - */ - ColResize.defaults = { - /** - * Callback function that is fired when columns are resized - * @type function():void - * @default null - * @static - */ - "resizeCallback": null, - - /** - * Exclude array for columns that are not resizable - * @property exclude - * @type array of indexes that are excluded from resizing - * @default [] - */ - "exclude": [], - - /** - * Check to see if user is using a fixed table width or dynamic - * if true: - * -Columns will resize themselves and their neighbour - * -If neighbour is excluded resize will not occur - * if false: - * -Columns will resize themselves and increase or decrease the width of the table accordingly - */ - "tableWidthFixed": true, - - /** - * Width of the resize handle in pixels - * @property handleWidth - * @type int (pixels) - * @default 10 - */ - "handleWidth": 10, - - /** - * Right to left support, when true flips which column they are resizing on mouse down - * @property rtl - * @type bool - * @default false - */ - "rtl": false - }; - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constants - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * ColResize version - * @constant version - * @type String - * @default As code - */ - ColResize.version = "0.0.10"; - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables interfaces - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - // Expose - $.fn.dataTable.ColResize = ColResize; - $.fn.DataTable.ColResize = ColResize; - - - // Register a new feature with DataTables - if (typeof $.fn.dataTable == "function" && - typeof $.fn.dataTableExt.fnVersionCheck == "function" && - $.fn.dataTableExt.fnVersionCheck('1.9.3')) { - $.fn.dataTableExt.aoFeatures.push({ - "fnInit": function (settings) { - var table = settings.oInstance; - - if (!settings._colResize) { - var dtInit = settings.oInit; - var opts = dtInit.colResize || dtInit.oColResize || {}; - - new ColResize(settings, opts); - } - else { - table.oApi._fnLog(settings, 1, "ColResize attempted to initialise twice. Ignoring second"); + ColResize.prototype.canResizeColumn = function (col, newWidth) { + return (col.resizable === undefined || col.resizable) && this.settings.minWidth <= newWidth && (!col.minWidth || col.minWidth <= newWidth) && (!this.settings.maxWidth || this.settings.maxWidth >= newWidth) && (!col.maxWidth || col.maxWidth >= newWidth); + }; + + ColResize.prototype.getColumnMaxWidth = function (col) { + return col.maxWidth ? col.maxWidth : this.settings.maxWidth; + }; + + ColResize.prototype.getColumnMinWidth = function (col) { + return col.minWidth ? col.minWidth : this.settings.minWidth; + }; + + ColResize.prototype.getPrevResizableColumnIdx = function (col, moveLength) { + var columns = this.dt.settings.aoColumns; + var colIdx = ColResizeHelper.indexOf(columns, col); + for (var i = colIdx; i >= 0; i--) { + if (!columns[i].bVisible) + continue; + var newWidth = this.$(columns[i].nTh).width() + moveLength; + if (this.canResizeColumn(columns[i], newWidth)) + return i; + } + return -1; + }; + + ColResize.prototype.getNextResizableColumnIdx = function (col, moveLength) { + var columns = this.dt.settings.aoColumns; + var colIdx = ColResizeHelper.indexOf(columns, col); + for (var i = (colIdx + 1); i < columns.length; i++) { + if (!columns[i].bVisible) + continue; + var newWidth = this.$(columns[i].nTh).width() - moveLength; + if (this.canResizeColumn(columns[i], newWidth)) + return i; + } + return -1; + }; + + ColResize.prototype.resizeColumn = function (col, startWidth, moveLength, lastMoveLength) { + if (moveLength == 0 || lastMoveLength == 0 || col.resizable === false) + return false; + var i; + var columns = this.dt.settings.aoColumns; + var headCol = this.$(col.nTh); + var headColNext = headCol.next(); + var colIdx = this.getColumnIndex(col); + var thWidth = startWidth + moveLength; + var thNextWidth; + var nextColIdx; + + if (!this.dom.scrollX) { + if (lastMoveLength < 0) { + thWidth = headColNext.width() - lastMoveLength; + nextColIdx = this.getPrevResizableColumnIdx(col, lastMoveLength); + if (nextColIdx < 0) + return false; + headCol = headColNext; + colIdx = colIdx + 1; + headColNext = this.$(columns[nextColIdx].nTh); + thNextWidth = headColNext.width() + lastMoveLength; + } else { + thWidth = headCol.width() + lastMoveLength; + nextColIdx = this.getNextResizableColumnIdx(col, lastMoveLength); + + //If there is no columns that can be shrinked dont resize anymore + if (nextColIdx < 0) + return false; + headColNext = this.$(columns[nextColIdx].nTh); + thNextWidth = headColNext.width() - lastMoveLength; + + if ((this.settings.maxWidth && this.settings.maxWidth < thWidth) || col.maxWidth && col.maxWidth < thWidth) + return false; + } + if (!this.canResizeColumn(columns[nextColIdx], thNextWidth) || !this.canResizeColumn(columns[colIdx], thWidth)) + return false; + headColNext.width(thNextWidth); + + //If fixed header is present we have to resize the cloned column too + if (this.dom.fixedHeader) { + this.$(columns[nextColIdx].fhTh).width(thNextWidth); + this.$(columns[colIdx].fhTh).width(thWidth); + + //If fixedfooter was enabled resize that too + if (columns[nextColIdx].fhTf) { + this.$(columns[nextColIdx].fhTf).width(thNextWidth); + this.$(columns[colIdx].fhTf).width(thWidth); } + } + } else { + if (!this.canResizeColumn(col, thWidth)) + return false; + var tSize = this.tableSize + moveLength + 'px'; + this.dom.scrollHeadInner.css('width', tSize); + this.dom.scrollHeadTable.css('width', tSize); + this.dom.scrollBodyTable.css('width', tSize); + this.dom.scrollFootTable.css('width', tSize); + } + headCol.width(thWidth); + + //scrollX or scrollY enabled + if (this.dom.scrollBody.length) { + var colDomIdx = 0; + for (i = 0; i < this.dt.settings.aoColumns.length && i != colIdx; i++) { + if (this.dt.settings.aoColumns[i].bVisible) + colDomIdx++; + } - return null; - /* No node for DataTables to insert */ - }, - "cFeature": "Z", - "sFeature": "ColResize" - }); - } else { - alert("Warning: ColResize requires DataTables 1.9.3 or greater - www.datatables.net/download"); - } + //Get the table + var bodyCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollBodyTable); + var footCol = this.$('thead>tr>th:nth(' + colDomIdx + ')', this.dom.scrollFootTable); + //This will happen only when scrollY is used without scrollX + if (!this.dom.scrollX) { + var nextColDomIdx = 0; + for (i = 0; i < this.dt.settings.aoColumns.length && i != nextColIdx; i++) { + if (this.dt.settings.aoColumns[i].bVisible) + nextColDomIdx++; + } + var bodyColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollBodyTable); + var footColNext = this.$('thead>tr>th:nth(' + nextColDomIdx + ')', this.dom.scrollFootTable); -// API augmentation - if ($.fn.dataTable.Api) { - $.fn.dataTable.Api.register('colResize.reset()', function () { - return this.iterator('table', function (ctx) { - ctx._colResize.fnReset(); - }); - }); - } + bodyColNext.width(thNextWidth); + if (thWidth > 0) + bodyCol.width(thWidth); - return ColResize; - }; // /factory + footColNext.width(thNextWidth); + if (thWidth > 0) + footCol.width(thWidth); + } + //Resize the table and the column + if (this.dom.scrollX && thWidth > 0) { + bodyCol.width(thWidth); + footCol.width(thWidth); + } + } + return true; + }; -// Define as an AMD module if possible -if ( typeof define === 'function' && define.amd ) { - define( ['jquery', 'datatables'], factory ); -} -else if ( typeof exports === 'object' ) { - // Node/CommonJS - factory( require('jquery'), require('datatables') ); -} -else if (jQuery && !jQuery.fn.dataTable.ColResize) { - // Otherwise simply initialise as normal, stopping multiple evaluation - factory(jQuery, jQuery.fn.dataTable); -} + ColResize.prototype.onMouseMove = function (e, col) { + var moveLength = e.pageX - this.dom.mouse.startX; + var lastMoveLength = e.pageX - this.dom.mouse.prevX; + this.resizeColumn(col, this.dom.mouse.startWidth, moveLength, lastMoveLength); + this.dom.mouse.prevX = e.pageX; + }; + ColResize.prototype.destroy = function () { + }; + ColResize.defaultSettings = { + minWidth: 1, + maxWidth: null, + fixedLayout: true, + fixedHeader: null, + dblClick: 'initWidth' + }; + return ColResize; + })(); + dt.ColResize = ColResize; -})(window, document);
\ No newline at end of file + var ColResizeHelper = (function () { + function ColResizeHelper() { + } + ColResizeHelper.indexOf = function (arr, item, equalFun) { + if (typeof equalFun === "undefined") { equalFun = null; } + for (var i = 0; i < arr.length; i++) { + if (equalFun) { + if (equalFun(arr[i], item)) + return i; + } else if (arr[i] === item) + return i; + } + return -1; + }; + return ColResizeHelper; + })(); + dt.ColResizeHelper = ColResizeHelper; +})(dt || (dt = {})); + +(function ($, window, document, undefined) { + //Register events + $.fn.DataTable.models.oSettings.colResizeInitCompleted = []; + + //Register api function + $.fn.DataTable.Api.register('colResize.init()', function (settings) { + var colResize = new dt.ColResize($, this, settings); + if (this.settings()[0]._bInitComplete) + colResize.initialize(); + else + this.one('init.dt', function () { + colResize.initialize(); + }); + return null; + }); + + $.fn.DataTable.Api.register('column().resize()', function (width) { + var oSettings = this.settings()[0]; + var colResize = oSettings.colResize; + return colResize.resize(oSettings.aoColumns[this[0][0]], width); + }); + + //Add as feature + $.fn.dataTable.ext.feature.push({ + "fnInit": function (oSettings) { + return oSettings.oInstance.api().colResize.init(oSettings.oInit.colResize); + }, + "cFeature": "J", + "sFeature": "ColResize" + }); +}(jQuery, window, document, undefined));
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css new file mode 100644 index 00000000..4001ab12 --- /dev/null +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css @@ -0,0 +1,4 @@ +div.FixedHeader_Cloned th, +div.FixedHeader_Cloned td { + background-color: white !important; +} diff --git a/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js new file mode 100644 index 00000000..c1f962c4 --- /dev/null +++ b/wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js @@ -0,0 +1,1027 @@ +/*! FixedHeader 2.1.2 + * ©2010-2014 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary FixedHeader + * @description Fix a table's header or footer, so it is always visible while + * Scrolling + * @version 2.1.2 + * @file dataTables.fixedHeader.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2009-2014 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 + */ + +/* Global scope for FixedColumns for backwards compatibility - will be removed + * in future. Not documented in 1.1.x. + */ + +/* Global scope for FixedColumns */ +var FixedHeader; + +(function(window, document, undefined) { + + +var factory = function( $, DataTable ) { +"use strict"; + +/* + * Function: FixedHeader + * Purpose: Provide 'fixed' header, footer and columns for a DataTable + * Returns: object:FixedHeader - must be called with 'new' + * Inputs: mixed:mTable - target table + * @param {object} dt DataTables instance or HTML table node. With DataTables + * 1.10 this can also be a jQuery collection (with just a single table in its + * result set), a jQuery selector, DataTables API instance or settings + * object. + * @param {object} [oInit] initialisation settings, with the following + * properties (each optional) + * * bool:top - fix the header (default true) + * * bool:bottom - fix the footer (default false) + * * int:left - fix the left column(s) (default 0) + * * int:right - fix the right column(s) (default 0) + * * int:zTop - fixed header zIndex + * * int:zBottom - fixed footer zIndex + * * int:zLeft - fixed left zIndex + * * int:zRight - fixed right zIndex + */ +FixedHeader = function ( mTable, oInit ) { + /* Sanity check - you just know it will happen */ + if ( ! this instanceof FixedHeader ) + { + alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." ); + return; + } + + var that = this; + var oSettings = { + "aoCache": [], + "oSides": { + "top": true, + "bottom": false, + "left": 0, + "right": 0 + }, + "oZIndexes": { + "top": 104, + "bottom": 103, + "left": 102, + "right": 101 + }, + "oCloneOnDraw": { + "top": false, + "bottom": false, + "left": true, + "right": true + }, + "oMes": { + "iTableWidth": 0, + "iTableHeight": 0, + "iTableLeft": 0, + "iTableRight": 0, /* note this is left+width, not actually "right" */ + "iTableTop": 0, + "iTableBottom": 0 /* note this is top+height, not actually "bottom" */ + }, + "oOffset": { + "top": 0 + }, + "nTable": null, + "bFooter": false, + "bInitComplete": false + }; + + /* + * Function: fnGetSettings + * Purpose: Get the settings for this object + * Returns: object: - settings object + * Inputs: - + */ + this.fnGetSettings = function () { + return oSettings; + }; + + /* + * Function: fnUpdate + * Purpose: Update the positioning and copies of the fixed elements + * Returns: - + * Inputs: - + */ + this.fnUpdate = function () { + this._fnUpdateClones(); + this._fnUpdatePositions(); + }; + + /* + * Function: fnPosition + * Purpose: Update the positioning of the fixed elements + * Returns: - + * Inputs: - + */ + this.fnPosition = function () { + this._fnUpdatePositions(); + }; + + + var dt = $.fn.dataTable.Api ? + new $.fn.dataTable.Api( mTable ).settings()[0] : + mTable.fnSettings(); + + dt._oPluginFixedHeader = this; + + /* Let's do it */ + this.fnInit( dt, oInit ); + +}; + + +/* + * Variable: FixedHeader + * Purpose: Prototype for FixedHeader + * Scope: global + */ +FixedHeader.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Initialisation + */ + + /* + * Function: fnInit + * Purpose: The "constructor" + * Returns: - + * Inputs: {as FixedHeader function} + */ + fnInit: function ( oDtSettings, oInit ) + { + var s = this.fnGetSettings(); + var that = this; + + /* Record the user definable settings */ + this.fnInitSettings( s, oInit ); + + if ( oDtSettings.oScroll.sX !== "" || oDtSettings.oScroll.sY !== "" ) + { + alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" ); + return; + } + + s.nTable = oDtSettings.nTable; + oDtSettings.aoDrawCallback.unshift( { + "fn": function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones.call(that); + that._fnUpdatePositions.call(that); + }, + "sName": "FixedHeader" + } ); + + s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false; + + /* Add the 'sides' that are fixed */ + if ( s.oSides.top ) + { + s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) ); + } + if ( s.oSides.bottom ) + { + s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) ); + } + if ( s.oSides.left ) + { + s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft, s.oSides.left ) ); + } + if ( s.oSides.right ) + { + s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight, s.oSides.right ) ); + } + + /* Event listeners for window movement */ + FixedHeader.afnScroll.push( function () { + that._fnUpdatePositions.call(that); + } ); + + $(window).resize( function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones.call(that); + that._fnUpdatePositions.call(that); + } ); + + $(s.nTable) + .on('column-reorder.dt', function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones( true ); + that._fnUpdatePositions(); + } ) + .on('column-visibility.dt', function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones( true ); + that._fnUpdatePositions(); + } ); + + /* Get things right to start with */ + FixedHeader.fnMeasure(); + that._fnUpdateClones(); + that._fnUpdatePositions(); + + s.bInitComplete = true; + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Support functions + */ + + /* + * Function: fnInitSettings + * Purpose: Take the user's settings and copy them to our local store + * Returns: - + * Inputs: object:s - the local settings object + * object:oInit - the user's settings object + */ + fnInitSettings: function ( s, oInit ) + { + if ( oInit !== undefined ) + { + if ( oInit.top !== undefined ) { + s.oSides.top = oInit.top; + } + if ( oInit.bottom !== undefined ) { + s.oSides.bottom = oInit.bottom; + } + if ( typeof oInit.left == 'boolean' ) { + s.oSides.left = oInit.left ? 1 : 0; + } + else if ( oInit.left !== undefined ) { + s.oSides.left = oInit.left; + } + if ( typeof oInit.right == 'boolean' ) { + s.oSides.right = oInit.right ? 1 : 0; + } + else if ( oInit.right !== undefined ) { + s.oSides.right = oInit.right; + } + + if ( oInit.zTop !== undefined ) { + s.oZIndexes.top = oInit.zTop; + } + if ( oInit.zBottom !== undefined ) { + s.oZIndexes.bottom = oInit.zBottom; + } + if ( oInit.zLeft !== undefined ) { + s.oZIndexes.left = oInit.zLeft; + } + if ( oInit.zRight !== undefined ) { + s.oZIndexes.right = oInit.zRight; + } + + if ( oInit.offsetTop !== undefined ) { + s.oOffset.top = oInit.offsetTop; + } + if ( oInit.alwaysCloneTop !== undefined ) { + s.oCloneOnDraw.top = oInit.alwaysCloneTop; + } + if ( oInit.alwaysCloneBottom !== undefined ) { + s.oCloneOnDraw.bottom = oInit.alwaysCloneBottom; + } + if ( oInit.alwaysCloneLeft !== undefined ) { + s.oCloneOnDraw.left = oInit.alwaysCloneLeft; + } + if ( oInit.alwaysCloneRight !== undefined ) { + s.oCloneOnDraw.right = oInit.alwaysCloneRight; + } + } + }, + + /* + * Function: _fnCloneTable + * Purpose: Clone the table node and do basic initialisation + * Returns: - + * Inputs: - + */ + _fnCloneTable: function ( sType, sClass, fnClone, iCells ) + { + var s = this.fnGetSettings(); + var nCTable; + + /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how + * DataTables works. Therefore, we can set this to be relatively position (if it is not + * alreadu absolute, and use this as the base point for the cloned header + */ + if ( $(s.nTable.parentNode).css('position') != "absolute" ) + { + s.nTable.parentNode.style.position = "relative"; + } + + /* Just a shallow clone will do - we only want the table node */ + nCTable = s.nTable.cloneNode( false ); + nCTable.removeAttribute( 'id' ); + + var nDiv = document.createElement( 'div' ); + nDiv.style.position = "absolute"; + nDiv.style.top = "0px"; + nDiv.style.left = "0px"; + nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass; + + /* Set the zIndexes */ + if ( sType == "fixedHeader" ) + { + nDiv.style.zIndex = s.oZIndexes.top; + } + if ( sType == "fixedFooter" ) + { + nDiv.style.zIndex = s.oZIndexes.bottom; + } + if ( sType == "fixedLeft" ) + { + nDiv.style.zIndex = s.oZIndexes.left; + } + else if ( sType == "fixedRight" ) + { + nDiv.style.zIndex = s.oZIndexes.right; + } + + /* remove margins since we are going to position it absolutely */ + nCTable.style.margin = "0"; + + /* Insert the newly cloned table into the DOM, on top of the "real" header */ + nDiv.appendChild( nCTable ); + document.body.appendChild( nDiv ); + + return { + "nNode": nCTable, + "nWrapper": nDiv, + "sType": sType, + "sPosition": "", + "sTop": "", + "sLeft": "", + "fnClone": fnClone, + "iCells": iCells + }; + }, + + /* + * Function: _fnMeasure + * Purpose: Get the current positioning of the table in the DOM + * Returns: - + * Inputs: - + */ + _fnMeasure: function () + { + var + s = this.fnGetSettings(), + m = s.oMes, + jqTable = $(s.nTable), + oOffset = jqTable.offset(), + iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ), + iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' ); + + m.iTableWidth = jqTable.outerWidth(); + m.iTableHeight = jqTable.outerHeight(); + m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft; + m.iTableTop = oOffset.top + iParentScrollTop; + m.iTableRight = m.iTableLeft + m.iTableWidth; + m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth; + m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight; + }, + + /* + * Function: _fnSumScroll + * Purpose: Sum node parameters all the way to the top + * Returns: int: sum + * Inputs: node:n - node to consider + * string:side - scrollTop or scrollLeft + */ + _fnSumScroll: function ( n, side ) + { + var i = n[side]; + while ( n = n.parentNode ) + { + if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' ) + { + break; + } + i = n[side]; + } + return i; + }, + + /* + * Function: _fnUpdatePositions + * Purpose: Loop over the fixed elements for this table and update their positions + * Returns: - + * Inputs: - + */ + _fnUpdatePositions: function () + { + var s = this.fnGetSettings(); + this._fnMeasure(); + + for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) + { + if ( s.aoCache[i].sType == "fixedHeader" ) + { + this._fnScrollFixedHeader( s.aoCache[i] ); + } + else if ( s.aoCache[i].sType == "fixedFooter" ) + { + this._fnScrollFixedFooter( s.aoCache[i] ); + } + else if ( s.aoCache[i].sType == "fixedLeft" ) + { + this._fnScrollHorizontalLeft( s.aoCache[i] ); + } + else + { + this._fnScrollHorizontalRight( s.aoCache[i] ); + } + } + }, + + /* + * Function: _fnUpdateClones + * Purpose: Loop over the fixed elements for this table and call their cloning functions + * Returns: - + * Inputs: - + */ + _fnUpdateClones: function ( full ) + { + var s = this.fnGetSettings(); + + if ( full ) { + // This is a little bit of a hack to force a full clone draw. When + // `full` is set to true, we want to reclone the source elements, + // regardless of the clone-on-draw settings + s.bInitComplete = false; + } + + for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) + { + s.aoCache[i].fnClone.call( this, s.aoCache[i] ); + } + + if ( full ) { + s.bInitComplete = true; + } + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Scrolling functions + */ + + /* + * Function: _fnScrollHorizontalLeft + * Purpose: Update the positioning of the scrolling elements + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnScrollHorizontalRight: function ( oCache ) + { + var + s = this.fnGetSettings(), + oMes = s.oMes, + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc, + nTable = oCache.nWrapper, + iFixedWidth = $(nTable).outerWidth(); + + if ( oWin.iScrollRight < oMes.iTableRight ) + { + /* Fully right aligned */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iFixedWidth)+"px", 'left', nTable.style ); + } + else if ( oMes.iTableLeft < oDoc.iWidth-oWin.iScrollRight-iFixedWidth ) + { + /* Middle */ + this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oWin.iWidth-iFixedWidth)+"px", 'left', nTable.style ); + } + else + { + /* Fully left aligned */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + }, + + /* + * Function: _fnScrollHorizontalLeft + * Purpose: Update the positioning of the scrolling elements + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnScrollHorizontalLeft: function ( oCache ) + { + var + s = this.fnGetSettings(), + oMes = s.oMes, + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc, + nTable = oCache.nWrapper, + iCellWidth = $(nTable).outerWidth(); + + if ( oWin.iScrollLeft < oMes.iTableLeft ) + { + /* Fully left align */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else if ( oWin.iScrollLeft < oMes.iTableLeft+oMes.iTableWidth-iCellWidth ) + { + this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', "0px", 'left', nTable.style ); + } + else + { + /* Fully right align */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iCellWidth)+"px", 'left', nTable.style ); + } + }, + + /* + * Function: _fnScrollFixedFooter + * Purpose: Update the positioning of the scrolling elements + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnScrollFixedFooter: function ( oCache ) + { + var + s = this.fnGetSettings(), + oMes = s.oMes, + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc, + nTable = oCache.nWrapper, + iTheadHeight = $("thead", s.nTable).outerHeight(), + iCellHeight = $(nTable).outerHeight(); + + if ( oWin.iScrollBottom < oMes.iTableBottom ) + { + /* Below */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+oMes.iTableHeight-iCellHeight)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else if ( oWin.iScrollBottom < oMes.iTableBottom+oMes.iTableHeight-iCellHeight-iTheadHeight ) + { + this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oWin.iHeight-iCellHeight)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); + } + else + { + /* Above */ + this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iCellHeight)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + }, + + /* + * Function: _fnScrollFixedHeader + * Purpose: Update the positioning of the scrolling elements + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnScrollFixedHeader: function ( oCache ) + { + var + s = this.fnGetSettings(), + oMes = s.oMes, + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc, + nTable = oCache.nWrapper, + iTbodyHeight = 0, + anTbodies = s.nTable.getElementsByTagName('tbody'); + + for (var i = 0; i < anTbodies.length; ++i) { + iTbodyHeight += anTbodies[i].offsetHeight; + } + + if ( oMes.iTableTop > oWin.iScrollTop + s.oOffset.top ) + { + /* Above the table */ + this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight ) + { + /* At the bottom of the table */ + this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else + { + /* In the middle of the table */ + this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); + } + }, + + /* + * Function: _fnUpdateCache + * Purpose: Check the cache and update cache and value if needed + * Returns: - + * Inputs: object:oCache - local cache object + * string:sCache - cache property + * string:sSet - value to set + * string:sProperty - object property to set + * object:oObj - object to update + */ + _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj ) + { + if ( oCache[sCache] != sSet ) + { + oObj[sProperty] = sSet; + oCache[sCache] = sSet; + } + }, + + + + /** + * Copy the classes of all child nodes from one element to another. This implies + * that the two have identical structure - no error checking is performed to that + * fact. + * @param {element} source Node to copy classes from + * @param {element} dest Node to copy classes too + */ + _fnClassUpdate: function ( source, dest ) + { + var that = this; + + if ( source.nodeName.toUpperCase() === "TR" || source.nodeName.toUpperCase() === "TH" || + source.nodeName.toUpperCase() === "TD" || source.nodeName.toUpperCase() === "SPAN" ) + { + dest.className = source.className; + } + + $(source).children().each( function (i) { + that._fnClassUpdate( $(source).children()[i], $(dest).children()[i] ); + } ); + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Cloning functions + */ + + /* + * Function: _fnCloneThead + * Purpose: Clone the thead element + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnCloneThead: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + + if ( s.bInitComplete && !s.oCloneOnDraw.top ) + { + this._fnClassUpdate( $('thead', s.nTable)[0], $('thead', nTable)[0] ); + return; + } + + /* Set the wrapper width to match that of the cloned table */ + var iDtWidth = $(s.nTable).outerWidth(); + oCache.nWrapper.style.width = iDtWidth+"px"; + nTable.style.width = iDtWidth+"px"; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + $('thead th', nTable).unbind( 'click' ); + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Clone the DataTables header */ + var nThead = $('thead', s.nTable).clone(true)[0]; + nTable.appendChild( nThead ); + + /* Copy the widths across - apparently a clone isn't good enough for this */ + var a = []; + var b = []; + + $("thead>tr th", s.nTable).each( function (i) { + a.push( $(this).width() ); + } ); + + $("thead>tr td", s.nTable).each( function (i) { + b.push( $(this).width() ); + } ); + + $("thead>tr th", s.nTable).each( function (i) { + $("thead>tr th:eq("+i+")", nTable).width( a[i] ); + $(this).width( a[i] ); + } ); + + $("thead>tr td", s.nTable).each( function (i) { + $("thead>tr td:eq("+i+")", nTable).width( b[i] ); + $(this).width( b[i] ); + } ); + + // Stop DataTables 1.9 from putting a focus ring on the headers when + // clicked to sort + $('th.sorting, th.sorting_desc, th.sorting_asc', nTable).bind( 'click', function () { + this.blur(); + } ); + }, + + /* + * Function: _fnCloneTfoot + * Purpose: Clone the tfoot element + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnCloneTfoot: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + + /* Set the wrapper width to match that of the cloned table */ + oCache.nWrapper.style.width = $(s.nTable).outerWidth()+"px"; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Clone the DataTables footer */ + var nTfoot = $('tfoot', s.nTable).clone(true)[0]; + nTable.appendChild( nTfoot ); + + /* Copy the widths across - apparently a clone isn't good enough for this */ + $("tfoot:eq(0)>tr th", s.nTable).each( function (i) { + $("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( $(this).width() ); + } ); + + $("tfoot:eq(0)>tr td", s.nTable).each( function (i) { + $("tfoot:eq(0)>tr td:eq("+i+")", nTable).width( $(this).width() ); + } ); + }, + + /* + * Function: _fnCloneTLeft + * Purpose: Clone the left column(s) + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnCloneTLeft: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + var nBody = $('tbody', s.nTable)[0]; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Is this the most efficient way to do this - it looks horrible... */ + nTable.appendChild( $("thead", s.nTable).clone(true)[0] ); + nTable.appendChild( $("tbody", s.nTable).clone(true)[0] ); + if ( s.bFooter ) + { + nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] ); + } + + /* Remove unneeded cells */ + var sSelector = 'gt(' + (oCache.iCells - 1) + ')'; + $('thead tr', nTable).each( function (k) { + $('th:' + sSelector, this).remove(); + } ); + + $('tfoot tr', nTable).each( function (k) { + $('th:' + sSelector, this).remove(); + } ); + + $('tbody tr', nTable).each( function (k) { + $('td:' + sSelector, this).remove(); + } ); + + this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable ); + this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); + this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable ); + + var iWidth = 0; + for (var i = 0; i < oCache.iCells; i++) { + iWidth += $('thead tr th:eq(' + i + ')', s.nTable).outerWidth(); + } + nTable.style.width = iWidth+"px"; + oCache.nWrapper.style.width = iWidth+"px"; + }, + + /* + * Function: _fnCloneTRight + * Purpose: Clone the right most column(s) + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnCloneTRight: function ( oCache ) + { + var s = this.fnGetSettings(); + var nBody = $('tbody', s.nTable)[0]; + var nTable = oCache.nNode; + var iCols = $('tbody tr:eq(0) td', s.nTable).length; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Is this the most efficient way to do this - it looks horrible... */ + nTable.appendChild( $("thead", s.nTable).clone(true)[0] ); + nTable.appendChild( $("tbody", s.nTable).clone(true)[0] ); + if ( s.bFooter ) + { + nTable.appendChild( $("tfoot", s.nTable).clone(true)[0] ); + } + $('thead tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove(); + $('tfoot tr th:lt('+(iCols-oCache.iCells)+')', nTable).remove(); + + /* Remove unneeded cells */ + $('tbody tr', nTable).each( function (k) { + $('td:lt('+(iCols-oCache.iCells)+')', this).remove(); + } ); + + this.fnEqualiseHeights( 'thead', nBody.parentNode, nTable ); + this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); + this.fnEqualiseHeights( 'tfoot', nBody.parentNode, nTable ); + + var iWidth = 0; + for (var i = 0; i < oCache.iCells; i++) { + iWidth += $('thead tr th:eq('+(iCols-1-i)+')', s.nTable).outerWidth(); + } + nTable.style.width = iWidth+"px"; + oCache.nWrapper.style.width = iWidth+"px"; + }, + + + /** + * Equalise the heights of the rows in a given table node in a cross browser way. Note that this + * is more or less lifted as is from FixedColumns + * @method fnEqualiseHeights + * @returns void + * @param {string} parent Node type - thead, tbody or tfoot + * @param {element} original Original node to take the heights from + * @param {element} clone Copy the heights to + * @private + */ + "fnEqualiseHeights": function ( parent, original, clone ) + { + var that = this; + var originals = $(parent +' tr', original); + var height; + + $(parent+' tr', clone).each( function (k) { + height = originals.eq( k ).css('height'); + + // This is nasty :-(. IE has a sub-pixel error even when setting + // the height below (the Firefox fix) which causes the fixed column + // to go out of alignment. Need to add a pixel before the assignment + // Can this be feature detected? Not sure how... + if ( navigator.appName == 'Microsoft Internet Explorer' ) { + height = parseInt( height, 10 ) + 1; + } + + $(this).css( 'height', height ); + + // For Firefox to work, we need to also set the height of the + // original row, to the value that we read from it! Otherwise there + // is a sub-pixel rounding error + originals.eq( k ).css( 'height', height ); + } ); + } +}; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Static properties and methods + * We use these for speed! This information is common to all instances of FixedHeader, so no + * point if having them calculated and stored for each different instance. + */ + +/* + * Variable: oWin + * Purpose: Store information about the window positioning + * Scope: FixedHeader + */ +FixedHeader.oWin = { + "iScrollTop": 0, + "iScrollRight": 0, + "iScrollBottom": 0, + "iScrollLeft": 0, + "iHeight": 0, + "iWidth": 0 +}; + +/* + * Variable: oDoc + * Purpose: Store information about the document size + * Scope: FixedHeader + */ +FixedHeader.oDoc = { + "iHeight": 0, + "iWidth": 0 +}; + +/* + * Variable: afnScroll + * Purpose: Array of functions that are to be used for the scrolling components + * Scope: FixedHeader + */ +FixedHeader.afnScroll = []; + +/* + * Function: fnMeasure + * Purpose: Update the measurements for the window and document + * Returns: - + * Inputs: - + */ +FixedHeader.fnMeasure = function () +{ + var + jqWin = $(window), + jqDoc = $(document), + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc; + + oDoc.iHeight = jqDoc.height(); + oDoc.iWidth = jqDoc.width(); + + oWin.iHeight = jqWin.height(); + oWin.iWidth = jqWin.width(); + oWin.iScrollTop = jqWin.scrollTop(); + oWin.iScrollLeft = jqWin.scrollLeft(); + oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth; + oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight; +}; + + +FixedHeader.version = "2.1.2"; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Global processing + */ + +/* + * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is + * done as an optimisation, to reduce calculation and proagation time + */ +$(window).scroll( function () { + FixedHeader.fnMeasure(); + + for ( var i=0, iLen=FixedHeader.afnScroll.length ; i<iLen ; i++ ) { + FixedHeader.afnScroll[i](); + } +} ); + + +$.fn.dataTable.FixedHeader = FixedHeader; +$.fn.DataTable.FixedHeader = FixedHeader; + + +return FixedHeader; +}; // /factory + + +// Define as an AMD module if possible +if ( typeof define === 'function' && define.amd ) { + define( ['jquery', 'datatables'], factory ); +} +else if ( typeof exports === 'object' ) { + // Node/CommonJS + factory( require('jquery'), require('datatables') ); +} +else if ( jQuery && !jQuery.fn.dataTable.FixedHeader ) { + // Otherwise simply initialise as normal, stopping multiple evaluation + factory( jQuery, jQuery.fn.dataTable ); +} + + +})(window, document); diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html index b60b4ea9..d53f930d 100755 --- a/wqflask/wqflask/templates/correlation_page.html +++ b/wqflask/wqflask/templates/correlation_page.html @@ -144,6 +144,7 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script> @@ -228,15 +229,14 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, - "scrollY": "600px", - "scrollX": true, - "scrollCollapse": true, + "scrollY": "700px", + "scrollCollapse": false, "colResize": { "tableWidthFixed": false }, @@ -257,15 +257,14 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, - "scrollY": "600px", - "scrollX": true, - "scrollCollapse": true, + "scrollY": "700px", + "scrollCollapse": false, "colResize": { "tableWidthFixed": false }, @@ -281,15 +280,14 @@ { "type": "natural" }, { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, - "scrollY": "600px", - "scrollX": true, - "scrollCollapse": true, + "scrollY": "700px", + "scrollCollapse": false, "colResize": { "tableWidthFixed": false }, @@ -298,11 +296,6 @@ {% endif %} console.timeEnd("Creating table"); - var table = $('#corr_results').DataTable(); - //new $.fn.dataTable.FixedHeader( table ); - new $.fn.dataTable.FixedColumns( table ); - - }); </script> {% endblock %} diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html index 1ae2a25a..7c8bdb1b 100755 --- a/wqflask/wqflask/templates/search_result_page.html +++ b/wqflask/wqflask/templates/search_result_page.html @@ -4,7 +4,7 @@ <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" /> - <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css" > + <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css" > <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css"> {% endblock %} {% block content %} @@ -47,7 +47,7 @@ <button class="btn btn-primary"><span class="glyphicon glyphicon-download"></span> Download Table</button> <br /> <br /> - <table class="table table-hover table-striped" id='trait_table' {% if dataset.type == 'Geno' %} width="400px" style="float: left;"{% endif %}> + <table class="table table-hover table-striped" id='trait_table' {% if dataset.type == 'Geno' %}width="400px"{% endif %} style="float: left;"> <thead> <tr> {% for header in header_fields %} @@ -119,11 +119,11 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script> + <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js"></script> - <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> - <script type="text/javascript" charset="utf-8"> function getValue(x) { @@ -173,28 +173,33 @@ console.time("Creating table"); {% if dataset.type == 'ProbeSet' %} - $('#trait_table').dataTable( { + $('#trait_table').DataTable( { "columns": [ { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, - { "type": "natural", "width": "35%"}, - { "type": "natural", "width": "15%"}, { "type": "natural" }, - { "type": "natural", "width": "8%"}, - { "type": "natural", "width": "15%"}, - { "type": "natural", "width": "7%"} + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, + "scrollY": "700px", + "scrollCollapse": false, + "colResize": { + "tableWidthFixed": false, + }, "paging": false } ); {% elif dataset.type == 'Publish' %} - $('#trait_table').dataTable( { + $('#trait_table').DataTable( { "columns": [ { "type": "natural" }, { "type": "natural" }, @@ -205,36 +210,46 @@ { "type": "natural", "width": "15%"}, { "type": "natural" } ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, + "scrollY": "700px", + "scrollCollapse": false, + "colResize": { + "tableWidthFixed": false, + }, "paging": false } ); {% elif dataset.type == 'Geno' %} - $('#trait_table').dataTable( { + $('#trait_table').DataTable( { "columns": [ { "type": "natural" }, { "type": "natural" }, { "type": "natural", "width": "40%"} ], - "sDom": "Ztir", + "sDom": "RJtir", "iDisplayLength": -1, "autoWidth": true, "bLengthChange": true, "bDeferRender": true, "bSortClasses": false, + "scrollY": "700px", + "scrollCollapse": false, + "colResize": { + "tableWidthFixed": false, + }, "paging": false } ); {% endif %} console.timeEnd("Creating table"); - - var table = $('#trait_table').DataTable(); - new $.fn.dataTable.FixedHeader( table ); - new $.fn.dataTable.FixedColumns( table ); + //var table = $('#trait_table').DataTable(); + //new $.fn.dataTable.FixedHeader( table ); + //new $.fn.dataTable.FixedColumns( table ); + }); </script> {% endblock %} diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index cdde5d9d..b4d6b85b 100755 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -13,6 +13,8 @@ <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" /> + <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css" > + <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/fixedcolumns/3.0.4/css/dataTables.fixedColumns.css"> {% endblock %} {% block content %} <!-- Start of body --> @@ -146,6 +148,10 @@ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.scientific.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colResize.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.colReorder.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js"></script> + <script language="javascript" type="text/javascript" src="//cdn.datatables.net/fixedcolumns/3.0.4/js/dataTables.fixedColumns.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> <script type="text/javascript" charset="utf-8"> @@ -195,68 +201,79 @@ }); console.time("Creating table"); - - {% if sample_groups[0].se_exists() %} - $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'yellow') - $('#samples_primary, #samples_other').dataTable( { - //"sDom": "<<'span3'l><'span3'T><'span4'f>'row-fluid'r>t<'row-fluid'<'span6'i><'span6'p>>", - "aoColumns": [ - { "sType": "natural" }, - null, - { "sType": "cust-txt" }, - { "bSortable": false }, - { "sType": "cust-txt" } + + $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'yellow') + {% if sample_groups[0].se_exists() %} + $('#samples_primary, #samples_other').DataTable( { + "columns": [ + { "type": "natural" }, + { "type": "natural" }, + { "type": "cust-txt" }, + { "bSortable": false }, + { "type": "cust-txt" } + ], + "sDom": "RJtir", + "oTableTools": { + "aButtons": [ + "copy", + "print", + { + "sExtends": "collection", + "sButtonText": 'Save <span class="caret" />', + "aButtons": [ "csv", "xls", "pdf" ] + } ], - "sDom": "ftr", - "oTableTools": { - "aButtons": [ - "copy", - "print", - { - "sExtends": "collection", - "sButtonText": 'Save <span class="caret" />', - "aButtons": [ "csv", "xls", "pdf" ] - } - ], - "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" - }, - "bPaginate": false, - "bLengthChange": true, - "bDeferRender": true, - "bSortClasses": false - } ); - console.timeEnd("Creating table"); + "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" + }, + "iDisplayLength": -1, + "autoWidth": true, + "bLengthChange": true, + "bDeferRender": true, + "bSortClasses": false, + "scrollY": "600px", + "scrollCollapse": false, + "colResize": { + "tableWidthFixed": false + }, + "paging": false + } ); + console.timeEnd("Creating table"); {% else %} - - - console.time("Creating table"); + console.time("Creating table"); - $('#samples_primary, #samples_other').dataTable( { - //"sDom": "<<'span3'l><'span3'T><'span4'f>'row-fluid'r>t<'row-fluid'<'span6'i><'span6'p>>", - "aoColumns": [ - { "sType": "natural" }, - null, - { "sType": "cust-txt" } + $('#samples_primary, #samples_other').DataTable( { + "columns": [ + { "type": "natural" }, + null, + { "type": "cust-txt" } + ], + "sDom": "RJtir", + "oTableTools": { + "aButtons": [ + "copy", + "print", + { + "sExtends": "collection", + "sButtonText": 'Save <span class="caret" />', + "aButtons": [ "csv", "xls", "pdf" ] + } ], - "sDom": "ftr", - "oTableTools": { - "aButtons": [ - "copy", - "print", - { - "sExtends": "collection", - "sButtonText": 'Save <span class="caret" />', - "aButtons": [ "csv", "xls", "pdf" ] - } - ], - "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" - }, - "bPaginate": false, - "bLengthChange": true, - "bDeferRender": true, - "bSortClasses": false - } ); + "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" + }, + "iDisplayLength": -1, + "autoWidth": true, + "bLengthChange": true, + "bDeferRender": true, + "bSortClasses": false, + "scrollY": "600px", + "scrollX": true, + "scrollCollapse": false, + "colResize": { + "tableWidthFixed": false + }, + "paging": false + } ); {% endif %} }); </script> diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html index a02dc409..8c919ee0 100755 --- a/wqflask/wqflask/templates/show_trait_edit_data.html +++ b/wqflask/wqflask/templates/show_trait_edit_data.html @@ -73,26 +73,25 @@ <br> - <div id="edit_sample_lists"> + <!--<div id="edit_sample_lists">--> {% for sample_type in sample_groups %} - <div class="sample_group"> + <!--<div class="sample_group">--> <h3>{{ sample_type.header }}</h3> - <table cellpadding="0" cellspacing="0" border="0" class="table table-hover table-striped table-bordered" - id="samples_{{ sample_type.sample_group_type }}"> + <table class="table table-hover table-striped" id="samples_{{ sample_type.sample_group_type }}" style="float: left;"> <thead> <tr> - <td>Index</td> - <td>Sample</td> - <td>Value</td> + <th>Index</td> + <th>Sample</td> + <th>Value</td> {% if sample_type.se_exists() %} - <td> </td> - <td>SE</td> + <th> </td> + <th>SE</td> {% endif %} {% for attribute in sample_type.attributes|sort() %} - <td> + <th> {{ sample_type.attributes[attribute].name }} - </td> + </th> {% endfor %} </tr> </thead> @@ -148,9 +147,9 @@ {% endfor %} </tbody> </table> - </div> + <!--</div>--> {% endfor %} - </div> + <!--</div>--> <input type="hidden" name="Default_Name"> |