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.
@@ -1,10 +1,8 @@
1
- // Underscore.js 1.3.1
2
- // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
- // Underscore is freely distributable under the MIT license.
4
- // Portions of Underscore are inspired or borrowed from Prototype,
5
- // Oliver Steele's Functional, and John Resig's Micro-Templating.
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 slice = ArrayProto.slice,
28
- unshift = ArrayProto.unshift,
29
- toString = ObjProto.toString,
30
- hasOwnProperty = ObjProto.hasOwnProperty;
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) { return new wrapper(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.3.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 (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
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[results.length] = iterator.call(context, value, index, list);
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('Reduce of empty array with no initial value');
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 reversed = _.toArray(obj).reverse();
134
- if (context && !initial) iterator = _.bind(iterator, context);
135
- return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
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[results.length] = value;
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
- var results = [];
166
- if (obj == null) return results;
167
- each(obj, function(value, index, list) {
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 a given value is included in the array or object using `===`.
201
- // Aliased as `contains`.
202
- _.include = _.contains = function(obj, target) {
203
- var found = false;
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
- found = any(obj, function(value) {
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 (_.isFunction(method) ? method || value : value[method]).apply(value, args);
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)) return Math.max.apply(Math, 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 >= result.computed && (result = {value : value, computed : 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)) return Math.min.apply(Math, 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 shuffled = [], rand;
252
- each(obj, function(value, index, list) {
253
- if (index == 0) {
254
- shuffled[0] = value;
255
- } else {
256
- rand = Math.floor(Math.random() * (index + 1));
257
- shuffled[index] = shuffled[rand];
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, iterator, context) {
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, b = right.criteria;
273
- return a < b ? -1 : a > b ? 1 : 0;
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
- // Groups the object's values by a criterion. Pass either a string attribute
278
- // to group by, or a function that returns the criterion.
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 = _.isFunction(val) ? val : function(obj) { return obj[val]; };
329
+ var iterator = lookupIterator(value == null ? _.identity : value);
282
330
  each(obj, function(value, index) {
283
- var key = iterator(value, index);
284
- (result[key] || (result[key] = [])).push(value);
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
- // Use a comparator function to figure out at what index an object should
290
- // be inserted so as to maintain order. Uses binary search.
291
- _.sortedIndex = function(array, obj, iterator) {
292
- iterator || (iterator = _.identity);
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) >> 1;
296
- iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = 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 convert anything iterable into a real, live array.
302
- _.toArray = function(iterable) {
303
- if (!iterable) return [];
304
- if (iterable.toArray) return iterable.toArray();
305
- if (_.isArray(iterable)) return slice.call(iterable);
306
- if (_.isArguments(iterable)) return slice.call(iterable);
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
- return _.toArray(obj).length;
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 allows it to work
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. Especcialy useful on
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 **index** will return
345
- // the rest of the values in the array from that index onward. The **guard**
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, index, guard) {
348
- return slice.call(array, (index == null) || guard ? 1 : index);
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, function(value){ return !!value; });
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 _.reduce(array, function(memo, value) {
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
- var initial = iterator ? _.map(array, iterator) : array;
375
- var result = [];
376
- _.reduce(initial, function(memo, el, i) {
377
- if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
378
- memo[memo.length] = el;
379
- result[result.length] = array[i];
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
- return memo;
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. (Aliased as "intersect" for back-compat.)
394
- _.intersection = _.intersect = function(array) {
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 = _.flatten(slice.call(arguments, 1));
407
- return _.filter(array, function(value){ return !_.include(rest, value); });
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
- var args = slice.call(arguments);
414
- var length = _.max(_.pluck(args, 'length'));
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++) results[i] = _.pluck(args, "" + 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
- i = _.sortedIndex(array, item);
431
- return array[i] === item ? i : -1;
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 (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
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
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
442
- var i = array.length;
443
- while (i--) if (i in array && array[i] === item) return i;
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). Binding with arguments is also known as `curry`.
477
- // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
478
- // We check for `func.bind` first, to fail fast when `func` is undefined.
479
- _.bind = function bind(func, context) {
480
- var bound, args;
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 == 0) funcs = _.functions(obj);
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(func, args); }, wait);
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
- _.throttle = function(func, wait) {
529
- var context, args, timeout, throttling, more;
530
- var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
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
- context = this; args = arguments;
533
- var later = function() {
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
- if (more) func.apply(context, args);
536
- whenDone();
537
- };
538
- if (!timeout) timeout = setTimeout(later, wait);
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
- whenDone();
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
- _.debounce = function(func, wait) {
553
- var timeout;
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
- return memo = func.apply(this, arguments);
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].concat(slice.call(arguments, 0));
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) { return func.apply(this, arguments); }
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[keys.length] = key;
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
- return _.map(obj, _.identity);
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
- for (var prop in source) {
638
- obj[prop] = source[prop];
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
- for (var prop in source) {
648
- if (obj[prop] == null) obj[prop] = source[prop];
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
- function eq(a, b, stack) {
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: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
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._chain) a = a._wrapped;
677
- if (b._chain) b = b._wrapped;
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 = stack.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 (stack[length] == a) return true;
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
- stack.push(a);
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
- // Ensure commutative equality for sparse arrays.
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], stack))) break;
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
- stack.pop();
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 == 1);
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
- // Is a given variable an arguments object?
786
- _.isArguments = function(obj) {
787
- return toString.call(obj) == '[object Arguments]';
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
- // Is a given value a function?
796
- _.isFunction = function(obj) {
797
- return toString.call(obj) == '[object Function]';
798
- };
799
-
800
- // Is a given value a string?
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 value a number?
806
- _.isNumber = function(obj) {
807
- return toString.call(obj) == '[object Number]';
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
- // `NaN` is the only value for which `===` is not reflexive.
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
- // Has own property?
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 (n, iterator, context) {
863
- for (var i = 0; i < n; i++) iterator.call(context, i);
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
+ '&': '&amp;',
1064
+ '<': '&lt;',
1065
+ '>': '&gt;',
1066
+ '"': '&quot;',
1067
+ "'": '&#x27;',
1068
+ '/': '&#x2F;'
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
- // Escape a string for HTML interpolation.
867
- _.escape = function(string) {
868
- return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
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, ensuring that
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
- addToWrapper(name, _[name] = obj[name]);
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
- // Within an interpolation, evaluation, or escaping, remove HTML escaping
901
- // that had been previously added.
902
- var unescape = function(code) {
903
- return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
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(str, data) {
910
- var c = _.templateSettings;
911
- var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
912
- 'with(obj||{}){__p.push(\'' +
913
- str.replace(/\\/g, '\\\\')
914
- .replace(/'/g, "\\'")
915
- .replace(c.escape || noMatch, function(match, code) {
916
- return "',_.escape(" + unescape(code) + "),'";
917
- })
918
- .replace(c.interpolate || noMatch, function(match, code) {
919
- return "'," + unescape(code) + ",'";
920
- })
921
- .replace(c.evaluate || noMatch, function(match, code) {
922
- return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
923
- })
924
- .replace(/\r/g, '\\r')
925
- .replace(/\n/g, '\\n')
926
- .replace(/\t/g, '\\t')
927
- + "');}return __p.join('');";
928
- var func = new Function('obj', '_', tmpl);
929
- if (data) return func(data, _);
930
- return function(data) {
931
- return func.call(this, data, _);
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
- // The OOP Wrapper
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, chain) {
953
- return chain ? _(obj).chain() : obj;
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
- wrapper.prototype[name] = function() {
972
- var wrapped = this._wrapped;
973
- method.apply(wrapped, arguments);
974
- var length = wrapped.length;
975
- if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
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
- wrapper.prototype[name] = function() {
984
- return result(method.apply(this._wrapped, arguments), this._chain);
1237
+ _.prototype[name] = function() {
1238
+ return result.call(this, method.apply(this._wrapped, arguments));
985
1239
  };
986
1240
  });
987
1241
 
988
- // Start chaining a wrapped Underscore object.
989
- wrapper.prototype.chain = function() {
990
- this._chain = true;
991
- return this;
992
- };
1242
+ _.extend(_.prototype, {
993
1243
 
994
- // Extracts the result from a wrapped and chained object.
995
- wrapper.prototype.value = function() {
996
- return this._wrapped;
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);