| 
176 | 176 | orderByFilter.$inject = ['$parse'];  | 
177 | 177 | function orderByFilter($parse) {  | 
178 | 178 |   return function(array, sortPredicate, reverseOrder) {  | 
 | 179 | + | 
179 | 180 |     if (!(isArrayLike(array))) return array;  | 
180 |  | -    sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];  | 
 | 181 | + | 
 | 182 | +    if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }  | 
181 | 183 |     if (sortPredicate.length === 0) { sortPredicate = ['+']; }  | 
182 |  | -    sortPredicate = sortPredicate.map(function(predicate) {  | 
183 |  | -      var descending = false, get = predicate || identity;  | 
184 |  | -      if (isString(predicate)) {  | 
 | 184 | + | 
 | 185 | +    var predicates = processPredicates(sortPredicate);  | 
 | 186 | +    var compareValues = Array.prototype.map.call(array, getComparisonObject);  | 
 | 187 | + | 
 | 188 | +    compareValues.sort(doComparison);  | 
 | 189 | +    array = compareValues.map(function(item) { return item.value; });  | 
 | 190 | +    if (reverseOrder) { array.reverse(); }  | 
 | 191 | +    return array;  | 
 | 192 | + | 
 | 193 | +    function getComparisonObject(value) {  | 
 | 194 | +      return {  | 
 | 195 | +        value: value,  | 
 | 196 | +        predicateValues: predicates.map(function(predicate) {  | 
 | 197 | +          return getPredicateValue(predicate.get(value));  | 
 | 198 | +        })  | 
 | 199 | +      };  | 
 | 200 | +    }  | 
 | 201 | + | 
 | 202 | +    function doComparison(v1, v2) {  | 
 | 203 | +      return predicates.reduce(function(result, predicate, index) {  | 
 | 204 | +        return result || compare(v1.predicateValues[index], v2.predicateValues[index]) * predicate.descending;  | 
 | 205 | +      }, 0);  | 
 | 206 | +    }  | 
 | 207 | +  };  | 
 | 208 | + | 
 | 209 | +  function processPredicates(sortPredicate) {  | 
 | 210 | +    return sortPredicate.map(function(predicate) {  | 
 | 211 | +      var descending = 1, get = identity;  | 
 | 212 | + | 
 | 213 | +      if (isFunction(predicate)) {  | 
 | 214 | +        get = predicate;  | 
 | 215 | +      } else if (isString(predicate)) {  | 
185 | 216 |         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {  | 
186 |  | -          descending = predicate.charAt(0) == '-';  | 
 | 217 | +          descending = predicate.charAt(0) == '-' ? -1 : 1;  | 
187 | 218 |           predicate = predicate.substring(1);  | 
188 | 219 |         }  | 
189 |  | -        if (predicate === '') {  | 
190 |  | -          // Effectively no predicate was passed so we compare identity  | 
191 |  | -          return reverseComparator(compare, descending);  | 
192 |  | -        }  | 
193 |  | -        get = $parse(predicate);  | 
194 |  | -        if (get.constant) {  | 
195 |  | -          var key = get();  | 
196 |  | -          return reverseComparator(function(a, b) {  | 
197 |  | -            return compare(a[key], b[key]);  | 
198 |  | -          }, descending);  | 
 | 220 | +        if (predicate !== '') {  | 
 | 221 | +          get = $parse(predicate);  | 
 | 222 | +          if (get.constant) {  | 
 | 223 | +            var key = get();  | 
 | 224 | +            get = function(value) { return value[key]; };  | 
 | 225 | +          }  | 
199 | 226 |         }  | 
200 | 227 |       }  | 
201 |  | -      return reverseComparator(function(a, b) {  | 
202 |  | -        return compare(get(a),get(b));  | 
203 |  | -      }, descending);  | 
 | 228 | +      return { get: get, descending: descending };  | 
204 | 229 |     });  | 
205 |  | -    return slice.call(array).sort(reverseComparator(comparator, reverseOrder));  | 
 | 230 | +  }  | 
206 | 231 | 
 
  | 
207 |  | -    function comparator(o1, o2) {  | 
208 |  | -      for (var i = 0; i < sortPredicate.length; i++) {  | 
209 |  | -        var comp = sortPredicate[i](o1, o2);  | 
210 |  | -        if (comp !== 0) return comp;  | 
211 |  | -      }  | 
212 |  | -      return 0;  | 
213 |  | -    }  | 
214 |  | -    function reverseComparator(comp, descending) {  | 
215 |  | -      return descending  | 
216 |  | -          ? function(a, b) {return comp(b,a);}  | 
217 |  | -          : comp;  | 
 | 232 | +  function isPrimitive(value) {  | 
 | 233 | +    switch (typeof value) {  | 
 | 234 | +      case 'number': /* falls through */  | 
 | 235 | +      case 'boolean': /* falls through */  | 
 | 236 | +      case 'string':  | 
 | 237 | +        return true;  | 
 | 238 | +      default:  | 
 | 239 | +        return false;  | 
218 | 240 |     }  | 
 | 241 | +  }  | 
219 | 242 | 
 
  | 
220 |  | -    function isPrimitive(value) {  | 
221 |  | -      switch (typeof value) {  | 
222 |  | -        case 'number': /* falls through */  | 
223 |  | -        case 'boolean': /* falls through */  | 
224 |  | -        case 'string':  | 
225 |  | -          return true;  | 
226 |  | -        default:  | 
227 |  | -          return false;  | 
228 |  | -      }  | 
 | 243 | +  function objectToString(value) {  | 
 | 244 | +    if (value === null) return 'null';  | 
 | 245 | +    if (typeof value.valueOf === 'function') {  | 
 | 246 | +      value = value.valueOf();  | 
 | 247 | +      if (isPrimitive(value)) return value;  | 
 | 248 | +    }  | 
 | 249 | +    if (typeof value.toString === 'function') {  | 
 | 250 | +      value = value.toString();  | 
 | 251 | +      if (isPrimitive(value)) return value;  | 
229 | 252 |     }  | 
 | 253 | +    return '';  | 
 | 254 | +  }  | 
230 | 255 | 
 
  | 
231 |  | -    function objectToString(value) {  | 
232 |  | -      if (value === null) return 'null';  | 
233 |  | -      if (typeof value.valueOf === 'function') {  | 
234 |  | -        value = value.valueOf();  | 
235 |  | -        if (isPrimitive(value)) return value;  | 
236 |  | -      }  | 
237 |  | -      if (typeof value.toString === 'function') {  | 
238 |  | -        value = value.toString();  | 
239 |  | -        if (isPrimitive(value)) return value;  | 
240 |  | -      }  | 
241 |  | -      return '';  | 
 | 256 | +  function getPredicateValue(value) {  | 
 | 257 | +    var type = typeof value;  | 
 | 258 | +    if (type === 'string') {  | 
 | 259 | +      value = value.toLowerCase();  | 
 | 260 | +    } else if (type === 'object') {  | 
 | 261 | +      value = objectToString(value);  | 
242 | 262 |     }  | 
 | 263 | +    return { value: value, type: type };  | 
 | 264 | +  }  | 
243 | 265 | 
 
  | 
244 |  | -    function compare(v1, v2) {  | 
245 |  | -      var t1 = typeof v1;  | 
246 |  | -      var t2 = typeof v2;  | 
247 |  | -      if (t1 === t2 && t1 === "object") {  | 
248 |  | -        v1 = objectToString(v1);  | 
249 |  | -        v2 = objectToString(v2);  | 
250 |  | -      }  | 
251 |  | -      if (t1 === t2) {  | 
252 |  | -        if (t1 === "string") {  | 
253 |  | -           v1 = v1.toLowerCase();  | 
254 |  | -           v2 = v2.toLowerCase();  | 
255 |  | -        }  | 
256 |  | -        if (v1 === v2) return 0;  | 
257 |  | -        return v1 < v2 ? -1 : 1;  | 
258 |  | -      } else {  | 
259 |  | -        return t1 < t2 ? -1 : 1;  | 
 | 266 | +  function compare(v1, v2) {  | 
 | 267 | +    var result = 0;  | 
 | 268 | +    if (v1.type === v2.type) {  | 
 | 269 | +      if (v1.value !== v2.value) {  | 
 | 270 | +        result = v1.value < v2.value ? -1 : 1;  | 
260 | 271 |       }  | 
 | 272 | +    } else {  | 
 | 273 | +      result = v1.type < v2.type ? -1 : 1;  | 
261 | 274 |     }  | 
262 |  | -  };  | 
 | 275 | +    return result;  | 
 | 276 | +  }  | 
263 | 277 | }  | 
0 commit comments