underscore-source 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/underscore-source/version.rb +1 -1
- data/vendor/assets/javascripts/underscore.js +120 -60
- metadata +1 -1
@@ -1,4 +1,4 @@
|
|
1
|
-
// Underscore.js 1.3.
|
1
|
+
// Underscore.js 1.3.2
|
2
2
|
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
3
3
|
// Underscore is freely distributable under the MIT license.
|
4
4
|
// Portions of Underscore are inspired or borrowed from Prototype,
|
@@ -62,7 +62,7 @@
|
|
62
62
|
}
|
63
63
|
|
64
64
|
// Current version.
|
65
|
-
_.VERSION = '1.3.
|
65
|
+
_.VERSION = '1.3.2';
|
66
66
|
|
67
67
|
// Collection Functions
|
68
68
|
// --------------------
|
@@ -180,7 +180,7 @@
|
|
180
180
|
each(obj, function(value, index, list) {
|
181
181
|
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
182
182
|
});
|
183
|
-
return result;
|
183
|
+
return !!result;
|
184
184
|
};
|
185
185
|
|
186
186
|
// Determine if at least one element in the object matches a truth test.
|
@@ -224,7 +224,7 @@
|
|
224
224
|
|
225
225
|
// Return the maximum element or (element-based computation).
|
226
226
|
_.max = function(obj, iterator, context) {
|
227
|
-
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
|
227
|
+
if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
|
228
228
|
if (!iterator && _.isEmpty(obj)) return -Infinity;
|
229
229
|
var result = {computed : -Infinity};
|
230
230
|
each(obj, function(value, index, list) {
|
@@ -236,7 +236,7 @@
|
|
236
236
|
|
237
237
|
// Return the minimum element (or element-based computation).
|
238
238
|
_.min = function(obj, iterator, context) {
|
239
|
-
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
|
239
|
+
if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
|
240
240
|
if (!iterator && _.isEmpty(obj)) return Infinity;
|
241
241
|
var result = {computed : Infinity};
|
242
242
|
each(obj, function(value, index, list) {
|
@@ -250,19 +250,16 @@
|
|
250
250
|
_.shuffle = function(obj) {
|
251
251
|
var shuffled = [], rand;
|
252
252
|
each(obj, function(value, index, list) {
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
rand = Math.floor(Math.random() * (index + 1));
|
257
|
-
shuffled[index] = shuffled[rand];
|
258
|
-
shuffled[rand] = value;
|
259
|
-
}
|
253
|
+
rand = Math.floor(Math.random() * (index + 1));
|
254
|
+
shuffled[index] = shuffled[rand];
|
255
|
+
shuffled[rand] = value;
|
260
256
|
});
|
261
257
|
return shuffled;
|
262
258
|
};
|
263
259
|
|
264
260
|
// Sort the object's values by a criterion produced by an iterator.
|
265
|
-
_.sortBy = function(obj,
|
261
|
+
_.sortBy = function(obj, val, context) {
|
262
|
+
var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
|
266
263
|
return _.pluck(_.map(obj, function(value, index, list) {
|
267
264
|
return {
|
268
265
|
value : value,
|
@@ -270,6 +267,8 @@
|
|
270
267
|
};
|
271
268
|
}).sort(function(left, right) {
|
272
269
|
var a = left.criteria, b = right.criteria;
|
270
|
+
if (a === void 0) return 1;
|
271
|
+
if (b === void 0) return -1;
|
273
272
|
return a < b ? -1 : a > b ? 1 : 0;
|
274
273
|
}), 'value');
|
275
274
|
};
|
@@ -299,26 +298,26 @@
|
|
299
298
|
};
|
300
299
|
|
301
300
|
// Safely convert anything iterable into a real, live array.
|
302
|
-
_.toArray = function(
|
303
|
-
if (!
|
304
|
-
if (
|
305
|
-
if (_.
|
306
|
-
if (_.
|
307
|
-
return _.values(
|
301
|
+
_.toArray = function(obj) {
|
302
|
+
if (!obj) return [];
|
303
|
+
if (_.isArray(obj)) return slice.call(obj);
|
304
|
+
if (_.isArguments(obj)) return slice.call(obj);
|
305
|
+
if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray();
|
306
|
+
return _.values(obj);
|
308
307
|
};
|
309
308
|
|
310
309
|
// Return the number of elements in an object.
|
311
310
|
_.size = function(obj) {
|
312
|
-
return _.
|
311
|
+
return _.isArray(obj) ? obj.length : _.keys(obj).length;
|
313
312
|
};
|
314
313
|
|
315
314
|
// Array Functions
|
316
315
|
// ---------------
|
317
316
|
|
318
317
|
// Get the first element of an array. Passing **n** will return the first N
|
319
|
-
// values in the array. Aliased as `head`. The **guard** check
|
320
|
-
// with `_.map`.
|
321
|
-
_.first = _.head = function(array, n, guard) {
|
318
|
+
// values in the array. Aliased as `head` and `take`. The **guard** check
|
319
|
+
// allows it to work with `_.map`.
|
320
|
+
_.first = _.head = _.take = function(array, n, guard) {
|
322
321
|
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
|
323
322
|
};
|
324
323
|
|
@@ -372,15 +371,17 @@
|
|
372
371
|
// Aliased as `unique`.
|
373
372
|
_.uniq = _.unique = function(array, isSorted, iterator) {
|
374
373
|
var initial = iterator ? _.map(array, iterator) : array;
|
375
|
-
var
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
374
|
+
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)) {
|
379
|
+
memo.push(value);
|
380
|
+
results.push(array[index]);
|
380
381
|
}
|
381
382
|
return memo;
|
382
383
|
}, []);
|
383
|
-
return
|
384
|
+
return results;
|
384
385
|
};
|
385
386
|
|
386
387
|
// Produce an array that contains the union: each distinct element from all of
|
@@ -403,7 +404,7 @@
|
|
403
404
|
// Take the difference between one array and a number of other arrays.
|
404
405
|
// Only the elements present in just the first array will remain.
|
405
406
|
_.difference = function(array) {
|
406
|
-
var rest = _.flatten(slice.call(arguments, 1));
|
407
|
+
var rest = _.flatten(slice.call(arguments, 1), true);
|
407
408
|
return _.filter(array, function(value){ return !_.include(rest, value); });
|
408
409
|
};
|
409
410
|
|
@@ -514,7 +515,7 @@
|
|
514
515
|
// it with the arguments supplied.
|
515
516
|
_.delay = function(func, wait) {
|
516
517
|
var args = slice.call(arguments, 2);
|
517
|
-
return setTimeout(function(){ return func.apply(
|
518
|
+
return setTimeout(function(){ return func.apply(null, args); }, wait);
|
518
519
|
};
|
519
520
|
|
520
521
|
// Defers a function, scheduling it to run after the current call stack has
|
@@ -526,7 +527,7 @@
|
|
526
527
|
// Returns a function, that, when invoked, will only be triggered at most once
|
527
528
|
// during a given window of time.
|
528
529
|
_.throttle = function(func, wait) {
|
529
|
-
var context, args, timeout, throttling, more;
|
530
|
+
var context, args, timeout, throttling, more, result;
|
530
531
|
var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
|
531
532
|
return function() {
|
532
533
|
context = this; args = arguments;
|
@@ -539,24 +540,27 @@
|
|
539
540
|
if (throttling) {
|
540
541
|
more = true;
|
541
542
|
} else {
|
542
|
-
func.apply(context, args);
|
543
|
+
result = func.apply(context, args);
|
543
544
|
}
|
544
545
|
whenDone();
|
545
546
|
throttling = true;
|
547
|
+
return result;
|
546
548
|
};
|
547
549
|
};
|
548
550
|
|
549
551
|
// Returns a function, that, as long as it continues to be invoked, will not
|
550
552
|
// be triggered. The function will be called after it stops being called for
|
551
|
-
// N milliseconds.
|
552
|
-
|
553
|
+
// N milliseconds. If `immediate` is passed, trigger the function on the
|
554
|
+
// leading edge, instead of the trailing.
|
555
|
+
_.debounce = function(func, wait, immediate) {
|
553
556
|
var timeout;
|
554
557
|
return function() {
|
555
558
|
var context = this, args = arguments;
|
556
559
|
var later = function() {
|
557
560
|
timeout = null;
|
558
|
-
func.apply(context, args);
|
561
|
+
if (!immediate) func.apply(context, args);
|
559
562
|
};
|
563
|
+
if (immediate && !timeout) func.apply(context, args);
|
560
564
|
clearTimeout(timeout);
|
561
565
|
timeout = setTimeout(later, wait);
|
562
566
|
};
|
@@ -641,6 +645,15 @@
|
|
641
645
|
return obj;
|
642
646
|
};
|
643
647
|
|
648
|
+
// Return a copy of the object only containing the whitelisted properties.
|
649
|
+
_.pick = function(obj) {
|
650
|
+
var result = {};
|
651
|
+
each(_.flatten(slice.call(arguments, 1)), function(key) {
|
652
|
+
if (key in obj) result[key] = obj[key];
|
653
|
+
});
|
654
|
+
return result;
|
655
|
+
};
|
656
|
+
|
644
657
|
// Fill in a given object with default properties.
|
645
658
|
_.defaults = function(obj) {
|
646
659
|
each(slice.call(arguments, 1), function(source) {
|
@@ -761,6 +774,7 @@
|
|
761
774
|
// Is a given array, string, or object empty?
|
762
775
|
// An "empty" object has no enumerable own-properties.
|
763
776
|
_.isEmpty = function(obj) {
|
777
|
+
if (obj == null) return true;
|
764
778
|
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
765
779
|
for (var key in obj) if (_.has(obj, key)) return false;
|
766
780
|
return true;
|
@@ -807,6 +821,11 @@
|
|
807
821
|
return toString.call(obj) == '[object Number]';
|
808
822
|
};
|
809
823
|
|
824
|
+
// Is a given object a finite number?
|
825
|
+
_.isFinite = function(obj) {
|
826
|
+
return _.isNumber(obj) && isFinite(obj);
|
827
|
+
};
|
828
|
+
|
810
829
|
// Is the given value `NaN`?
|
811
830
|
_.isNaN = function(obj) {
|
812
831
|
// `NaN` is the only value for which `===` is not reflexive.
|
@@ -868,6 +887,14 @@
|
|
868
887
|
return (''+string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/');
|
869
888
|
};
|
870
889
|
|
890
|
+
// If the value of the named property is a function then invoke it;
|
891
|
+
// otherwise, return it.
|
892
|
+
_.result = function(object, property) {
|
893
|
+
if (object == null) return null;
|
894
|
+
var value = object[property];
|
895
|
+
return _.isFunction(value) ? value.call(object) : value;
|
896
|
+
};
|
897
|
+
|
871
898
|
// Add your own custom functions to the Underscore object, ensuring that
|
872
899
|
// they're correctly added to the OOP wrapper as well.
|
873
900
|
_.mixin = function(obj) {
|
@@ -897,39 +924,72 @@
|
|
897
924
|
// guaranteed not to match.
|
898
925
|
var noMatch = /.^/;
|
899
926
|
|
927
|
+
// Certain characters need to be escaped so that they can be put into a
|
928
|
+
// string literal.
|
929
|
+
var escapes = {
|
930
|
+
'\\': '\\',
|
931
|
+
"'": "'",
|
932
|
+
'r': '\r',
|
933
|
+
'n': '\n',
|
934
|
+
't': '\t',
|
935
|
+
'u2028': '\u2028',
|
936
|
+
'u2029': '\u2029'
|
937
|
+
};
|
938
|
+
|
939
|
+
for (var p in escapes) escapes[escapes[p]] = p;
|
940
|
+
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
941
|
+
var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
|
942
|
+
|
900
943
|
// Within an interpolation, evaluation, or escaping, remove HTML escaping
|
901
944
|
// that had been previously added.
|
902
945
|
var unescape = function(code) {
|
903
|
-
return code.replace(
|
946
|
+
return code.replace(unescaper, function(match, escape) {
|
947
|
+
return escapes[escape];
|
948
|
+
});
|
904
949
|
};
|
905
950
|
|
906
951
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
907
952
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
908
953
|
// and correctly escapes quotes within interpolated code.
|
909
|
-
_.template = function(
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
954
|
+
_.template = function(text, data, settings) {
|
955
|
+
settings = _.extend(_.templateSettings, settings);
|
956
|
+
|
957
|
+
// Compile the template source, taking care to escape characters that
|
958
|
+
// cannot be included in a string literal and then unescape them in code
|
959
|
+
// blocks.
|
960
|
+
var source = "__p+='" + text
|
961
|
+
.replace(escaper, function(match) {
|
962
|
+
return '\\' + escapes[match];
|
963
|
+
})
|
964
|
+
.replace(settings.escape || noMatch, function(match, code) {
|
965
|
+
return "'+\n_.escape(" + unescape(code) + ")+\n'";
|
966
|
+
})
|
967
|
+
.replace(settings.interpolate || noMatch, function(match, code) {
|
968
|
+
return "'+\n(" + unescape(code) + ")+\n'";
|
969
|
+
})
|
970
|
+
.replace(settings.evaluate || noMatch, function(match, code) {
|
971
|
+
return "';\n" + unescape(code) + "\n;__p+='";
|
972
|
+
}) + "';\n";
|
973
|
+
|
974
|
+
// If a variable is not specified, place data values in local scope.
|
975
|
+
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
976
|
+
|
977
|
+
source = "var __p='';" +
|
978
|
+
"var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
|
979
|
+
source + "return __p;\n";
|
980
|
+
|
981
|
+
var render = new Function(settings.variable || 'obj', '_', source);
|
982
|
+
if (data) return render(data, _);
|
983
|
+
var template = function(data) {
|
984
|
+
return render.call(this, data, _);
|
932
985
|
};
|
986
|
+
|
987
|
+
// Provide the compiled function source as a convenience for build time
|
988
|
+
// precompilation.
|
989
|
+
template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
|
990
|
+
source + '}';
|
991
|
+
|
992
|
+
return template;
|
933
993
|
};
|
934
994
|
|
935
995
|
// Add a "chain" function, which will delegate to the wrapper.
|