So I traced deeper and deeper into the Ext source code. I discovered that if you make your selections from bottom up then the "last selected" property stays at the first row you selected. But if you select from top down, then it keeps changing to the last row you selected. I walked up the stack trace until I found where the code handles top down different from bottom up.
To fix this, I overrode the Ext.selection.Model.selectRange I kept all of the existing code but added in a records.reverse() line in there with a tiny flag to see f you need it or not. Take a look below.
Code:
Ext.override(Ext.selection.Model, {
/**
* Selects a range of rows if the selection model {@link #isLocked is not locked}.
* All rows in between startRow and endRow are also selected.
* @param {Ext.data.Model/Number} startRow The record or index of the first row in the range
* @param {Ext.data.Model/Number} endRow The record or index of the last row in the range
* @param {Boolean} keepExisting (optional) True to retain existing selections
*/
selectRange : function(startRow, endRow, keepExisting, dir){
var me = this,
store = me.store,
selectedCount = 0,
i,
tmp,
dontDeselect,
records = [];
if (me.isLocked()){
return;
}
if (!keepExisting) {
me.deselectAll(true);
}
if (!Ext.isNumber(startRow)) {
startRow = store.indexOf(startRow);
}
if (!Ext.isNumber(endRow)) {
endRow = store.indexOf(endRow);
}
// WG: create a flag to see if we are swapping
var swapped = false;
// ---
// swap values
if (startRow > endRow){
// WG: set value to true for my flag
swapped = true;
// ----
tmp = endRow;
endRow = startRow;
startRow = tmp;
}
for (i = startRow; i <= endRow; i++) {
if (me.isSelected(store.getAt(i))) {
selectedCount++;
}
}
if (!dir) {
dontDeselect = -1;
} else {
dontDeselect = (dir == 'up') ? startRow : endRow;
}
for (i = startRow; i <= endRow; i++){
if (selectedCount == (endRow - startRow + 1)) {
if (i != dontDeselect) {
me.doDeselect(i, true);
}
} else {
records.push(store.getAt(i));
}
}
//WG: START CHANGE
// This is my fix, we need to flip the order
// for it to correctly track what was selected first.
if(!swapped){
records.reverse();
}
//WG: END CHANGE
me.doMultiSelect(records, true);
}
});