diff --git a/docs/index.html b/docs/index.html index 48210e62..d509f8c8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1178,6 +1178,19 @@ From the example function above, you'll end up with something similar to this HT Example + + + Boolean + false + + Setting this option to true and sorting two rows with exactly the same content, the original sort order is maintained (v2.14). +

+ This isn't exactly a stable sort because the sort order maintains the original unsorted order when sorting the column in an ascending direction. When sorting the column in a descending order, the opposite of the original unsorted order is returned. If that doesn't make any sense, please refer to issue # +
+ + + + sortMultiSortKey String diff --git a/js/jquery.tablesorter.js b/js/jquery.tablesorter.js index d065f552..6e5d4b3b 100644 --- a/js/jquery.tablesorter.js +++ b/js/jquery.tablesorter.js @@ -55,6 +55,7 @@ sortForce : null, // column(s) first sorted; always applied sortList : [], // Initial sort order; applied initially; updated when manually sorted sortAppend : null, // column(s) sorted last; always applied + sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained sortInitialOrder : 'asc', // sort direction on first click sortLocaleCompare: false, // replace equivalent character (accented characters) @@ -665,14 +666,9 @@ // sort direction, true = asc, false = desc dir = order === 0; - // set a & b depending on sort direction - x = dir ? a : b; - y = dir ? b : a; - - // determine how to sort empty cells - e = c.string[ (c.empties[col] || c.emptyTo ) ]; - if (x[col] === '' && e !== 0) { return ((typeof(e) === 'boolean') ? (e ? -1 : 1) : (e || 1)) * (dir ? 1 : -1); } - if (y[col] === '' && e !== 0) { return ((typeof(e) === 'boolean') ? (e ? 1 : -1) : (-e || -1)) * (dir ? 1 : -1); } + if (c.sortStable && a[col] === b[col] && l === 1) { + return a[orgOrderCol] - b[orgOrderCol]; + } // fallback to natural sort since it is more robust num = /n/i.test(getCachedSortType(c.parsers, col)); @@ -685,8 +681,12 @@ } // fall back to built-in numeric sort // var sort = $.tablesorter["sort" + s](table, a[c], b[c], c, colMax[c], dir); - sort = c.numberSorter ? c.numberSorter(x[col], y[col], dir, colMax[col], table) : ts.sortNumeric(x[col], y[col], num, colMax[col]); + sort = c.numberSorter ? c.numberSorter(x[col], y[col], dir, colMax[col], table) : + ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table); } else { + // set a & b depending on sort direction + x = dir ? a : b; + y = dir ? b : a; // text sort function if (typeof(cts) === 'function') { // custom OVERALL text sorter @@ -696,7 +696,7 @@ sort = cts[col](x[col], y[col], dir, col, table); } else { // fall back to natural sort - sort = ts.sortNatural(x[col], y[col]); + sort = ts[ 'sortNatural' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], col, table, c); } } if (sort) { return sort; } @@ -1082,6 +1082,7 @@ if ( xD < yD ) { return -1; } if ( xD > yD ) { return 1; } } + // chunk/tokenize xN = a.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); yN = b.replace(r.chunk, '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); @@ -1104,6 +1105,22 @@ return 0; }; + ts.sortNaturalAsc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + return ts.sortNatural(a, b); + }; + + ts.sortNaturalDesc = function(a, b, col, table, c) { + if (a === b) { return 0; } + var e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + return ts.sortNatural(b, a); + }; + // basic alphabetical sort ts.sortText = function(a, b) { return a > b ? 1 : (a < b ? -1 : 0); @@ -1112,22 +1129,41 @@ // return text string value by adding up ascii value // so the text is somewhat sorted when using a digital sort // this is NOT an alphanumeric sort - ts.getTextValue = function(a, d, mx) { + ts.getTextValue = function(a, num, mx) { if (mx) { // make sure the text value is greater than the max numerical value (mx) - var i, l = a ? a.length : 0, n = mx + d; + var i, l = a ? a.length : 0, n = mx + num; for (i = 0; i < l; i++) { n += a.charCodeAt(i); } - return d * n; + return num * n; } return 0; }; - ts.sortNumeric = function(a, b, dir, mx) { + ts.sortNumericAsc = function(a, b, num, mx, col, table) { if (a === b) { return 0; } - if (isNaN(a)) { a = ts.getTextValue(a, dir, mx); } - if (isNaN(b)) { b = ts.getTextValue(b, dir, mx); } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return a - b; + }; + + ts.sortNumericDesc = function(a, b, num, mx, col, table) { + if (a === b) { return 0; } + var c = table.config, + e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (isNaN(a)) { a = ts.getTextValue(a, num, mx); } + if (isNaN(b)) { b = ts.getTextValue(b, num, mx); } + return b - a; + }; + + ts.sortNumeric = function(a, b) { return a - b; }; diff --git a/js/jquery.tablesorter.widgets.js b/js/jquery.tablesorter.widgets.js index fab8cbae..0415e99f 100644 --- a/js/jquery.tablesorter.widgets.js +++ b/js/jquery.tablesorter.widgets.js @@ -968,7 +968,7 @@ ts.filter = { arry = $.grep(arry, function(value, indx) { return $.inArray(value, arry) === indx; }); - arry = (ts.sortNatural) ? arry.sort(function(a, b) { return ts.sortNatural(a, b); }) : arry.sort(true); + arry = (ts.sortNatural) ? arry.sort(function(a, b) { return ts.sortNatural(a, b, column, tabl); }) : arry.sort(true); // Get curent filter value currentValue = c.$table.find('thead').find('select.tablesorter-filter[data-column="' + column + '"]').val();