diff --git a/src/js/headerRenderer.js b/src/js/headerRenderer.js index 70b292182bc..c1d7547e43b 100644 --- a/src/js/headerRenderer.js +++ b/src/js/headerRenderer.js @@ -310,20 +310,26 @@ HeaderRenderer.prototype.createHeaderCell = function(column, grouped, headerGrou HeaderRenderer.prototype.addSortHandling = function(headerCellLabel, colDefWrapper) { var that = this; - headerCellLabel.addEventListener("click", function() { + headerCellLabel.addEventListener("click", function(e) { // update sort on current col - if (colDefWrapper.sort === constants.ASC) { - colDefWrapper.sort = constants.DESC; - } else if (colDefWrapper.sort === constants.DESC) { + if (colDefWrapper.sort === constants.DESC) { colDefWrapper.sort = null - } else { - colDefWrapper.sort = constants.ASC; + } + else { + if (colDefWrapper.sort === constants.ASC) { + colDefWrapper.sort = constants.DESC; + } else { + colDefWrapper.sort = constants.ASC; + } + // Useful for determining the order in which the user sorted the columns: + colDefWrapper.sortedAt = new Date().valueOf(); } // clear sort on all columns except this one, and update the icons that.columnModel.getAllColumns().forEach(function(columnToClear) { - if (columnToClear !== colDefWrapper) { + // Do not clear if either holding shift, or if column in question was clicked + if (!(e.shiftKey || columnToClear === colDefWrapper)) { columnToClear.sort = null; } diff --git a/src/js/inMemoryRowController.js b/src/js/inMemoryRowController.js index 808035c934a..b11fa5becc8 100644 --- a/src/js/inMemoryRowController.js +++ b/src/js/inMemoryRowController.js @@ -137,20 +137,27 @@ InMemoryRowController.prototype.recursivelyCreateAggData = function(nodes, group // private InMemoryRowController.prototype.doSort = function() { //see if there is a col we are sorting by - var columnForSorting = null; + var sortingOptions = []; this.columnModel.getAllColumns().forEach(function(column) { if (column.sort) { - columnForSorting = column; + var ascending = column.sort === constants.ASC; + sortingOptions.push({ + inverter: ascending ? 1 : -1, + sortedAt: column.sortedAt, + colDef: column.colDef + }); } }); - var rowNodesBeforeSort = this.rowsAfterFilter.slice(0); + // The columns are to be sorted in the order that the user selected them: + sortingOptions.sort(function(optionA, optionB){ + return optionA.sortedAt - optionB.sortedAt; + }); - if (columnForSorting) { - var ascending = columnForSorting.sort === constants.ASC; - var inverter = ascending ? 1 : -1; + var rowNodesBeforeSort = this.rowsAfterFilter.slice(0); - this.sortList(rowNodesBeforeSort, columnForSorting.colDef, inverter); + if (sortingOptions.length) { + this.sortList(rowNodesBeforeSort, sortingOptions); } else { // if no sorting, set all group children after sort to the original list this.recursivelyResetSort(rowNodesBeforeSort); @@ -171,7 +178,7 @@ InMemoryRowController.prototype.recursivelyResetSort = function(rowNodes) { }; // private -InMemoryRowController.prototype.sortList = function(nodes, colDef, inverter) { +InMemoryRowController.prototype.sortList = function(nodes, sortOptions) { // sort any groups recursively for (var i = 0, l = nodes.length; i < l; i++) { // critical section, no functional programming @@ -183,19 +190,29 @@ InMemoryRowController.prototype.sortList = function(nodes, colDef, inverter) { } var that = this; - nodes.sort(function(objA, objB) { - + function compare(objA, objB, colDef){ var valueA = that.getValue(objA.data, colDef, objA); var valueB = that.getValue(objB.data, colDef, objB); - if (colDef.comparator) { //if comparator provided, use it - return colDef.comparator(valueA, valueB, objA, objB) * inverter; + return colDef.comparator(valueA, valueB, objA, objB); } else { //otherwise do our own comparison - return utils.defaultComparator(valueA, valueB, objA, objB) * inverter; + return utils.defaultComparator(valueA, valueB, objA, objB); } + } + nodes.sort(function(objA, objB) { + // Iterate columns, return the first that doesn't match + for(var i = 0, len = sortOptions.length; i < len; i++){ + var sortOption = sortOptions[i]; + var compared = compare(objA, objB, sortOption.colDef); + if(compared !== 0){ + return compared * sortOption.inverter; + } + } + // All matched, these are identical as far as the sort is concerned: + return 0; }); };