backbone-rails 1.1.2 → 1.2.3
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.
- checksums.yaml +7 -0
- data/vendor/assets/javascripts/backbone.js +717 -431
- data/vendor/assets/javascripts/underscore.js +756 -551
- metadata +13 -17
@@ -1,6 +1,6 @@
|
|
1
|
-
// Underscore.js 1.
|
1
|
+
// Underscore.js 1.8.3
|
2
2
|
// http://underscorejs.org
|
3
|
-
// (c) 2009-
|
3
|
+
// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
4
4
|
// Underscore may be freely distributed under the MIT license.
|
5
5
|
|
6
6
|
(function() {
|
@@ -14,9 +14,6 @@
|
|
14
14
|
// Save the previous value of the `_` variable.
|
15
15
|
var previousUnderscore = root._;
|
16
16
|
|
17
|
-
// Establish the object that gets returned to break out of a loop iteration.
|
18
|
-
var breaker = {};
|
19
|
-
|
20
17
|
// Save bytes in the minified (but not gzipped) version:
|
21
18
|
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
22
19
|
|
@@ -24,25 +21,19 @@
|
|
24
21
|
var
|
25
22
|
push = ArrayProto.push,
|
26
23
|
slice = ArrayProto.slice,
|
27
|
-
concat = ArrayProto.concat,
|
28
24
|
toString = ObjProto.toString,
|
29
25
|
hasOwnProperty = ObjProto.hasOwnProperty;
|
30
26
|
|
31
27
|
// All **ECMAScript 5** native function implementations that we hope to use
|
32
28
|
// are declared here.
|
33
29
|
var
|
34
|
-
nativeForEach = ArrayProto.forEach,
|
35
|
-
nativeMap = ArrayProto.map,
|
36
|
-
nativeReduce = ArrayProto.reduce,
|
37
|
-
nativeReduceRight = ArrayProto.reduceRight,
|
38
|
-
nativeFilter = ArrayProto.filter,
|
39
|
-
nativeEvery = ArrayProto.every,
|
40
|
-
nativeSome = ArrayProto.some,
|
41
|
-
nativeIndexOf = ArrayProto.indexOf,
|
42
|
-
nativeLastIndexOf = ArrayProto.lastIndexOf,
|
43
30
|
nativeIsArray = Array.isArray,
|
44
31
|
nativeKeys = Object.keys,
|
45
|
-
nativeBind = FuncProto.bind
|
32
|
+
nativeBind = FuncProto.bind,
|
33
|
+
nativeCreate = Object.create;
|
34
|
+
|
35
|
+
// Naked function reference for surrogate-prototype-swapping.
|
36
|
+
var Ctor = function(){};
|
46
37
|
|
47
38
|
// Create a safe reference to the Underscore object for use below.
|
48
39
|
var _ = function(obj) {
|
@@ -53,8 +44,7 @@
|
|
53
44
|
|
54
45
|
// Export the Underscore object for **Node.js**, with
|
55
46
|
// backwards-compatibility for the old `require()` API. If we're in
|
56
|
-
// the browser, add `_` as a global object
|
57
|
-
// for Closure Compiler "advanced" mode.
|
47
|
+
// the browser, add `_` as a global object.
|
58
48
|
if (typeof exports !== 'undefined') {
|
59
49
|
if (typeof module !== 'undefined' && module.exports) {
|
60
50
|
exports = module.exports = _;
|
@@ -65,161 +55,217 @@
|
|
65
55
|
}
|
66
56
|
|
67
57
|
// Current version.
|
68
|
-
_.VERSION = '1.
|
58
|
+
_.VERSION = '1.8.3';
|
59
|
+
|
60
|
+
// Internal function that returns an efficient (for current engines) version
|
61
|
+
// of the passed-in callback, to be repeatedly applied in other Underscore
|
62
|
+
// functions.
|
63
|
+
var optimizeCb = function(func, context, argCount) {
|
64
|
+
if (context === void 0) return func;
|
65
|
+
switch (argCount == null ? 3 : argCount) {
|
66
|
+
case 1: return function(value) {
|
67
|
+
return func.call(context, value);
|
68
|
+
};
|
69
|
+
case 2: return function(value, other) {
|
70
|
+
return func.call(context, value, other);
|
71
|
+
};
|
72
|
+
case 3: return function(value, index, collection) {
|
73
|
+
return func.call(context, value, index, collection);
|
74
|
+
};
|
75
|
+
case 4: return function(accumulator, value, index, collection) {
|
76
|
+
return func.call(context, accumulator, value, index, collection);
|
77
|
+
};
|
78
|
+
}
|
79
|
+
return function() {
|
80
|
+
return func.apply(context, arguments);
|
81
|
+
};
|
82
|
+
};
|
83
|
+
|
84
|
+
// A mostly-internal function to generate callbacks that can be applied
|
85
|
+
// to each element in a collection, returning the desired result — either
|
86
|
+
// identity, an arbitrary callback, a property matcher, or a property accessor.
|
87
|
+
var cb = function(value, context, argCount) {
|
88
|
+
if (value == null) return _.identity;
|
89
|
+
if (_.isFunction(value)) return optimizeCb(value, context, argCount);
|
90
|
+
if (_.isObject(value)) return _.matcher(value);
|
91
|
+
return _.property(value);
|
92
|
+
};
|
93
|
+
_.iteratee = function(value, context) {
|
94
|
+
return cb(value, context, Infinity);
|
95
|
+
};
|
96
|
+
|
97
|
+
// An internal function for creating assigner functions.
|
98
|
+
var createAssigner = function(keysFunc, undefinedOnly) {
|
99
|
+
return function(obj) {
|
100
|
+
var length = arguments.length;
|
101
|
+
if (length < 2 || obj == null) return obj;
|
102
|
+
for (var index = 1; index < length; index++) {
|
103
|
+
var source = arguments[index],
|
104
|
+
keys = keysFunc(source),
|
105
|
+
l = keys.length;
|
106
|
+
for (var i = 0; i < l; i++) {
|
107
|
+
var key = keys[i];
|
108
|
+
if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
|
109
|
+
}
|
110
|
+
}
|
111
|
+
return obj;
|
112
|
+
};
|
113
|
+
};
|
114
|
+
|
115
|
+
// An internal function for creating a new object that inherits from another.
|
116
|
+
var baseCreate = function(prototype) {
|
117
|
+
if (!_.isObject(prototype)) return {};
|
118
|
+
if (nativeCreate) return nativeCreate(prototype);
|
119
|
+
Ctor.prototype = prototype;
|
120
|
+
var result = new Ctor;
|
121
|
+
Ctor.prototype = null;
|
122
|
+
return result;
|
123
|
+
};
|
124
|
+
|
125
|
+
var property = function(key) {
|
126
|
+
return function(obj) {
|
127
|
+
return obj == null ? void 0 : obj[key];
|
128
|
+
};
|
129
|
+
};
|
130
|
+
|
131
|
+
// Helper for collection methods to determine whether a collection
|
132
|
+
// should be iterated as an array or as an object
|
133
|
+
// Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
|
134
|
+
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
|
135
|
+
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
|
136
|
+
var getLength = property('length');
|
137
|
+
var isArrayLike = function(collection) {
|
138
|
+
var length = getLength(collection);
|
139
|
+
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
|
140
|
+
};
|
69
141
|
|
70
142
|
// Collection Functions
|
71
143
|
// --------------------
|
72
144
|
|
73
145
|
// The cornerstone, an `each` implementation, aka `forEach`.
|
74
|
-
// Handles objects
|
75
|
-
//
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
146
|
+
// Handles raw objects in addition to array-likes. Treats all
|
147
|
+
// sparse array-likes as if they were dense.
|
148
|
+
_.each = _.forEach = function(obj, iteratee, context) {
|
149
|
+
iteratee = optimizeCb(iteratee, context);
|
150
|
+
var i, length;
|
151
|
+
if (isArrayLike(obj)) {
|
152
|
+
for (i = 0, length = obj.length; i < length; i++) {
|
153
|
+
iteratee(obj[i], i, obj);
|
83
154
|
}
|
84
155
|
} else {
|
85
156
|
var keys = _.keys(obj);
|
86
|
-
for (
|
87
|
-
|
157
|
+
for (i = 0, length = keys.length; i < length; i++) {
|
158
|
+
iteratee(obj[keys[i]], keys[i], obj);
|
88
159
|
}
|
89
160
|
}
|
90
161
|
return obj;
|
91
162
|
};
|
92
163
|
|
93
|
-
// Return the results of applying the
|
94
|
-
|
95
|
-
|
96
|
-
var
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
164
|
+
// Return the results of applying the iteratee to each element.
|
165
|
+
_.map = _.collect = function(obj, iteratee, context) {
|
166
|
+
iteratee = cb(iteratee, context);
|
167
|
+
var keys = !isArrayLike(obj) && _.keys(obj),
|
168
|
+
length = (keys || obj).length,
|
169
|
+
results = Array(length);
|
170
|
+
for (var index = 0; index < length; index++) {
|
171
|
+
var currentKey = keys ? keys[index] : index;
|
172
|
+
results[index] = iteratee(obj[currentKey], currentKey, obj);
|
173
|
+
}
|
102
174
|
return results;
|
103
175
|
};
|
104
176
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
return
|
177
|
+
// Create a reducing function iterating left or right.
|
178
|
+
function createReduce(dir) {
|
179
|
+
// Optimized iterator function as using arguments.length
|
180
|
+
// in the main function will deoptimize the, see #1991.
|
181
|
+
function iterator(obj, iteratee, memo, keys, index, length) {
|
182
|
+
for (; index >= 0 && index < length; index += dir) {
|
183
|
+
var currentKey = keys ? keys[index] : index;
|
184
|
+
memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
185
|
+
}
|
186
|
+
return memo;
|
115
187
|
}
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
188
|
+
|
189
|
+
return function(obj, iteratee, memo, context) {
|
190
|
+
iteratee = optimizeCb(iteratee, context, 4);
|
191
|
+
var keys = !isArrayLike(obj) && _.keys(obj),
|
192
|
+
length = (keys || obj).length,
|
193
|
+
index = dir > 0 ? 0 : length - 1;
|
194
|
+
// Determine the initial value if none is provided.
|
195
|
+
if (arguments.length < 3) {
|
196
|
+
memo = obj[keys ? keys[index] : index];
|
197
|
+
index += dir;
|
122
198
|
}
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
199
|
+
return iterator(obj, iteratee, memo, keys, index, length);
|
200
|
+
};
|
201
|
+
}
|
202
|
+
|
203
|
+
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
204
|
+
// or `foldl`.
|
205
|
+
_.reduce = _.foldl = _.inject = createReduce(1);
|
127
206
|
|
128
207
|
// The right-associative version of reduce, also known as `foldr`.
|
129
|
-
|
130
|
-
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
131
|
-
var initial = arguments.length > 2;
|
132
|
-
if (obj == null) obj = [];
|
133
|
-
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
134
|
-
if (context) iterator = _.bind(iterator, context);
|
135
|
-
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
136
|
-
}
|
137
|
-
var length = obj.length;
|
138
|
-
if (length !== +length) {
|
139
|
-
var keys = _.keys(obj);
|
140
|
-
length = keys.length;
|
141
|
-
}
|
142
|
-
each(obj, function(value, index, list) {
|
143
|
-
index = keys ? keys[--length] : --length;
|
144
|
-
if (!initial) {
|
145
|
-
memo = obj[index];
|
146
|
-
initial = true;
|
147
|
-
} else {
|
148
|
-
memo = iterator.call(context, memo, obj[index], index, list);
|
149
|
-
}
|
150
|
-
});
|
151
|
-
if (!initial) throw new TypeError(reduceError);
|
152
|
-
return memo;
|
153
|
-
};
|
208
|
+
_.reduceRight = _.foldr = createReduce(-1);
|
154
209
|
|
155
210
|
// Return the first value which passes a truth test. Aliased as `detect`.
|
156
211
|
_.find = _.detect = function(obj, predicate, context) {
|
157
|
-
var
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
return result;
|
212
|
+
var key;
|
213
|
+
if (isArrayLike(obj)) {
|
214
|
+
key = _.findIndex(obj, predicate, context);
|
215
|
+
} else {
|
216
|
+
key = _.findKey(obj, predicate, context);
|
217
|
+
}
|
218
|
+
if (key !== void 0 && key !== -1) return obj[key];
|
165
219
|
};
|
166
220
|
|
167
221
|
// Return all the elements that pass a truth test.
|
168
|
-
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
169
222
|
// Aliased as `select`.
|
170
223
|
_.filter = _.select = function(obj, predicate, context) {
|
171
224
|
var results = [];
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
if (predicate.call(context, value, index, list)) results.push(value);
|
225
|
+
predicate = cb(predicate, context);
|
226
|
+
_.each(obj, function(value, index, list) {
|
227
|
+
if (predicate(value, index, list)) results.push(value);
|
176
228
|
});
|
177
229
|
return results;
|
178
230
|
};
|
179
231
|
|
180
232
|
// Return all the elements for which a truth test fails.
|
181
233
|
_.reject = function(obj, predicate, context) {
|
182
|
-
return _.filter(obj,
|
183
|
-
return !predicate.call(context, value, index, list);
|
184
|
-
}, context);
|
234
|
+
return _.filter(obj, _.negate(cb(predicate)), context);
|
185
235
|
};
|
186
236
|
|
187
237
|
// Determine whether all of the elements match a truth test.
|
188
|
-
// Delegates to **ECMAScript 5**'s native `every` if available.
|
189
238
|
// Aliased as `all`.
|
190
239
|
_.every = _.all = function(obj, predicate, context) {
|
191
|
-
predicate
|
192
|
-
var
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
if (!
|
197
|
-
}
|
198
|
-
return
|
240
|
+
predicate = cb(predicate, context);
|
241
|
+
var keys = !isArrayLike(obj) && _.keys(obj),
|
242
|
+
length = (keys || obj).length;
|
243
|
+
for (var index = 0; index < length; index++) {
|
244
|
+
var currentKey = keys ? keys[index] : index;
|
245
|
+
if (!predicate(obj[currentKey], currentKey, obj)) return false;
|
246
|
+
}
|
247
|
+
return true;
|
199
248
|
};
|
200
249
|
|
201
250
|
// Determine if at least one element in the object matches a truth test.
|
202
|
-
// Delegates to **ECMAScript 5**'s native `some` if available.
|
203
251
|
// Aliased as `any`.
|
204
|
-
|
205
|
-
predicate
|
206
|
-
var
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
if (
|
211
|
-
}
|
212
|
-
return
|
252
|
+
_.some = _.any = function(obj, predicate, context) {
|
253
|
+
predicate = cb(predicate, context);
|
254
|
+
var keys = !isArrayLike(obj) && _.keys(obj),
|
255
|
+
length = (keys || obj).length;
|
256
|
+
for (var index = 0; index < length; index++) {
|
257
|
+
var currentKey = keys ? keys[index] : index;
|
258
|
+
if (predicate(obj[currentKey], currentKey, obj)) return true;
|
259
|
+
}
|
260
|
+
return false;
|
213
261
|
};
|
214
262
|
|
215
|
-
// Determine if the array or object contains a given
|
216
|
-
// Aliased as `include`.
|
217
|
-
_.contains = _.include = function(obj,
|
218
|
-
if (obj
|
219
|
-
if (
|
220
|
-
return
|
221
|
-
return value === target;
|
222
|
-
});
|
263
|
+
// Determine if the array or object contains a given item (using `===`).
|
264
|
+
// Aliased as `includes` and `include`.
|
265
|
+
_.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
|
266
|
+
if (!isArrayLike(obj)) obj = _.values(obj);
|
267
|
+
if (typeof fromIndex != 'number' || guard) fromIndex = 0;
|
268
|
+
return _.indexOf(obj, item, fromIndex) >= 0;
|
223
269
|
};
|
224
270
|
|
225
271
|
// Invoke a method (with arguments) on every item in a collection.
|
@@ -227,7 +273,8 @@
|
|
227
273
|
var args = slice.call(arguments, 2);
|
228
274
|
var isFunc = _.isFunction(method);
|
229
275
|
return _.map(obj, function(value) {
|
230
|
-
|
276
|
+
var func = isFunc ? method : value[method];
|
277
|
+
return func == null ? func : func.apply(value, args);
|
231
278
|
});
|
232
279
|
};
|
233
280
|
|
@@ -239,60 +286,76 @@
|
|
239
286
|
// Convenience version of a common use case of `filter`: selecting only objects
|
240
287
|
// containing specific `key:value` pairs.
|
241
288
|
_.where = function(obj, attrs) {
|
242
|
-
return _.filter(obj, _.
|
289
|
+
return _.filter(obj, _.matcher(attrs));
|
243
290
|
};
|
244
291
|
|
245
292
|
// Convenience version of a common use case of `find`: getting the first object
|
246
293
|
// containing specific `key:value` pairs.
|
247
294
|
_.findWhere = function(obj, attrs) {
|
248
|
-
return _.find(obj, _.
|
295
|
+
return _.find(obj, _.matcher(attrs));
|
249
296
|
};
|
250
297
|
|
251
|
-
// Return the maximum element or
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if (
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
result = value;
|
263
|
-
lastComputed = computed;
|
298
|
+
// Return the maximum element (or element-based computation).
|
299
|
+
_.max = function(obj, iteratee, context) {
|
300
|
+
var result = -Infinity, lastComputed = -Infinity,
|
301
|
+
value, computed;
|
302
|
+
if (iteratee == null && obj != null) {
|
303
|
+
obj = isArrayLike(obj) ? obj : _.values(obj);
|
304
|
+
for (var i = 0, length = obj.length; i < length; i++) {
|
305
|
+
value = obj[i];
|
306
|
+
if (value > result) {
|
307
|
+
result = value;
|
308
|
+
}
|
264
309
|
}
|
265
|
-
}
|
310
|
+
} else {
|
311
|
+
iteratee = cb(iteratee, context);
|
312
|
+
_.each(obj, function(value, index, list) {
|
313
|
+
computed = iteratee(value, index, list);
|
314
|
+
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
|
315
|
+
result = value;
|
316
|
+
lastComputed = computed;
|
317
|
+
}
|
318
|
+
});
|
319
|
+
}
|
266
320
|
return result;
|
267
321
|
};
|
268
322
|
|
269
323
|
// Return the minimum element (or element-based computation).
|
270
|
-
_.min = function(obj,
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
324
|
+
_.min = function(obj, iteratee, context) {
|
325
|
+
var result = Infinity, lastComputed = Infinity,
|
326
|
+
value, computed;
|
327
|
+
if (iteratee == null && obj != null) {
|
328
|
+
obj = isArrayLike(obj) ? obj : _.values(obj);
|
329
|
+
for (var i = 0, length = obj.length; i < length; i++) {
|
330
|
+
value = obj[i];
|
331
|
+
if (value < result) {
|
332
|
+
result = value;
|
333
|
+
}
|
280
334
|
}
|
281
|
-
}
|
335
|
+
} else {
|
336
|
+
iteratee = cb(iteratee, context);
|
337
|
+
_.each(obj, function(value, index, list) {
|
338
|
+
computed = iteratee(value, index, list);
|
339
|
+
if (computed < lastComputed || computed === Infinity && result === Infinity) {
|
340
|
+
result = value;
|
341
|
+
lastComputed = computed;
|
342
|
+
}
|
343
|
+
});
|
344
|
+
}
|
282
345
|
return result;
|
283
346
|
};
|
284
347
|
|
285
|
-
// Shuffle
|
348
|
+
// Shuffle a collection, using the modern version of the
|
286
349
|
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
287
350
|
_.shuffle = function(obj) {
|
288
|
-
var
|
289
|
-
var
|
290
|
-
var shuffled =
|
291
|
-
|
292
|
-
rand = _.random(index
|
293
|
-
shuffled[index
|
294
|
-
shuffled[rand] =
|
295
|
-
}
|
351
|
+
var set = isArrayLike(obj) ? obj : _.values(obj);
|
352
|
+
var length = set.length;
|
353
|
+
var shuffled = Array(length);
|
354
|
+
for (var index = 0, rand; index < length; index++) {
|
355
|
+
rand = _.random(0, index);
|
356
|
+
if (rand !== index) shuffled[index] = shuffled[rand];
|
357
|
+
shuffled[rand] = set[index];
|
358
|
+
}
|
296
359
|
return shuffled;
|
297
360
|
};
|
298
361
|
|
@@ -301,27 +364,20 @@
|
|
301
364
|
// The internal `guard` argument allows it to work with `map`.
|
302
365
|
_.sample = function(obj, n, guard) {
|
303
366
|
if (n == null || guard) {
|
304
|
-
if (obj
|
367
|
+
if (!isArrayLike(obj)) obj = _.values(obj);
|
305
368
|
return obj[_.random(obj.length - 1)];
|
306
369
|
}
|
307
370
|
return _.shuffle(obj).slice(0, Math.max(0, n));
|
308
371
|
};
|
309
372
|
|
310
|
-
//
|
311
|
-
|
312
|
-
|
313
|
-
if (_.isFunction(value)) return value;
|
314
|
-
return _.property(value);
|
315
|
-
};
|
316
|
-
|
317
|
-
// Sort the object's values by a criterion produced by an iterator.
|
318
|
-
_.sortBy = function(obj, iterator, context) {
|
319
|
-
iterator = lookupIterator(iterator);
|
373
|
+
// Sort the object's values by a criterion produced by an iteratee.
|
374
|
+
_.sortBy = function(obj, iteratee, context) {
|
375
|
+
iteratee = cb(iteratee, context);
|
320
376
|
return _.pluck(_.map(obj, function(value, index, list) {
|
321
377
|
return {
|
322
378
|
value: value,
|
323
379
|
index: index,
|
324
|
-
criteria:
|
380
|
+
criteria: iteratee(value, index, list)
|
325
381
|
};
|
326
382
|
}).sort(function(left, right) {
|
327
383
|
var a = left.criteria;
|
@@ -336,12 +392,12 @@
|
|
336
392
|
|
337
393
|
// An internal function used for aggregate "group by" operations.
|
338
394
|
var group = function(behavior) {
|
339
|
-
return function(obj,
|
395
|
+
return function(obj, iteratee, context) {
|
340
396
|
var result = {};
|
341
|
-
|
342
|
-
each(obj, function(value, index) {
|
343
|
-
var key =
|
344
|
-
behavior(result,
|
397
|
+
iteratee = cb(iteratee, context);
|
398
|
+
_.each(obj, function(value, index) {
|
399
|
+
var key = iteratee(value, index, obj);
|
400
|
+
behavior(result, value, key);
|
345
401
|
});
|
346
402
|
return result;
|
347
403
|
};
|
@@ -349,48 +405,46 @@
|
|
349
405
|
|
350
406
|
// Groups the object's values by a criterion. Pass either a string attribute
|
351
407
|
// to group by, or a function that returns the criterion.
|
352
|
-
_.groupBy = group(function(result,
|
353
|
-
_.has(result, key)
|
408
|
+
_.groupBy = group(function(result, value, key) {
|
409
|
+
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
|
354
410
|
});
|
355
411
|
|
356
412
|
// Indexes the object's values by a criterion, similar to `groupBy`, but for
|
357
413
|
// when you know that your index values will be unique.
|
358
|
-
_.indexBy = group(function(result,
|
414
|
+
_.indexBy = group(function(result, value, key) {
|
359
415
|
result[key] = value;
|
360
416
|
});
|
361
417
|
|
362
418
|
// Counts instances of an object that group by a certain criterion. Pass
|
363
419
|
// either a string attribute to count by, or a function that returns the
|
364
420
|
// criterion.
|
365
|
-
_.countBy = group(function(result, key) {
|
366
|
-
_.has(result, key)
|
421
|
+
_.countBy = group(function(result, value, key) {
|
422
|
+
if (_.has(result, key)) result[key]++; else result[key] = 1;
|
367
423
|
});
|
368
424
|
|
369
|
-
// Use a comparator function to figure out the smallest index at which
|
370
|
-
// an object should be inserted so as to maintain order. Uses binary search.
|
371
|
-
_.sortedIndex = function(array, obj, iterator, context) {
|
372
|
-
iterator = lookupIterator(iterator);
|
373
|
-
var value = iterator.call(context, obj);
|
374
|
-
var low = 0, high = array.length;
|
375
|
-
while (low < high) {
|
376
|
-
var mid = (low + high) >>> 1;
|
377
|
-
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
|
378
|
-
}
|
379
|
-
return low;
|
380
|
-
};
|
381
|
-
|
382
425
|
// Safely create a real, live array from anything iterable.
|
383
426
|
_.toArray = function(obj) {
|
384
427
|
if (!obj) return [];
|
385
428
|
if (_.isArray(obj)) return slice.call(obj);
|
386
|
-
if (obj
|
429
|
+
if (isArrayLike(obj)) return _.map(obj, _.identity);
|
387
430
|
return _.values(obj);
|
388
431
|
};
|
389
432
|
|
390
433
|
// Return the number of elements in an object.
|
391
434
|
_.size = function(obj) {
|
392
435
|
if (obj == null) return 0;
|
393
|
-
return (obj
|
436
|
+
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
|
437
|
+
};
|
438
|
+
|
439
|
+
// Split a collection into two arrays: one whose elements all satisfy the given
|
440
|
+
// predicate, and one whose elements all do not satisfy the predicate.
|
441
|
+
_.partition = function(obj, predicate, context) {
|
442
|
+
predicate = cb(predicate, context);
|
443
|
+
var pass = [], fail = [];
|
444
|
+
_.each(obj, function(value, key, obj) {
|
445
|
+
(predicate(value, key, obj) ? pass : fail).push(value);
|
446
|
+
});
|
447
|
+
return [pass, fail];
|
394
448
|
};
|
395
449
|
|
396
450
|
// Array Functions
|
@@ -401,33 +455,30 @@
|
|
401
455
|
// allows it to work with `_.map`.
|
402
456
|
_.first = _.head = _.take = function(array, n, guard) {
|
403
457
|
if (array == null) return void 0;
|
404
|
-
if (
|
405
|
-
|
406
|
-
return slice.call(array, 0, n);
|
458
|
+
if (n == null || guard) return array[0];
|
459
|
+
return _.initial(array, array.length - n);
|
407
460
|
};
|
408
461
|
|
409
462
|
// Returns everything but the last entry of the array. Especially useful on
|
410
463
|
// the arguments object. Passing **n** will return all the values in
|
411
|
-
// the array, excluding the last N.
|
412
|
-
// `_.map`.
|
464
|
+
// the array, excluding the last N.
|
413
465
|
_.initial = function(array, n, guard) {
|
414
|
-
return slice.call(array, 0, array.length - (
|
466
|
+
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
|
415
467
|
};
|
416
468
|
|
417
469
|
// Get the last element of an array. Passing **n** will return the last N
|
418
|
-
// values in the array.
|
470
|
+
// values in the array.
|
419
471
|
_.last = function(array, n, guard) {
|
420
472
|
if (array == null) return void 0;
|
421
|
-
if (
|
422
|
-
return
|
473
|
+
if (n == null || guard) return array[array.length - 1];
|
474
|
+
return _.rest(array, Math.max(0, array.length - n));
|
423
475
|
};
|
424
476
|
|
425
477
|
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
426
478
|
// Especially useful on the arguments object. Passing an **n** will return
|
427
|
-
// the rest N values in the array.
|
428
|
-
// check allows it to work with `_.map`.
|
479
|
+
// the rest N values in the array.
|
429
480
|
_.rest = _.tail = _.drop = function(array, n, guard) {
|
430
|
-
return slice.call(array,
|
481
|
+
return slice.call(array, n == null || guard ? 1 : n);
|
431
482
|
};
|
432
483
|
|
433
484
|
// Trim out all falsy values from an array.
|
@@ -436,23 +487,28 @@
|
|
436
487
|
};
|
437
488
|
|
438
489
|
// Internal implementation of a recursive `flatten` function.
|
439
|
-
var flatten = function(input, shallow,
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
output.
|
490
|
+
var flatten = function(input, shallow, strict, startIndex) {
|
491
|
+
var output = [], idx = 0;
|
492
|
+
for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
|
493
|
+
var value = input[i];
|
494
|
+
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
|
495
|
+
//flatten current level of array or arguments object
|
496
|
+
if (!shallow) value = flatten(value, shallow, strict);
|
497
|
+
var j = 0, len = value.length;
|
498
|
+
output.length += len;
|
499
|
+
while (j < len) {
|
500
|
+
output[idx++] = value[j++];
|
501
|
+
}
|
502
|
+
} else if (!strict) {
|
503
|
+
output[idx++] = value;
|
448
504
|
}
|
449
|
-
}
|
505
|
+
}
|
450
506
|
return output;
|
451
507
|
};
|
452
508
|
|
453
509
|
// Flatten out an array, either recursively (by default), or just one level.
|
454
510
|
_.flatten = function(array, shallow) {
|
455
|
-
return flatten(array, shallow,
|
511
|
+
return flatten(array, shallow, false);
|
456
512
|
};
|
457
513
|
|
458
514
|
// Return a version of the array that does not contain the specified value(s).
|
@@ -460,79 +516,91 @@
|
|
460
516
|
return _.difference(array, slice.call(arguments, 1));
|
461
517
|
};
|
462
518
|
|
463
|
-
// Split an array into two arrays: one whose elements all satisfy the given
|
464
|
-
// predicate, and one whose elements all do not satisfy the predicate.
|
465
|
-
_.partition = function(array, predicate) {
|
466
|
-
var pass = [], fail = [];
|
467
|
-
each(array, function(elem) {
|
468
|
-
(predicate(elem) ? pass : fail).push(elem);
|
469
|
-
});
|
470
|
-
return [pass, fail];
|
471
|
-
};
|
472
|
-
|
473
519
|
// Produce a duplicate-free version of the array. If the array has already
|
474
520
|
// been sorted, you have the option of using a faster algorithm.
|
475
521
|
// Aliased as `unique`.
|
476
|
-
_.uniq = _.unique = function(array, isSorted,
|
477
|
-
if (_.
|
478
|
-
context =
|
479
|
-
|
522
|
+
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
|
523
|
+
if (!_.isBoolean(isSorted)) {
|
524
|
+
context = iteratee;
|
525
|
+
iteratee = isSorted;
|
480
526
|
isSorted = false;
|
481
527
|
}
|
482
|
-
|
483
|
-
var
|
528
|
+
if (iteratee != null) iteratee = cb(iteratee, context);
|
529
|
+
var result = [];
|
484
530
|
var seen = [];
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
531
|
+
for (var i = 0, length = getLength(array); i < length; i++) {
|
532
|
+
var value = array[i],
|
533
|
+
computed = iteratee ? iteratee(value, i, array) : value;
|
534
|
+
if (isSorted) {
|
535
|
+
if (!i || seen !== computed) result.push(value);
|
536
|
+
seen = computed;
|
537
|
+
} else if (iteratee) {
|
538
|
+
if (!_.contains(seen, computed)) {
|
539
|
+
seen.push(computed);
|
540
|
+
result.push(value);
|
541
|
+
}
|
542
|
+
} else if (!_.contains(result, value)) {
|
543
|
+
result.push(value);
|
489
544
|
}
|
490
|
-
}
|
491
|
-
return
|
545
|
+
}
|
546
|
+
return result;
|
492
547
|
};
|
493
548
|
|
494
549
|
// Produce an array that contains the union: each distinct element from all of
|
495
550
|
// the passed-in arrays.
|
496
551
|
_.union = function() {
|
497
|
-
return _.uniq(
|
552
|
+
return _.uniq(flatten(arguments, true, true));
|
498
553
|
};
|
499
554
|
|
500
555
|
// Produce an array that contains every item shared between all the
|
501
556
|
// passed-in arrays.
|
502
557
|
_.intersection = function(array) {
|
503
|
-
var
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
558
|
+
var result = [];
|
559
|
+
var argsLength = arguments.length;
|
560
|
+
for (var i = 0, length = getLength(array); i < length; i++) {
|
561
|
+
var item = array[i];
|
562
|
+
if (_.contains(result, item)) continue;
|
563
|
+
for (var j = 1; j < argsLength; j++) {
|
564
|
+
if (!_.contains(arguments[j], item)) break;
|
565
|
+
}
|
566
|
+
if (j === argsLength) result.push(item);
|
567
|
+
}
|
568
|
+
return result;
|
509
569
|
};
|
510
570
|
|
511
571
|
// Take the difference between one array and a number of other arrays.
|
512
572
|
// Only the elements present in just the first array will remain.
|
513
573
|
_.difference = function(array) {
|
514
|
-
var rest =
|
515
|
-
return _.filter(array, function(value){
|
574
|
+
var rest = flatten(arguments, true, true, 1);
|
575
|
+
return _.filter(array, function(value){
|
576
|
+
return !_.contains(rest, value);
|
577
|
+
});
|
516
578
|
};
|
517
579
|
|
518
580
|
// Zip together multiple lists into a single array -- elements that share
|
519
581
|
// an index go together.
|
520
582
|
_.zip = function() {
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
583
|
+
return _.unzip(arguments);
|
584
|
+
};
|
585
|
+
|
586
|
+
// Complement of _.zip. Unzip accepts an array of arrays and groups
|
587
|
+
// each array's elements on shared indices
|
588
|
+
_.unzip = function(array) {
|
589
|
+
var length = array && _.max(array, getLength).length || 0;
|
590
|
+
var result = Array(length);
|
591
|
+
|
592
|
+
for (var index = 0; index < length; index++) {
|
593
|
+
result[index] = _.pluck(array, index);
|
525
594
|
}
|
526
|
-
return
|
595
|
+
return result;
|
527
596
|
};
|
528
597
|
|
529
598
|
// Converts lists into objects. Pass either a single array of `[key, value]`
|
530
599
|
// pairs, or two parallel arrays of the same length -- one of keys, and one of
|
531
600
|
// the corresponding values.
|
532
601
|
_.object = function(list, values) {
|
533
|
-
if (list == null) return {};
|
534
602
|
var result = {};
|
535
|
-
for (var i = 0, length = list
|
603
|
+
for (var i = 0, length = getLength(list); i < length; i++) {
|
536
604
|
if (values) {
|
537
605
|
result[list[i]] = values[i];
|
538
606
|
} else {
|
@@ -542,57 +610,83 @@
|
|
542
610
|
return result;
|
543
611
|
};
|
544
612
|
|
545
|
-
//
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
var i = 0, length = array.length;
|
554
|
-
if (isSorted) {
|
555
|
-
if (typeof isSorted == 'number') {
|
556
|
-
i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
|
557
|
-
} else {
|
558
|
-
i = _.sortedIndex(array, item);
|
559
|
-
return array[i] === item ? i : -1;
|
613
|
+
// Generator function to create the findIndex and findLastIndex functions
|
614
|
+
function createPredicateIndexFinder(dir) {
|
615
|
+
return function(array, predicate, context) {
|
616
|
+
predicate = cb(predicate, context);
|
617
|
+
var length = getLength(array);
|
618
|
+
var index = dir > 0 ? 0 : length - 1;
|
619
|
+
for (; index >= 0 && index < length; index += dir) {
|
620
|
+
if (predicate(array[index], index, array)) return index;
|
560
621
|
}
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
622
|
+
return -1;
|
623
|
+
};
|
624
|
+
}
|
625
|
+
|
626
|
+
// Returns the first index on an array-like that passes a predicate test
|
627
|
+
_.findIndex = createPredicateIndexFinder(1);
|
628
|
+
_.findLastIndex = createPredicateIndexFinder(-1);
|
566
629
|
|
567
|
-
//
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
630
|
+
// Use a comparator function to figure out the smallest index at which
|
631
|
+
// an object should be inserted so as to maintain order. Uses binary search.
|
632
|
+
_.sortedIndex = function(array, obj, iteratee, context) {
|
633
|
+
iteratee = cb(iteratee, context, 1);
|
634
|
+
var value = iteratee(obj);
|
635
|
+
var low = 0, high = getLength(array);
|
636
|
+
while (low < high) {
|
637
|
+
var mid = Math.floor((low + high) / 2);
|
638
|
+
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
|
573
639
|
}
|
574
|
-
|
575
|
-
while (i--) if (array[i] === item) return i;
|
576
|
-
return -1;
|
640
|
+
return low;
|
577
641
|
};
|
578
642
|
|
643
|
+
// Generator function to create the indexOf and lastIndexOf functions
|
644
|
+
function createIndexFinder(dir, predicateFind, sortedIndex) {
|
645
|
+
return function(array, item, idx) {
|
646
|
+
var i = 0, length = getLength(array);
|
647
|
+
if (typeof idx == 'number') {
|
648
|
+
if (dir > 0) {
|
649
|
+
i = idx >= 0 ? idx : Math.max(idx + length, i);
|
650
|
+
} else {
|
651
|
+
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
|
652
|
+
}
|
653
|
+
} else if (sortedIndex && idx && length) {
|
654
|
+
idx = sortedIndex(array, item);
|
655
|
+
return array[idx] === item ? idx : -1;
|
656
|
+
}
|
657
|
+
if (item !== item) {
|
658
|
+
idx = predicateFind(slice.call(array, i, length), _.isNaN);
|
659
|
+
return idx >= 0 ? idx + i : -1;
|
660
|
+
}
|
661
|
+
for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
|
662
|
+
if (array[idx] === item) return idx;
|
663
|
+
}
|
664
|
+
return -1;
|
665
|
+
};
|
666
|
+
}
|
667
|
+
|
668
|
+
// Return the position of the first occurrence of an item in an array,
|
669
|
+
// or -1 if the item is not included in the array.
|
670
|
+
// If the array is large and already in sort order, pass `true`
|
671
|
+
// for **isSorted** to use binary search.
|
672
|
+
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
|
673
|
+
_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
|
674
|
+
|
579
675
|
// Generate an integer Array containing an arithmetic progression. A port of
|
580
676
|
// the native Python `range()` function. See
|
581
677
|
// [the Python documentation](http://docs.python.org/library/functions.html#range).
|
582
678
|
_.range = function(start, stop, step) {
|
583
|
-
if (
|
679
|
+
if (stop == null) {
|
584
680
|
stop = start || 0;
|
585
681
|
start = 0;
|
586
682
|
}
|
587
|
-
step =
|
683
|
+
step = step || 1;
|
588
684
|
|
589
685
|
var length = Math.max(Math.ceil((stop - start) / step), 0);
|
590
|
-
var
|
591
|
-
var range = new Array(length);
|
686
|
+
var range = Array(length);
|
592
687
|
|
593
|
-
|
594
|
-
range[idx
|
595
|
-
start += step;
|
688
|
+
for (var idx = 0; idx < length; idx++, start += step) {
|
689
|
+
range[idx] = start;
|
596
690
|
}
|
597
691
|
|
598
692
|
return range;
|
@@ -601,26 +695,27 @@
|
|
601
695
|
// Function (ahem) Functions
|
602
696
|
// ------------------
|
603
697
|
|
604
|
-
//
|
605
|
-
|
698
|
+
// Determines whether to execute a function as a constructor
|
699
|
+
// or a normal function with the provided arguments
|
700
|
+
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
|
701
|
+
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
|
702
|
+
var self = baseCreate(sourceFunc.prototype);
|
703
|
+
var result = sourceFunc.apply(self, args);
|
704
|
+
if (_.isObject(result)) return result;
|
705
|
+
return self;
|
706
|
+
};
|
606
707
|
|
607
708
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
608
709
|
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
609
710
|
// available.
|
610
711
|
_.bind = function(func, context) {
|
611
|
-
var args, bound;
|
612
712
|
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
613
|
-
if (!_.isFunction(func)) throw new TypeError;
|
614
|
-
args = slice.call(arguments, 2);
|
615
|
-
|
616
|
-
|
617
|
-
ctor.prototype = func.prototype;
|
618
|
-
var self = new ctor;
|
619
|
-
ctor.prototype = null;
|
620
|
-
var result = func.apply(self, args.concat(slice.call(arguments)));
|
621
|
-
if (Object(result) === result) return result;
|
622
|
-
return self;
|
713
|
+
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
|
714
|
+
var args = slice.call(arguments, 2);
|
715
|
+
var bound = function() {
|
716
|
+
return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
|
623
717
|
};
|
718
|
+
return bound;
|
624
719
|
};
|
625
720
|
|
626
721
|
// Partially apply a function by creating a version that has had some of its
|
@@ -628,49 +723,55 @@
|
|
628
723
|
// as a placeholder, allowing any combination of arguments to be pre-filled.
|
629
724
|
_.partial = function(func) {
|
630
725
|
var boundArgs = slice.call(arguments, 1);
|
631
|
-
|
632
|
-
var position = 0;
|
633
|
-
var args =
|
634
|
-
for (var i = 0
|
635
|
-
|
726
|
+
var bound = function() {
|
727
|
+
var position = 0, length = boundArgs.length;
|
728
|
+
var args = Array(length);
|
729
|
+
for (var i = 0; i < length; i++) {
|
730
|
+
args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
|
636
731
|
}
|
637
732
|
while (position < arguments.length) args.push(arguments[position++]);
|
638
|
-
return func
|
733
|
+
return executeBound(func, bound, this, this, args);
|
639
734
|
};
|
735
|
+
return bound;
|
640
736
|
};
|
641
737
|
|
642
738
|
// Bind a number of an object's methods to that object. Remaining arguments
|
643
739
|
// are the method names to be bound. Useful for ensuring that all callbacks
|
644
740
|
// defined on an object belong to it.
|
645
741
|
_.bindAll = function(obj) {
|
646
|
-
var
|
647
|
-
if (
|
648
|
-
|
742
|
+
var i, length = arguments.length, key;
|
743
|
+
if (length <= 1) throw new Error('bindAll must be passed function names');
|
744
|
+
for (i = 1; i < length; i++) {
|
745
|
+
key = arguments[i];
|
746
|
+
obj[key] = _.bind(obj[key], obj);
|
747
|
+
}
|
649
748
|
return obj;
|
650
749
|
};
|
651
750
|
|
652
751
|
// Memoize an expensive function by storing its results.
|
653
752
|
_.memoize = function(func, hasher) {
|
654
|
-
var
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
return
|
753
|
+
var memoize = function(key) {
|
754
|
+
var cache = memoize.cache;
|
755
|
+
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
|
756
|
+
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
|
757
|
+
return cache[address];
|
659
758
|
};
|
759
|
+
memoize.cache = {};
|
760
|
+
return memoize;
|
660
761
|
};
|
661
762
|
|
662
763
|
// Delays a function for the given number of milliseconds, and then calls
|
663
764
|
// it with the arguments supplied.
|
664
765
|
_.delay = function(func, wait) {
|
665
766
|
var args = slice.call(arguments, 2);
|
666
|
-
return setTimeout(function(){
|
767
|
+
return setTimeout(function(){
|
768
|
+
return func.apply(null, args);
|
769
|
+
}, wait);
|
667
770
|
};
|
668
771
|
|
669
772
|
// Defers a function, scheduling it to run after the current call stack has
|
670
773
|
// cleared.
|
671
|
-
_.defer =
|
672
|
-
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
673
|
-
};
|
774
|
+
_.defer = _.partial(_.delay, _, 1);
|
674
775
|
|
675
776
|
// Returns a function, that, when invoked, will only be triggered at most once
|
676
777
|
// during a given window of time. Normally, the throttled function will run
|
@@ -681,12 +782,12 @@
|
|
681
782
|
var context, args, result;
|
682
783
|
var timeout = null;
|
683
784
|
var previous = 0;
|
684
|
-
|
785
|
+
if (!options) options = {};
|
685
786
|
var later = function() {
|
686
787
|
previous = options.leading === false ? 0 : _.now();
|
687
788
|
timeout = null;
|
688
789
|
result = func.apply(context, args);
|
689
|
-
context = args = null;
|
790
|
+
if (!timeout) context = args = null;
|
690
791
|
};
|
691
792
|
return function() {
|
692
793
|
var now = _.now();
|
@@ -694,12 +795,14 @@
|
|
694
795
|
var remaining = wait - (now - previous);
|
695
796
|
context = this;
|
696
797
|
args = arguments;
|
697
|
-
if (remaining <= 0) {
|
698
|
-
|
699
|
-
|
798
|
+
if (remaining <= 0 || remaining > wait) {
|
799
|
+
if (timeout) {
|
800
|
+
clearTimeout(timeout);
|
801
|
+
timeout = null;
|
802
|
+
}
|
700
803
|
previous = now;
|
701
804
|
result = func.apply(context, args);
|
702
|
-
context = args = null;
|
805
|
+
if (!timeout) context = args = null;
|
703
806
|
} else if (!timeout && options.trailing !== false) {
|
704
807
|
timeout = setTimeout(later, remaining);
|
705
808
|
}
|
@@ -716,13 +819,14 @@
|
|
716
819
|
|
717
820
|
var later = function() {
|
718
821
|
var last = _.now() - timestamp;
|
719
|
-
|
822
|
+
|
823
|
+
if (last < wait && last >= 0) {
|
720
824
|
timeout = setTimeout(later, wait - last);
|
721
825
|
} else {
|
722
826
|
timeout = null;
|
723
827
|
if (!immediate) {
|
724
828
|
result = func.apply(context, args);
|
725
|
-
context = args = null;
|
829
|
+
if (!timeout) context = args = null;
|
726
830
|
}
|
727
831
|
}
|
728
832
|
};
|
@@ -732,9 +836,7 @@
|
|
732
836
|
args = arguments;
|
733
837
|
timestamp = _.now();
|
734
838
|
var callNow = immediate && !timeout;
|
735
|
-
if (!timeout)
|
736
|
-
timeout = setTimeout(later, wait);
|
737
|
-
}
|
839
|
+
if (!timeout) timeout = setTimeout(later, wait);
|
738
840
|
if (callNow) {
|
739
841
|
result = func.apply(context, args);
|
740
842
|
context = args = null;
|
@@ -744,19 +846,6 @@
|
|
744
846
|
};
|
745
847
|
};
|
746
848
|
|
747
|
-
// Returns a function that will be executed at most one time, no matter how
|
748
|
-
// often you call it. Useful for lazy initialization.
|
749
|
-
_.once = function(func) {
|
750
|
-
var ran = false, memo;
|
751
|
-
return function() {
|
752
|
-
if (ran) return memo;
|
753
|
-
ran = true;
|
754
|
-
memo = func.apply(this, arguments);
|
755
|
-
func = null;
|
756
|
-
return memo;
|
757
|
-
};
|
758
|
-
};
|
759
|
-
|
760
849
|
// Returns the first function passed as an argument to the second,
|
761
850
|
// allowing you to adjust arguments, run code before and after, and
|
762
851
|
// conditionally execute the original function.
|
@@ -764,20 +853,27 @@
|
|
764
853
|
return _.partial(wrapper, func);
|
765
854
|
};
|
766
855
|
|
856
|
+
// Returns a negated version of the passed-in predicate.
|
857
|
+
_.negate = function(predicate) {
|
858
|
+
return function() {
|
859
|
+
return !predicate.apply(this, arguments);
|
860
|
+
};
|
861
|
+
};
|
862
|
+
|
767
863
|
// Returns a function that is the composition of a list of functions, each
|
768
864
|
// consuming the return value of the function that follows.
|
769
865
|
_.compose = function() {
|
770
|
-
var
|
866
|
+
var args = arguments;
|
867
|
+
var start = args.length - 1;
|
771
868
|
return function() {
|
772
|
-
var
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
return args[0];
|
869
|
+
var i = start;
|
870
|
+
var result = args[start].apply(this, arguments);
|
871
|
+
while (i--) result = args[i].call(this, result);
|
872
|
+
return result;
|
777
873
|
};
|
778
874
|
};
|
779
875
|
|
780
|
-
// Returns a function that will only be executed after
|
876
|
+
// Returns a function that will only be executed on and after the Nth call.
|
781
877
|
_.after = function(times, func) {
|
782
878
|
return function() {
|
783
879
|
if (--times < 1) {
|
@@ -786,16 +882,66 @@
|
|
786
882
|
};
|
787
883
|
};
|
788
884
|
|
885
|
+
// Returns a function that will only be executed up to (but not including) the Nth call.
|
886
|
+
_.before = function(times, func) {
|
887
|
+
var memo;
|
888
|
+
return function() {
|
889
|
+
if (--times > 0) {
|
890
|
+
memo = func.apply(this, arguments);
|
891
|
+
}
|
892
|
+
if (times <= 1) func = null;
|
893
|
+
return memo;
|
894
|
+
};
|
895
|
+
};
|
896
|
+
|
897
|
+
// Returns a function that will be executed at most one time, no matter how
|
898
|
+
// often you call it. Useful for lazy initialization.
|
899
|
+
_.once = _.partial(_.before, 2);
|
900
|
+
|
789
901
|
// Object Functions
|
790
902
|
// ----------------
|
791
903
|
|
792
|
-
//
|
904
|
+
// Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
|
905
|
+
var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
|
906
|
+
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
|
907
|
+
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
|
908
|
+
|
909
|
+
function collectNonEnumProps(obj, keys) {
|
910
|
+
var nonEnumIdx = nonEnumerableProps.length;
|
911
|
+
var constructor = obj.constructor;
|
912
|
+
var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
|
913
|
+
|
914
|
+
// Constructor is a special case.
|
915
|
+
var prop = 'constructor';
|
916
|
+
if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
|
917
|
+
|
918
|
+
while (nonEnumIdx--) {
|
919
|
+
prop = nonEnumerableProps[nonEnumIdx];
|
920
|
+
if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
|
921
|
+
keys.push(prop);
|
922
|
+
}
|
923
|
+
}
|
924
|
+
}
|
925
|
+
|
926
|
+
// Retrieve the names of an object's own properties.
|
793
927
|
// Delegates to **ECMAScript 5**'s native `Object.keys`
|
794
928
|
_.keys = function(obj) {
|
795
929
|
if (!_.isObject(obj)) return [];
|
796
930
|
if (nativeKeys) return nativeKeys(obj);
|
797
931
|
var keys = [];
|
798
932
|
for (var key in obj) if (_.has(obj, key)) keys.push(key);
|
933
|
+
// Ahem, IE < 9.
|
934
|
+
if (hasEnumBug) collectNonEnumProps(obj, keys);
|
935
|
+
return keys;
|
936
|
+
};
|
937
|
+
|
938
|
+
// Retrieve all the property names of an object.
|
939
|
+
_.allKeys = function(obj) {
|
940
|
+
if (!_.isObject(obj)) return [];
|
941
|
+
var keys = [];
|
942
|
+
for (var key in obj) keys.push(key);
|
943
|
+
// Ahem, IE < 9.
|
944
|
+
if (hasEnumBug) collectNonEnumProps(obj, keys);
|
799
945
|
return keys;
|
800
946
|
};
|
801
947
|
|
@@ -803,18 +949,33 @@
|
|
803
949
|
_.values = function(obj) {
|
804
950
|
var keys = _.keys(obj);
|
805
951
|
var length = keys.length;
|
806
|
-
var values =
|
952
|
+
var values = Array(length);
|
807
953
|
for (var i = 0; i < length; i++) {
|
808
954
|
values[i] = obj[keys[i]];
|
809
955
|
}
|
810
956
|
return values;
|
811
957
|
};
|
812
958
|
|
959
|
+
// Returns the results of applying the iteratee to each element of the object
|
960
|
+
// In contrast to _.map it returns an object
|
961
|
+
_.mapObject = function(obj, iteratee, context) {
|
962
|
+
iteratee = cb(iteratee, context);
|
963
|
+
var keys = _.keys(obj),
|
964
|
+
length = keys.length,
|
965
|
+
results = {},
|
966
|
+
currentKey;
|
967
|
+
for (var index = 0; index < length; index++) {
|
968
|
+
currentKey = keys[index];
|
969
|
+
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
|
970
|
+
}
|
971
|
+
return results;
|
972
|
+
};
|
973
|
+
|
813
974
|
// Convert an object into a list of `[key, value]` pairs.
|
814
975
|
_.pairs = function(obj) {
|
815
976
|
var keys = _.keys(obj);
|
816
977
|
var length = keys.length;
|
817
|
-
var pairs =
|
978
|
+
var pairs = Array(length);
|
818
979
|
for (var i = 0; i < length; i++) {
|
819
980
|
pairs[i] = [keys[i], obj[keys[i]]];
|
820
981
|
}
|
@@ -842,47 +1003,65 @@
|
|
842
1003
|
};
|
843
1004
|
|
844
1005
|
// Extend a given object with all the properties in passed-in object(s).
|
845
|
-
_.extend =
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
1006
|
+
_.extend = createAssigner(_.allKeys);
|
1007
|
+
|
1008
|
+
// Assigns a given object with all the own properties in the passed-in object(s)
|
1009
|
+
// (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
|
1010
|
+
_.extendOwn = _.assign = createAssigner(_.keys);
|
1011
|
+
|
1012
|
+
// Returns the first key on an object that passes a predicate test
|
1013
|
+
_.findKey = function(obj, predicate, context) {
|
1014
|
+
predicate = cb(predicate, context);
|
1015
|
+
var keys = _.keys(obj), key;
|
1016
|
+
for (var i = 0, length = keys.length; i < length; i++) {
|
1017
|
+
key = keys[i];
|
1018
|
+
if (predicate(obj[key], key, obj)) return key;
|
1019
|
+
}
|
854
1020
|
};
|
855
1021
|
|
856
1022
|
// Return a copy of the object only containing the whitelisted properties.
|
857
|
-
_.pick = function(
|
858
|
-
var
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
1023
|
+
_.pick = function(object, oiteratee, context) {
|
1024
|
+
var result = {}, obj = object, iteratee, keys;
|
1025
|
+
if (obj == null) return result;
|
1026
|
+
if (_.isFunction(oiteratee)) {
|
1027
|
+
keys = _.allKeys(obj);
|
1028
|
+
iteratee = optimizeCb(oiteratee, context);
|
1029
|
+
} else {
|
1030
|
+
keys = flatten(arguments, false, false, 1);
|
1031
|
+
iteratee = function(value, key, obj) { return key in obj; };
|
1032
|
+
obj = Object(obj);
|
1033
|
+
}
|
1034
|
+
for (var i = 0, length = keys.length; i < length; i++) {
|
1035
|
+
var key = keys[i];
|
1036
|
+
var value = obj[key];
|
1037
|
+
if (iteratee(value, key, obj)) result[key] = value;
|
1038
|
+
}
|
1039
|
+
return result;
|
864
1040
|
};
|
865
1041
|
|
866
1042
|
// Return a copy of the object without the blacklisted properties.
|
867
|
-
_.omit = function(obj) {
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
1043
|
+
_.omit = function(obj, iteratee, context) {
|
1044
|
+
if (_.isFunction(iteratee)) {
|
1045
|
+
iteratee = _.negate(iteratee);
|
1046
|
+
} else {
|
1047
|
+
var keys = _.map(flatten(arguments, false, false, 1), String);
|
1048
|
+
iteratee = function(value, key) {
|
1049
|
+
return !_.contains(keys, key);
|
1050
|
+
};
|
872
1051
|
}
|
873
|
-
return
|
1052
|
+
return _.pick(obj, iteratee, context);
|
874
1053
|
};
|
875
1054
|
|
876
1055
|
// Fill in a given object with default properties.
|
877
|
-
_.defaults =
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
return
|
1056
|
+
_.defaults = createAssigner(_.allKeys, true);
|
1057
|
+
|
1058
|
+
// Creates an object that inherits from the given prototype object.
|
1059
|
+
// If additional properties are provided then they will be added to the
|
1060
|
+
// created object.
|
1061
|
+
_.create = function(prototype, props) {
|
1062
|
+
var result = baseCreate(prototype);
|
1063
|
+
if (props) _.extendOwn(result, props);
|
1064
|
+
return result;
|
886
1065
|
};
|
887
1066
|
|
888
1067
|
// Create a (shallow-cloned) duplicate of an object.
|
@@ -899,11 +1078,24 @@
|
|
899
1078
|
return obj;
|
900
1079
|
};
|
901
1080
|
|
1081
|
+
// Returns whether an object has a given set of `key:value` pairs.
|
1082
|
+
_.isMatch = function(object, attrs) {
|
1083
|
+
var keys = _.keys(attrs), length = keys.length;
|
1084
|
+
if (object == null) return !length;
|
1085
|
+
var obj = Object(object);
|
1086
|
+
for (var i = 0; i < length; i++) {
|
1087
|
+
var key = keys[i];
|
1088
|
+
if (attrs[key] !== obj[key] || !(key in obj)) return false;
|
1089
|
+
}
|
1090
|
+
return true;
|
1091
|
+
};
|
1092
|
+
|
1093
|
+
|
902
1094
|
// Internal recursive comparison function for `isEqual`.
|
903
1095
|
var eq = function(a, b, aStack, bStack) {
|
904
1096
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
905
1097
|
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
906
|
-
if (a === b) return a !== 0 || 1 / a
|
1098
|
+
if (a === b) return a !== 0 || 1 / a === 1 / b;
|
907
1099
|
// A strict comparison is necessary because `null == undefined`.
|
908
1100
|
if (a == null || b == null) return a === b;
|
909
1101
|
// Unwrap any wrapped objects.
|
@@ -911,98 +1103,98 @@
|
|
911
1103
|
if (b instanceof _) b = b._wrapped;
|
912
1104
|
// Compare `[[Class]]` names.
|
913
1105
|
var className = toString.call(a);
|
914
|
-
if (className
|
1106
|
+
if (className !== toString.call(b)) return false;
|
915
1107
|
switch (className) {
|
916
|
-
// Strings, numbers, dates, and booleans are compared by value.
|
1108
|
+
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
|
1109
|
+
case '[object RegExp]':
|
1110
|
+
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
917
1111
|
case '[object String]':
|
918
1112
|
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
919
1113
|
// equivalent to `new String("5")`.
|
920
|
-
return a
|
1114
|
+
return '' + a === '' + b;
|
921
1115
|
case '[object Number]':
|
922
|
-
// `NaN`s are equivalent, but non-reflexive.
|
923
|
-
//
|
924
|
-
|
1116
|
+
// `NaN`s are equivalent, but non-reflexive.
|
1117
|
+
// Object(NaN) is equivalent to NaN
|
1118
|
+
if (+a !== +a) return +b !== +b;
|
1119
|
+
// An `egal` comparison is performed for other numeric values.
|
1120
|
+
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
|
925
1121
|
case '[object Date]':
|
926
1122
|
case '[object Boolean]':
|
927
1123
|
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
928
1124
|
// millisecond representations. Note that invalid dates with millisecond representations
|
929
1125
|
// of `NaN` are not equivalent.
|
930
|
-
return +a
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
1126
|
+
return +a === +b;
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
var areArrays = className === '[object Array]';
|
1130
|
+
if (!areArrays) {
|
1131
|
+
if (typeof a != 'object' || typeof b != 'object') return false;
|
1132
|
+
|
1133
|
+
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
|
1134
|
+
// from different frames are.
|
1135
|
+
var aCtor = a.constructor, bCtor = b.constructor;
|
1136
|
+
if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
|
1137
|
+
_.isFunction(bCtor) && bCtor instanceof bCtor)
|
1138
|
+
&& ('constructor' in a && 'constructor' in b)) {
|
1139
|
+
return false;
|
1140
|
+
}
|
937
1141
|
}
|
938
|
-
if (typeof a != 'object' || typeof b != 'object') return false;
|
939
1142
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
940
1143
|
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
1144
|
+
|
1145
|
+
// Initializing stack of traversed objects.
|
1146
|
+
// It's done here since we only need them for objects and arrays comparison.
|
1147
|
+
aStack = aStack || [];
|
1148
|
+
bStack = bStack || [];
|
941
1149
|
var length = aStack.length;
|
942
1150
|
while (length--) {
|
943
1151
|
// Linear search. Performance is inversely proportional to the number of
|
944
1152
|
// unique nested structures.
|
945
|
-
if (aStack[length]
|
946
|
-
}
|
947
|
-
// Objects with different constructors are not equivalent, but `Object`s
|
948
|
-
// from different frames are.
|
949
|
-
var aCtor = a.constructor, bCtor = b.constructor;
|
950
|
-
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
951
|
-
_.isFunction(bCtor) && (bCtor instanceof bCtor))
|
952
|
-
&& ('constructor' in a && 'constructor' in b)) {
|
953
|
-
return false;
|
1153
|
+
if (aStack[length] === a) return bStack[length] === b;
|
954
1154
|
}
|
1155
|
+
|
955
1156
|
// Add the first object to the stack of traversed objects.
|
956
1157
|
aStack.push(a);
|
957
1158
|
bStack.push(b);
|
958
|
-
|
1159
|
+
|
959
1160
|
// Recursively compare objects and arrays.
|
960
|
-
if (
|
1161
|
+
if (areArrays) {
|
961
1162
|
// Compare array lengths to determine if a deep comparison is necessary.
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
968
|
-
}
|
1163
|
+
length = a.length;
|
1164
|
+
if (length !== b.length) return false;
|
1165
|
+
// Deep compare the contents, ignoring non-numeric properties.
|
1166
|
+
while (length--) {
|
1167
|
+
if (!eq(a[length], b[length], aStack, bStack)) return false;
|
969
1168
|
}
|
970
1169
|
} else {
|
971
1170
|
// Deep compare objects.
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
// Ensure that both objects contain the same number of properties.
|
981
|
-
if (result) {
|
982
|
-
for (key in b) {
|
983
|
-
if (_.has(b, key) && !(size--)) break;
|
984
|
-
}
|
985
|
-
result = !size;
|
1171
|
+
var keys = _.keys(a), key;
|
1172
|
+
length = keys.length;
|
1173
|
+
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
1174
|
+
if (_.keys(b).length !== length) return false;
|
1175
|
+
while (length--) {
|
1176
|
+
// Deep compare each member
|
1177
|
+
key = keys[length];
|
1178
|
+
if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
|
986
1179
|
}
|
987
1180
|
}
|
988
1181
|
// Remove the first object from the stack of traversed objects.
|
989
1182
|
aStack.pop();
|
990
1183
|
bStack.pop();
|
991
|
-
return
|
1184
|
+
return true;
|
992
1185
|
};
|
993
1186
|
|
994
1187
|
// Perform a deep comparison to check if two objects are equal.
|
995
1188
|
_.isEqual = function(a, b) {
|
996
|
-
return eq(a, b
|
1189
|
+
return eq(a, b);
|
997
1190
|
};
|
998
1191
|
|
999
1192
|
// Is a given array, string, or object empty?
|
1000
1193
|
// An "empty" object has no enumerable own-properties.
|
1001
1194
|
_.isEmpty = function(obj) {
|
1002
1195
|
if (obj == null) return true;
|
1003
|
-
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
1004
|
-
|
1005
|
-
return true;
|
1196
|
+
if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
|
1197
|
+
return _.keys(obj).length === 0;
|
1006
1198
|
};
|
1007
1199
|
|
1008
1200
|
// Is a given value a DOM element?
|
@@ -1013,33 +1205,35 @@
|
|
1013
1205
|
// Is a given value an array?
|
1014
1206
|
// Delegates to ECMA5's native Array.isArray
|
1015
1207
|
_.isArray = nativeIsArray || function(obj) {
|
1016
|
-
return toString.call(obj)
|
1208
|
+
return toString.call(obj) === '[object Array]';
|
1017
1209
|
};
|
1018
1210
|
|
1019
1211
|
// Is a given variable an object?
|
1020
1212
|
_.isObject = function(obj) {
|
1021
|
-
|
1213
|
+
var type = typeof obj;
|
1214
|
+
return type === 'function' || type === 'object' && !!obj;
|
1022
1215
|
};
|
1023
1216
|
|
1024
|
-
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
1025
|
-
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
1217
|
+
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
|
1218
|
+
_.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
|
1026
1219
|
_['is' + name] = function(obj) {
|
1027
|
-
return toString.call(obj)
|
1220
|
+
return toString.call(obj) === '[object ' + name + ']';
|
1028
1221
|
};
|
1029
1222
|
});
|
1030
1223
|
|
1031
|
-
// Define a fallback version of the method in browsers (ahem, IE), where
|
1224
|
+
// Define a fallback version of the method in browsers (ahem, IE < 9), where
|
1032
1225
|
// there isn't any inspectable "Arguments" type.
|
1033
1226
|
if (!_.isArguments(arguments)) {
|
1034
1227
|
_.isArguments = function(obj) {
|
1035
|
-
return
|
1228
|
+
return _.has(obj, 'callee');
|
1036
1229
|
};
|
1037
1230
|
}
|
1038
1231
|
|
1039
|
-
// Optimize `isFunction` if appropriate.
|
1040
|
-
|
1232
|
+
// Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
|
1233
|
+
// IE 11 (#1621), and in Safari 8 (#1929).
|
1234
|
+
if (typeof /./ != 'function' && typeof Int8Array != 'object') {
|
1041
1235
|
_.isFunction = function(obj) {
|
1042
|
-
return typeof obj
|
1236
|
+
return typeof obj == 'function' || false;
|
1043
1237
|
};
|
1044
1238
|
}
|
1045
1239
|
|
@@ -1050,12 +1244,12 @@
|
|
1050
1244
|
|
1051
1245
|
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
1052
1246
|
_.isNaN = function(obj) {
|
1053
|
-
return _.isNumber(obj) && obj
|
1247
|
+
return _.isNumber(obj) && obj !== +obj;
|
1054
1248
|
};
|
1055
1249
|
|
1056
1250
|
// Is a given value a boolean?
|
1057
1251
|
_.isBoolean = function(obj) {
|
1058
|
-
return obj === true || obj === false || toString.call(obj)
|
1252
|
+
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
|
1059
1253
|
};
|
1060
1254
|
|
1061
1255
|
// Is a given value equal to null?
|
@@ -1071,7 +1265,7 @@
|
|
1071
1265
|
// Shortcut function for checking if an object has a given property directly
|
1072
1266
|
// on itself (in other words, not on a prototype).
|
1073
1267
|
_.has = function(obj, key) {
|
1074
|
-
return hasOwnProperty.call(obj, key);
|
1268
|
+
return obj != null && hasOwnProperty.call(obj, key);
|
1075
1269
|
};
|
1076
1270
|
|
1077
1271
|
// Utility Functions
|
@@ -1084,39 +1278,43 @@
|
|
1084
1278
|
return this;
|
1085
1279
|
};
|
1086
1280
|
|
1087
|
-
// Keep the identity function around for default
|
1281
|
+
// Keep the identity function around for default iteratees.
|
1088
1282
|
_.identity = function(value) {
|
1089
1283
|
return value;
|
1090
1284
|
};
|
1091
1285
|
|
1286
|
+
// Predicate-generating functions. Often useful outside of Underscore.
|
1092
1287
|
_.constant = function(value) {
|
1093
|
-
return function
|
1288
|
+
return function() {
|
1094
1289
|
return value;
|
1095
1290
|
};
|
1096
1291
|
};
|
1097
1292
|
|
1098
|
-
_.
|
1099
|
-
|
1293
|
+
_.noop = function(){};
|
1294
|
+
|
1295
|
+
_.property = property;
|
1296
|
+
|
1297
|
+
// Generates a function for a given object that returns a given property.
|
1298
|
+
_.propertyOf = function(obj) {
|
1299
|
+
return obj == null ? function(){} : function(key) {
|
1100
1300
|
return obj[key];
|
1101
1301
|
};
|
1102
1302
|
};
|
1103
1303
|
|
1104
|
-
// Returns a predicate for checking whether an object has a given set of
|
1105
|
-
|
1304
|
+
// Returns a predicate for checking whether an object has a given set of
|
1305
|
+
// `key:value` pairs.
|
1306
|
+
_.matcher = _.matches = function(attrs) {
|
1307
|
+
attrs = _.extendOwn({}, attrs);
|
1106
1308
|
return function(obj) {
|
1107
|
-
|
1108
|
-
|
1109
|
-
if (attrs[key] !== obj[key])
|
1110
|
-
return false;
|
1111
|
-
}
|
1112
|
-
return true;
|
1113
|
-
}
|
1309
|
+
return _.isMatch(obj, attrs);
|
1310
|
+
};
|
1114
1311
|
};
|
1115
1312
|
|
1116
1313
|
// Run a function **n** times.
|
1117
|
-
_.times = function(n,
|
1314
|
+
_.times = function(n, iteratee, context) {
|
1118
1315
|
var accum = Array(Math.max(0, n));
|
1119
|
-
|
1316
|
+
iteratee = optimizeCb(iteratee, context, 1);
|
1317
|
+
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
|
1120
1318
|
return accum;
|
1121
1319
|
};
|
1122
1320
|
|
@@ -1130,56 +1328,48 @@
|
|
1130
1328
|
};
|
1131
1329
|
|
1132
1330
|
// A (possibly faster) way to get the current timestamp as an integer.
|
1133
|
-
_.now = Date.now || function() {
|
1134
|
-
|
1135
|
-
// List of HTML entities for escaping.
|
1136
|
-
var entityMap = {
|
1137
|
-
escape: {
|
1138
|
-
'&': '&',
|
1139
|
-
'<': '<',
|
1140
|
-
'>': '>',
|
1141
|
-
'"': '"',
|
1142
|
-
"'": '''
|
1143
|
-
}
|
1331
|
+
_.now = Date.now || function() {
|
1332
|
+
return new Date().getTime();
|
1144
1333
|
};
|
1145
|
-
entityMap.unescape = _.invert(entityMap.escape);
|
1146
1334
|
|
1147
|
-
|
1148
|
-
var
|
1149
|
-
|
1150
|
-
|
1335
|
+
// List of HTML entities for escaping.
|
1336
|
+
var escapeMap = {
|
1337
|
+
'&': '&',
|
1338
|
+
'<': '<',
|
1339
|
+
'>': '>',
|
1340
|
+
'"': '"',
|
1341
|
+
"'": ''',
|
1342
|
+
'`': '`'
|
1151
1343
|
};
|
1344
|
+
var unescapeMap = _.invert(escapeMap);
|
1152
1345
|
|
1153
1346
|
// Functions for escaping and unescaping strings to/from HTML interpolation.
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
return ('' + string).replace(entityRegexes[method], function(match) {
|
1158
|
-
return entityMap[method][match];
|
1159
|
-
});
|
1347
|
+
var createEscaper = function(map) {
|
1348
|
+
var escaper = function(match) {
|
1349
|
+
return map[match];
|
1160
1350
|
};
|
1161
|
-
|
1351
|
+
// Regexes for identifying a key that needs to be escaped
|
1352
|
+
var source = '(?:' + _.keys(map).join('|') + ')';
|
1353
|
+
var testRegexp = RegExp(source);
|
1354
|
+
var replaceRegexp = RegExp(source, 'g');
|
1355
|
+
return function(string) {
|
1356
|
+
string = string == null ? '' : '' + string;
|
1357
|
+
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
|
1358
|
+
};
|
1359
|
+
};
|
1360
|
+
_.escape = createEscaper(escapeMap);
|
1361
|
+
_.unescape = createEscaper(unescapeMap);
|
1162
1362
|
|
1163
1363
|
// If the value of the named `property` is a function then invoke it with the
|
1164
1364
|
// `object` as context; otherwise, return it.
|
1165
|
-
_.result = function(object, property) {
|
1166
|
-
|
1167
|
-
|
1365
|
+
_.result = function(object, property, fallback) {
|
1366
|
+
var value = object == null ? void 0 : object[property];
|
1367
|
+
if (value === void 0) {
|
1368
|
+
value = fallback;
|
1369
|
+
}
|
1168
1370
|
return _.isFunction(value) ? value.call(object) : value;
|
1169
1371
|
};
|
1170
1372
|
|
1171
|
-
// Add your own custom functions to the Underscore object.
|
1172
|
-
_.mixin = function(obj) {
|
1173
|
-
each(_.functions(obj), function(name) {
|
1174
|
-
var func = _[name] = obj[name];
|
1175
|
-
_.prototype[name] = function() {
|
1176
|
-
var args = [this._wrapped];
|
1177
|
-
push.apply(args, arguments);
|
1178
|
-
return result.call(this, func.apply(_, args));
|
1179
|
-
};
|
1180
|
-
});
|
1181
|
-
};
|
1182
|
-
|
1183
1373
|
// Generate a unique integer id (unique within the entire client session).
|
1184
1374
|
// Useful for temporary DOM ids.
|
1185
1375
|
var idCounter = 0;
|
@@ -1208,22 +1398,26 @@
|
|
1208
1398
|
'\\': '\\',
|
1209
1399
|
'\r': 'r',
|
1210
1400
|
'\n': 'n',
|
1211
|
-
'\t': 't',
|
1212
1401
|
'\u2028': 'u2028',
|
1213
1402
|
'\u2029': 'u2029'
|
1214
1403
|
};
|
1215
1404
|
|
1216
|
-
var escaper = /\\|'|\r|\n|\
|
1405
|
+
var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
|
1406
|
+
|
1407
|
+
var escapeChar = function(match) {
|
1408
|
+
return '\\' + escapes[match];
|
1409
|
+
};
|
1217
1410
|
|
1218
1411
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
1219
1412
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
1220
1413
|
// and correctly escapes quotes within interpolated code.
|
1221
|
-
|
1222
|
-
|
1414
|
+
// NB: `oldSettings` only exists for backwards compatibility.
|
1415
|
+
_.template = function(text, settings, oldSettings) {
|
1416
|
+
if (!settings && oldSettings) settings = oldSettings;
|
1223
1417
|
settings = _.defaults({}, settings, _.templateSettings);
|
1224
1418
|
|
1225
1419
|
// Combine delimiters into one regular expression via alternation.
|
1226
|
-
var matcher =
|
1420
|
+
var matcher = RegExp([
|
1227
1421
|
(settings.escape || noMatch).source,
|
1228
1422
|
(settings.interpolate || noMatch).source,
|
1229
1423
|
(settings.evaluate || noMatch).source
|
@@ -1233,19 +1427,18 @@
|
|
1233
1427
|
var index = 0;
|
1234
1428
|
var source = "__p+='";
|
1235
1429
|
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
1236
|
-
source += text.slice(index, offset)
|
1237
|
-
|
1430
|
+
source += text.slice(index, offset).replace(escaper, escapeChar);
|
1431
|
+
index = offset + match.length;
|
1238
1432
|
|
1239
1433
|
if (escape) {
|
1240
1434
|
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
1241
|
-
}
|
1242
|
-
if (interpolate) {
|
1435
|
+
} else if (interpolate) {
|
1243
1436
|
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
1244
|
-
}
|
1245
|
-
if (evaluate) {
|
1437
|
+
} else if (evaluate) {
|
1246
1438
|
source += "';\n" + evaluate + "\n__p+='";
|
1247
1439
|
}
|
1248
|
-
|
1440
|
+
|
1441
|
+
// Adobe VMs need the match returned to produce the correct offest.
|
1249
1442
|
return match;
|
1250
1443
|
});
|
1251
1444
|
source += "';\n";
|
@@ -1255,29 +1448,31 @@
|
|
1255
1448
|
|
1256
1449
|
source = "var __t,__p='',__j=Array.prototype.join," +
|
1257
1450
|
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
1258
|
-
source +
|
1451
|
+
source + 'return __p;\n';
|
1259
1452
|
|
1260
1453
|
try {
|
1261
|
-
render = new Function(settings.variable || 'obj', '_', source);
|
1454
|
+
var render = new Function(settings.variable || 'obj', '_', source);
|
1262
1455
|
} catch (e) {
|
1263
1456
|
e.source = source;
|
1264
1457
|
throw e;
|
1265
1458
|
}
|
1266
1459
|
|
1267
|
-
if (data) return render(data, _);
|
1268
1460
|
var template = function(data) {
|
1269
1461
|
return render.call(this, data, _);
|
1270
1462
|
};
|
1271
1463
|
|
1272
|
-
// Provide the compiled
|
1273
|
-
|
1464
|
+
// Provide the compiled source as a convenience for precompilation.
|
1465
|
+
var argument = settings.variable || 'obj';
|
1466
|
+
template.source = 'function(' + argument + '){\n' + source + '}';
|
1274
1467
|
|
1275
1468
|
return template;
|
1276
1469
|
};
|
1277
1470
|
|
1278
|
-
// Add a "chain" function
|
1471
|
+
// Add a "chain" function. Start chaining a wrapped Underscore object.
|
1279
1472
|
_.chain = function(obj) {
|
1280
|
-
|
1473
|
+
var instance = _(obj);
|
1474
|
+
instance._chain = true;
|
1475
|
+
return instance;
|
1281
1476
|
};
|
1282
1477
|
|
1283
1478
|
// OOP
|
@@ -1287,46 +1482,56 @@
|
|
1287
1482
|
// underscore functions. Wrapped objects may be chained.
|
1288
1483
|
|
1289
1484
|
// Helper function to continue chaining intermediate results.
|
1290
|
-
var result = function(obj) {
|
1291
|
-
return
|
1485
|
+
var result = function(instance, obj) {
|
1486
|
+
return instance._chain ? _(obj).chain() : obj;
|
1487
|
+
};
|
1488
|
+
|
1489
|
+
// Add your own custom functions to the Underscore object.
|
1490
|
+
_.mixin = function(obj) {
|
1491
|
+
_.each(_.functions(obj), function(name) {
|
1492
|
+
var func = _[name] = obj[name];
|
1493
|
+
_.prototype[name] = function() {
|
1494
|
+
var args = [this._wrapped];
|
1495
|
+
push.apply(args, arguments);
|
1496
|
+
return result(this, func.apply(_, args));
|
1497
|
+
};
|
1498
|
+
});
|
1292
1499
|
};
|
1293
1500
|
|
1294
1501
|
// Add all of the Underscore functions to the wrapper object.
|
1295
1502
|
_.mixin(_);
|
1296
1503
|
|
1297
1504
|
// Add all mutator Array functions to the wrapper.
|
1298
|
-
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
1505
|
+
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
1299
1506
|
var method = ArrayProto[name];
|
1300
1507
|
_.prototype[name] = function() {
|
1301
1508
|
var obj = this._wrapped;
|
1302
1509
|
method.apply(obj, arguments);
|
1303
|
-
if ((name
|
1304
|
-
return result
|
1510
|
+
if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
|
1511
|
+
return result(this, obj);
|
1305
1512
|
};
|
1306
1513
|
});
|
1307
1514
|
|
1308
1515
|
// Add all accessor Array functions to the wrapper.
|
1309
|
-
each(['concat', 'join', 'slice'], function(name) {
|
1516
|
+
_.each(['concat', 'join', 'slice'], function(name) {
|
1310
1517
|
var method = ArrayProto[name];
|
1311
1518
|
_.prototype[name] = function() {
|
1312
|
-
return result
|
1519
|
+
return result(this, method.apply(this._wrapped, arguments));
|
1313
1520
|
};
|
1314
1521
|
});
|
1315
1522
|
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
this._chain = true;
|
1321
|
-
return this;
|
1322
|
-
},
|
1523
|
+
// Extracts the result from a wrapped and chained object.
|
1524
|
+
_.prototype.value = function() {
|
1525
|
+
return this._wrapped;
|
1526
|
+
};
|
1323
1527
|
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
}
|
1528
|
+
// Provide unwrapping proxy for some methods used in engine operations
|
1529
|
+
// such as arithmetic and JSON stringification.
|
1530
|
+
_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
|
1328
1531
|
|
1329
|
-
|
1532
|
+
_.prototype.toString = function() {
|
1533
|
+
return '' + this._wrapped;
|
1534
|
+
};
|
1330
1535
|
|
1331
1536
|
// AMD registration happens at the end for compatibility with AMD loaders
|
1332
1537
|
// that may not enforce next-turn semantics on modules. Even though general
|
@@ -1340,4 +1545,4 @@
|
|
1340
1545
|
return _;
|
1341
1546
|
});
|
1342
1547
|
}
|
1343
|
-
}
|
1548
|
+
}.call(this));
|