ultimate-base 0.6.2 → 0.7.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/app/assets/javascripts/ultimate/backbone/app.js.coffee +23 -2
- data/app/assets/javascripts/ultimate/backbone/lib/backbone.js +213 -178
- data/app/assets/javascripts/ultimate/backbone/view.js.coffee +8 -9
- data/app/assets/javascripts/ultimate/helpers.js.coffee.erb +15 -2
- data/app/assets/javascripts/ultimate/underscore/underscore.js +219 -125
- data/app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee +16 -2
- data/app/assets/javascripts/ultimate/underscore/underscore.string.js +38 -9
- data/lib/ultimate/base/version.rb +1 -1
- metadata +2 -2
@@ -4,9 +4,13 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
4
4
|
|
5
5
|
@mixinNames: null
|
6
6
|
|
7
|
+
constructor: (options) ->
|
8
|
+
@reflectOptions options
|
9
|
+
super
|
10
|
+
|
7
11
|
# Rest mixinNames
|
8
12
|
@mixinable: ->
|
9
|
-
@mixinNames = _.clone(@mixinNames)
|
13
|
+
@mixinNames = if @mixinNames then _.clone(@mixinNames) else []
|
10
14
|
|
11
15
|
# Mixins support
|
12
16
|
@include: (mixin, name = null) ->
|
@@ -17,11 +21,11 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
17
21
|
_.extend @::, mixin
|
18
22
|
|
19
23
|
mixinsEvents: (events = {}) ->
|
20
|
-
_.reduce( @constructor.mixinNames, ( (memo, name) -> _.extend(memo, _.result(@,
|
24
|
+
_.reduce( @constructor.mixinNames, ( (memo, name) -> _.extend(memo, _.result(@, name + 'Events')) ), events, @ )
|
21
25
|
|
22
26
|
mixinsInitialize: ->
|
23
27
|
for name in @constructor.mixinNames
|
24
|
-
@[
|
28
|
+
@[name + 'Initialize']? arguments...
|
25
29
|
@
|
26
30
|
|
27
31
|
# TODO comment for this trick
|
@@ -34,11 +38,6 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
34
38
|
throw new Error("__super can't find super method '#{methodName}'")
|
35
39
|
superMethod.apply @, args
|
36
40
|
|
37
|
-
|
38
|
-
_configure: (options) ->
|
39
|
-
super
|
40
|
-
@reflectOptions()
|
41
|
-
|
42
|
-
reflectOptions: (options = @options) ->
|
41
|
+
reflectOptions: (options) ->
|
43
42
|
@[attr] = value for attr, value of options when not _.isUndefined(@[attr])
|
44
43
|
@
|
@@ -15,9 +15,9 @@ window.LOG_TODO ?= DEBUG_MODE
|
|
15
15
|
method.apply(console, args)
|
16
16
|
else
|
17
17
|
method(args)
|
18
|
-
|
18
|
+
args[0]
|
19
19
|
|
20
|
-
@_cout =
|
20
|
+
@_cout = ->
|
21
21
|
console.log(arguments) if console?
|
22
22
|
arguments[0]
|
23
23
|
|
@@ -55,3 +55,16 @@ window.LOG_TODO ?= DEBUG_MODE
|
|
55
55
|
ah[0] = ad.join('.')
|
56
56
|
aq[0] = ah.join('#')
|
57
57
|
aq.join('?')
|
58
|
+
|
59
|
+
@waitFor = (delay, times, check, success, fail) ->
|
60
|
+
startWaitFor = ->
|
61
|
+
setTimeout ( ->
|
62
|
+
times--
|
63
|
+
if check()
|
64
|
+
success?(times)
|
65
|
+
else if times > 0
|
66
|
+
startWaitFor()
|
67
|
+
else
|
68
|
+
fail?()
|
69
|
+
), delay
|
70
|
+
startWaitFor()
|
@@ -1,15 +1,14 @@
|
|
1
|
-
//
|
2
|
-
//
|
1
|
+
// Underscore.js 1.5.2
|
2
|
+
// http://underscorejs.org
|
3
|
+
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
4
|
+
// Underscore may be freely distributed under the MIT license.
|
3
5
|
|
4
|
-
// > http://underscorejs.org
|
5
|
-
// > (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
6
|
-
// > Underscore may be freely distributed under the MIT license.
|
7
|
-
|
8
|
-
// Baseline setup
|
9
|
-
// --------------
|
10
6
|
(function() {
|
11
7
|
|
12
|
-
//
|
8
|
+
// Baseline setup
|
9
|
+
// --------------
|
10
|
+
|
11
|
+
// Establish the root object, `window` in the browser, or `exports` on the server.
|
13
12
|
var root = this;
|
14
13
|
|
15
14
|
// Save the previous value of the `_` variable.
|
@@ -21,12 +20,18 @@
|
|
21
20
|
// Save bytes in the minified (but not gzipped) version:
|
22
21
|
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
23
22
|
|
23
|
+
//use the faster Date.now if available.
|
24
|
+
var getTime = (Date.now || function() {
|
25
|
+
return new Date().getTime();
|
26
|
+
});
|
27
|
+
|
24
28
|
// Create quick reference variables for speed access to core prototypes.
|
25
|
-
var
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
var
|
30
|
+
push = ArrayProto.push,
|
31
|
+
slice = ArrayProto.slice,
|
32
|
+
concat = ArrayProto.concat,
|
33
|
+
toString = ObjProto.toString,
|
34
|
+
hasOwnProperty = ObjProto.hasOwnProperty;
|
30
35
|
|
31
36
|
// All **ECMAScript 5** native function implementations that we hope to use
|
32
37
|
// are declared here.
|
@@ -65,7 +70,7 @@
|
|
65
70
|
}
|
66
71
|
|
67
72
|
// Current version.
|
68
|
-
_.VERSION = '1.
|
73
|
+
_.VERSION = '1.5.2';
|
69
74
|
|
70
75
|
// Collection Functions
|
71
76
|
// --------------------
|
@@ -78,14 +83,13 @@
|
|
78
83
|
if (nativeForEach && obj.forEach === nativeForEach) {
|
79
84
|
obj.forEach(iterator, context);
|
80
85
|
} else if (obj.length === +obj.length) {
|
81
|
-
for (var i = 0,
|
86
|
+
for (var i = 0, length = obj.length; i < length; i++) {
|
82
87
|
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
83
88
|
}
|
84
89
|
} else {
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
90
|
+
var keys = _.keys(obj);
|
91
|
+
for (var i = 0, length = keys.length; i < length; i++) {
|
92
|
+
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
|
89
93
|
}
|
90
94
|
}
|
91
95
|
};
|
@@ -97,7 +101,7 @@
|
|
97
101
|
if (obj == null) return results;
|
98
102
|
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
99
103
|
each(obj, function(value, index, list) {
|
100
|
-
results
|
104
|
+
results.push(iterator.call(context, value, index, list));
|
101
105
|
});
|
102
106
|
return results;
|
103
107
|
};
|
@@ -172,7 +176,7 @@
|
|
172
176
|
if (obj == null) return results;
|
173
177
|
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
174
178
|
each(obj, function(value, index, list) {
|
175
|
-
if (iterator.call(context, value, index, list)) results
|
179
|
+
if (iterator.call(context, value, index, list)) results.push(value);
|
176
180
|
});
|
177
181
|
return results;
|
178
182
|
};
|
@@ -233,13 +237,12 @@
|
|
233
237
|
|
234
238
|
// Convenience version of a common use case of `map`: fetching a property.
|
235
239
|
_.pluck = function(obj, key) {
|
236
|
-
return _.map(obj,
|
240
|
+
return _.map(obj, _.property(key));
|
237
241
|
};
|
238
242
|
|
239
243
|
// Convenience version of a common use case of `filter`: selecting only objects
|
240
244
|
// containing specific `key:value` pairs.
|
241
245
|
_.where = function(obj, attrs, first) {
|
242
|
-
if (_.isEmpty(attrs)) return first ? null : [];
|
243
246
|
return _[first ? 'find' : 'filter'](obj, function(value) {
|
244
247
|
for (var key in attrs) {
|
245
248
|
if (attrs[key] !== value[key]) return false;
|
@@ -256,7 +259,7 @@
|
|
256
259
|
|
257
260
|
// Return the maximum element or (element-based computation).
|
258
261
|
// Can't optimize arrays of integers longer than 65,535 elements.
|
259
|
-
// See
|
262
|
+
// See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
|
260
263
|
_.max = function(obj, iterator, context) {
|
261
264
|
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
262
265
|
return Math.max.apply(Math, obj);
|
@@ -265,7 +268,7 @@
|
|
265
268
|
var result = {computed : -Infinity, value: -Infinity};
|
266
269
|
each(obj, function(value, index, list) {
|
267
270
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
268
|
-
computed
|
271
|
+
computed > result.computed && (result = {value : value, computed : computed});
|
269
272
|
});
|
270
273
|
return result.value;
|
271
274
|
};
|
@@ -284,7 +287,8 @@
|
|
284
287
|
return result.value;
|
285
288
|
};
|
286
289
|
|
287
|
-
// Shuffle an array
|
290
|
+
// Shuffle an array, using the modern version of the
|
291
|
+
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
288
292
|
_.shuffle = function(obj) {
|
289
293
|
var rand;
|
290
294
|
var index = 0;
|
@@ -297,19 +301,32 @@
|
|
297
301
|
return shuffled;
|
298
302
|
};
|
299
303
|
|
304
|
+
// Sample **n** random values from a collection.
|
305
|
+
// If **n** is not specified, returns a single random element.
|
306
|
+
// The internal `guard` argument allows it to work with `map`.
|
307
|
+
_.sample = function(obj, n, guard) {
|
308
|
+
if (n == null || guard) {
|
309
|
+
if (obj.length !== +obj.length) obj = _.values(obj);
|
310
|
+
return obj[_.random(obj.length - 1)];
|
311
|
+
}
|
312
|
+
return _.shuffle(obj).slice(0, Math.max(0, n));
|
313
|
+
};
|
314
|
+
|
300
315
|
// An internal function to generate lookup iterators.
|
301
316
|
var lookupIterator = function(value) {
|
302
|
-
|
317
|
+
if (value == null) return _.identity;
|
318
|
+
if (_.isFunction(value)) return value;
|
319
|
+
return _.property(value);
|
303
320
|
};
|
304
321
|
|
305
322
|
// Sort the object's values by a criterion produced by an iterator.
|
306
|
-
_.sortBy = function(obj,
|
307
|
-
|
323
|
+
_.sortBy = function(obj, iterator, context) {
|
324
|
+
iterator = lookupIterator(iterator);
|
308
325
|
return _.pluck(_.map(obj, function(value, index, list) {
|
309
326
|
return {
|
310
|
-
value
|
311
|
-
index
|
312
|
-
criteria
|
327
|
+
value: value,
|
328
|
+
index: index,
|
329
|
+
criteria: iterator.call(context, value, index, list)
|
313
330
|
};
|
314
331
|
}).sort(function(left, right) {
|
315
332
|
var a = left.criteria;
|
@@ -318,43 +335,46 @@
|
|
318
335
|
if (a > b || a === void 0) return 1;
|
319
336
|
if (a < b || b === void 0) return -1;
|
320
337
|
}
|
321
|
-
return left.index
|
338
|
+
return left.index - right.index;
|
322
339
|
}), 'value');
|
323
340
|
};
|
324
341
|
|
325
342
|
// An internal function used for aggregate "group by" operations.
|
326
|
-
var group = function(
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
343
|
+
var group = function(behavior) {
|
344
|
+
return function(obj, iterator, context) {
|
345
|
+
var result = {};
|
346
|
+
iterator = lookupIterator(iterator);
|
347
|
+
each(obj, function(value, index) {
|
348
|
+
var key = iterator.call(context, value, index, obj);
|
349
|
+
behavior(result, key, value);
|
350
|
+
});
|
351
|
+
return result;
|
352
|
+
};
|
334
353
|
};
|
335
354
|
|
336
355
|
// Groups the object's values by a criterion. Pass either a string attribute
|
337
356
|
// to group by, or a function that returns the criterion.
|
338
|
-
_.groupBy = function(
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
357
|
+
_.groupBy = group(function(result, key, value) {
|
358
|
+
_.has(result, key) ? result[key].push(value) : result[key] = [value];
|
359
|
+
});
|
360
|
+
|
361
|
+
// Indexes the object's values by a criterion, similar to `groupBy`, but for
|
362
|
+
// when you know that your index values will be unique.
|
363
|
+
_.indexBy = group(function(result, key, value) {
|
364
|
+
result[key] = value;
|
365
|
+
});
|
343
366
|
|
344
367
|
// Counts instances of an object that group by a certain criterion. Pass
|
345
368
|
// either a string attribute to count by, or a function that returns the
|
346
369
|
// criterion.
|
347
|
-
_.countBy = function(
|
348
|
-
|
349
|
-
|
350
|
-
result[key]++;
|
351
|
-
});
|
352
|
-
};
|
370
|
+
_.countBy = group(function(result, key) {
|
371
|
+
_.has(result, key) ? result[key]++ : result[key] = 1;
|
372
|
+
});
|
353
373
|
|
354
374
|
// Use a comparator function to figure out the smallest index at which
|
355
375
|
// an object should be inserted so as to maintain order. Uses binary search.
|
356
376
|
_.sortedIndex = function(array, obj, iterator, context) {
|
357
|
-
iterator =
|
377
|
+
iterator = lookupIterator(iterator);
|
358
378
|
var value = iterator.call(context, obj);
|
359
379
|
var low = 0, high = array.length;
|
360
380
|
while (low < high) {
|
@@ -364,7 +384,7 @@
|
|
364
384
|
return low;
|
365
385
|
};
|
366
386
|
|
367
|
-
// Safely
|
387
|
+
// Safely create a real, live array from anything iterable.
|
368
388
|
_.toArray = function(obj) {
|
369
389
|
if (!obj) return [];
|
370
390
|
if (_.isArray(obj)) return slice.call(obj);
|
@@ -386,7 +406,9 @@
|
|
386
406
|
// allows it to work with `_.map`.
|
387
407
|
_.first = _.head = _.take = function(array, n, guard) {
|
388
408
|
if (array == null) return void 0;
|
389
|
-
|
409
|
+
if ((n == null) || guard) return array[0];
|
410
|
+
if (n < 0) return [];
|
411
|
+
return slice.call(array, 0, n);
|
390
412
|
};
|
391
413
|
|
392
414
|
// Returns everything but the last entry of the array. Especially useful on
|
@@ -401,11 +423,8 @@
|
|
401
423
|
// values in the array. The **guard** check allows it to work with `_.map`.
|
402
424
|
_.last = function(array, n, guard) {
|
403
425
|
if (array == null) return void 0;
|
404
|
-
if ((n
|
405
|
-
|
406
|
-
} else {
|
407
|
-
return array[array.length - 1];
|
408
|
-
}
|
426
|
+
if ((n == null) || guard) return array[array.length - 1];
|
427
|
+
return slice.call(array, Math.max(array.length - n, 0));
|
409
428
|
};
|
410
429
|
|
411
430
|
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
@@ -423,8 +442,11 @@
|
|
423
442
|
|
424
443
|
// Internal implementation of a recursive `flatten` function.
|
425
444
|
var flatten = function(input, shallow, output) {
|
445
|
+
if (shallow && _.every(input, _.isArray)) {
|
446
|
+
return concat.apply(output, input);
|
447
|
+
}
|
426
448
|
each(input, function(value) {
|
427
|
-
if (_.isArray(value)) {
|
449
|
+
if (_.isArray(value) || _.isArguments(value)) {
|
428
450
|
shallow ? push.apply(output, value) : flatten(value, shallow, output);
|
429
451
|
} else {
|
430
452
|
output.push(value);
|
@@ -433,7 +455,7 @@
|
|
433
455
|
return output;
|
434
456
|
};
|
435
457
|
|
436
|
-
//
|
458
|
+
// Flatten out an array, either recursively (by default), or just one level.
|
437
459
|
_.flatten = function(array, shallow) {
|
438
460
|
return flatten(array, shallow, []);
|
439
461
|
};
|
@@ -467,7 +489,7 @@
|
|
467
489
|
// Produce an array that contains the union: each distinct element from all of
|
468
490
|
// the passed-in arrays.
|
469
491
|
_.union = function() {
|
470
|
-
return _.uniq(
|
492
|
+
return _.uniq(_.flatten(arguments, true));
|
471
493
|
};
|
472
494
|
|
473
495
|
// Produce an array that contains every item shared between all the
|
@@ -491,11 +513,10 @@
|
|
491
513
|
// Zip together multiple lists into a single array -- elements that share
|
492
514
|
// an index go together.
|
493
515
|
_.zip = function() {
|
494
|
-
var
|
495
|
-
var length = _.max(_.pluck(args, 'length'));
|
516
|
+
var length = _.max(_.pluck(arguments, "length").concat(0));
|
496
517
|
var results = new Array(length);
|
497
518
|
for (var i = 0; i < length; i++) {
|
498
|
-
results[i] = _.pluck(
|
519
|
+
results[i] = _.pluck(arguments, '' + i);
|
499
520
|
}
|
500
521
|
return results;
|
501
522
|
};
|
@@ -506,7 +527,7 @@
|
|
506
527
|
_.object = function(list, values) {
|
507
528
|
if (list == null) return {};
|
508
529
|
var result = {};
|
509
|
-
for (var i = 0,
|
530
|
+
for (var i = 0, length = list.length; i < length; i++) {
|
510
531
|
if (values) {
|
511
532
|
result[list[i]] = values[i];
|
512
533
|
} else {
|
@@ -524,17 +545,17 @@
|
|
524
545
|
// for **isSorted** to use binary search.
|
525
546
|
_.indexOf = function(array, item, isSorted) {
|
526
547
|
if (array == null) return -1;
|
527
|
-
var i = 0,
|
548
|
+
var i = 0, length = array.length;
|
528
549
|
if (isSorted) {
|
529
550
|
if (typeof isSorted == 'number') {
|
530
|
-
i = (isSorted < 0 ? Math.max(0,
|
551
|
+
i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
|
531
552
|
} else {
|
532
553
|
i = _.sortedIndex(array, item);
|
533
554
|
return array[i] === item ? i : -1;
|
534
555
|
}
|
535
556
|
}
|
536
557
|
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
537
|
-
for (; i <
|
558
|
+
for (; i < length; i++) if (array[i] === item) return i;
|
538
559
|
return -1;
|
539
560
|
};
|
540
561
|
|
@@ -560,11 +581,11 @@
|
|
560
581
|
}
|
561
582
|
step = arguments[2] || 1;
|
562
583
|
|
563
|
-
var
|
584
|
+
var length = Math.max(Math.ceil((stop - start) / step), 0);
|
564
585
|
var idx = 0;
|
565
|
-
var range = new Array(
|
586
|
+
var range = new Array(length);
|
566
587
|
|
567
|
-
while(idx <
|
588
|
+
while(idx < length) {
|
568
589
|
range[idx++] = start;
|
569
590
|
start += step;
|
570
591
|
}
|
@@ -575,31 +596,51 @@
|
|
575
596
|
// Function (ahem) Functions
|
576
597
|
// ------------------
|
577
598
|
|
599
|
+
// Reusable constructor function for prototype setting.
|
600
|
+
var ctor = function(){};
|
601
|
+
|
578
602
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
579
603
|
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
580
604
|
// available.
|
581
605
|
_.bind = function(func, context) {
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
606
|
+
var args, bound;
|
607
|
+
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
608
|
+
if (!_.isFunction(func)) throw new TypeError;
|
609
|
+
args = slice.call(arguments, 2);
|
610
|
+
return bound = function() {
|
611
|
+
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
612
|
+
ctor.prototype = func.prototype;
|
613
|
+
var self = new ctor;
|
614
|
+
ctor.prototype = null;
|
615
|
+
var result = func.apply(self, args.concat(slice.call(arguments)));
|
616
|
+
if (Object(result) === result) return result;
|
617
|
+
return self;
|
586
618
|
};
|
587
619
|
};
|
588
620
|
|
589
621
|
// Partially apply a function by creating a version that has had some of its
|
590
|
-
// arguments pre-filled, without changing its dynamic `this` context.
|
622
|
+
// arguments pre-filled, without changing its dynamic `this` context. _ acts
|
623
|
+
// as a placeholder, allowing any combination of arguments to be pre-filled.
|
591
624
|
_.partial = function(func) {
|
592
|
-
var
|
625
|
+
var boundArgs = slice.call(arguments, 1);
|
593
626
|
return function() {
|
594
|
-
|
627
|
+
var args = slice.call(boundArgs);
|
628
|
+
_.each(arguments, function(arg) {
|
629
|
+
var index = args.indexOf(_);
|
630
|
+
args[index >= 0 ? index : args.length] = arg;
|
631
|
+
});
|
632
|
+
return func.apply(this, _.map(args, function(value) {
|
633
|
+
return value === _ ? void 0 : value;
|
634
|
+
}));
|
595
635
|
};
|
596
636
|
};
|
597
637
|
|
598
|
-
// Bind
|
599
|
-
//
|
638
|
+
// Bind a number of an object's methods to that object. Remaining arguments
|
639
|
+
// are the method names to be bound. Useful for ensuring that all callbacks
|
640
|
+
// defined on an object belong to it.
|
600
641
|
_.bindAll = function(obj) {
|
601
642
|
var funcs = slice.call(arguments, 1);
|
602
|
-
if (funcs.length === 0)
|
643
|
+
if (funcs.length === 0) throw new Error("bindAll must be passed function names");
|
603
644
|
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
604
645
|
return obj;
|
605
646
|
};
|
@@ -628,17 +669,24 @@
|
|
628
669
|
};
|
629
670
|
|
630
671
|
// Returns a function, that, when invoked, will only be triggered at most once
|
631
|
-
// during a given window of time.
|
632
|
-
|
633
|
-
|
672
|
+
// during a given window of time. Normally, the throttled function will run
|
673
|
+
// as much as it can, without ever going more than once per `wait` duration;
|
674
|
+
// but if you'd like to disable the execution on the leading edge, pass
|
675
|
+
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
676
|
+
_.throttle = function(func, wait, options) {
|
677
|
+
var context, args, result;
|
678
|
+
var timeout = null;
|
634
679
|
var previous = 0;
|
680
|
+
options || (options = {});
|
635
681
|
var later = function() {
|
636
|
-
previous =
|
682
|
+
previous = options.leading === false ? 0 : getTime();
|
637
683
|
timeout = null;
|
638
684
|
result = func.apply(context, args);
|
685
|
+
context = args = null;
|
639
686
|
};
|
640
687
|
return function() {
|
641
|
-
var now =
|
688
|
+
var now = getTime();
|
689
|
+
if (!previous && options.leading === false) previous = now;
|
642
690
|
var remaining = wait - (now - previous);
|
643
691
|
context = this;
|
644
692
|
args = arguments;
|
@@ -647,7 +695,8 @@
|
|
647
695
|
timeout = null;
|
648
696
|
previous = now;
|
649
697
|
result = func.apply(context, args);
|
650
|
-
|
698
|
+
context = args = null;
|
699
|
+
} else if (!timeout && options.trailing !== false) {
|
651
700
|
timeout = setTimeout(later, remaining);
|
652
701
|
}
|
653
702
|
return result;
|
@@ -659,17 +708,32 @@
|
|
659
708
|
// N milliseconds. If `immediate` is passed, trigger the function on the
|
660
709
|
// leading edge, instead of the trailing.
|
661
710
|
_.debounce = function(func, wait, immediate) {
|
662
|
-
var timeout, result;
|
711
|
+
var timeout, args, context, timestamp, result;
|
663
712
|
return function() {
|
664
|
-
|
713
|
+
context = this;
|
714
|
+
args = arguments;
|
715
|
+
timestamp = getTime();
|
665
716
|
var later = function() {
|
666
|
-
|
667
|
-
if (
|
717
|
+
var last = getTime() - timestamp;
|
718
|
+
if (last < wait) {
|
719
|
+
timeout = setTimeout(later, wait - last);
|
720
|
+
} else {
|
721
|
+
timeout = null;
|
722
|
+
if (!immediate) {
|
723
|
+
result = func.apply(context, args);
|
724
|
+
context = args = null;
|
725
|
+
}
|
726
|
+
}
|
668
727
|
};
|
669
728
|
var callNow = immediate && !timeout;
|
670
|
-
|
671
|
-
|
672
|
-
|
729
|
+
if (!timeout) {
|
730
|
+
timeout = setTimeout(later, wait);
|
731
|
+
}
|
732
|
+
if (callNow) {
|
733
|
+
result = func.apply(context, args);
|
734
|
+
context = args = null;
|
735
|
+
}
|
736
|
+
|
673
737
|
return result;
|
674
738
|
};
|
675
739
|
};
|
@@ -691,11 +755,7 @@
|
|
691
755
|
// allowing you to adjust arguments, run code before and after, and
|
692
756
|
// conditionally execute the original function.
|
693
757
|
_.wrap = function(func, wrapper) {
|
694
|
-
return
|
695
|
-
var args = [func];
|
696
|
-
push.apply(args, arguments);
|
697
|
-
return wrapper.apply(this, args);
|
698
|
-
};
|
758
|
+
return _.partial(wrapper, func);
|
699
759
|
};
|
700
760
|
|
701
761
|
// Returns a function that is the composition of a list of functions, each
|
@@ -713,7 +773,6 @@
|
|
713
773
|
|
714
774
|
// Returns a function that will only be executed after being called N times.
|
715
775
|
_.after = function(times, func) {
|
716
|
-
if (times <= 0) return func();
|
717
776
|
return function() {
|
718
777
|
if (--times < 1) {
|
719
778
|
return func.apply(this, arguments);
|
@@ -729,28 +788,39 @@
|
|
729
788
|
_.keys = nativeKeys || function(obj) {
|
730
789
|
if (obj !== Object(obj)) throw new TypeError('Invalid object');
|
731
790
|
var keys = [];
|
732
|
-
for (var key in obj) if (_.has(obj, key)) keys
|
791
|
+
for (var key in obj) if (_.has(obj, key)) keys.push(key);
|
733
792
|
return keys;
|
734
793
|
};
|
735
794
|
|
736
795
|
// Retrieve the values of an object's properties.
|
737
796
|
_.values = function(obj) {
|
738
|
-
var
|
739
|
-
|
797
|
+
var keys = _.keys(obj);
|
798
|
+
var length = keys.length;
|
799
|
+
var values = new Array(length);
|
800
|
+
for (var i = 0; i < length; i++) {
|
801
|
+
values[i] = obj[keys[i]];
|
802
|
+
}
|
740
803
|
return values;
|
741
804
|
};
|
742
805
|
|
743
806
|
// Convert an object into a list of `[key, value]` pairs.
|
744
807
|
_.pairs = function(obj) {
|
745
|
-
var
|
746
|
-
|
808
|
+
var keys = _.keys(obj);
|
809
|
+
var length = keys.length;
|
810
|
+
var pairs = new Array(length);
|
811
|
+
for (var i = 0; i < length; i++) {
|
812
|
+
pairs[i] = [keys[i], obj[keys[i]]];
|
813
|
+
}
|
747
814
|
return pairs;
|
748
815
|
};
|
749
816
|
|
750
817
|
// Invert the keys and values of an object. The values must be serializable.
|
751
818
|
_.invert = function(obj) {
|
752
819
|
var result = {};
|
753
|
-
|
820
|
+
var keys = _.keys(obj);
|
821
|
+
for (var i = 0, length = keys.length; i < length; i++) {
|
822
|
+
result[obj[keys[i]]] = keys[i];
|
823
|
+
}
|
754
824
|
return result;
|
755
825
|
};
|
756
826
|
|
@@ -801,7 +871,7 @@
|
|
801
871
|
each(slice.call(arguments, 1), function(source) {
|
802
872
|
if (source) {
|
803
873
|
for (var prop in source) {
|
804
|
-
if (obj[prop]
|
874
|
+
if (obj[prop] === void 0) obj[prop] = source[prop];
|
805
875
|
}
|
806
876
|
}
|
807
877
|
});
|
@@ -825,7 +895,7 @@
|
|
825
895
|
// Internal recursive comparison function for `isEqual`.
|
826
896
|
var eq = function(a, b, aStack, bStack) {
|
827
897
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
828
|
-
// See the Harmony `egal` proposal
|
898
|
+
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
829
899
|
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
830
900
|
// A strict comparison is necessary because `null == undefined`.
|
831
901
|
if (a == null || b == null) return a === b;
|
@@ -867,6 +937,14 @@
|
|
867
937
|
// unique nested structures.
|
868
938
|
if (aStack[length] == a) return bStack[length] == b;
|
869
939
|
}
|
940
|
+
// Objects with different constructors are not equivalent, but `Object`s
|
941
|
+
// from different frames are.
|
942
|
+
var aCtor = a.constructor, bCtor = b.constructor;
|
943
|
+
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
944
|
+
_.isFunction(bCtor) && (bCtor instanceof bCtor))
|
945
|
+
&& ('constructor' in a && 'constructor' in b)) {
|
946
|
+
return false;
|
947
|
+
}
|
870
948
|
// Add the first object to the stack of traversed objects.
|
871
949
|
aStack.push(a);
|
872
950
|
bStack.push(b);
|
@@ -883,13 +961,6 @@
|
|
883
961
|
}
|
884
962
|
}
|
885
963
|
} else {
|
886
|
-
// Objects with different constructors are not equivalent, but `Object`s
|
887
|
-
// from different frames are.
|
888
|
-
var aCtor = a.constructor, bCtor = b.constructor;
|
889
|
-
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
890
|
-
_.isFunction(bCtor) && (bCtor instanceof bCtor))) {
|
891
|
-
return false;
|
892
|
-
}
|
893
964
|
// Deep compare objects.
|
894
965
|
for (var key in a) {
|
895
966
|
if (_.has(a, key)) {
|
@@ -1011,9 +1082,21 @@
|
|
1011
1082
|
return value;
|
1012
1083
|
};
|
1013
1084
|
|
1085
|
+
_.constant = function(value) {
|
1086
|
+
return function () {
|
1087
|
+
return value;
|
1088
|
+
};
|
1089
|
+
};
|
1090
|
+
|
1091
|
+
_.property = function(key) {
|
1092
|
+
return function(obj) {
|
1093
|
+
return obj[key];
|
1094
|
+
};
|
1095
|
+
};
|
1096
|
+
|
1014
1097
|
// Run a function **n** times.
|
1015
1098
|
_.times = function(n, iterator, context) {
|
1016
|
-
var accum = Array(n);
|
1099
|
+
var accum = Array(Math.max(0, n));
|
1017
1100
|
for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
|
1018
1101
|
return accum;
|
1019
1102
|
};
|
@@ -1034,8 +1117,7 @@
|
|
1034
1117
|
'<': '<',
|
1035
1118
|
'>': '>',
|
1036
1119
|
'"': '"',
|
1037
|
-
"'": '''
|
1038
|
-
'/': '/'
|
1120
|
+
"'": '''
|
1039
1121
|
}
|
1040
1122
|
};
|
1041
1123
|
entityMap.unescape = _.invert(entityMap.escape);
|
@@ -1056,17 +1138,17 @@
|
|
1056
1138
|
};
|
1057
1139
|
});
|
1058
1140
|
|
1059
|
-
// If the value of the named property is a function then invoke it
|
1060
|
-
// otherwise, return it.
|
1141
|
+
// If the value of the named `property` is a function then invoke it with the
|
1142
|
+
// `object` as context; otherwise, return it.
|
1061
1143
|
_.result = function(object, property) {
|
1062
|
-
if (object == null) return
|
1144
|
+
if (object == null) return void 0;
|
1063
1145
|
var value = object[property];
|
1064
1146
|
return _.isFunction(value) ? value.call(object) : value;
|
1065
1147
|
};
|
1066
1148
|
|
1067
1149
|
// Add your own custom functions to the Underscore object.
|
1068
1150
|
_.mixin = function(obj) {
|
1069
|
-
each(_.functions(obj), function(name){
|
1151
|
+
each(_.functions(obj), function(name) {
|
1070
1152
|
var func = _[name] = obj[name];
|
1071
1153
|
_.prototype[name] = function() {
|
1072
1154
|
var args = [this._wrapped];
|
@@ -1224,4 +1306,16 @@
|
|
1224
1306
|
|
1225
1307
|
});
|
1226
1308
|
|
1309
|
+
// AMD registration happens at the end for compatibility with AMD loaders
|
1310
|
+
// that may not enforce next-turn semantics on modules. Even though general
|
1311
|
+
// practice for AMD registration is to be anonymous, underscore registers
|
1312
|
+
// as a named module because, like jQuery, it is a base library that is
|
1313
|
+
// popular enough to be bundled in a third party lib, but not be part of
|
1314
|
+
// an AMD load request. Those cases could generate an error when an
|
1315
|
+
// anonymous define() is called outside of a loader request.
|
1316
|
+
if (typeof define === 'function' && define.amd) {
|
1317
|
+
define('underscore', [], function() {
|
1318
|
+
return _;
|
1319
|
+
});
|
1320
|
+
}
|
1227
1321
|
}).call(this);
|