underscore-source 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|