diff --git a/qgrid/grid.py b/qgrid/grid.py index bdf2bc55..6e4a5a70 100644 --- a/qgrid/grid.py +++ b/qgrid/grid.py @@ -31,7 +31,7 @@ def template_contents(filename): SLICK_GRID_CSS = template_contents('slickgrid.css.template') SLICK_GRID_JS = template_contents('slickgrid.js.template') -REMOTE_URL = ("https://cdn.rawgit.com/quantopian/qgrid/" +REMOTE_URL = ("https://cdn.rawgit.com/sbremer/qgrid/" "73eaa7adf1762f66eaf4d30ed9cbf385a7e9d9fa/qgrid/qgridjs/") LOCAL_URL = "/nbextensions/qgridjs" diff --git a/qgrid/qgridjs/lib/slick.core.2.2.js b/qgrid/qgridjs/lib/slick.core.js similarity index 73% rename from qgrid/qgridjs/lib/slick.core.2.2.js rename to qgrid/qgridjs/lib/slick.core.js index f540dbd5..57217449 100644 --- a/qgrid/qgridjs/lib/slick.core.2.2.js +++ b/qgrid/qgridjs/lib/slick.core.js @@ -1,18 +1,22 @@ /*** - * @license - * (c) 2009-2013 Michael Leibman - * michael{dot}leibman{at}gmail{dot}com - * http://github.com/mleibman/slickgrid - * - * Distributed under MIT license. - * All rights reserved. - * * Contains core SlickGrid classes. * @module Core * @namespace Slick */ -(function ($) { +// CommonJS, AMD or browser globals +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { // register namespace $.extend(true, window, { "Slick": { @@ -31,7 +35,8 @@ * @static * @constructor */ - "GlobalEditorLock": new EditorLock() + "GlobalEditorLock": new EditorLock(), + "TreeColumns": TreeColumns } }); @@ -155,7 +160,7 @@ var i = handlers.length; while (i--) { if (handlers[i].event === event && - handlers[i].handler === handler) { + handlers[i].handler === handler) { handlers.splice(i, 1); event.unsubscribe(handler); return; @@ -242,7 +247,7 @@ */ this.contains = function (row, cell) { return row >= this.fromRow && row <= this.toRow && - cell >= this.fromCell && cell <= this.toCell; + cell >= this.fromCell && cell <= this.toCell; }; /*** @@ -355,9 +360,9 @@ */ Group.prototype.equals = function (group) { return this.value === group.value && - this.count === group.count && - this.collapsed === group.collapsed && - this.title === group.title; + this.count === group.count && + this.collapsed === group.collapsed && + this.title === group.title; }; /*** @@ -470,6 +475,179 @@ return (activeEditController ? activeEditController.cancelCurrentEdit() : true); }; } -})(jQuery); + + /** + * + * @param {Array} treeColumns Array com levels of columns + * @returns {{hasDepth: 'hasDepth', getTreeColumns: 'getTreeColumns', extractColumns: 'extractColumns', getDepth: 'getDepth', getColumnsInDepth: 'getColumnsInDepth', getColumnsInGroup: 'getColumnsInGroup', visibleColumns: 'visibleColumns', filter: 'filter', reOrder: reOrder}} + * @constructor + */ + function TreeColumns(treeColumns) { + + var columnsById = {}; + + function init() { + mapToId(treeColumns); + } + + function mapToId(columns) { + columns + .forEach(function (column) { + columnsById[column.id] = column; + + if (column.columns) + mapToId(column.columns); + }); + } + + function filter(node, condition) { + + return node.filter(function (column) { + + var valid = condition.call(column); + + if (valid && column.columns) + column.columns = filter(column.columns, condition); + + return valid && (!column.columns || column.columns.length); + }); + + } + + function sort(columns, grid) { + columns + .sort(function (a, b) { + var indexA = getOrDefault(grid.getColumnIndex(a.id)), + indexB = getOrDefault(grid.getColumnIndex(b.id)); + + return indexA - indexB; + }) + .forEach(function (column) { + if (column.columns) + sort(column.columns, grid); + }); + } + + function getOrDefault(value) { + return typeof value === 'undefined' ? -1 : value; + } + + function getDepth(node) { + if (node.length) + for (var i in node) + return getDepth(node[i]); + else if (node.columns) + return 1 + getDepth(node.columns); + else + return 1; + } + + function getColumnsInDepth(node, depth, current) { + var columns = []; + current = current || 0; + + if (depth == current) { + + if (node.length) + node.forEach(function(n) { + if (n.columns) + n.extractColumns = function() { + return extractColumns(n); + }; + }); + + return node; + } else + for (var i in node) + if (node[i].columns) { + columns = columns.concat(getColumnsInDepth(node[i].columns, depth, current + 1)); + } + + return columns; + } + + function extractColumns(node) { + var result = []; + + if (node.hasOwnProperty('length')) { + + for (var i = 0; i < node.length; i++) + result = result.concat(extractColumns(node[i])); + + } else { + + if (node.hasOwnProperty('columns')) + + result = result.concat(extractColumns(node.columns)); + + else + return node; + + } + + return result; + } + + function cloneTreeColumns() { + return $.extend(true, [], treeColumns); + } + + init(); + + this.hasDepth = function () { + + for (var i in treeColumns) + if (treeColumns[i].hasOwnProperty('columns')) + return true; + + return false; + }; + + this.getTreeColumns = function () { + return treeColumns; + }; + + this.extractColumns = function () { + return this.hasDepth()? extractColumns(treeColumns): treeColumns; + }; + + this.getDepth = function () { + return getDepth(treeColumns); + }; + + this.getColumnsInDepth = function (depth) { + return getColumnsInDepth(treeColumns, depth); + }; + + this.getColumnsInGroup = function (groups) { + return extractColumns(groups); + }; + + this.visibleColumns = function () { + return filter(cloneTreeColumns(), function () { + return this.visible; + }); + }; + + this.filter = function (condition) { + return filter(cloneTreeColumns(), condition); + }; + + this.reOrder = function (grid) { + return sort(treeColumns, grid); + }; + + this.getById = function (id) { + return columnsById[id]; + }; + + this.getInIds = function (ids) { + return ids.map(function (id) { + return columnsById[id]; + }); + } + } + +})); diff --git a/qgrid/qgridjs/lib/slick.dataview.2.2.js b/qgrid/qgridjs/lib/slick.dataview.js similarity index 81% rename from qgrid/qgridjs/lib/slick.dataview.2.2.js rename to qgrid/qgridjs/lib/slick.dataview.js index fd824f65..883537f8 100644 --- a/qgrid/qgridjs/lib/slick.dataview.2.2.js +++ b/qgrid/qgridjs/lib/slick.dataview.js @@ -1,20 +1,19 @@ -/*** - * @license - * (c) 2009-2013 Michael Leibman - * michael{dot}leibman{at}gmail{dot}com - * http://github.com/mleibman/slickgrid - * - * Distributed under MIT license. - * All rights reserved. - */ - -(function ($) { +(function (factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object') { + module.exports = factory(require('jquery')); + } else { + factory(jQuery); + } +}(function ($) { $.extend(true, window, { Slick: { Data: { DataView: DataView, Aggregators: { Avg: AvgAggregator, + WeightedAvg: WeightedAvgAggregator, Min: MinAggregator, Max: MaxAggregator, Sum: SumAggregator @@ -30,6 +29,7 @@ * * Relies on the data item having an "id" property uniquely identifying it. */ + function DataView(options) { var self = this; @@ -38,16 +38,15 @@ inlineFilters: false }; - // private - var idProperty = "id"; // property holding a unique row id - var items = []; // data by index - var rows = []; // data by row - var idxById = {}; // indexes by id - var rowsById = null; // rows by id; lazy-calculated - var filter = null; // filter function - var updated = null; // updated item ids - var suspend = false; // suspends the recalculation + var idProperty = "id"; // property holding a unique row id + var items = []; // data by index + var rows = []; // data by row + var idxById = {}; // indexes by id + var rowsById = null; // rows by id; lazy-calculated + var filter = null; // filter function + var updated = null; // updated item ids + var suspend = false; // suspends the recalculation var sortAsc = true; var fastSortField; var sortComparer; @@ -63,7 +62,9 @@ var groupingInfoDefaults = { getter: null, formatter: null, - comparer: function(a, b) { return a.value - b.value; }, + comparer: function (a, b) { + return a.value - b.value; + }, predefinedValues: [], aggregators: [], aggregateEmpty: false, @@ -89,7 +90,6 @@ options = $.extend(true, {}, defaults, options); - function beginUpdate() { suspend = true; } @@ -145,12 +145,12 @@ } function setPagingOptions(args) { - if (args.pageSize != undefined) { + if (args.pageSize !== undefined) { pagesize = args.pageSize; pagenum = pagesize ? Math.min(pagenum, Math.max(0, Math.ceil(totalRows / pagesize) - 1)) : 0; } - if (args.pageNum != undefined) { + if (args.pageNum !== undefined) { pagenum = Math.min(args.pageNum, Math.max(0, Math.ceil(totalRows / pagesize) - 1)); } @@ -161,7 +161,12 @@ function getPagingInfo() { var totalPages = pagesize ? Math.max(1, Math.ceil(totalRows / pagesize)) : 1; - return {pageSize: pagesize, pageNum: pagenum, totalRows: totalRows, totalPages: totalPages}; + return { + pageSize: pagesize, + pageNum: pagenum, + totalRows: totalRows, + totalPages: totalPages + }; } function sort(comparer, ascending) { @@ -185,13 +190,14 @@ * Does a [lexicographic] sort on a give column by temporarily overriding Object.prototype.toString * to return the value of that field and then doing a native Array.sort(). */ + function fastSort(field, ascending) { sortAsc = ascending; fastSortField = field; sortComparer = null; var oldToString = Object.prototype.toString; - Object.prototype.toString = (typeof field == "function") ? field : function () { - return this[field] + Object.prototype.toString = (typeof field === "function") ? field : function () { + return this[field]; }; // an extra reversal for descending sort keeps the sort stable // (assuming a stable native sort implementation, which isn't true in some cases) @@ -260,7 +266,7 @@ * @deprecated Please use {@link setGrouping}. */ function groupBy(valueGetter, valueFormatter, sortComparer) { - if (valueGetter == null) { + if (valueGetter === null) { setGrouping([]); return; } @@ -317,7 +323,7 @@ ensureRowsByIdCache(); for (var i = 0, l = idArray.length; i < l; i++) { var row = rowsById[idArray[i]]; - if (row != null) { + if (row !== null) { rows[rows.length] = row; } } @@ -408,11 +414,15 @@ return options.groupItemMetadataProvider.getTotalsRowMetadata(item); } + if (options.groupItemMetadataProvider) { + return options.groupItemMetadataProvider.getRowMetadata(item); + } + return null; } function expandCollapseAllGroups(level, collapse) { - if (level == null) { + if (level === null) { for (var i = 0; i < groupingInfos.length; i++) { toggledGroupsByLevel[i] = {}; groupingInfos[i].collapsed = collapse; @@ -438,11 +448,21 @@ expandCollapseAllGroups(level, false); } - function expandCollapseGroup(level, groupingKey, collapse) { - toggledGroupsByLevel[level][groupingKey] = groupingInfos[level].collapsed ^ collapse; + function expandCollapseGroup(args, collapse) { + var opts = resolveLevelAndGroupingKey(args); + toggledGroupsByLevel[opts.level][opts.groupingKey] = groupingInfos[opts.level].collapsed ^ collapse; refresh(); } + function resolveLevelAndGroupingKey(args) { + var arg0 = args[0]; + if (args.length === 1 && arg0.indexOf(groupingDelimiter) !== -1) { + return {level: arg0.split(groupingDelimiter).length - 1, groupingKey: arg0}; + } else { + return {level: args.length - 1, groupingKey: args.join(groupingDelimiter)}; + } + } + /** * @param varArgs Either a Slick.Group's "groupingKey" property, or a * variable argument list of grouping values denoting a unique path to the row. For @@ -451,12 +471,7 @@ */ function collapseGroup(varArgs) { var args = Array.prototype.slice.call(arguments); - var arg0 = args[0]; - if (args.length == 1 && arg0.indexOf(groupingDelimiter) != -1) { - expandCollapseGroup(arg0.split(groupingDelimiter).length - 1, arg0, true); - } else { - expandCollapseGroup(args.length - 1, args.join(groupingDelimiter), true); - } + expandCollapseGroup(args, true); } /** @@ -467,18 +482,28 @@ */ function expandGroup(varArgs) { var args = Array.prototype.slice.call(arguments); - var arg0 = args[0]; - if (args.length == 1 && arg0.indexOf(groupingDelimiter) != -1) { - expandCollapseGroup(arg0.split(groupingDelimiter).length - 1, arg0, false); - } else { - expandCollapseGroup(args.length - 1, args.join(groupingDelimiter), false); - } + expandCollapseGroup(args, false); } function getGroups() { return groups; } + function getOrCreateGroup(groupsByVal, val, level, parentGroup, groups) { + var group = groupsByVal[val]; + + if (!group) { + group = new Slick.Group(); + group.value = val; + group.level = level; + group.groupingKey = (parentGroup ? parentGroup.groupingKey + groupingDelimiter : '') + val; + groups[groups.length] = group; + groupsByVal[val] = group; + } + + return group; + } + function extractGroups(rows, parentGroup) { var group; var val; @@ -490,29 +515,14 @@ for (var i = 0, l = gi.predefinedValues.length; i < l; i++) { val = gi.predefinedValues[i]; - group = groupsByVal[val]; - if (!group) { - group = new Slick.Group(); - group.value = val; - group.level = level; - group.groupingKey = (parentGroup ? parentGroup.groupingKey + groupingDelimiter : '') + val; - groups[groups.length] = group; - groupsByVal[val] = group; - } + group = getOrCreateGroup(groupsByVal, val, level, parentGroup, groups); } for (var i = 0, l = rows.length; i < l; i++) { r = rows[i]; val = gi.getterIsAFn ? gi.getter(r) : r[gi.getter]; - group = groupsByVal[val]; - if (!group) { - group = new Slick.Group(); - group.value = val; - group.level = level; - group.groupingKey = (parentGroup ? parentGroup.groupingKey + groupingDelimiter : '') + val; - groups[groups.length] = group; - groupsByVal[val] = group; - } + + group = getOrCreateGroup(groupsByVal, val, level, parentGroup, groups); group.rows[group.count++] = r; } @@ -522,7 +532,7 @@ group = groups[i]; group.groups = extractGroups(group.rows, group); } - } + } groups.sort(groupingInfos[level].comparer); @@ -532,7 +542,7 @@ function calculateTotals(totals) { var group = totals.group; var gi = groupingInfos[group.level]; - var isLeafLevel = (group.level == groupingInfos.length); + var isLeafLevel = (group.level === groupingInfos.length); var agg, idx = gi.aggregators.length; if (!isLeafLevel && gi.aggregateChildGroups) { @@ -572,7 +582,7 @@ level = level || 0; var gi = groupingInfos[level]; var groupCollapsed = gi.collapsed; - var toggledGroups = toggledGroupsByLevel[level]; + var toggledGroups = toggledGroupsByLevel[level]; var idx = groups.length, g; while (idx--) { g = groups[idx]; @@ -587,14 +597,14 @@ } if (gi.aggregators.length && ( - gi.aggregateEmpty || g.rows.length || (g.groups && g.groups.length))) { + gi.aggregateEmpty || g.rows.length || (g.groups && g.groups.length))) { addGroupTotals(g); } g.collapsed = groupCollapsed ^ toggledGroups[g.groupingKey]; g.title = gi.formatter ? gi.formatter(g) : g.value; } - } + } function flattenGroupedRows(groups, level) { level = level || 0; @@ -630,10 +640,10 @@ function compileAccumulatorLoop(aggregator) { var accumulatorInfo = getFunctionInfo(aggregator.accumulate); var fn = new Function( - "_items", + "_items", "for (var " + accumulatorInfo.params[0] + ", _i=0, _il=_items.length; _i<_il; _i++) {" + - accumulatorInfo.params[0] + " = _items[_i]; " + - accumulatorInfo.body + + accumulatorInfo.params[0] + " = _items[_i]; " + + accumulatorInfo.body + "}" ); fn.displayName = fn.name = "compiledAccumulatorLoop"; @@ -644,10 +654,10 @@ var filterInfo = getFunctionInfo(filter); var filterBody = filterInfo.body - .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1") - .replace(/return true\s*([;}]|$)/gi, "{ _retval[_idx++] = $item$; continue _coreloop; }$1") - .replace(/return ([^;}]+?)\s*([;}]|$)/gi, - "{ if ($1) { _retval[_idx++] = $item$; }; continue _coreloop; }$2"); + .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1") + .replace(/return true\s*([;}]|$)/gi, "{ _retval[_idx++] = $item$; continue _coreloop; }$1") + .replace(/return ([^;}]+?)\s*([;}]|$)/gi, + "{ if ($1) { _retval[_idx++] = $item$; }; continue _coreloop; }$2"); // This preserves the function template code after JS compression, // so that replace() commands still work as expected. @@ -676,10 +686,10 @@ var filterInfo = getFunctionInfo(filter); var filterBody = filterInfo.body - .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1") - .replace(/return true\s*([;}]|$)/gi, "{ _cache[_i] = true;_retval[_idx++] = $item$; continue _coreloop; }$1") - .replace(/return ([^;}]+?)\s*([;}]|$)/gi, - "{ if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue _coreloop; }$2"); + .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1") + .replace(/return true\s*([;}]|$)/gi, "{ _cache[_i] = true;_retval[_idx++] = $item$; continue _coreloop; }$1") + .replace(/return ([^;}]+?)\s*([;}]|$)/gi, + "{ if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue _coreloop; }$2"); // This preserves the function template code after JS compression, // so that replace() commands still work as expected. @@ -709,7 +719,8 @@ } function uncompiledFilter(items, args) { - var retval = [], idx = 0; + var retval = [], + idx = 0; for (var i = 0, ii = items.length; i < ii; i++) { if (filter(items[i], args)) { @@ -721,7 +732,9 @@ } function uncompiledFilterWithCaching(items, args, cache) { - var retval = [], idx = 0, item; + var retval = [], + idx = 0, + item; for (var i = 0, ii = items.length; i < ii; i++) { item = items[i]; @@ -766,21 +779,23 @@ paged = filteredItems; } - return {totalRows: filteredItems.length, rows: paged}; + return { + totalRows: filteredItems.length, + rows: paged + }; } function getRowDiffs(rows, newRows) { var item, r, eitherIsNonData, diff = []; - var from = 0, to = newRows.length; + var from = 0, + to = newRows.length; if (refreshHints && refreshHints.ignoreDiffsBefore) { - from = Math.max(0, - Math.min(newRows.length, refreshHints.ignoreDiffsBefore)); + from = Math.max(0, Math.min(newRows.length, refreshHints.ignoreDiffsBefore)); } if (refreshHints && refreshHints.ignoreDiffsAfter) { - to = Math.min(newRows.length, - Math.max(0, refreshHints.ignoreDiffsAfter)); + to = Math.min(newRows.length, Math.max(0, refreshHints.ignoreDiffsAfter)); } for (var i = from, rl = rows.length; i < to; i++) { @@ -791,16 +806,16 @@ r = rows[i]; if ((groupingInfos.length && (eitherIsNonData = (item.__nonDataRow) || (r.__nonDataRow)) && - item.__group !== r.__group || - item.__group && !item.equals(r)) - || (eitherIsNonData && + item.__group !== r.__group || + item.__group && !item.equals(r)) + || (eitherIsNonData && // no good way to compare totals since they are arbitrary DTOs // deep object comparison is pretty expensive // always considering them 'dirty' seems easier for the time being (item.__groupTotals || r.__groupTotals)) - || item[idProperty] != r[idProperty] - || (updated && updated[item[idProperty]]) - ) { + || item[idProperty] !== r[idProperty] + || (updated && updated[item[idProperty]]) + ) { diff[diff.length] = i; } } @@ -811,8 +826,8 @@ function recalc(_items) { rowsById = null; - if (refreshHints.isFilterNarrowing != prevRefreshHints.isFilterNarrowing || - refreshHints.isFilterExpanding != prevRefreshHints.isFilterExpanding) { + if (refreshHints.isFilterNarrowing !== prevRefreshHints.isFilterNarrowing || + refreshHints.isFilterExpanding !== prevRefreshHints.isFilterExpanding) { filterCache = []; } @@ -845,7 +860,6 @@ var totalRowsBefore = totalRows; var diff = recalc(items, filter); // pass as direct refs to avoid closure perf hit - // if the current page is no longer valid, go to last page and recalc // we suffer a performance penalty here, but the main loop (recalc) remains highly optimized if (pagesize && totalRows < pagenum * pagesize) { @@ -857,14 +871,19 @@ prevRefreshHints = refreshHints; refreshHints = {}; - if (totalRowsBefore != totalRows) { + if (totalRowsBefore !== totalRows) { onPagingInfoChanged.notify(getPagingInfo(), null, self); } - if (countBefore != rows.length) { - onRowCountChanged.notify({previous: countBefore, current: rows.length}, null, self); + if (countBefore !== rows.length) { + onRowCountChanged.notify({ + previous: countBefore, + current: rows.length + }, null, self); } if (diff.length > 0) { - onRowsChanged.notify({rows: diff}, null, self); + onRowsChanged.notify({ + rows: diff + }, null, self); } } @@ -888,13 +907,12 @@ * @method syncGridSelection */ function syncGridSelection(grid, preserveHidden, preserveHiddenOnSelectionChange) { - var self = this; - var inHandler; + var self = this; var inHandler; var selectedRowIds = self.mapRowsToIds(grid.getSelectedRows()); var onSelectedRowIdsChanged = new Slick.Event(); function setSelectedRowIds(rowIds) { - if (selectedRowIds.join(",") == rowIds.join(",")) { + if (selectedRowIds.join(",") === rowIds.join(",")) { return; } @@ -911,21 +929,25 @@ inHandler = true; var selectedRows = self.mapIdsToRows(selectedRowIds); if (!preserveHidden) { - setSelectedRowIds(self.mapRowsToIds(selectedRows)); + setSelectedRowIds(self.mapRowsToIds(selectedRows)); } grid.setSelectedRows(selectedRows); inHandler = false; } } - grid.onSelectedRowsChanged.subscribe(function(e, args) { - if (inHandler) { return; } + grid.onSelectedRowsChanged.subscribe(function (e, args) { + if (inHandler) { + return; + } var newSelectedRowIds = self.mapRowsToIds(grid.getSelectedRows()); if (!preserveHiddenOnSelectionChange || !grid.getOptions().multiSelect) { setSelectedRowIds(newSelectedRowIds); } else { // keep the ones that are hidden - var existing = $.grep(selectedRowIds, function(id) { return self.getRowById(id) === undefined; }); + var existing = $.grep(selectedRowIds, function (id) { + return self.getRowById(id) === undefined; + }); // add the newly selected ones setSelectedRowIds(existing.concat(newSelectedRowIds)); } @@ -961,7 +983,7 @@ var newHash = {}; for (var id in hashById) { var row = rowsById[id]; - if (row != undefined) { + if (row !== undefined) { newHash[row] = hashById[id]; } } @@ -970,9 +992,13 @@ } } - grid.onCellCssStylesChanged.subscribe(function(e, args) { - if (inHandler) { return; } - if (key != args.key) { return; } + grid.onCellCssStylesChanged.subscribe(function (e, args) { + if (inHandler) { + return; + } + if (key !== args.key) { + return; + } if (args.hash) { storeCellCssStyles(args.hash); } @@ -1044,7 +1070,7 @@ this.accumulate = function (item) { var val = item[this.field_]; this.count_++; - if (val != null && val !== "" && val !== NaN) { + if (val !== null && val !== "" && val !== NaN) { this.nonNullCount_++; this.sum_ += parseFloat(val); } @@ -1054,12 +1080,45 @@ if (!groupTotals.avg) { groupTotals.avg = {}; } - if (this.nonNullCount_ != 0) { + if (this.nonNullCount_ !== 0) { groupTotals.avg[this.field_] = this.sum_ / this.nonNullCount_; } }; } + function WeightedAvgAggregator(field, weightedField) { + this.field_ = field; + this.weightedField_ = weightedField; + + this.init = function () { + this.sum_ = 0; + this.weightedSum_ = 0; + }; + + this.accumulate = function (item) { + var val = item[this.field_]; + var valWeighted = item[this.weightedField_]; + if (this.isValid(val) && this.isValid(valWeighted)) { + this.weightedSum_ += parseFloat(valWeighted); + this.sum_ += parseFloat(val) * parseFloat(valWeighted); + } + }; + + this.storeResult = function (groupTotals) { + if (!groupTotals.avg) { + groupTotals.avg = {}; + } + + if (this.sum_ && this.weightedSum_) { + groupTotals.avg[this.field_] = this.sum_ / this.weightedSum_; + } + }; + + this.isValid = function (val) { + return val !== null && val !== "" && val !== NaN; + }; + } + function MinAggregator(field) { this.field_ = field; @@ -1069,8 +1128,8 @@ this.accumulate = function (item) { var val = item[this.field_]; - if (val != null && val !== "" && val !== NaN) { - if (this.min_ == null || val < this.min_) { + if (val !== null && val !== "" && val !== NaN) { + if (this.min_ === null || val < this.min_) { this.min_ = val; } } @@ -1081,7 +1140,7 @@ groupTotals.min = {}; } groupTotals.min[this.field_] = this.min_; - } + }; } function MaxAggregator(field) { @@ -1093,8 +1152,8 @@ this.accumulate = function (item) { var val = item[this.field_]; - if (val != null && val !== "" && val !== NaN) { - if (this.max_ == null || val > this.max_) { + if (val !== null && val !== "" && val !== NaN) { + if (this.max_ === null || val > this.max_) { this.max_ = val; } } @@ -1105,7 +1164,7 @@ groupTotals.max = {}; } groupTotals.max[this.field_] = this.max_; - } + }; } function SumAggregator(field) { @@ -1117,7 +1176,7 @@ this.accumulate = function (item) { var val = item[this.field_]; - if (val != null && val !== "" && val !== NaN) { + if (val !== null && val !== "" && val !== NaN) { this.sum_ += parseFloat(val); } }; @@ -1127,10 +1186,9 @@ groupTotals.sum = {}; } groupTotals.sum[this.field_] = this.sum_; - } + }; } // TODO: add more built-in aggregators // TODO: merge common aggregators in one to prevent needles iterating - -})(jQuery); +})); diff --git a/qgrid/qgridjs/lib/slick.grid.css b/qgrid/qgridjs/lib/slick.grid.css index 547a3245..7fbfdb59 100644 --- a/qgrid/qgridjs/lib/slick.grid.css +++ b/qgrid/qgridjs/lib/slick.grid.css @@ -1,32 +1,24 @@ /* -* @license -* (c) 2009-2013 Michael Leibman -* michael{dot}leibman{at}gmail{dot}com -* http://github.com/mleibman/slickgrid -* -* Distributed under MIT license. -* All rights reserved. -* IMPORTANT: In order to preserve the uniform grid appearance, all cell styles need to have padding, margin and border sizes. No built-in (selected, editable, highlight, flashing, invalid, loading, :focus) or user-specified CSS classes should alter those! */ -.slick-header.ui-state-default, .slick-headerrow.ui-state-default { +.slick-header.ui-state-default, .slick-headerrow.ui-state-default, .slick-footerrow.ui-state-default, .slick-group-header.ui-state-default { width: 100%; overflow: hidden; border-left: 0px; } -.slick-header-columns, .slick-headerrow-columns { +.slick-header-columns, .slick-headerrow-columns, .slick-footerrow-columns, .slick-group-header-columns { position: relative; white-space: nowrap; cursor: default; overflow: hidden; } -.slick-header-column.ui-state-default { +.slick-header-column.ui-state-default, .slick-group-header-column.ui-state-default { position: relative; display: inline-block; overflow: hidden; @@ -43,7 +35,21 @@ classes should alter those! float: left; } -.slick-headerrow-column.ui-state-default { +.slick-footerrow-column.ui-state-default { + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + margin: 0; + padding: 4px; + border-right: 1px solid silver; + border-left: 0px; + border-top: 0px; + border-bottom: 0px; + float: left; + line-height: 20px; + vertical-align: middle; +} + +.slick-headerrow-column.ui-state-default, .slick-footerrow-column.ui-state-default { padding: 4px; } @@ -56,14 +62,16 @@ classes should alter those! width: 8px; height: 5px; margin-left: 4px; + margin-top: 6px; + float: left; } .slick-sort-indicator-desc { - background: url(sort_desc.png); + background: url(images/sort-desc.gif); } .slick-sort-indicator-asc { - background: url(sort_asc.png); + background: url(images/sort-asc.gif); } .slick-resizable-handle { @@ -77,6 +85,10 @@ classes should alter those! height: 100%; } +.slick-resizable-handle-hover { + background-color: #ccc; +} + .slick-sortable-placeholder { background: silver; } @@ -84,6 +96,7 @@ classes should alter those! .grid-canvas { position: relative; outline: 0; + overflow: hidden; } .slick-row.ui-widget-content, .slick-row.ui-state-active { @@ -92,7 +105,7 @@ classes should alter those! width: 100%; } -.slick-cell, .slick-headerrow-column { +.slick-cell, .slick-headerrow-column, .slick-footerrow-column { position: absolute; border: 1px solid transparent; border-right: 1px dotted silver; @@ -144,7 +157,7 @@ classes should alter those! display: inline-block; background: blue; opacity: 0.15; - filter: alpha(opacity = 15); + filter: alpha(opacity=15); cursor: move; } @@ -153,7 +166,7 @@ classes should alter those! height: 2px; background: blue; opacity: 0.7; - filter: alpha(opacity = 70); + filter: alpha(opacity=70); } .slick-selection { @@ -161,3 +174,39 @@ classes should alter those! position: absolute; border: 2px dashed black; } + +.slick-pane { + position: absolute; + outline: 0; + overflow: hidden; + width: 100%; +} + +.slick-pane-header { + display: block; +} + +.slick-header { + overflow: hidden; + position: relative; +} + +.slick-headerrow { + overflow: hidden; + position: relative; +} + +.slick-top-panel-scroller { + overflow: hidden; + position: relative; +} + +.slick-top-panel { + width: 10000px +} + +.slick-viewport { + position: relative; + outline: 0; + width: 100%; +} diff --git a/qgrid/qgridjs/lib/slick.grid.2.2.js b/qgrid/qgridjs/lib/slick.grid.js similarity index 61% rename from qgrid/qgridjs/lib/slick.grid.2.2.js rename to qgrid/qgridjs/lib/slick.grid.js index 6e159675..5ee019e1 100644 --- a/qgrid/qgridjs/lib/slick.grid.2.2.js +++ b/qgrid/qgridjs/lib/slick.grid.js @@ -1,3459 +1,4740 @@ -/** - * @license - * (c) 2009-2013 Michael Leibman - * michael{dot}leibman{at}gmail{dot}com - * http://github.com/mleibman/slickgrid - * - * Distributed under MIT license. - * All rights reserved. - * - * SlickGrid v2.2 - * - * NOTES: - * Cell/row DOM manipulations are done directly bypassing jQuery's DOM manipulation methods. - * This increases the speed dramatically, but can only be done safely because there are no event handlers - * or data associated with any cell/row DOM nodes. Cell editors must make sure they implement .destroy() - * and do proper cleanup. - */ - -// make sure required JavaScript modules are loaded -if (typeof jQuery === "undefined") { - throw "SlickGrid requires jquery module to be loaded"; -} -if (!jQuery.fn.drag) { - throw "SlickGrid requires jquery.event.drag module to be loaded"; -} -if (typeof Slick === "undefined") { - throw "slick.core.js not loaded"; -} - - -(function ($) { - // Slick.Grid - $.extend(true, window, { - Slick: { - Grid: SlickGrid - } - }); - - // shared across all grids on the page - var scrollbarDimensions; - var maxSupportedCssHeight; // browser's breaking point - - ////////////////////////////////////////////////////////////////////////////////////////////// - // SlickGrid class implementation (available as Slick.Grid) - - /** - * Creates a new instance of the grid. - * @class SlickGrid - * @constructor - * @param {Node} container Container node to create the grid in. - * @param {Array,Object} data An array of objects for databinding. - * @param {Array} columns An array of column definitions. - * @param {Object} options Grid options. - **/ - function SlickGrid(container, data, columns, options) { - // settings - var defaults = { - explicitInitialization: false, - rowHeight: 25, - defaultColumnWidth: 80, - enableAddRow: false, - leaveSpaceForNewRows: false, - editable: false, - autoEdit: true, - enableCellNavigation: true, - enableColumnReorder: true, - asyncEditorLoading: false, - asyncEditorLoadDelay: 100, - forceFitColumns: false, - enableAsyncPostRender: false, - asyncPostRenderDelay: 50, - autoHeight: false, - editorLock: Slick.GlobalEditorLock, - showHeaderRow: false, - headerRowHeight: 25, - showTopPanel: false, - topPanelHeight: 25, - formatterFactory: null, - editorFactory: null, - cellFlashingCssClass: "flashing", - selectedCellCssClass: "selected", - multiSelect: true, - enableTextSelectionOnCells: false, - dataItemColumnValueExtractor: null, - fullWidthRows: false, - multiColumnSort: false, - defaultFormatter: defaultFormatter, - forceSyncScrolling: false, - addNewRowCssClass: "new-row" - }; - - var columnDefaults = { - name: "", - resizable: true, - sortable: false, - minWidth: 30, - rerenderOnResize: false, - headerCssClass: null, - defaultSortAsc: true, - focusable: true, - selectable: true - }; - - // scroller - var th; // virtual height - var h; // real scrollable height - var ph; // page height - var n; // number of pages - var cj; // "jumpiness" coefficient - - var page = 0; // current page - var offset = 0; // current page offset - var vScrollDir = 1; - - // private - var initialized = false; - var $container; - var uid = "slickgrid_" + Math.round(1000000 * Math.random()); - var self = this; - var $focusSink, $focusSink2; - var $headerScroller; - var $headers; - var $headerRow, $headerRowScroller, $headerRowSpacer; - var $topPanelScroller; - var $topPanel; - var $viewport; - var $canvas; - var $style; - var $boundAncestors; - var stylesheet, columnCssRulesL, columnCssRulesR; - var viewportH, viewportW; - var canvasWidth; - var viewportHasHScroll, viewportHasVScroll; - var headerColumnWidthDiff = 0, headerColumnHeightDiff = 0, // border+padding - cellWidthDiff = 0, cellHeightDiff = 0; - var absoluteColumnMinWidth; - - var tabbingDirection = 1; - var activePosX; - var activeRow, activeCell; - var activeCellNode = null; - var currentEditor = null; - var serializedEditorValue; - var editController; - - var rowsCache = {}; - var renderedRows = 0; - var numVisibleRows; - var prevScrollTop = 0; - var scrollTop = 0; - var lastRenderedScrollTop = 0; - var lastRenderedScrollLeft = 0; - var prevScrollLeft = 0; - var scrollLeft = 0; - - var selectionModel; - var selectedRows = []; - - var plugins = []; - var cellCssClasses = {}; - - var columnsById = {}; - var sortColumns = []; - var columnPosLeft = []; - var columnPosRight = []; - - - // async call handles - var h_editorLoader = null; - var h_render = null; - var h_postrender = null; - var postProcessedRows = {}; - var postProcessToRow = null; - var postProcessFromRow = null; - - // perf counters - var counter_rows_rendered = 0; - var counter_rows_removed = 0; - - // These two variables work around a bug with inertial scrolling in Webkit/Blink on Mac. - // See http://crbug.com/312427. - var rowNodeFromLastMouseWheelEvent; // this node must not be deleted while inertial scrolling - var zombieRowNodeFromLastMouseWheelEvent; // node that was hidden instead of getting deleted - - - ////////////////////////////////////////////////////////////////////////////////////////////// - // Initialization - - function init() { - $container = $(container); - if ($container.length < 1) { - throw new Error("SlickGrid requires a valid container, " + container + " does not exist in the DOM."); - } - - // calculate these only once and share between grid instances - maxSupportedCssHeight = maxSupportedCssHeight || getMaxSupportedCssHeight(); - scrollbarDimensions = scrollbarDimensions || measureScrollbar(); - - options = $.extend({}, defaults, options); - validateAndEnforceOptions(); - columnDefaults.width = options.defaultColumnWidth; - - columnsById = {}; - for (var i = 0; i < columns.length; i++) { - var m = columns[i] = $.extend({}, columnDefaults, columns[i]); - columnsById[m.id] = i; - if (m.minWidth && m.width < m.minWidth) { - m.width = m.minWidth; - } - if (m.maxWidth && m.width > m.maxWidth) { - m.width = m.maxWidth; - } - } - - // validate loaded JavaScript modules against requested options - if (options.enableColumnReorder && !$.fn.sortable) { - throw new Error("SlickGrid's 'enableColumnReorder = true' option requires jquery-ui.sortable module to be loaded"); - } - - editController = { - "commitCurrentEdit": commitCurrentEdit, - "cancelCurrentEdit": cancelCurrentEdit - }; - - $container - .empty() - .css("overflow", "hidden") - .css("outline", 0) - .addClass(uid) - .addClass("ui-widget"); - - // set up a positioning container if needed - if (!/relative|absolute|fixed/.test($container.css("position"))) { - $container.css("position", "relative"); - } - - $focusSink = $("
").appendTo($container); - - $headerScroller = $("
").appendTo($container); - $headers = $("
").appendTo($headerScroller); - $headers.width(getHeadersWidth()); - - $headerRowScroller = $("
").appendTo($container); - $headerRow = $("
").appendTo($headerRowScroller); - $headerRowSpacer = $("
") - .css("width", getCanvasWidth() + scrollbarDimensions.width + "px") - .appendTo($headerRowScroller); - - $topPanelScroller = $("
").appendTo($container); - $topPanel = $("
").appendTo($topPanelScroller); - - if (!options.showTopPanel) { - $topPanelScroller.hide(); - } - - if (!options.showHeaderRow) { - $headerRowScroller.hide(); - } - - $viewport = $("
").appendTo($container); - $viewport.css("overflow-y", options.autoHeight ? "hidden" : "auto"); - - $canvas = $("
").appendTo($viewport); - - $focusSink2 = $focusSink.clone().appendTo($container); - - if (!options.explicitInitialization) { - finishInitialization(); - } - } - - function finishInitialization() { - if (!initialized) { - initialized = true; - - viewportW = parseFloat($.css($container[0], "width", true)); - - // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?) - // calculate the diff so we can set consistent sizes - measureCellPaddingAndBorder(); - - // for usability reasons, all text selection in SlickGrid is disabled - // with the exception of input and textarea elements (selection must - // be enabled there so that editors work as expected); note that - // selection in grid cells (grid body) is already unavailable in - // all browsers except IE - disableSelection($headers); // disable all text selection in header (including input and textarea) - - if (!options.enableTextSelectionOnCells) { - // disable text selection in grid cells except in input and textarea elements - // (this is IE-specific, because selectstart event will only fire in IE) - $viewport.bind("selectstart.ui", function (event) { - return $(event.target).is("input,textarea"); - }); - } - - updateColumnCaches(); - createColumnHeaders(); - setupColumnSort(); - createCssRules(); - resizeCanvas(); - bindAncestorScrollEvents(); - - $container - .bind("resize.slickgrid", resizeCanvas); - $viewport - //.bind("click", handleClick) - .bind("scroll", handleScroll); - $headerScroller - .bind("contextmenu", handleHeaderContextMenu) - .bind("click", handleHeaderClick) - .delegate(".slick-header-column", "mouseenter", handleHeaderMouseEnter) - .delegate(".slick-header-column", "mouseleave", handleHeaderMouseLeave); - $headerRowScroller - .bind("scroll", handleHeaderRowScroll); - $focusSink.add($focusSink2) - .bind("keydown", handleKeyDown); - $canvas - .bind("keydown", handleKeyDown) - .bind("click", handleClick) - .bind("mousedown", handleMouseDown) // QUANTOPIAN ADDED - .bind("dblclick", handleDblClick) - .bind("contextmenu", handleContextMenu) - .bind("draginit", handleDragInit) - .bind("dragstart", {distance: 3}, handleDragStart) - .bind("drag", handleDrag) - .bind("dragend", handleDragEnd) - .delegate(".slick-cell", "mouseenter", handleMouseEnter) - .delegate(".slick-cell", "mouseleave", handleMouseLeave); - - // Work around http://crbug.com/312427. - if (navigator.userAgent.toLowerCase().match(/webkit/) && - navigator.userAgent.toLowerCase().match(/macintosh/)) { - $canvas.bind("mousewheel", handleMouseWheel); - } - } - } - - function registerPlugin(plugin) { - plugins.unshift(plugin); - plugin.init(self); - } - - function unregisterPlugin(plugin) { - for (var i = plugins.length; i >= 0; i--) { - if (plugins[i] === plugin) { - if (plugins[i].destroy) { - plugins[i].destroy(); - } - plugins.splice(i, 1); - break; - } - } - } - - function setSelectionModel(model) { - if (selectionModel) { - selectionModel.onSelectedRangesChanged.unsubscribe(handleSelectedRangesChanged); - if (selectionModel.destroy) { - selectionModel.destroy(); - } - } - - selectionModel = model; - if (selectionModel) { - selectionModel.init(self); - selectionModel.onSelectedRangesChanged.subscribe(handleSelectedRangesChanged); - } - } - - function getSelectionModel() { - return selectionModel; - } - - function getCanvasNode() { - return $canvas[0]; - } - - function measureScrollbar() { - var $c = $("
").appendTo("body"); - var dim = { - width: $c.width() - $c[0].clientWidth, - height: $c.height() - $c[0].clientHeight - }; - $c.remove(); - return dim; - } - - function getHeadersWidth() { - var headersWidth = 0; - for (var i = 0, ii = columns.length; i < ii; i++) { - var width = columns[i].width; - headersWidth += width; - } - headersWidth += scrollbarDimensions.width; - return Math.max(headersWidth, viewportW) + 1000; - } - - function getCanvasWidth() { - var availableWidth = viewportHasVScroll ? viewportW - scrollbarDimensions.width : viewportW; - var rowWidth = 0; - var i = columns.length; - while (i--) { - rowWidth += columns[i].width; - } - return options.fullWidthRows ? Math.max(rowWidth, availableWidth) : rowWidth; - } - - function updateCanvasWidth(forceColumnWidthsUpdate) { - var oldCanvasWidth = canvasWidth; - canvasWidth = getCanvasWidth(); - - if (canvasWidth != oldCanvasWidth) { - $canvas.width(canvasWidth); - $headerRow.width(canvasWidth); - $headers.width(getHeadersWidth()); - viewportHasHScroll = (canvasWidth > viewportW - scrollbarDimensions.width); - } - - $headerRowSpacer.width(canvasWidth + (viewportHasVScroll ? scrollbarDimensions.width : 0)); - - if (canvasWidth != oldCanvasWidth || forceColumnWidthsUpdate) { - applyColumnWidths(); - } - } - - function disableSelection($target) { - if ($target && $target.jquery) { - $target - .attr("unselectable", "on") - .css("MozUserSelect", "none") - .bind("selectstart.ui", function () { - return false; - }); // from jquery:ui.core.js 1.7.2 - } - } - - function getMaxSupportedCssHeight() { - var supportedHeight = 1000000; - // FF reports the height back but still renders blank after ~6M px - var testUpTo = navigator.userAgent.toLowerCase().match(/firefox/) ? 6000000 : 1000000000; - var div = $("
").appendTo(document.body); - - while (true) { - var test = supportedHeight * 2; - div.css("height", test); - if (test > testUpTo || div.height() !== test) { - break; - } else { - supportedHeight = test; - } - } - - div.remove(); - return supportedHeight; - } - - // TODO: this is static. need to handle page mutation. - function bindAncestorScrollEvents() { - var elem = $canvas[0]; - while ((elem = elem.parentNode) != document.body && elem != null) { - // bind to scroll containers only - if (elem == $viewport[0] || elem.scrollWidth != elem.clientWidth || elem.scrollHeight != elem.clientHeight) { - var $elem = $(elem); - if (!$boundAncestors) { - $boundAncestors = $elem; - } else { - $boundAncestors = $boundAncestors.add($elem); - } - $elem.bind("scroll." + uid, handleActiveCellPositionChange); - } - } - } - - function unbindAncestorScrollEvents() { - if (!$boundAncestors) { - return; - } - $boundAncestors.unbind("scroll." + uid); - $boundAncestors = null; - } - - function updateColumnHeader(columnId, title, toolTip) { - if (!initialized) { return; } - var idx = getColumnIndex(columnId); - if (idx == null) { - return; - } - - var columnDef = columns[idx]; - var $header = $headers.children().eq(idx); - if ($header) { - if (title !== undefined) { - columns[idx].name = title; - } - if (toolTip !== undefined) { - columns[idx].toolTip = toolTip; - } - - trigger(self.onBeforeHeaderCellDestroy, { - "node": $header[0], - "column": columnDef - }); - - $header - .attr("title", toolTip || "") - .children().eq(0).html(title); - - trigger(self.onHeaderCellRendered, { - "node": $header[0], - "column": columnDef - }); - } - } - - function getHeaderRow() { - return $headerRow[0]; - } - - function getHeaderRowColumn(columnId) { - var idx = getColumnIndex(columnId); - var $header = $headerRow.children().eq(idx); - return $header && $header[0]; - } - - function createColumnHeaders() { - function onMouseEnter() { - $(this).addClass("ui-state-hover"); - } - - function onMouseLeave() { - $(this).removeClass("ui-state-hover"); - } - - $headers.find(".slick-header-column") - .each(function() { - var columnDef = $(this).data("column"); - if (columnDef) { - trigger(self.onBeforeHeaderCellDestroy, { - "node": this, - "column": columnDef - }); - } - }); - $headers.empty(); - $headers.width(getHeadersWidth()); - - $headerRow.find(".slick-headerrow-column") - .each(function() { - var columnDef = $(this).data("column"); - if (columnDef) { - trigger(self.onBeforeHeaderRowCellDestroy, { - "node": this, - "column": columnDef - }); - } - }); - $headerRow.empty(); - - for (var i = 0; i < columns.length; i++) { - var m = columns[i]; - - var header = $("
") - .html("" + m.name + "") - .width(m.width - headerColumnWidthDiff) - .attr("id", "" + uid + m.id) - .attr("title", m.toolTip || "") - .data("column", m) - .addClass(m.headerCssClass || "") - .appendTo($headers); - - if (options.enableColumnReorder || m.sortable) { - header - .on('mouseenter', onMouseEnter) - .on('mouseleave', onMouseLeave); - } - - if (m.sortable) { - header.addClass("slick-header-sortable"); - header.append(""); - } - - trigger(self.onHeaderCellRendered, { - "node": header[0], - "column": m - }); - - if (options.showHeaderRow) { - var headerRowCell = $("
") - .data("column", m) - .appendTo($headerRow); - - trigger(self.onHeaderRowCellRendered, { - "node": headerRowCell[0], - "column": m - }); - } - } - - setSortColumns(sortColumns); - setupColumnResize(); - if (options.enableColumnReorder) { - setupColumnReorder(); - } - } - - function setupColumnSort() { - $headers.click(function (e) { - // temporary workaround for a bug in jQuery 1.7.1 (http://bugs.jquery.com/ticket/11328) - e.metaKey = e.metaKey || e.ctrlKey; - - if ($(e.target).hasClass("slick-resizable-handle")) { - return; - } - - var $col = $(e.target).closest(".slick-header-column"); - if (!$col.length) { - return; - } - - var column = $col.data("column"); - if (column.sortable) { - if (!getEditorLock().commitCurrentEdit()) { - return; - } - - var sortOpts = null; - var i = 0; - for (; i < sortColumns.length; i++) { - if (sortColumns[i].columnId == column.id) { - sortOpts = sortColumns[i]; - sortOpts.sortAsc = !sortOpts.sortAsc; - break; - } - } - - if (e.metaKey && options.multiColumnSort) { - if (sortOpts) { - sortColumns.splice(i, 1); - } - } - else { - if ((!e.shiftKey && !e.metaKey) || !options.multiColumnSort) { - sortColumns = []; - } - - if (!sortOpts) { - sortOpts = { columnId: column.id, sortAsc: column.defaultSortAsc }; - sortColumns.push(sortOpts); - } else if (sortColumns.length == 0) { - sortColumns.push(sortOpts); - } - } - - setSortColumns(sortColumns); - - if (!options.multiColumnSort) { - trigger(self.onSort, { - multiColumnSort: false, - sortCol: column, - sortAsc: sortOpts.sortAsc}, e); - } else { - trigger(self.onSort, { - multiColumnSort: true, - sortCols: $.map(sortColumns, function(col) { - return {sortCol: columns[getColumnIndex(col.columnId)], sortAsc: col.sortAsc }; - })}, e); - } - } - }); - } - - function setupColumnReorder() { - $headers.filter(":ui-sortable").sortable("destroy"); - $headers.sortable({ - containment: "parent", - distance: 3, - axis: "x", - cursor: "default", - tolerance: "intersection", - helper: "clone", - placeholder: "slick-sortable-placeholder ui-state-default slick-header-column", - start: function (e, ui) { - ui.placeholder.width(ui.helper.outerWidth() - headerColumnWidthDiff); - $(ui.helper).addClass("slick-header-column-active"); - }, - beforeStop: function (e, ui) { - $(ui.helper).removeClass("slick-header-column-active"); - }, - stop: function (e) { - if (!getEditorLock().commitCurrentEdit()) { - $(this).sortable("cancel"); - return; - } - - var reorderedIds = $headers.sortable("toArray"); - var reorderedColumns = []; - for (var i = 0; i < reorderedIds.length; i++) { - reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]); - } - setColumns(reorderedColumns); - - trigger(self.onColumnsReordered, {}); - e.stopPropagation(); - setupColumnResize(); - } - }); - } - - function setupColumnResize() { - var $col, j, c, pageX, columnElements, minPageX, maxPageX, firstResizable, lastResizable; - columnElements = $headers.children(); - columnElements.find(".slick-resizable-handle").remove(); - columnElements.each(function (i, e) { - if (columns[i].resizable) { - if (firstResizable === undefined) { - firstResizable = i; - } - lastResizable = i; - } - }); - if (firstResizable === undefined) { - return; - } - columnElements.each(function (i, e) { - if (i < firstResizable || (options.forceFitColumns && i >= lastResizable)) { - return; - } - $col = $(e); - $("
") - .appendTo(e) - .bind("dragstart", function (e, dd) { - if (!getEditorLock().commitCurrentEdit()) { - return false; - } - pageX = e.pageX; - $(this).parent().addClass("slick-header-column-active"); - var shrinkLeewayOnRight = null, stretchLeewayOnRight = null; - // lock each column's width option to current width - columnElements.each(function (i, e) { - columns[i].previousWidth = $(e).outerWidth(); - }); - if (options.forceFitColumns) { - shrinkLeewayOnRight = 0; - stretchLeewayOnRight = 0; - // colums on right affect maxPageX/minPageX - for (j = i + 1; j < columnElements.length; j++) { - c = columns[j]; - if (c.resizable) { - if (stretchLeewayOnRight !== null) { - if (c.maxWidth) { - stretchLeewayOnRight += c.maxWidth - c.previousWidth; - } else { - stretchLeewayOnRight = null; - } - } - shrinkLeewayOnRight += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth); - } - } - } - var shrinkLeewayOnLeft = 0, stretchLeewayOnLeft = 0; - for (j = 0; j <= i; j++) { - // columns on left only affect minPageX - c = columns[j]; - if (c.resizable) { - if (stretchLeewayOnLeft !== null) { - if (c.maxWidth) { - stretchLeewayOnLeft += c.maxWidth - c.previousWidth; - } else { - stretchLeewayOnLeft = null; - } - } - shrinkLeewayOnLeft += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth); - } - } - if (shrinkLeewayOnRight === null) { - shrinkLeewayOnRight = 100000; - } - if (shrinkLeewayOnLeft === null) { - shrinkLeewayOnLeft = 100000; - } - if (stretchLeewayOnRight === null) { - stretchLeewayOnRight = 100000; - } - if (stretchLeewayOnLeft === null) { - stretchLeewayOnLeft = 100000; - } - maxPageX = pageX + Math.min(shrinkLeewayOnRight, stretchLeewayOnLeft); - minPageX = pageX - Math.min(shrinkLeewayOnLeft, stretchLeewayOnRight); - }) - .bind("drag", function (e, dd) { - var actualMinWidth, d = Math.min(maxPageX, Math.max(minPageX, e.pageX)) - pageX, x; - if (d < 0) { // shrink column - x = d; - for (j = i; j >= 0; j--) { - c = columns[j]; - if (c.resizable) { - actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth); - if (x && c.previousWidth + x < actualMinWidth) { - x += c.previousWidth - actualMinWidth; - c.width = actualMinWidth; - } else { - c.width = c.previousWidth + x; - x = 0; - } - } - } - - if (options.forceFitColumns) { - x = -d; - for (j = i + 1; j < columnElements.length; j++) { - c = columns[j]; - if (c.resizable) { - if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) { - x -= c.maxWidth - c.previousWidth; - c.width = c.maxWidth; - } else { - c.width = c.previousWidth + x; - x = 0; - } - } - } - } - } else { // stretch column - x = d; - for (j = i; j >= 0; j--) { - c = columns[j]; - if (c.resizable) { - if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) { - x -= c.maxWidth - c.previousWidth; - c.width = c.maxWidth; - } else { - c.width = c.previousWidth + x; - x = 0; - } - } - } - - if (options.forceFitColumns) { - x = -d; - for (j = i + 1; j < columnElements.length; j++) { - c = columns[j]; - if (c.resizable) { - actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth); - if (x && c.previousWidth + x < actualMinWidth) { - x += c.previousWidth - actualMinWidth; - c.width = actualMinWidth; - } else { - c.width = c.previousWidth + x; - x = 0; - } - } - } - } - } - applyColumnHeaderWidths(); - if (options.syncColumnCellResize) { - applyColumnWidths(); - } - }) - .bind("dragend", function (e, dd) { - var newWidth; - $(this).parent().removeClass("slick-header-column-active"); - for (j = 0; j < columnElements.length; j++) { - c = columns[j]; - newWidth = $(columnElements[j]).outerWidth(); - - if (c.previousWidth !== newWidth && c.rerenderOnResize) { - invalidateAllRows(); - } - } - updateCanvasWidth(true); - render(); - trigger(self.onColumnsResized, {}); - }); - }); - } - - function getVBoxDelta($el) { - var p = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"]; - var delta = 0; - $.each(p, function (n, val) { - delta += parseFloat($el.css(val)) || 0; - }); - return delta; - } - - function measureCellPaddingAndBorder() { - var el; - var h = ["borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight"]; - var v = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"]; - - el = $("").appendTo($headers); - headerColumnWidthDiff = headerColumnHeightDiff = 0; - if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") { - $.each(h, function (n, val) { - headerColumnWidthDiff += parseFloat(el.css(val)) || 0; - }); - $.each(v, function (n, val) { - headerColumnHeightDiff += parseFloat(el.css(val)) || 0; - }); - } - el.remove(); - - var r = $("
").appendTo($canvas); - el = $("").appendTo(r); - cellWidthDiff = cellHeightDiff = 0; - if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") { - $.each(h, function (n, val) { - cellWidthDiff += parseFloat(el.css(val)) || 0; - }); - $.each(v, function (n, val) { - cellHeightDiff += parseFloat(el.css(val)) || 0; - }); - } - r.remove(); - - absoluteColumnMinWidth = Math.max(headerColumnWidthDiff, cellWidthDiff); - } - - function createCssRules() { - $style = $("