diff --git a/source/Ox/js/Array.js b/source/Ox/js/Array.js index 7471b1f7..b9a52d02 100644 --- a/source/Ox/js/Array.js +++ b/source/Ox/js/Array.js @@ -9,6 +9,7 @@ Ox.api Turns an array into a list API cache If true, cache results enums Enumerables, for example `{size: ['S', 'M', 'L']}` geo If true, return combined area with totals + map Sort map, for example `{name: function(v, o) { return o.sortName; }}` sort <[o]|[s]> Default sort, for example `['+name', '-age']` sums <[s]> List of keys to be included in totals unique The name of the unique key @@ -129,6 +130,17 @@ Ox.api Turns an array into a list API }, sort: [{key: 'size', operator: '-'}] }); + Ox.test.api = Ox.api([ + {name: 'John Cale', sortName: 'Cale, John'}, + {name: 'Brian Eno', sortName: 'Eno, Brian'} + ], { + map: {name: function(value, object) { return object.sortName; }}, + unique: 'name' + }); + Ox.test.apiResults[9] = Ox.test.api({ + keys: ['name'], + sort: [{key: 'name', operator: '+'}] + }); > Ox.test.apiResults[0].data {items: 3, n: 5} @@ -148,6 +160,8 @@ Ox.api Turns an array into a list API {positions: {foo: 2, bar: 0}} > Ox.test.apiResults[8].data {items: [{i: 2, size: 'L'}, {i: 1, size: 'M'}]} + > Ox.test.apiResults[9].data + {items: [{name: 'John Cale'}, {name: 'Brian Eno'}]} @*/ Ox.api = function(items, options) { @@ -155,6 +169,7 @@ Ox.api = function(items, options) { cache: options.cache, enums: options.enums ? parseEnums(options.enums) : {}, geo: options.geo, + map: options.map || {}, sort: options.sort || [], sums: options.sums || [], unique: options.unique || 'id' @@ -162,8 +177,8 @@ Ox.api = function(items, options) { fn = function(options, callback) { var data, keys, - result = {data: {}, status: {code: 200, text: 'ok'}}, - sort = {}; + map = {}, + result = {data: {}, status: {code: 200, text: 'ok'}}; options = options || {}; if (options.query) { // find @@ -187,9 +202,11 @@ Ox.api = function(items, options) { options.sort.forEach(function(v) { var key = v.key; if (api.enums[key]) { - sort[key] = function(value) { + map[key] = function(value) { return api.enums[key].indexOf(value.toLowerCase()); }; + } else if (api.map[key]) { + map[key] = api.map[key]; }/* else if (Ox.isArray(items[0][key])) { sort[key] = function(value) { return value.join(', '); @@ -197,7 +214,7 @@ Ox.api = function(items, options) { }*/ }); if (options.keys || options.positions) { - result.data.items = sortBy(result.data.items, options.sort, sort, options.query); + result.data.items = sortBy(result.data.items, options.sort, map, options.query); } } if (options.positions) { @@ -566,56 +583,36 @@ Ox.range = function() { (function() { - function getSortValues(array, map) { - var mappedArray = map ? array.map(map) : array, length = 0, sort = {}; - // find numbers, and length of longest number - array.forEach(function(value, i) { - var mappedValue = mappedArray[i], matches; - if (Ox.isString(mappedValue)) { - matches = mappedValue.match(/\d+/g); - if (matches) { - length = Ox.max(matches.map(function(match) { - return match.length; - }).concat(length)); + var getSortValue = Ox.cache(function getSortValue(value) { + var sortValue = value; + function trim(value) { + return value.replace(/^\W+/, ''); + } + if ( + Ox.isEmpty(value) + || Ox.isNull(value) + || Ox.isUndefined(value) + ) { + sortValue = null; + } else if (Ox.isString(value)) { + // make lowercase and remove leading non-word characters + sortValue = trim(value.toLowerCase()); + // move leading articles to the end + // and remove leading non-word characters + Ox.forEach(['a', 'an', 'the'], function(article) { + if (new RegExp('^' + article + ' ').test(sortValue)) { + sortValue = trim(sortValue.slice(article.length + 1)) + + ', ' + sortValue.slice(0, article.length); + return false; // break } - } - }); - // make lowercase, remove leading non-word characters, - // pad numbers and move leading articles to the end - array.forEach(function(value, i) { - function pad(value) { - return value - .replace(/^\W+/, '') - .replace(/\d+/g, function(match) { - return Ox.pad(match, 'left', length, '0'); - }); - } - var mappedValue = mappedArray[i]; - if ( - Ox.isEmpty(mappedValue) - || Ox.isNull(mappedValue) - || Ox.isUndefined(mappedValue) - ) { - sort[value] = null; - } else if (Ox.isString(mappedValue)) { - sort[value] = pad(mappedValue.toLowerCase()); - Ox.forEach(['a', 'an', 'the'], function(article) { - var length; - if (new RegExp('^' + article + ' ').test(sort[value])) { - length = article.length; - sort[value] = pad( - sort[value].slice(length + 1) + ', ' - + sort[value].slice(0, length) - ); - return false; // break - } - }); - } else { - sort[value] = mappedValue; - } - }); - return sort; - } + }); + // pad numbers + sortValue = sortValue.replace(/\d+/g, function(match) { + return Ox.pad(match, 'left', 64, '0'); + }); + } + return sortValue; + }); /*@ Ox.sort Sorts an array, handling articles and digits, ignoring capitalization @@ -637,15 +634,9 @@ Ox.range = function() { Ox.sort = function(array, map) { var values = getSortValues(map ? array.map(map) : array); return array.sort(function(a, b) { - a = map ? map(a) : a; - b = map ? map(b) : b; - var ret = 0; - if (values[a] < values[b]) { - ret = -1; - } else if (values[a] > values[b]) { - ret = 1; - } - return ret; + a = getSortValue(map ? map(a) : a); + b = getSortValue(map ? map(b) : b); + return a < b ? -1 : a > b ? 1 : 0; }); }; @@ -661,28 +652,24 @@ Ox.range = function() { [{id: 1, name: '8 Women'}, {id: 0, name: '80 Days'}] @*/ Ox.sortBy = function(array, by, map) { - var values = {}; - by = Ox.makeArray(by); - map = map || {}; - by = by.map(function(value) { + var sortValues = {}; + by = Ox.makeArray(by).map(function(value) { return Ox.isString(value) ? { key: value.replace(/^[\+\-]/, ''), operator: value[0] == '-' ? '-' : '+' } : value; }); - by.map(function(value) { - return value.key; - }).forEach(function(key) { - values[key] = getSortValues(array.map(function(value) { - return value[key]; - }), map[key]); - }); + map = map || {}; return array.sort(function(a, b) { var aValue, bValue, index = 0, key, ret = 0; while (ret == 0 && index < by.length) { key = by[index].key; - aValue = values[key][a[key]]; - bValue = values[key][b[key]]; + aValue = getSortValue( + map[key] ? map[key](a[key], a) : a[key] + ); + bValue = getSortValue( + map[key] ? map[key](b[key], b) : b[key] + ); if ((aValue === null) != (bValue === null)) { ret = aValue === null ? 1 : -1; } else if (aValue < bValue) {