1
0
mirror of https://github.com/DataTables/DataTables.git synced 2025-02-18 16:54:14 +01:00

Fixed: Stable sorting algorithm was slightly wrong when dealing with values which match each other. The idea for the stable sort is that the position shouldn't change so it should do a numeric sort of the row's current positions (the comment reflected this...) but it was in fact doing the sort on the value (aoData index), thus the "stable sort" position would reflect the original starting positions of the data, rather than the current position. The fix is to correctly look up the position of the index in the array and sort on that position (note the array is cloned, so it doesn't try to sort the dynamically sorted positions, which would make the sort unstable) - 2746

This commit is contained in:
Allan Jardine 2010-09-30 08:17:38 +01:00
parent 34aa952ec1
commit e4bed66535
2 changed files with 209 additions and 4 deletions

View File

@ -4234,7 +4234,10 @@
* }
* So basically we have a test for each column, and if that column matches, test the
* next one. If all columns match, then we use a numeric sort on the position the two
* row have in the original data array in order to provide a stable sort.
* row have in the original data array in order to provide a stable sort. In order to
* get the position for the numeric stablisation, we need to take a clone of the current
* display array and then get the position of the sorting value from that during the
* sort.
*
* Note that for use with the Closure compiler, we need to be very careful how we deal
* with this eval. Closure will rename all of our local variables, resutling in breakage
@ -4245,11 +4248,13 @@
this.ClosureDataTables = {
"fn": function(){},
"data": aoData,
"sort": _oExt.oSort
"sort": _oExt.oSort,
"master": oSettings.aiDisplayMaster.slice()
};
var sDynamicSort = "this.ClosureDataTables.fn = function(a,b){"+
"var iTest, oSort=this.ClosureDataTables.sort, "+
"aoData=this.ClosureDataTables.data;";
"aoData=this.ClosureDataTables.data, "+
"aiOrig=this.ClosureDataTables.master;";
for ( i=0 ; i<aaSort.length-1 ; i++ )
{
@ -4265,7 +4270,8 @@
iDataType = oSettings.aoColumns[ iDataSort ].sType;
sDynamicSort += "iTest = oSort['"+iDataType+"-"+aaSort[aaSort.length-1][1]+"']"+
"( aoData[a]._aData["+iDataSort+"], aoData[b]._aData["+iDataSort+"] );"+
"if (iTest===0) return oSort['numeric-"+aaSort[aaSort.length-1][1]+"'](a, b); "+
"if (iTest===0) "+
"return oSort['numeric-asc'](jQuery.inArray(a,aiOrig), jQuery.inArray(b,aiOrig)); "+
"return iTest;}";
/* The eval has to be done to a variable for IE */

View File

@ -0,0 +1,199 @@
// DATA_TEMPLATE: dom_data
oTest.fnStart( "2746 - Stable sorting" );
$(document).ready( function () {
$('#example').dataTable();
oTest.fnTest(
"Initial sort",
null,
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
return ret;
}
);
oTest.fnTest(
"Reserve initial sort",
function () {
$('#example thead th:eq(0)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Webkit' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Safari 1.2' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 1.3' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
return ret;
}
);
oTest.fnTest(
"Reserve to go back to initial sort sort",
function () {
$('#example thead th:eq(0)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
return ret;
}
);
oTest.fnTest(
"Reserve initial sort again",
function () {
$('#example thead th:eq(0)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Webkit' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Safari 1.2' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 1.3' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
return ret;
}
);
oTest.fnTest(
"And once more back to the initial sort",
function () {
$('#example thead th:eq(0)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Firefox 1.0' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Firefox 1.5' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Firefox 2.0';
return ret;
}
);
oTest.fnTest(
"Sort on second column",
function () {
$('#example thead th:eq(1)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'AOL browser (AOL desktop)' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.0';
return ret;
}
);
oTest.fnTest(
"Reserve sort on second column",
function () {
$('#example thead th:eq(1)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Webkit' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Seamonkey 1.1' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Safari 3.0' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Safari 2.0';
return ret;
}
);
oTest.fnTest(
"And back to asc sorting on second column",
function () {
$('#example thead th:eq(1)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'AOL browser (AOL desktop)' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.0';
return ret;
}
);
oTest.fnTest(
"Sort on third column, having now sorted on second",
function () {
$('#example thead th:eq(2)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Misc' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Dillo 0.8' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'NetFront 3.1';
return ret;
}
);
oTest.fnTest(
"Reserve sort on third column",
function () {
$('#example thead th:eq(2)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Misc' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Trident' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'IE Mobile' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Internet Explorer 7' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'AOL browser (AOL desktop)';
return ret;
}
);
oTest.fnTest(
"Return sorting on third column to asc",
function () {
$('#example thead th:eq(2)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Other browsers' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Misc' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'All others' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Dillo 0.8' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'NetFront 3.1';
return ret;
}
);
oTest.fnTest(
"Sort on first column having sorted on second then third columns",
function () {
$('#example thead th:eq(0)').click();
},
function () {
var ret =
$('#example tbody tr:eq(0) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(1) td:eq(0)').html() == 'Gecko' &&
$('#example tbody tr:eq(0) td:eq(1)').html() == 'Epiphany 2.20' &&
$('#example tbody tr:eq(1) td:eq(1)').html() == 'Camino 1.0' &&
$('#example tbody tr:eq(2) td:eq(1)').html() == 'Camino 1.5';
return ret;
}
);
oTest.fnComplete();
} );