ng-grid
Version:
__Contributors:__
168 lines (166 loc) • 6.32 kB
JavaScript
ngGridServices.factory('SortService', ['$parse', function($parse) {
var sortService = {};
sortService.colSortFnCache = {}; // cache of sorting functions. Once we create them, we don't want to keep re-doing it
// this takes an piece of data from the cell and tries to determine its type and what sorting
// function to use for it
// @item - the cell data
sortService.guessSortFn = function(item) {
var itemType = typeof(item);
//check for numbers and booleans
switch (itemType) {
case "number":
return sortService.sortNumber;
case "boolean":
return sortService.sortBool;
case "string":
// if number string return number string sort fn. else return the str
return item.match(/^-?[£$¤]?[\d,.]+%?$/) ? sortService.sortNumberStr : sortService.sortAlpha;
default:
//check if the item is a valid Date
if (Object.prototype.toString.call(item) === '[object Date]') {
return sortService.sortDate;
} else {
//finally just sort the basic sort...
return sortService.basicSort;
}
}
};
//#region Sorting Functions
sortService.basicSort = function(a, b) {
if (a == b) {
return 0;
}
if (a < b) {
return -1;
}
return 1;
};
sortService.sortNumber = function(a, b) {
return a - b;
};
sortService.sortNumberStr = function(a, b) {
var numA, numB, badA = false, badB = false;
numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
if (isNaN(numA)) {
badA = true;
}
numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
if (isNaN(numB)) {
badB = true;
}
// we want bad ones to get pushed to the bottom... which effectively is "greater than"
if (badA && badB) {
return 0;
}
if (badA) {
return 1;
}
if (badB) {
return -1;
}
return numA - numB;
};
sortService.sortAlpha = function(a, b) {
var strA = a.toLowerCase(),
strB = b.toLowerCase();
return strA == strB ? 0 : (strA < strB ? -1 : 1);
};
sortService.sortDate = function(a, b) {
var timeA = a.getTime(),
timeB = b.getTime();
return timeA == timeB ? 0 : (timeA < timeB ? -1 : 1);
};
sortService.sortBool = function(a, b) {
if (a && b) {
return 0;
}
if (!a && !b) {
return 0;
} else {
return a ? 1 : -1;
}
};
//#endregion
// the core sorting logic trigger
sortService.sortData = function(sortInfo, data /*datasource*/) {
// first make sure we are even supposed to do work
if (!data || !sortInfo) {
return;
}
var l = sortInfo.fields.length,
order = sortInfo.fields,
col,
direction,
// IE9 HACK.... omg, I can't reference data array within the sort fn below. has to be a separate reference....!!!!
d = data.slice(0);
//now actually sort the data
data.sort(function (itemA, itemB) {
var tem = 0,
indx = 0,
sortFn;
while (tem == 0 && indx < l) {
// grab the metadata for the rest of the logic
col = sortInfo.columns[indx];
direction = sortInfo.directions[indx],
sortFn = sortService.getSortFn(col, d);
var propA = $parse(order[indx])(itemA);
var propB = $parse(order[indx])(itemB);
// we want to allow zero values to be evaluated in the sort function
if ((!propA && propA != 0) || (!propB && propB != 0)) {
// we want to force nulls and such to the bottom when we sort... which effectively is "greater than"
if (!propB && !propA) {
tem = 0;
} else if (!propA) {
tem = 1;
} else if (!propB) {
tem = -1;
}
} else {
tem = sortFn(propA, propB);
}
indx++;
}
//made it this far, we don't have to worry about null & undefined
if (direction === ASC) {
return tem;
} else {
return 0 - tem;
}
});
};
sortService.Sort = function(sortInfo, data) {
if (sortService.isSorting) {
return;
}
sortService.isSorting = true;
sortService.sortData(sortInfo, data);
sortService.isSorting = false;
};
sortService.getSortFn = function(col, data) {
var sortFn = undefined, item;
//see if we already figured out what to use to sort the column
if (sortService.colSortFnCache[col.field]) {
sortFn = sortService.colSortFnCache[col.field];
} else if (col.sortingAlgorithm != undefined) {
sortFn = col.sortingAlgorithm;
sortService.colSortFnCache[col.field] = col.sortingAlgorithm;
} else { // try and guess what sort function to use
item = data[0];
if (!item) {
return sortFn;
}
sortFn = sortService.guessSortFn($parse(col.field)(item));
//cache it
if (sortFn) {
sortService.colSortFnCache[col.field] = sortFn;
} else {
// we assign the alpha sort because anything that is null/undefined will never get passed to
// the actual sorting function. It will get caught in our null check and returned to be sorted
// down to the bottom
sortFn = sortService.sortAlpha;
}
}
return sortFn;
};
return sortService;
}]);