ultimate-base 0.2.3.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ # TODO list
2
+ # * load all locales
3
+
4
+ @I18n ||=
5
+ locale: "en"
6
+ translations: {}
7
+
8
+ t: (path) ->
9
+ path = path.split('.') if _.isString(path)
10
+ scope = @translations
11
+ for step in path
12
+ scope = scope[step]
13
+ return path.join('.') unless scope
14
+ scope
@@ -1,6 +1,6 @@
1
1
  // Underscore.js 1.3.3
2
2
  // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
- // Underscore is freely distributable under the MIT license.
3
+ // Underscore may be freely distributed under the MIT license.
4
4
  // Portions of Underscore are inspired or borrowed from Prototype,
5
5
  // Oliver Steele's Functional, and John Resig's Micro-Templating.
6
6
  // For all details and documentation:
@@ -24,7 +24,8 @@
24
24
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
25
25
 
26
26
  // Create quick reference variables for speed access to core prototypes.
27
- var slice = ArrayProto.slice,
27
+ var push = ArrayProto.push,
28
+ slice = ArrayProto.slice,
28
29
  unshift = ArrayProto.unshift,
29
30
  toString = ObjProto.toString,
30
31
  hasOwnProperty = ObjProto.hasOwnProperty;
@@ -76,7 +77,7 @@
76
77
  obj.forEach(iterator, context);
77
78
  } else if (obj.length === +obj.length) {
78
79
  for (var i = 0, l = obj.length; i < l; i++) {
79
- if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
80
+ if (iterator.call(context, obj[i], i, obj) === breaker) return;
80
81
  }
81
82
  } else {
82
83
  for (var key in obj) {
@@ -96,7 +97,6 @@
96
97
  each(obj, function(value, index, list) {
97
98
  results[results.length] = iterator.call(context, value, index, list);
98
99
  });
99
- if (obj.length === +obj.length) results.length = obj.length;
100
100
  return results;
101
101
  };
102
102
 
@@ -213,7 +213,7 @@
213
213
  _.invoke = function(obj, method) {
214
214
  var args = slice.call(arguments, 2);
215
215
  return _.map(obj, function(value) {
216
- return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
216
+ return (_.isFunction(method) ? method : value[method]).apply(value, args);
217
217
  });
218
218
  };
219
219
 
@@ -223,8 +223,12 @@
223
223
  };
224
224
 
225
225
  // Return the maximum element or (element-based computation).
226
+ // Can't optimize arrays of integers longer than 65,535 elements.
227
+ // See: https://bugs.webkit.org/show_bug.cgi?id=80797
226
228
  _.max = function(obj, iterator, context) {
227
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
229
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
230
+ return Math.max.apply(Math, obj);
231
+ }
228
232
  if (!iterator && _.isEmpty(obj)) return -Infinity;
229
233
  var result = {computed : -Infinity};
230
234
  each(obj, function(value, index, list) {
@@ -236,7 +240,9 @@
236
240
 
237
241
  // Return the minimum element (or element-based computation).
238
242
  _.min = function(obj, iterator, context) {
239
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
243
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
244
+ return Math.min.apply(Math, obj);
245
+ }
240
246
  if (!iterator && _.isEmpty(obj)) return Infinity;
241
247
  var result = {computed : Infinity};
242
248
  each(obj, function(value, index, list) {
@@ -248,10 +254,12 @@
248
254
 
249
255
  // Shuffle an array.
250
256
  _.shuffle = function(obj) {
251
- var shuffled = [], rand;
252
- each(obj, function(value, index, list) {
253
- rand = Math.floor(Math.random() * (index + 1));
254
- shuffled[index] = shuffled[rand];
257
+ var rand;
258
+ var index = 0;
259
+ var shuffled = [];
260
+ each(obj, function(value) {
261
+ rand = Math.floor(Math.random() * ++index);
262
+ shuffled[index - 1] = shuffled[rand];
255
263
  shuffled[rand] = value;
256
264
  });
257
265
  return shuffled;
@@ -259,7 +267,7 @@
259
267
 
260
268
  // Sort the object's values by a criterion produced by an iterator.
261
269
  _.sortBy = function(obj, val, context) {
262
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
270
+ var iterator = lookupIterator(obj, val);
263
271
  return _.pluck(_.map(obj, function(value, index, list) {
264
272
  return {
265
273
  value : value,
@@ -273,26 +281,49 @@
273
281
  }), 'value');
274
282
  };
275
283
 
276
- // Groups the object's values by a criterion. Pass either a string attribute
277
- // to group by, or a function that returns the criterion.
278
- _.groupBy = function(obj, val) {
284
+ // An internal function to generate lookup iterators.
285
+ var lookupIterator = function(obj, val) {
286
+ return _.isFunction(val) ? val : function(obj) { return obj[val]; };
287
+ };
288
+
289
+ // An internal function used for aggregate "group by" operations.
290
+ var group = function(obj, val, behavior) {
279
291
  var result = {};
280
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
292
+ var iterator = lookupIterator(obj, val);
281
293
  each(obj, function(value, index) {
282
294
  var key = iterator(value, index);
283
- (result[key] || (result[key] = [])).push(value);
295
+ behavior(result, key, value);
284
296
  });
285
297
  return result;
286
298
  };
287
299
 
288
- // Use a comparator function to figure out at what index an object should
289
- // be inserted so as to maintain order. Uses binary search.
300
+ // Groups the object's values by a criterion. Pass either a string attribute
301
+ // to group by, or a function that returns the criterion.
302
+ _.groupBy = function(obj, val) {
303
+ return group(obj, val, function(result, key, value) {
304
+ (result[key] || (result[key] = [])).push(value);
305
+ });
306
+ };
307
+
308
+ // Counts instances of an object that group by a certain criterion. Pass
309
+ // either a string attribute to count by, or a function that returns the
310
+ // criterion.
311
+ _.countBy = function(obj, val) {
312
+ return group(obj, val, function(result, key, value) {
313
+ result[key] || (result[key] = 0);
314
+ result[key]++;
315
+ });
316
+ };
317
+
318
+ // Use a comparator function to figure out the smallest index at which
319
+ // an object should be inserted so as to maintain order. Uses binary search.
290
320
  _.sortedIndex = function(array, obj, iterator) {
291
321
  iterator || (iterator = _.identity);
322
+ var value = iterator(obj);
292
323
  var low = 0, high = array.length;
293
324
  while (low < high) {
294
325
  var mid = (low + high) >> 1;
295
- iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
326
+ iterator(array[mid]) < value ? low = mid + 1 : high = mid;
296
327
  }
297
328
  return low;
298
329
  };
@@ -321,7 +352,7 @@
321
352
  return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
322
353
  };
323
354
 
324
- // Returns everything but the last entry of the array. Especcialy useful on
355
+ // Returns everything but the last entry of the array. Especially useful on
325
356
  // the arguments object. Passing **n** will return all the values in
326
357
  // the array, excluding the last N. The **guard** check allows it to work with
327
358
  // `_.map`.
@@ -352,13 +383,21 @@
352
383
  return _.filter(array, function(value){ return !!value; });
353
384
  };
354
385
 
386
+ // Internal implementation of a recursive `flatten` function.
387
+ var flatten = function(input, shallow, output) {
388
+ each(input, function(value) {
389
+ if (_.isArray(value)) {
390
+ shallow ? push.apply(output, value) : flatten(value, shallow, output);
391
+ } else {
392
+ output.push(value);
393
+ }
394
+ });
395
+ return output;
396
+ };
397
+
355
398
  // Return a completely flattened version of an array.
356
399
  _.flatten = function(array, shallow) {
357
- return _.reduce(array, function(memo, value) {
358
- if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
359
- memo[memo.length] = value;
360
- return memo;
361
- }, []);
400
+ return flatten(array, shallow, []);
362
401
  };
363
402
 
364
403
  // Return a version of the array that does not contain the specified value(s).
@@ -372,10 +411,8 @@
372
411
  _.uniq = _.unique = function(array, isSorted, iterator) {
373
412
  var initial = iterator ? _.map(array, iterator) : array;
374
413
  var results = [];
375
- // The `isSorted` flag is irrelevant if the array only contains two elements.
376
- if (array.length < 3) isSorted = true;
377
- _.reduce(initial, function (memo, value, index) {
378
- if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
414
+ _.reduce(initial, function(memo, value, index) {
415
+ if (isSorted ? (_.last(memo) !== value || !memo.length) : !_.include(memo, value)) {
379
416
  memo.push(value);
380
417
  results.push(array[index]);
381
418
  }
@@ -387,12 +424,12 @@
387
424
  // Produce an array that contains the union: each distinct element from all of
388
425
  // the passed-in arrays.
389
426
  _.union = function() {
390
- return _.uniq(_.flatten(arguments, true));
427
+ return _.uniq(flatten(arguments, true, []));
391
428
  };
392
429
 
393
430
  // Produce an array that contains every item shared between all the
394
- // passed-in arrays. (Aliased as "intersect" for back-compat.)
395
- _.intersection = _.intersect = function(array) {
431
+ // passed-in arrays.
432
+ _.intersection = function(array) {
396
433
  var rest = slice.call(arguments, 1);
397
434
  return _.filter(_.uniq(array), function(item) {
398
435
  return _.every(rest, function(other) {
@@ -404,7 +441,7 @@
404
441
  // Take the difference between one array and a number of other arrays.
405
442
  // Only the elements present in just the first array will remain.
406
443
  _.difference = function(array) {
407
- var rest = _.flatten(slice.call(arguments, 1), true);
444
+ var rest = flatten(slice.call(arguments, 1), true, []);
408
445
  return _.filter(array, function(value){ return !_.include(rest, value); });
409
446
  };
410
447
 
@@ -414,10 +451,22 @@
414
451
  var args = slice.call(arguments);
415
452
  var length = _.max(_.pluck(args, 'length'));
416
453
  var results = new Array(length);
417
- for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
454
+ for (var i = 0; i < length; i++) {
455
+ results[i] = _.pluck(args, "" + i);
456
+ }
418
457
  return results;
419
458
  };
420
459
 
460
+ // Zip together two arrays -- an array of keys and an array of values -- into
461
+ // a single object.
462
+ _.zipObject = function(keys, values) {
463
+ var result = {};
464
+ for (var i = 0, l = keys.length; i < l; i++) {
465
+ result[keys[i]] = values[i];
466
+ }
467
+ return result;
468
+ };
469
+
421
470
  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
422
471
  // we need this function. Return the position of the first occurrence of an
423
472
  // item in an array, or -1 if the item is not included in the array.
@@ -432,7 +481,7 @@
432
481
  return array[i] === item ? i : -1;
433
482
  }
434
483
  if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
435
- for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
484
+ for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
436
485
  return -1;
437
486
  };
438
487
 
@@ -441,7 +490,7 @@
441
490
  if (array == null) return -1;
442
491
  if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
443
492
  var i = array.length;
444
- while (i--) if (i in array && array[i] === item) return i;
493
+ while (i--) if (array[i] === item) return i;
445
494
  return -1;
446
495
  };
447
496
 
@@ -540,10 +589,10 @@
540
589
  if (throttling) {
541
590
  more = true;
542
591
  } else {
592
+ throttling = true;
543
593
  result = func.apply(context, args);
544
594
  }
545
595
  whenDone();
546
- throttling = true;
547
596
  return result;
548
597
  };
549
598
  };
@@ -560,9 +609,10 @@
560
609
  timeout = null;
561
610
  if (!immediate) func.apply(context, args);
562
611
  };
563
- if (immediate && !timeout) func.apply(context, args);
612
+ var callNow = immediate && !timeout;
564
613
  clearTimeout(timeout);
565
614
  timeout = setTimeout(later, wait);
615
+ if (callNow) func.apply(context, args);
566
616
  };
567
617
  };
568
618
 
@@ -604,7 +654,9 @@
604
654
  _.after = function(times, func) {
605
655
  if (times <= 0) return func();
606
656
  return function() {
607
- if (--times < 1) { return func.apply(this, arguments); }
657
+ if (--times < 1) {
658
+ return func.apply(this, arguments);
659
+ }
608
660
  };
609
661
  };
610
662
 
@@ -648,7 +700,7 @@
648
700
  // Return a copy of the object only containing the whitelisted properties.
649
701
  _.pick = function(obj) {
650
702
  var result = {};
651
- each(_.flatten(slice.call(arguments, 1)), function(key) {
703
+ each(flatten(slice.call(arguments, 1), true, []), function(key) {
652
704
  if (key in obj) result[key] = obj[key];
653
705
  });
654
706
  return result;
@@ -678,8 +730,8 @@
678
730
  return obj;
679
731
  };
680
732
 
681
- // Internal recursive comparison function.
682
- function eq(a, b, stack) {
733
+ // Internal recursive comparison function for `isEqual`.
734
+ var eq = function(a, b, stack) {
683
735
  // Identical objects are equal. `0 === -0`, but they aren't identical.
684
736
  // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
685
737
  if (a === b) return a !== 0 || 1 / a == 1 / b;
@@ -764,7 +816,7 @@
764
816
  // Remove the first object from the stack of traversed objects.
765
817
  stack.pop();
766
818
  return result;
767
- }
819
+ };
768
820
 
769
821
  // Perform a deep comparison to check if two objects are equal.
770
822
  _.isEqual = function(a, b) {
@@ -796,31 +848,21 @@
796
848
  return obj === Object(obj);
797
849
  };
798
850
 
799
- // Is a given variable an arguments object?
800
- _.isArguments = function(obj) {
801
- return toString.call(obj) == '[object Arguments]';
802
- };
851
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
852
+ each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
853
+ _['is' + name] = function(obj) {
854
+ return toString.call(obj) == '[object ' + name + ']';
855
+ };
856
+ });
857
+
858
+ // Define a fallback version of the method in browsers (ahem, IE), where
859
+ // there isn't any inspectable "Arguments" type.
803
860
  if (!_.isArguments(arguments)) {
804
861
  _.isArguments = function(obj) {
805
862
  return !!(obj && _.has(obj, 'callee'));
806
863
  };
807
864
  }
808
865
 
809
- // Is a given value a function?
810
- _.isFunction = function(obj) {
811
- return toString.call(obj) == '[object Function]';
812
- };
813
-
814
- // Is a given value a string?
815
- _.isString = function(obj) {
816
- return toString.call(obj) == '[object String]';
817
- };
818
-
819
- // Is a given value a number?
820
- _.isNumber = function(obj) {
821
- return toString.call(obj) == '[object Number]';
822
- };
823
-
824
866
  // Is a given object a finite number?
825
867
  _.isFinite = function(obj) {
826
868
  return _.isNumber(obj) && isFinite(obj);
@@ -837,16 +879,6 @@
837
879
  return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
838
880
  };
839
881
 
840
- // Is a given value a date?
841
- _.isDate = function(obj) {
842
- return toString.call(obj) == '[object Date]';
843
- };
844
-
845
- // Is the given value a regular expression?
846
- _.isRegExp = function(obj) {
847
- return toString.call(obj) == '[object RegExp]';
848
- };
849
-
850
882
  // Is a given value equal to null?
851
883
  _.isNull = function(obj) {
852
884
  return obj === null;
@@ -857,7 +889,8 @@
857
889
  return obj === void 0;
858
890
  };
859
891
 
860
- // Has own property?
892
+ // Shortcut function for checking if an object has a given property directly
893
+ // on itself (in other words, not on a prototype).
861
894
  _.has = function(obj, key) {
862
895
  return hasOwnProperty.call(obj, key);
863
896
  };
@@ -878,13 +911,28 @@
878
911
  };
879
912
 
880
913
  // Run a function **n** times.
881
- _.times = function (n, iterator, context) {
914
+ _.times = function(n, iterator, context) {
882
915
  for (var i = 0; i < n; i++) iterator.call(context, i);
883
916
  };
884
917
 
918
+ // List of HTML entities for escaping.
919
+ var htmlEscapes = {
920
+ '&': '&amp;',
921
+ '<': '&lt;',
922
+ '>': '&gt;',
923
+ '"': '&quot;',
924
+ "'": '&#x27;',
925
+ '/': '&#x2F;'
926
+ };
927
+
928
+ // Regex containing the keys listed immediately above.
929
+ var htmlEscaper = /[&<>"'\/]/g;
930
+
885
931
  // Escape a string for HTML interpolation.
886
932
  _.escape = function(string) {
887
- return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
933
+ return ('' + string).replace(htmlEscaper, function(match) {
934
+ return htmlEscapes[match];
935
+ });
888
936
  };
889
937
 
890
938
  // If the value of the named property is a function then invoke it;
@@ -927,16 +975,16 @@
927
975
  // Certain characters need to be escaped so that they can be put into a
928
976
  // string literal.
929
977
  var escapes = {
930
- '\\': '\\',
931
- "'": "'",
932
- 'r': '\r',
933
- 'n': '\n',
934
- 't': '\t',
935
- 'u2028': '\u2028',
936
- 'u2029': '\u2029'
978
+ '\\': '\\',
979
+ "'": "'",
980
+ r: '\r',
981
+ n: '\n',
982
+ t: '\t',
983
+ u2028: '\u2028',
984
+ u2029: '\u2029'
937
985
  };
938
986
 
939
- for (var p in escapes) escapes[escapes[p]] = p;
987
+ for (var key in escapes) escapes[escapes[key]] = key;
940
988
  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
941
989
  var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
942
990
 
@@ -962,20 +1010,20 @@
962
1010
  return '\\' + escapes[match];
963
1011
  })
964
1012
  .replace(settings.escape || noMatch, function(match, code) {
965
- return "'+\n_.escape(" + unescape(code) + ")+\n'";
1013
+ return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'";
966
1014
  })
967
1015
  .replace(settings.interpolate || noMatch, function(match, code) {
968
- return "'+\n(" + unescape(code) + ")+\n'";
1016
+ return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'";
969
1017
  })
970
1018
  .replace(settings.evaluate || noMatch, function(match, code) {
971
- return "';\n" + unescape(code) + "\n;__p+='";
1019
+ return "';\n" + unescape(code) + "\n__p+='";
972
1020
  }) + "';\n";
973
1021
 
974
1022
  // If a variable is not specified, place data values in local scope.
975
1023
  if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
976
1024
 
977
- source = "var __p='';" +
978
- "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
1025
+ source = "var __t,__p='',__j=Array.prototype.join," +
1026
+ "print=function(){__p+=__j.call(arguments,'')};\n" +
979
1027
  source + "return __p;\n";
980
1028
 
981
1029
  var render = new Function(settings.variable || 'obj', '_', source);
@@ -984,10 +1032,8 @@
984
1032
  return render.call(this, data, _);
985
1033
  };
986
1034
 
987
- // Provide the compiled function source as a convenience for build time
988
- // precompilation.
989
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
990
- source + '}';
1035
+ // Provide the compiled function source as a convenience for precompilation.
1036
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
991
1037
 
992
1038
  return template;
993
1039
  };
@@ -1029,11 +1075,10 @@
1029
1075
  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1030
1076
  var method = ArrayProto[name];
1031
1077
  wrapper.prototype[name] = function() {
1032
- var wrapped = this._wrapped;
1033
- method.apply(wrapped, arguments);
1034
- var length = wrapped.length;
1035
- if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
1036
- return result(wrapped, this._chain);
1078
+ var obj = this._wrapped;
1079
+ method.apply(obj, arguments);
1080
+ if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1081
+ return result(obj, this._chain);
1037
1082
  };
1038
1083
  });
1039
1084