backbonejs-rails 0.0.7 → 1.0.0
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 +8 -8
- data/backbonejs-rails.gemspec +3 -4
- data/lib/backbonejs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/backbone.js +1003 -722
- data/vendor/assets/javascripts/underscore.js +532 -274
- metadata +5 -24
- data/vendor/assets/javascripts/backbone.min.js +0 -37
- data/vendor/assets/javascripts/icanhaz.min.js +0 -11
- data/vendor/assets/javascripts/underscore.min.js +0 -31
@@ -1,10 +1,8 @@
|
|
1
|
-
// Underscore.js 1.
|
2
|
-
//
|
3
|
-
//
|
4
|
-
//
|
5
|
-
//
|
6
|
-
// For all details and documentation:
|
7
|
-
// http://documentcloud.github.com/underscore
|
1
|
+
// Underscore.js 1.5.0
|
2
|
+
// http://underscorejs.org
|
3
|
+
// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc.
|
4
|
+
// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
5
|
+
// Underscore may be freely distributed under the MIT license.
|
8
6
|
|
9
7
|
(function() {
|
10
8
|
|
@@ -24,10 +22,12 @@
|
|
24
22
|
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
25
23
|
|
26
24
|
// Create quick reference variables for speed access to core prototypes.
|
27
|
-
var
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
var
|
26
|
+
push = ArrayProto.push,
|
27
|
+
slice = ArrayProto.slice,
|
28
|
+
concat = ArrayProto.concat,
|
29
|
+
toString = ObjProto.toString,
|
30
|
+
hasOwnProperty = ObjProto.hasOwnProperty;
|
31
31
|
|
32
32
|
// All **ECMAScript 5** native function implementations that we hope to use
|
33
33
|
// are declared here.
|
@@ -46,7 +46,11 @@
|
|
46
46
|
nativeBind = FuncProto.bind;
|
47
47
|
|
48
48
|
// Create a safe reference to the Underscore object for use below.
|
49
|
-
var _ = function(obj) {
|
49
|
+
var _ = function(obj) {
|
50
|
+
if (obj instanceof _) return obj;
|
51
|
+
if (!(this instanceof _)) return new _(obj);
|
52
|
+
this._wrapped = obj;
|
53
|
+
};
|
50
54
|
|
51
55
|
// Export the Underscore object for **Node.js**, with
|
52
56
|
// backwards-compatibility for the old `require()` API. If we're in
|
@@ -58,11 +62,11 @@
|
|
58
62
|
}
|
59
63
|
exports._ = _;
|
60
64
|
} else {
|
61
|
-
root
|
65
|
+
root._ = _;
|
62
66
|
}
|
63
67
|
|
64
68
|
// Current version.
|
65
|
-
_.VERSION = '1.
|
69
|
+
_.VERSION = '1.5.0';
|
66
70
|
|
67
71
|
// Collection Functions
|
68
72
|
// --------------------
|
@@ -76,7 +80,7 @@
|
|
76
80
|
obj.forEach(iterator, context);
|
77
81
|
} else if (obj.length === +obj.length) {
|
78
82
|
for (var i = 0, l = obj.length; i < l; i++) {
|
79
|
-
if (
|
83
|
+
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
80
84
|
}
|
81
85
|
} else {
|
82
86
|
for (var key in obj) {
|
@@ -94,12 +98,13 @@
|
|
94
98
|
if (obj == null) return results;
|
95
99
|
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
96
100
|
each(obj, function(value, index, list) {
|
97
|
-
results
|
101
|
+
results.push(iterator.call(context, value, index, list));
|
98
102
|
});
|
99
|
-
if (obj.length === +obj.length) results.length = obj.length;
|
100
103
|
return results;
|
101
104
|
};
|
102
105
|
|
106
|
+
var reduceError = 'Reduce of empty array with no initial value';
|
107
|
+
|
103
108
|
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
104
109
|
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
105
110
|
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
@@ -117,7 +122,7 @@
|
|
117
122
|
memo = iterator.call(context, memo, value, index, list);
|
118
123
|
}
|
119
124
|
});
|
120
|
-
if (!initial) throw new TypeError(
|
125
|
+
if (!initial) throw new TypeError(reduceError);
|
121
126
|
return memo;
|
122
127
|
};
|
123
128
|
|
@@ -130,9 +135,22 @@
|
|
130
135
|
if (context) iterator = _.bind(iterator, context);
|
131
136
|
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
132
137
|
}
|
133
|
-
var
|
134
|
-
if (
|
135
|
-
|
138
|
+
var length = obj.length;
|
139
|
+
if (length !== +length) {
|
140
|
+
var keys = _.keys(obj);
|
141
|
+
length = keys.length;
|
142
|
+
}
|
143
|
+
each(obj, function(value, index, list) {
|
144
|
+
index = keys ? keys[--length] : --length;
|
145
|
+
if (!initial) {
|
146
|
+
memo = obj[index];
|
147
|
+
initial = true;
|
148
|
+
} else {
|
149
|
+
memo = iterator.call(context, memo, obj[index], index, list);
|
150
|
+
}
|
151
|
+
});
|
152
|
+
if (!initial) throw new TypeError(reduceError);
|
153
|
+
return memo;
|
136
154
|
};
|
137
155
|
|
138
156
|
// Return the first value which passes a truth test. Aliased as `detect`.
|
@@ -155,32 +173,30 @@
|
|
155
173
|
if (obj == null) return results;
|
156
174
|
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
157
175
|
each(obj, function(value, index, list) {
|
158
|
-
if (iterator.call(context, value, index, list)) results
|
176
|
+
if (iterator.call(context, value, index, list)) results.push(value);
|
159
177
|
});
|
160
178
|
return results;
|
161
179
|
};
|
162
180
|
|
163
181
|
// Return all the elements for which a truth test fails.
|
164
182
|
_.reject = function(obj, iterator, context) {
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
if (!iterator.call(context, value, index, list)) results[results.length] = value;
|
169
|
-
});
|
170
|
-
return results;
|
183
|
+
return _.filter(obj, function(value, index, list) {
|
184
|
+
return !iterator.call(context, value, index, list);
|
185
|
+
}, context);
|
171
186
|
};
|
172
187
|
|
173
188
|
// Determine whether all of the elements match a truth test.
|
174
189
|
// Delegates to **ECMAScript 5**'s native `every` if available.
|
175
190
|
// Aliased as `all`.
|
176
191
|
_.every = _.all = function(obj, iterator, context) {
|
192
|
+
iterator || (iterator = _.identity);
|
177
193
|
var result = true;
|
178
194
|
if (obj == null) return result;
|
179
195
|
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
180
196
|
each(obj, function(value, index, list) {
|
181
197
|
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
182
198
|
});
|
183
|
-
return result;
|
199
|
+
return !!result;
|
184
200
|
};
|
185
201
|
|
186
202
|
// Determine if at least one element in the object matches a truth test.
|
@@ -197,23 +213,22 @@
|
|
197
213
|
return !!result;
|
198
214
|
};
|
199
215
|
|
200
|
-
// Determine if
|
201
|
-
// Aliased as `
|
202
|
-
_.
|
203
|
-
|
204
|
-
if (obj == null) return found;
|
216
|
+
// Determine if the array or object contains a given value (using `===`).
|
217
|
+
// Aliased as `include`.
|
218
|
+
_.contains = _.include = function(obj, target) {
|
219
|
+
if (obj == null) return false;
|
205
220
|
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
206
|
-
|
221
|
+
return any(obj, function(value) {
|
207
222
|
return value === target;
|
208
223
|
});
|
209
|
-
return found;
|
210
224
|
};
|
211
225
|
|
212
226
|
// Invoke a method (with arguments) on every item in a collection.
|
213
227
|
_.invoke = function(obj, method) {
|
214
228
|
var args = slice.call(arguments, 2);
|
229
|
+
var isFunc = _.isFunction(method);
|
215
230
|
return _.map(obj, function(value) {
|
216
|
-
return (
|
231
|
+
return (isFunc ? method : value[method]).apply(value, args);
|
217
232
|
});
|
218
233
|
};
|
219
234
|
|
@@ -222,23 +237,47 @@
|
|
222
237
|
return _.map(obj, function(value){ return value[key]; });
|
223
238
|
};
|
224
239
|
|
240
|
+
// Convenience version of a common use case of `filter`: selecting only objects
|
241
|
+
// containing specific `key:value` pairs.
|
242
|
+
_.where = function(obj, attrs, first) {
|
243
|
+
if (_.isEmpty(attrs)) return first ? void 0 : [];
|
244
|
+
return _[first ? 'find' : 'filter'](obj, function(value) {
|
245
|
+
for (var key in attrs) {
|
246
|
+
if (attrs[key] !== value[key]) return false;
|
247
|
+
}
|
248
|
+
return true;
|
249
|
+
});
|
250
|
+
};
|
251
|
+
|
252
|
+
// Convenience version of a common use case of `find`: getting the first object
|
253
|
+
// containing specific `key:value` pairs.
|
254
|
+
_.findWhere = function(obj, attrs) {
|
255
|
+
return _.where(obj, attrs, true);
|
256
|
+
};
|
257
|
+
|
225
258
|
// Return the maximum element or (element-based computation).
|
259
|
+
// Can't optimize arrays of integers longer than 65,535 elements.
|
260
|
+
// See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
|
226
261
|
_.max = function(obj, iterator, context) {
|
227
|
-
if (!iterator && _.isArray(obj)
|
262
|
+
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
263
|
+
return Math.max.apply(Math, obj);
|
264
|
+
}
|
228
265
|
if (!iterator && _.isEmpty(obj)) return -Infinity;
|
229
|
-
var result = {computed : -Infinity};
|
266
|
+
var result = {computed : -Infinity, value: -Infinity};
|
230
267
|
each(obj, function(value, index, list) {
|
231
268
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
232
|
-
computed
|
269
|
+
computed > result.computed && (result = {value : value, computed : computed});
|
233
270
|
});
|
234
271
|
return result.value;
|
235
272
|
};
|
236
273
|
|
237
274
|
// Return the minimum element (or element-based computation).
|
238
275
|
_.min = function(obj, iterator, context) {
|
239
|
-
if (!iterator && _.isArray(obj)
|
276
|
+
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
277
|
+
return Math.min.apply(Math, obj);
|
278
|
+
}
|
240
279
|
if (!iterator && _.isEmpty(obj)) return Infinity;
|
241
|
-
var result = {computed : Infinity};
|
280
|
+
var result = {computed : Infinity, value: Infinity};
|
242
281
|
each(obj, function(value, index, list) {
|
243
282
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
244
283
|
computed < result.computed && (result = {value : value, computed : computed});
|
@@ -248,81 +287,110 @@
|
|
248
287
|
|
249
288
|
// Shuffle an array.
|
250
289
|
_.shuffle = function(obj) {
|
251
|
-
var
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
shuffled[rand] = value;
|
259
|
-
}
|
290
|
+
var rand;
|
291
|
+
var index = 0;
|
292
|
+
var shuffled = [];
|
293
|
+
each(obj, function(value) {
|
294
|
+
rand = _.random(index++);
|
295
|
+
shuffled[index - 1] = shuffled[rand];
|
296
|
+
shuffled[rand] = value;
|
260
297
|
});
|
261
298
|
return shuffled;
|
262
299
|
};
|
263
300
|
|
301
|
+
// An internal function to generate lookup iterators.
|
302
|
+
var lookupIterator = function(value) {
|
303
|
+
return _.isFunction(value) ? value : function(obj){ return obj[value]; };
|
304
|
+
};
|
305
|
+
|
264
306
|
// Sort the object's values by a criterion produced by an iterator.
|
265
|
-
_.sortBy = function(obj,
|
307
|
+
_.sortBy = function(obj, value, context) {
|
308
|
+
var iterator = lookupIterator(value);
|
266
309
|
return _.pluck(_.map(obj, function(value, index, list) {
|
267
310
|
return {
|
268
311
|
value : value,
|
312
|
+
index : index,
|
269
313
|
criteria : iterator.call(context, value, index, list)
|
270
314
|
};
|
271
315
|
}).sort(function(left, right) {
|
272
|
-
var a = left.criteria
|
273
|
-
|
316
|
+
var a = left.criteria;
|
317
|
+
var b = right.criteria;
|
318
|
+
if (a !== b) {
|
319
|
+
if (a > b || a === void 0) return 1;
|
320
|
+
if (a < b || b === void 0) return -1;
|
321
|
+
}
|
322
|
+
return left.index < right.index ? -1 : 1;
|
274
323
|
}), 'value');
|
275
324
|
};
|
276
325
|
|
277
|
-
//
|
278
|
-
|
279
|
-
_.groupBy = function(obj, val) {
|
326
|
+
// An internal function used for aggregate "group by" operations.
|
327
|
+
var group = function(obj, value, context, behavior) {
|
280
328
|
var result = {};
|
281
|
-
var iterator =
|
329
|
+
var iterator = lookupIterator(value == null ? _.identity : value);
|
282
330
|
each(obj, function(value, index) {
|
283
|
-
var key = iterator(value, index);
|
284
|
-
(result
|
331
|
+
var key = iterator.call(context, value, index, obj);
|
332
|
+
behavior(result, key, value);
|
285
333
|
});
|
286
334
|
return result;
|
287
335
|
};
|
288
336
|
|
289
|
-
//
|
290
|
-
//
|
291
|
-
_.
|
292
|
-
|
337
|
+
// Groups the object's values by a criterion. Pass either a string attribute
|
338
|
+
// to group by, or a function that returns the criterion.
|
339
|
+
_.groupBy = function(obj, value, context) {
|
340
|
+
return group(obj, value, context, function(result, key, value) {
|
341
|
+
(_.has(result, key) ? result[key] : (result[key] = [])).push(value);
|
342
|
+
});
|
343
|
+
};
|
344
|
+
|
345
|
+
// Counts instances of an object that group by a certain criterion. Pass
|
346
|
+
// either a string attribute to count by, or a function that returns the
|
347
|
+
// criterion.
|
348
|
+
_.countBy = function(obj, value, context) {
|
349
|
+
return group(obj, value, context, function(result, key) {
|
350
|
+
if (!_.has(result, key)) result[key] = 0;
|
351
|
+
result[key]++;
|
352
|
+
});
|
353
|
+
};
|
354
|
+
|
355
|
+
// Use a comparator function to figure out the smallest index at which
|
356
|
+
// an object should be inserted so as to maintain order. Uses binary search.
|
357
|
+
_.sortedIndex = function(array, obj, iterator, context) {
|
358
|
+
iterator = iterator == null ? _.identity : lookupIterator(iterator);
|
359
|
+
var value = iterator.call(context, obj);
|
293
360
|
var low = 0, high = array.length;
|
294
361
|
while (low < high) {
|
295
|
-
var mid = (low + high)
|
296
|
-
iterator(array[mid]) <
|
362
|
+
var mid = (low + high) >>> 1;
|
363
|
+
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
|
297
364
|
}
|
298
365
|
return low;
|
299
366
|
};
|
300
367
|
|
301
|
-
// Safely
|
302
|
-
_.toArray = function(
|
303
|
-
if (!
|
304
|
-
if (
|
305
|
-
if (
|
306
|
-
|
307
|
-
return _.values(iterable);
|
368
|
+
// Safely create a real, live array from anything iterable.
|
369
|
+
_.toArray = function(obj) {
|
370
|
+
if (!obj) return [];
|
371
|
+
if (_.isArray(obj)) return slice.call(obj);
|
372
|
+
if (obj.length === +obj.length) return _.map(obj, _.identity);
|
373
|
+
return _.values(obj);
|
308
374
|
};
|
309
375
|
|
310
376
|
// Return the number of elements in an object.
|
311
377
|
_.size = function(obj) {
|
312
|
-
|
378
|
+
if (obj == null) return 0;
|
379
|
+
return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
|
313
380
|
};
|
314
381
|
|
315
382
|
// Array Functions
|
316
383
|
// ---------------
|
317
384
|
|
318
385
|
// Get the first element of an array. Passing **n** will return the first N
|
319
|
-
// values in the array. Aliased as `head`. The **guard** check
|
320
|
-
// with `_.map`.
|
321
|
-
_.first = _.head = function(array, n, guard) {
|
386
|
+
// values in the array. Aliased as `head` and `take`. The **guard** check
|
387
|
+
// allows it to work with `_.map`.
|
388
|
+
_.first = _.head = _.take = function(array, n, guard) {
|
389
|
+
if (array == null) return void 0;
|
322
390
|
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
|
323
391
|
};
|
324
392
|
|
325
|
-
// Returns everything but the last entry of the array.
|
393
|
+
// Returns everything but the last entry of the array. Especially useful on
|
326
394
|
// the arguments object. Passing **n** will return all the values in
|
327
395
|
// the array, excluding the last N. The **guard** check allows it to work with
|
328
396
|
// `_.map`.
|
@@ -333,6 +401,7 @@
|
|
333
401
|
// Get the last element of an array. Passing **n** will return the last N
|
334
402
|
// values in the array. The **guard** check allows it to work with `_.map`.
|
335
403
|
_.last = function(array, n, guard) {
|
404
|
+
if (array == null) return void 0;
|
336
405
|
if ((n != null) && !guard) {
|
337
406
|
return slice.call(array, Math.max(array.length - n, 0));
|
338
407
|
} else {
|
@@ -340,26 +409,37 @@
|
|
340
409
|
}
|
341
410
|
};
|
342
411
|
|
343
|
-
// Returns everything but the first entry of the array. Aliased as `tail`.
|
344
|
-
// Especially useful on the arguments object. Passing an **
|
345
|
-
// the rest
|
412
|
+
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
413
|
+
// Especially useful on the arguments object. Passing an **n** will return
|
414
|
+
// the rest N values in the array. The **guard**
|
346
415
|
// check allows it to work with `_.map`.
|
347
|
-
_.rest = _.tail = function(array,
|
348
|
-
return slice.call(array, (
|
416
|
+
_.rest = _.tail = _.drop = function(array, n, guard) {
|
417
|
+
return slice.call(array, (n == null) || guard ? 1 : n);
|
349
418
|
};
|
350
419
|
|
351
420
|
// Trim out all falsy values from an array.
|
352
421
|
_.compact = function(array) {
|
353
|
-
return _.filter(array,
|
422
|
+
return _.filter(array, _.identity);
|
423
|
+
};
|
424
|
+
|
425
|
+
// Internal implementation of a recursive `flatten` function.
|
426
|
+
var flatten = function(input, shallow, output) {
|
427
|
+
if (shallow && _.every(input, _.isArray)) {
|
428
|
+
return concat.apply(output, input);
|
429
|
+
}
|
430
|
+
each(input, function(value) {
|
431
|
+
if (_.isArray(value) || _.isArguments(value)) {
|
432
|
+
shallow ? push.apply(output, value) : flatten(value, shallow, output);
|
433
|
+
} else {
|
434
|
+
output.push(value);
|
435
|
+
}
|
436
|
+
});
|
437
|
+
return output;
|
354
438
|
};
|
355
439
|
|
356
440
|
// Return a completely flattened version of an array.
|
357
441
|
_.flatten = function(array, shallow) {
|
358
|
-
return
|
359
|
-
if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
|
360
|
-
memo[memo.length] = value;
|
361
|
-
return memo;
|
362
|
-
}, []);
|
442
|
+
return flatten(array, shallow, []);
|
363
443
|
};
|
364
444
|
|
365
445
|
// Return a version of the array that does not contain the specified value(s).
|
@@ -370,17 +450,22 @@
|
|
370
450
|
// Produce a duplicate-free version of the array. If the array has already
|
371
451
|
// been sorted, you have the option of using a faster algorithm.
|
372
452
|
// Aliased as `unique`.
|
373
|
-
_.uniq = _.unique = function(array, isSorted, iterator) {
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
453
|
+
_.uniq = _.unique = function(array, isSorted, iterator, context) {
|
454
|
+
if (_.isFunction(isSorted)) {
|
455
|
+
context = iterator;
|
456
|
+
iterator = isSorted;
|
457
|
+
isSorted = false;
|
458
|
+
}
|
459
|
+
var initial = iterator ? _.map(array, iterator, context) : array;
|
460
|
+
var results = [];
|
461
|
+
var seen = [];
|
462
|
+
each(initial, function(value, index) {
|
463
|
+
if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
|
464
|
+
seen.push(value);
|
465
|
+
results.push(array[index]);
|
380
466
|
}
|
381
|
-
|
382
|
-
|
383
|
-
return result;
|
467
|
+
});
|
468
|
+
return results;
|
384
469
|
};
|
385
470
|
|
386
471
|
// Produce an array that contains the union: each distinct element from all of
|
@@ -390,8 +475,8 @@
|
|
390
475
|
};
|
391
476
|
|
392
477
|
// Produce an array that contains every item shared between all the
|
393
|
-
// passed-in arrays.
|
394
|
-
_.intersection =
|
478
|
+
// passed-in arrays.
|
479
|
+
_.intersection = function(array) {
|
395
480
|
var rest = slice.call(arguments, 1);
|
396
481
|
return _.filter(_.uniq(array), function(item) {
|
397
482
|
return _.every(rest, function(other) {
|
@@ -403,20 +488,47 @@
|
|
403
488
|
// Take the difference between one array and a number of other arrays.
|
404
489
|
// Only the elements present in just the first array will remain.
|
405
490
|
_.difference = function(array) {
|
406
|
-
var rest =
|
407
|
-
return _.filter(array, function(value){ return !_.
|
491
|
+
var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
|
492
|
+
return _.filter(array, function(value){ return !_.contains(rest, value); });
|
408
493
|
};
|
409
494
|
|
410
495
|
// Zip together multiple lists into a single array -- elements that share
|
411
496
|
// an index go together.
|
412
497
|
_.zip = function() {
|
413
|
-
|
414
|
-
|
498
|
+
return _.unzip.apply(_, slice.call(arguments));
|
499
|
+
};
|
500
|
+
|
501
|
+
// The inverse operation to `_.zip`. If given an array of pairs it
|
502
|
+
// returns an array of the paired elements split into two left and
|
503
|
+
// right element arrays, if given an array of triples it returns a
|
504
|
+
// three element array and so on. For example, `_.unzip` given
|
505
|
+
// `[['a',1],['b',2],['c',3]]` returns the array
|
506
|
+
// [['a','b','c'],[1,2,3]].
|
507
|
+
_.unzip = function() {
|
508
|
+
var length = _.max(_.pluck(arguments, "length").concat(0));
|
415
509
|
var results = new Array(length);
|
416
|
-
for (var i = 0; i < length; i++)
|
510
|
+
for (var i = 0; i < length; i++) {
|
511
|
+
results[i] = _.pluck(arguments, '' + i);
|
512
|
+
}
|
417
513
|
return results;
|
418
514
|
};
|
419
515
|
|
516
|
+
// Converts lists into objects. Pass either a single array of `[key, value]`
|
517
|
+
// pairs, or two parallel arrays of the same length -- one of keys, and one of
|
518
|
+
// the corresponding values.
|
519
|
+
_.object = function(list, values) {
|
520
|
+
if (list == null) return {};
|
521
|
+
var result = {};
|
522
|
+
for (var i = 0, l = list.length; i < l; i++) {
|
523
|
+
if (values) {
|
524
|
+
result[list[i]] = values[i];
|
525
|
+
} else {
|
526
|
+
result[list[i][0]] = list[i][1];
|
527
|
+
}
|
528
|
+
}
|
529
|
+
return result;
|
530
|
+
};
|
531
|
+
|
420
532
|
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
|
421
533
|
// we need this function. Return the position of the first occurrence of an
|
422
534
|
// item in an array, or -1 if the item is not included in the array.
|
@@ -425,22 +537,29 @@
|
|
425
537
|
// for **isSorted** to use binary search.
|
426
538
|
_.indexOf = function(array, item, isSorted) {
|
427
539
|
if (array == null) return -1;
|
428
|
-
var i, l;
|
540
|
+
var i = 0, l = array.length;
|
429
541
|
if (isSorted) {
|
430
|
-
|
431
|
-
|
542
|
+
if (typeof isSorted == 'number') {
|
543
|
+
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
|
544
|
+
} else {
|
545
|
+
i = _.sortedIndex(array, item);
|
546
|
+
return array[i] === item ? i : -1;
|
547
|
+
}
|
432
548
|
}
|
433
|
-
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
434
|
-
for (
|
549
|
+
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
550
|
+
for (; i < l; i++) if (array[i] === item) return i;
|
435
551
|
return -1;
|
436
552
|
};
|
437
553
|
|
438
554
|
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
439
|
-
_.lastIndexOf = function(array, item) {
|
555
|
+
_.lastIndexOf = function(array, item, from) {
|
440
556
|
if (array == null) return -1;
|
441
|
-
|
442
|
-
|
443
|
-
|
557
|
+
var hasIndex = from != null;
|
558
|
+
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
|
559
|
+
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
|
560
|
+
}
|
561
|
+
var i = (hasIndex ? from : array.length);
|
562
|
+
while (i--) if (array[i] === item) return i;
|
444
563
|
return -1;
|
445
564
|
};
|
446
565
|
|
@@ -473,29 +592,38 @@
|
|
473
592
|
var ctor = function(){};
|
474
593
|
|
475
594
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
476
|
-
// optionally).
|
477
|
-
//
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
595
|
+
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
596
|
+
// available.
|
597
|
+
_.bind = function(func, context) {
|
598
|
+
var args, bound;
|
599
|
+
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
482
600
|
if (!_.isFunction(func)) throw new TypeError;
|
483
601
|
args = slice.call(arguments, 2);
|
484
602
|
return bound = function() {
|
485
603
|
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
486
604
|
ctor.prototype = func.prototype;
|
487
605
|
var self = new ctor;
|
606
|
+
ctor.prototype = null;
|
488
607
|
var result = func.apply(self, args.concat(slice.call(arguments)));
|
489
608
|
if (Object(result) === result) return result;
|
490
609
|
return self;
|
491
610
|
};
|
492
611
|
};
|
493
612
|
|
613
|
+
// Partially apply a function by creating a version that has had some of its
|
614
|
+
// arguments pre-filled, without changing its dynamic `this` context.
|
615
|
+
_.partial = function(func) {
|
616
|
+
var args = slice.call(arguments, 1);
|
617
|
+
return function() {
|
618
|
+
return func.apply(this, args.concat(slice.call(arguments)));
|
619
|
+
};
|
620
|
+
};
|
621
|
+
|
494
622
|
// Bind all of an object's methods to that object. Useful for ensuring that
|
495
623
|
// all callbacks defined on an object belong to it.
|
496
624
|
_.bindAll = function(obj) {
|
497
625
|
var funcs = slice.call(arguments, 1);
|
498
|
-
if (funcs.length
|
626
|
+
if (funcs.length === 0) throw new Error("bindAll must be passed function names");
|
499
627
|
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
500
628
|
return obj;
|
501
629
|
};
|
@@ -514,7 +642,7 @@
|
|
514
642
|
// it with the arguments supplied.
|
515
643
|
_.delay = function(func, wait) {
|
516
644
|
var args = slice.call(arguments, 2);
|
517
|
-
return setTimeout(function(){ return func.apply(
|
645
|
+
return setTimeout(function(){ return func.apply(null, args); }, wait);
|
518
646
|
};
|
519
647
|
|
520
648
|
// Defers a function, scheduling it to run after the current call stack has
|
@@ -524,41 +652,56 @@
|
|
524
652
|
};
|
525
653
|
|
526
654
|
// Returns a function, that, when invoked, will only be triggered at most once
|
527
|
-
// during a given window of time.
|
528
|
-
|
529
|
-
|
530
|
-
|
655
|
+
// during a given window of time. Normally, the throttled function will run
|
656
|
+
// as much as it can, without ever going more than once per `wait` duration;
|
657
|
+
// but if you'd like to disable the execution on the leading edge, pass
|
658
|
+
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
659
|
+
_.throttle = function(func, wait, options) {
|
660
|
+
var context, args, result;
|
661
|
+
var timeout = null;
|
662
|
+
var previous = 0;
|
663
|
+
options || (options = {});
|
664
|
+
var later = function() {
|
665
|
+
previous = new Date;
|
666
|
+
timeout = null;
|
667
|
+
result = func.apply(context, args);
|
668
|
+
};
|
531
669
|
return function() {
|
532
|
-
|
533
|
-
|
670
|
+
var now = new Date;
|
671
|
+
if (!previous && options.leading === false) previous = now;
|
672
|
+
var remaining = wait - (now - previous);
|
673
|
+
context = this;
|
674
|
+
args = arguments;
|
675
|
+
if (remaining <= 0) {
|
676
|
+
clearTimeout(timeout);
|
534
677
|
timeout = null;
|
535
|
-
|
536
|
-
|
537
|
-
}
|
538
|
-
|
539
|
-
if (throttling) {
|
540
|
-
more = true;
|
541
|
-
} else {
|
542
|
-
func.apply(context, args);
|
678
|
+
previous = now;
|
679
|
+
result = func.apply(context, args);
|
680
|
+
} else if (!timeout && options.trailing !== false) {
|
681
|
+
timeout = setTimeout(later, remaining);
|
543
682
|
}
|
544
|
-
|
545
|
-
throttling = true;
|
683
|
+
return result;
|
546
684
|
};
|
547
685
|
};
|
548
686
|
|
549
687
|
// Returns a function, that, as long as it continues to be invoked, will not
|
550
688
|
// be triggered. The function will be called after it stops being called for
|
551
|
-
// N milliseconds.
|
552
|
-
|
553
|
-
|
689
|
+
// N milliseconds. If `immediate` is passed, trigger the function on the
|
690
|
+
// leading edge, instead of the trailing.
|
691
|
+
_.debounce = function(func, wait, immediate) {
|
692
|
+
var result;
|
693
|
+
var timeout = null;
|
554
694
|
return function() {
|
555
695
|
var context = this, args = arguments;
|
556
696
|
var later = function() {
|
557
697
|
timeout = null;
|
558
|
-
func.apply(context, args);
|
698
|
+
if (!immediate) result = func.apply(context, args);
|
559
699
|
};
|
700
|
+
var callNow = immediate && !timeout;
|
560
701
|
clearTimeout(timeout);
|
561
702
|
timeout = setTimeout(later, wait);
|
703
|
+
if (callNow) result = func.apply(context, args);
|
704
|
+
return result;
|
562
705
|
};
|
563
706
|
};
|
564
707
|
|
@@ -569,7 +712,9 @@
|
|
569
712
|
return function() {
|
570
713
|
if (ran) return memo;
|
571
714
|
ran = true;
|
572
|
-
|
715
|
+
memo = func.apply(this, arguments);
|
716
|
+
func = null;
|
717
|
+
return memo;
|
573
718
|
};
|
574
719
|
};
|
575
720
|
|
@@ -578,7 +723,8 @@
|
|
578
723
|
// conditionally execute the original function.
|
579
724
|
_.wrap = function(func, wrapper) {
|
580
725
|
return function() {
|
581
|
-
var args = [func]
|
726
|
+
var args = [func];
|
727
|
+
push.apply(args, arguments);
|
582
728
|
return wrapper.apply(this, args);
|
583
729
|
};
|
584
730
|
};
|
@@ -598,9 +744,10 @@
|
|
598
744
|
|
599
745
|
// Returns a function that will only be executed after being called N times.
|
600
746
|
_.after = function(times, func) {
|
601
|
-
if (times <= 0) return func();
|
602
747
|
return function() {
|
603
|
-
if (--times < 1) {
|
748
|
+
if (--times < 1) {
|
749
|
+
return func.apply(this, arguments);
|
750
|
+
}
|
604
751
|
};
|
605
752
|
};
|
606
753
|
|
@@ -612,13 +759,29 @@
|
|
612
759
|
_.keys = nativeKeys || function(obj) {
|
613
760
|
if (obj !== Object(obj)) throw new TypeError('Invalid object');
|
614
761
|
var keys = [];
|
615
|
-
for (var key in obj) if (_.has(obj, key)) keys
|
762
|
+
for (var key in obj) if (_.has(obj, key)) keys.push(key);
|
616
763
|
return keys;
|
617
764
|
};
|
618
765
|
|
619
766
|
// Retrieve the values of an object's properties.
|
620
767
|
_.values = function(obj) {
|
621
|
-
|
768
|
+
var values = [];
|
769
|
+
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
|
770
|
+
return values;
|
771
|
+
};
|
772
|
+
|
773
|
+
// Convert an object into a list of `[key, value]` pairs.
|
774
|
+
_.pairs = function(obj) {
|
775
|
+
var pairs = [];
|
776
|
+
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
|
777
|
+
return pairs;
|
778
|
+
};
|
779
|
+
|
780
|
+
// Invert the keys and values of an object. The values must be serializable.
|
781
|
+
_.invert = function(obj) {
|
782
|
+
var result = {};
|
783
|
+
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
|
784
|
+
return result;
|
622
785
|
};
|
623
786
|
|
624
787
|
// Return a sorted list of the function names available on the object.
|
@@ -634,18 +797,42 @@
|
|
634
797
|
// Extend a given object with all the properties in passed-in object(s).
|
635
798
|
_.extend = function(obj) {
|
636
799
|
each(slice.call(arguments, 1), function(source) {
|
637
|
-
|
638
|
-
|
800
|
+
if (source) {
|
801
|
+
for (var prop in source) {
|
802
|
+
obj[prop] = source[prop];
|
803
|
+
}
|
639
804
|
}
|
640
805
|
});
|
641
806
|
return obj;
|
642
807
|
};
|
643
808
|
|
809
|
+
// Return a copy of the object only containing the whitelisted properties.
|
810
|
+
_.pick = function(obj) {
|
811
|
+
var copy = {};
|
812
|
+
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
813
|
+
each(keys, function(key) {
|
814
|
+
if (key in obj) copy[key] = obj[key];
|
815
|
+
});
|
816
|
+
return copy;
|
817
|
+
};
|
818
|
+
|
819
|
+
// Return a copy of the object without the blacklisted properties.
|
820
|
+
_.omit = function(obj) {
|
821
|
+
var copy = {};
|
822
|
+
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
823
|
+
for (var key in obj) {
|
824
|
+
if (!_.contains(keys, key)) copy[key] = obj[key];
|
825
|
+
}
|
826
|
+
return copy;
|
827
|
+
};
|
828
|
+
|
644
829
|
// Fill in a given object with default properties.
|
645
830
|
_.defaults = function(obj) {
|
646
831
|
each(slice.call(arguments, 1), function(source) {
|
647
|
-
|
648
|
-
|
832
|
+
if (source) {
|
833
|
+
for (var prop in source) {
|
834
|
+
if (obj[prop] === void 0) obj[prop] = source[prop];
|
835
|
+
}
|
649
836
|
}
|
650
837
|
});
|
651
838
|
return obj;
|
@@ -665,19 +852,16 @@
|
|
665
852
|
return obj;
|
666
853
|
};
|
667
854
|
|
668
|
-
// Internal recursive comparison function
|
669
|
-
|
855
|
+
// Internal recursive comparison function for `isEqual`.
|
856
|
+
var eq = function(a, b, aStack, bStack) {
|
670
857
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
671
|
-
// See the Harmony `egal` proposal
|
858
|
+
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
672
859
|
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
673
860
|
// A strict comparison is necessary because `null == undefined`.
|
674
861
|
if (a == null || b == null) return a === b;
|
675
862
|
// Unwrap any wrapped objects.
|
676
|
-
if (a
|
677
|
-
if (b
|
678
|
-
// Invoke a custom `isEqual` method if one is provided.
|
679
|
-
if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
|
680
|
-
if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
|
863
|
+
if (a instanceof _) a = a._wrapped;
|
864
|
+
if (b instanceof _) b = b._wrapped;
|
681
865
|
// Compare `[[Class]]` names.
|
682
866
|
var className = toString.call(a);
|
683
867
|
if (className != toString.call(b)) return false;
|
@@ -707,14 +891,22 @@
|
|
707
891
|
if (typeof a != 'object' || typeof b != 'object') return false;
|
708
892
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
709
893
|
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
710
|
-
var length =
|
894
|
+
var length = aStack.length;
|
711
895
|
while (length--) {
|
712
896
|
// Linear search. Performance is inversely proportional to the number of
|
713
897
|
// unique nested structures.
|
714
|
-
if (
|
898
|
+
if (aStack[length] == a) return bStack[length] == b;
|
899
|
+
}
|
900
|
+
// Objects with different constructors are not equivalent, but `Object`s
|
901
|
+
// from different frames are.
|
902
|
+
var aCtor = a.constructor, bCtor = b.constructor;
|
903
|
+
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
904
|
+
_.isFunction(bCtor) && (bCtor instanceof bCtor))) {
|
905
|
+
return false;
|
715
906
|
}
|
716
907
|
// Add the first object to the stack of traversed objects.
|
717
|
-
|
908
|
+
aStack.push(a);
|
909
|
+
bStack.push(b);
|
718
910
|
var size = 0, result = true;
|
719
911
|
// Recursively compare objects and arrays.
|
720
912
|
if (className == '[object Array]') {
|
@@ -724,20 +916,17 @@
|
|
724
916
|
if (result) {
|
725
917
|
// Deep compare the contents, ignoring non-numeric properties.
|
726
918
|
while (size--) {
|
727
|
-
|
728
|
-
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
|
919
|
+
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
729
920
|
}
|
730
921
|
}
|
731
922
|
} else {
|
732
|
-
// Objects with different constructors are not equivalent.
|
733
|
-
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
|
734
923
|
// Deep compare objects.
|
735
924
|
for (var key in a) {
|
736
925
|
if (_.has(a, key)) {
|
737
926
|
// Count the expected number of properties.
|
738
927
|
size++;
|
739
928
|
// Deep compare each member.
|
740
|
-
if (!(result = _.has(b, key) && eq(a[key], b[key],
|
929
|
+
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
741
930
|
}
|
742
931
|
}
|
743
932
|
// Ensure that both objects contain the same number of properties.
|
@@ -749,18 +938,20 @@
|
|
749
938
|
}
|
750
939
|
}
|
751
940
|
// Remove the first object from the stack of traversed objects.
|
752
|
-
|
941
|
+
aStack.pop();
|
942
|
+
bStack.pop();
|
753
943
|
return result;
|
754
|
-
}
|
944
|
+
};
|
755
945
|
|
756
946
|
// Perform a deep comparison to check if two objects are equal.
|
757
947
|
_.isEqual = function(a, b) {
|
758
|
-
return eq(a, b, []);
|
948
|
+
return eq(a, b, [], []);
|
759
949
|
};
|
760
950
|
|
761
951
|
// Is a given array, string, or object empty?
|
762
952
|
// An "empty" object has no enumerable own-properties.
|
763
953
|
_.isEmpty = function(obj) {
|
954
|
+
if (obj == null) return true;
|
764
955
|
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
765
956
|
for (var key in obj) if (_.has(obj, key)) return false;
|
766
957
|
return true;
|
@@ -768,7 +959,7 @@
|
|
768
959
|
|
769
960
|
// Is a given value a DOM element?
|
770
961
|
_.isElement = function(obj) {
|
771
|
-
return !!(obj && obj.nodeType
|
962
|
+
return !!(obj && obj.nodeType === 1);
|
772
963
|
};
|
773
964
|
|
774
965
|
// Is a given value an array?
|
@@ -782,35 +973,36 @@
|
|
782
973
|
return obj === Object(obj);
|
783
974
|
};
|
784
975
|
|
785
|
-
//
|
786
|
-
|
787
|
-
|
788
|
-
|
976
|
+
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
977
|
+
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
978
|
+
_['is' + name] = function(obj) {
|
979
|
+
return toString.call(obj) == '[object ' + name + ']';
|
980
|
+
};
|
981
|
+
});
|
982
|
+
|
983
|
+
// Define a fallback version of the method in browsers (ahem, IE), where
|
984
|
+
// there isn't any inspectable "Arguments" type.
|
789
985
|
if (!_.isArguments(arguments)) {
|
790
986
|
_.isArguments = function(obj) {
|
791
987
|
return !!(obj && _.has(obj, 'callee'));
|
792
988
|
};
|
793
989
|
}
|
794
990
|
|
795
|
-
//
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
_.isString = function(obj) {
|
802
|
-
return toString.call(obj) == '[object String]';
|
803
|
-
};
|
991
|
+
// Optimize `isFunction` if appropriate.
|
992
|
+
if (typeof (/./) !== 'function') {
|
993
|
+
_.isFunction = function(obj) {
|
994
|
+
return typeof obj === 'function';
|
995
|
+
};
|
996
|
+
}
|
804
997
|
|
805
|
-
// Is a given
|
806
|
-
_.
|
807
|
-
return
|
998
|
+
// Is a given object a finite number?
|
999
|
+
_.isFinite = function(obj) {
|
1000
|
+
return isFinite(obj) && !isNaN(parseFloat(obj));
|
808
1001
|
};
|
809
1002
|
|
810
|
-
// Is the given value `NaN`?
|
1003
|
+
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
811
1004
|
_.isNaN = function(obj) {
|
812
|
-
|
813
|
-
return obj !== obj;
|
1005
|
+
return _.isNumber(obj) && obj != +obj;
|
814
1006
|
};
|
815
1007
|
|
816
1008
|
// Is a given value a boolean?
|
@@ -818,16 +1010,6 @@
|
|
818
1010
|
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
|
819
1011
|
};
|
820
1012
|
|
821
|
-
// Is a given value a date?
|
822
|
-
_.isDate = function(obj) {
|
823
|
-
return toString.call(obj) == '[object Date]';
|
824
|
-
};
|
825
|
-
|
826
|
-
// Is the given value a regular expression?
|
827
|
-
_.isRegExp = function(obj) {
|
828
|
-
return toString.call(obj) == '[object RegExp]';
|
829
|
-
};
|
830
|
-
|
831
1013
|
// Is a given value equal to null?
|
832
1014
|
_.isNull = function(obj) {
|
833
1015
|
return obj === null;
|
@@ -838,7 +1020,8 @@
|
|
838
1020
|
return obj === void 0;
|
839
1021
|
};
|
840
1022
|
|
841
|
-
//
|
1023
|
+
// Shortcut function for checking if an object has a given property directly
|
1024
|
+
// on itself (in other words, not on a prototype).
|
842
1025
|
_.has = function(obj, key) {
|
843
1026
|
return hasOwnProperty.call(obj, key);
|
844
1027
|
};
|
@@ -859,20 +1042,67 @@
|
|
859
1042
|
};
|
860
1043
|
|
861
1044
|
// Run a function **n** times.
|
862
|
-
_.times = function
|
863
|
-
|
1045
|
+
_.times = function(n, iterator, context) {
|
1046
|
+
var accum = Array(Math.max(0, n));
|
1047
|
+
for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
|
1048
|
+
return accum;
|
1049
|
+
};
|
1050
|
+
|
1051
|
+
// Return a random integer between min and max (inclusive).
|
1052
|
+
_.random = function(min, max) {
|
1053
|
+
if (max == null) {
|
1054
|
+
max = min;
|
1055
|
+
min = 0;
|
1056
|
+
}
|
1057
|
+
return min + Math.floor(Math.random() * (max - min + 1));
|
1058
|
+
};
|
1059
|
+
|
1060
|
+
// List of HTML entities for escaping.
|
1061
|
+
var entityMap = {
|
1062
|
+
escape: {
|
1063
|
+
'&': '&',
|
1064
|
+
'<': '<',
|
1065
|
+
'>': '>',
|
1066
|
+
'"': '"',
|
1067
|
+
"'": ''',
|
1068
|
+
'/': '/'
|
1069
|
+
}
|
864
1070
|
};
|
1071
|
+
entityMap.unescape = _.invert(entityMap.escape);
|
1072
|
+
|
1073
|
+
// Regexes containing the keys and values listed immediately above.
|
1074
|
+
var entityRegexes = {
|
1075
|
+
escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
|
1076
|
+
unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
|
1077
|
+
};
|
1078
|
+
|
1079
|
+
// Functions for escaping and unescaping strings to/from HTML interpolation.
|
1080
|
+
_.each(['escape', 'unescape'], function(method) {
|
1081
|
+
_[method] = function(string) {
|
1082
|
+
if (string == null) return '';
|
1083
|
+
return ('' + string).replace(entityRegexes[method], function(match) {
|
1084
|
+
return entityMap[method][match];
|
1085
|
+
});
|
1086
|
+
};
|
1087
|
+
});
|
865
1088
|
|
866
|
-
//
|
867
|
-
|
868
|
-
|
1089
|
+
// If the value of the named `property` is a function then invoke it with the
|
1090
|
+
// `object` as context; otherwise, return it.
|
1091
|
+
_.result = function(object, property) {
|
1092
|
+
if (object == null) return void 0;
|
1093
|
+
var value = object[property];
|
1094
|
+
return _.isFunction(value) ? value.call(object) : value;
|
869
1095
|
};
|
870
1096
|
|
871
|
-
// Add your own custom functions to the Underscore object
|
872
|
-
// they're correctly added to the OOP wrapper as well.
|
1097
|
+
// Add your own custom functions to the Underscore object.
|
873
1098
|
_.mixin = function(obj) {
|
874
1099
|
each(_.functions(obj), function(name){
|
875
|
-
|
1100
|
+
var func = _[name] = obj[name];
|
1101
|
+
_.prototype[name] = function() {
|
1102
|
+
var args = [this._wrapped];
|
1103
|
+
push.apply(args, arguments);
|
1104
|
+
return result.call(this, func.apply(_, args));
|
1105
|
+
};
|
876
1106
|
});
|
877
1107
|
};
|
878
1108
|
|
@@ -880,7 +1110,7 @@
|
|
880
1110
|
// Useful for temporary DOM ids.
|
881
1111
|
var idCounter = 0;
|
882
1112
|
_.uniqueId = function(prefix) {
|
883
|
-
var id = idCounter
|
1113
|
+
var id = ++idCounter + '';
|
884
1114
|
return prefix ? prefix + id : id;
|
885
1115
|
};
|
886
1116
|
|
@@ -895,41 +1125,80 @@
|
|
895
1125
|
// When customizing `templateSettings`, if you don't want to define an
|
896
1126
|
// interpolation, evaluation or escaping regex, we need one that is
|
897
1127
|
// guaranteed not to match.
|
898
|
-
var noMatch =
|
1128
|
+
var noMatch = /(.)^/;
|
899
1129
|
|
900
|
-
//
|
901
|
-
//
|
902
|
-
var
|
903
|
-
|
1130
|
+
// Certain characters need to be escaped so that they can be put into a
|
1131
|
+
// string literal.
|
1132
|
+
var escapes = {
|
1133
|
+
"'": "'",
|
1134
|
+
'\\': '\\',
|
1135
|
+
'\r': 'r',
|
1136
|
+
'\n': 'n',
|
1137
|
+
'\t': 't',
|
1138
|
+
'\u2028': 'u2028',
|
1139
|
+
'\u2029': 'u2029'
|
904
1140
|
};
|
905
1141
|
|
1142
|
+
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
1143
|
+
|
906
1144
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
907
1145
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
908
1146
|
// and correctly escapes quotes within interpolated code.
|
909
|
-
_.template = function(
|
910
|
-
var
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
1147
|
+
_.template = function(text, data, settings) {
|
1148
|
+
var render;
|
1149
|
+
settings = _.defaults({}, settings, _.templateSettings);
|
1150
|
+
|
1151
|
+
// Combine delimiters into one regular expression via alternation.
|
1152
|
+
var matcher = new RegExp([
|
1153
|
+
(settings.escape || noMatch).source,
|
1154
|
+
(settings.interpolate || noMatch).source,
|
1155
|
+
(settings.evaluate || noMatch).source
|
1156
|
+
].join('|') + '|$', 'g');
|
1157
|
+
|
1158
|
+
// Compile the template source, escaping string literals appropriately.
|
1159
|
+
var index = 0;
|
1160
|
+
var source = "__p+='";
|
1161
|
+
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
1162
|
+
source += text.slice(index, offset)
|
1163
|
+
.replace(escaper, function(match) { return '\\' + escapes[match]; });
|
1164
|
+
|
1165
|
+
if (escape) {
|
1166
|
+
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
1167
|
+
}
|
1168
|
+
if (interpolate) {
|
1169
|
+
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
1170
|
+
}
|
1171
|
+
if (evaluate) {
|
1172
|
+
source += "';\n" + evaluate + "\n__p+='";
|
1173
|
+
}
|
1174
|
+
index = offset + match.length;
|
1175
|
+
return match;
|
1176
|
+
});
|
1177
|
+
source += "';\n";
|
1178
|
+
|
1179
|
+
// If a variable is not specified, place data values in local scope.
|
1180
|
+
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
1181
|
+
|
1182
|
+
source = "var __t,__p='',__j=Array.prototype.join," +
|
1183
|
+
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
1184
|
+
source + "return __p;\n";
|
1185
|
+
|
1186
|
+
try {
|
1187
|
+
render = new Function(settings.variable || 'obj', '_', source);
|
1188
|
+
} catch (e) {
|
1189
|
+
e.source = source;
|
1190
|
+
throw e;
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
if (data) return render(data, _);
|
1194
|
+
var template = function(data) {
|
1195
|
+
return render.call(this, data, _);
|
932
1196
|
};
|
1197
|
+
|
1198
|
+
// Provide the compiled function source as a convenience for precompilation.
|
1199
|
+
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
|
1200
|
+
|
1201
|
+
return template;
|
933
1202
|
};
|
934
1203
|
|
935
1204
|
// Add a "chain" function, which will delegate to the wrapper.
|
@@ -937,29 +1206,15 @@
|
|
937
1206
|
return _(obj).chain();
|
938
1207
|
};
|
939
1208
|
|
940
|
-
//
|
1209
|
+
// OOP
|
941
1210
|
// ---------------
|
942
|
-
|
943
1211
|
// If Underscore is called as a function, it returns a wrapped object that
|
944
1212
|
// can be used OO-style. This wrapper holds altered versions of all the
|
945
1213
|
// underscore functions. Wrapped objects may be chained.
|
946
|
-
var wrapper = function(obj) { this._wrapped = obj; };
|
947
|
-
|
948
|
-
// Expose `wrapper.prototype` as `_.prototype`
|
949
|
-
_.prototype = wrapper.prototype;
|
950
1214
|
|
951
1215
|
// Helper function to continue chaining intermediate results.
|
952
|
-
var result = function(obj
|
953
|
-
return
|
954
|
-
};
|
955
|
-
|
956
|
-
// A method to easily add functions to the OOP wrapper.
|
957
|
-
var addToWrapper = function(name, func) {
|
958
|
-
wrapper.prototype[name] = function() {
|
959
|
-
var args = slice.call(arguments);
|
960
|
-
unshift.call(args, this._wrapped);
|
961
|
-
return result(func.apply(_, args), this._chain);
|
962
|
-
};
|
1216
|
+
var result = function(obj) {
|
1217
|
+
return this._chain ? _(obj).chain() : obj;
|
963
1218
|
};
|
964
1219
|
|
965
1220
|
// Add all of the Underscore functions to the wrapper object.
|
@@ -968,32 +1223,35 @@
|
|
968
1223
|
// Add all mutator Array functions to the wrapper.
|
969
1224
|
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
970
1225
|
var method = ArrayProto[name];
|
971
|
-
|
972
|
-
var
|
973
|
-
method.apply(
|
974
|
-
|
975
|
-
|
976
|
-
return result(wrapped, this._chain);
|
1226
|
+
_.prototype[name] = function() {
|
1227
|
+
var obj = this._wrapped;
|
1228
|
+
method.apply(obj, arguments);
|
1229
|
+
if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
|
1230
|
+
return result.call(this, obj);
|
977
1231
|
};
|
978
1232
|
});
|
979
1233
|
|
980
1234
|
// Add all accessor Array functions to the wrapper.
|
981
1235
|
each(['concat', 'join', 'slice'], function(name) {
|
982
1236
|
var method = ArrayProto[name];
|
983
|
-
|
984
|
-
return result(method.apply(this._wrapped, arguments)
|
1237
|
+
_.prototype[name] = function() {
|
1238
|
+
return result.call(this, method.apply(this._wrapped, arguments));
|
985
1239
|
};
|
986
1240
|
});
|
987
1241
|
|
988
|
-
|
989
|
-
wrapper.prototype.chain = function() {
|
990
|
-
this._chain = true;
|
991
|
-
return this;
|
992
|
-
};
|
1242
|
+
_.extend(_.prototype, {
|
993
1243
|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
1244
|
+
// Start chaining a wrapped Underscore object.
|
1245
|
+
chain: function() {
|
1246
|
+
this._chain = true;
|
1247
|
+
return this;
|
1248
|
+
},
|
1249
|
+
|
1250
|
+
// Extracts the result from a wrapped and chained object.
|
1251
|
+
value: function() {
|
1252
|
+
return this._wrapped;
|
1253
|
+
}
|
1254
|
+
|
1255
|
+
});
|
998
1256
|
|
999
1257
|
}).call(this);
|