From c053ff453e6c8354e61b227d028378712ab240d6 Mon Sep 17 00:00:00 2001 From: zsloan Date: Thu, 23 Jul 2015 16:20:55 +0000 Subject: Committing most recent changes to tables so Lei can pull; still have a few more issues to resolve, like setting initial column width --- .../DataTables/extensions/dataTables.colReorder.js | 1372 ++++++++++++++++ .../DataTables/extensions/dataTables.colResize.js | 1669 +++++++++++--------- .../extensions/dataTables.fixedHeader.css | 4 + .../extensions/dataTables.fixedHeader.js | 1027 ++++++++++++ wqflask/wqflask/templates/correlation_page.html | 27 +- wqflask/wqflask/templates/search_result_page.html | 55 +- wqflask/wqflask/templates/show_trait.html | 131 +- .../wqflask/templates/show_trait_edit_data.html | 25 +- 8 files changed, 3417 insertions(+), 893 deletions(-) create mode 100644 wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.colReorder.js create mode 100644 wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.css create mode 100644 wqflask/wqflask/static/new/packages/DataTables/extensions/dataTables.fixedHeader.js (limited to 'wqflask') 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= iCols ) + { + this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); + return; + } + + if ( iTo < 0 || iTo >= iCols ) + { + this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); + return; + } + + /* + * Calculate the new column array index, so we have a mapping between the old and new + */ + var aiMapping = []; + for ( i=0, iLen=iCols ; i this.s.fixed-1 && i < iLen - this.s.fixedRight ) + { + this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh ); + } + + /* Mark the original column order for later reference */ + this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; + } + + /* State saving */ + this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { + that._fnStateSave.call( that, oData ); + }, "ColReorder_State" ); + + /* An initial column order has been specified */ + var aiOrder = null; + if ( this.s.init.aiOrder ) + { + aiOrder = this.s.init.aiOrder.slice(); + } + + /* State loading, overrides the column order given */ + if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && + this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) + { + aiOrder = this.s.dt.oLoadedState.ColReorder; + } + + /* If we have an order to apply - do so */ + if ( aiOrder ) + { + /* We might be called during or after the DataTables initialisation. If before, then we need + * to wait until the draw is done, if after, then do what we need to do right away + */ + if ( !that.s.dt._bInitComplete ) + { + var bDone = false; + 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') + .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 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.$('
').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 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 + @@ -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 ); - - }); {% 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 @@ - + {% endblock %} {% block content %} @@ -47,7 +47,7 @@

- +
{% for header in header_fields %} @@ -119,11 +119,11 @@ + + + - - - {% 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 @@ + + {% endblock %} {% block content %} @@ -146,6 +148,10 @@ + + + + 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 @@
-
+ {% for sample_type in sample_groups %} -
+

{{ sample_type.header }}

-
+
- - - + - + {% endfor %} @@ -148,9 +147,9 @@ {% endfor %}
IndexSampleValueIndex + Sample + Value {% if sample_type.se_exists() %} -  SE  + SE {% endif %} {% for attribute in sample_type.attributes|sort() %} - + {{ sample_type.attributes[attribute].name }} - +
-
+ {% endfor %} - + -- cgit v1.2.3