socialcast-i18n-js 4.0.0.rc5 → 4.0.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,7 @@ module I18n
4
4
  MAJOR = 4
5
5
  MINOR = 0
6
6
  PATCH = 0
7
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc5"
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc6"
8
8
  end
9
9
  end
10
10
  end
@@ -1,5 +1,3 @@
1
- //= require underscore
2
-
3
1
  // I18n.js
4
2
  // =======
5
3
  //
@@ -54,11 +52,11 @@ var I18n = {};
54
52
  I18n.locales.get = function(locale) {
55
53
  var result = this[locale] || this[I18n.locale] || this["default"];
56
54
 
57
- if (_.isFunction(result)) {
55
+ if (Object.prototype.toString.call(result) == '[object Function]') {
58
56
  result = result(locale);
59
57
  }
60
58
 
61
- if (!_.isArray(result)) {
59
+ if (Object.prototype.toString.call(result) != '[object Array]') {
62
60
  result = [result];
63
61
  }
64
62
 
@@ -95,11 +93,11 @@ var I18n = {};
95
93
  locales.forEach(function(locale){
96
94
  countryCode = locale.split("-")[0];
97
95
 
98
- if (!_.include(list, locale)) {
96
+ if (!~list.indexOf(locale)) {
99
97
  list.push(locale);
100
98
  }
101
99
 
102
- if (I18n.fallbacks && countryCode && countryCode !== locale && !_.include(list, countryCode)) {
100
+ if (I18n.fallbacks && countryCode && countryCode !== locale && !~list.indexOf(countryCode)) {
103
101
  list.push(countryCode);
104
102
  }
105
103
  });
@@ -144,7 +142,7 @@ var I18n = {};
144
142
 
145
143
  // Check if value is different than undefined and null;
146
144
  I18n.isSet = function(value) {
147
- return !_.isUndefined(value) && !_.isNull(value);
145
+ return value !== void 0 && value !== null;
148
146
  };
149
147
 
150
148
  // Find and process the translation using the provided scope and options.
@@ -165,19 +163,19 @@ var I18n = {};
165
163
  scopes = scope.split(this.defaultSeparator);
166
164
  translations = this.translations[locale];
167
165
 
168
- if (_.isUndefined(translations)) {
166
+ if (translations === void 0) {
169
167
  continue;
170
168
  }
171
169
 
172
170
  while (scopes.length) {
173
171
  translations = translations[scopes.shift()];
174
172
 
175
- if (_.isUndefined(translations)) {
173
+ if (translations === void 0) {
176
174
  break;
177
175
  }
178
176
  }
179
177
 
180
- if (!_.isUndefined(translations)) {
178
+ if (translations !== void 0) {
181
179
  return translations;
182
180
  }
183
181
  }
@@ -201,12 +199,12 @@ var I18n = {};
201
199
  for (var i = 0, count = args.length; i < count; i++) {
202
200
  var o = args.shift();
203
201
 
204
- if (!_.isObject(o)) {
202
+ if (o !== Object(o)) {
205
203
  continue;
206
204
  }
207
205
 
208
206
  for (var attr in o) {
209
- if (!_.has(o, attr)) {
207
+ if (!hasOwnProperty.call(o, attr)) {
210
208
  continue;
211
209
  }
212
210
 
@@ -226,13 +224,13 @@ var I18n = {};
226
224
  options = this.prepareOptions(options);
227
225
  var translation = this.lookup(scope, options);
228
226
 
229
- if (_.isUndefined(translation)) {
227
+ if (translation === void 0) {
230
228
  return this.missingTranslation(scope);
231
229
  }
232
230
 
233
- if (_.isString(translation)) {
231
+ if (Object.prototype.toString.call(translation) == '[object String]') {
234
232
  translation = this.interpolate(translation, options);
235
- } else if (_.isObject(translation) && this.isSet(options.count)) {
233
+ } else if (translation === Object(translation) && this.isSet(options.count)) {
236
234
  translation = this.pluralize(options.count, translation, options);
237
235
  }
238
236
 
@@ -276,13 +274,13 @@ var I18n = {};
276
274
  options = this.prepareOptions(options);
277
275
  var translations, pluralizer, keys, key, message;
278
276
 
279
- if (_.isObject(scope)) {
277
+ if (scope === Object(scope)) {
280
278
  translations = scope;
281
279
  } else {
282
280
  translations = this.lookup(scope, options);
283
281
  }
284
282
 
285
- if (_.isUndefined(translations)) {
283
+ if (translations === void 0) {
286
284
  return this.missingTranslation(scope);
287
285
  }
288
286
 
@@ -446,7 +444,7 @@ var I18n = {};
446
444
  var matches, convertedDate;
447
445
 
448
446
  // we have a date, so just return it.
449
- if (_.isDate(date)) {
447
+ if (Object.prototype.toString.call(date) == '[object Date]') {
450
448
  return date;
451
449
  };
452
450
 
@@ -659,3 +657,40 @@ var I18n = {};
659
657
  if(typeof exports !== 'undefined'){
660
658
  module.exports = I18n;
661
659
  }
660
+
661
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
662
+ if (!Array.prototype.indexOf) {
663
+ Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
664
+ "use strict";
665
+
666
+ if (this === void 0 || this === null)
667
+ throw new TypeError();
668
+
669
+ var t = Object(this);
670
+ var len = t.length >>> 0;
671
+ if (len === 0)
672
+ return -1;
673
+
674
+ var n = 0;
675
+ if (arguments.length > 0) {
676
+ n = Number(arguments[1]);
677
+ if (n !== n) // shortcut for verifying if it's NaN
678
+ n = 0;
679
+ else if (n !== 0 && n !== (Infinity) && n !== -(Infinity))
680
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
681
+ }
682
+
683
+ if (n >= len)
684
+ return -1;
685
+
686
+ var k = n >= 0
687
+ ? n
688
+ : Math.max(len - Math.abs(n), 0);
689
+
690
+ for (; k < len; k++) {
691
+ if (k in t && t[k] === searchElement)
692
+ return k;
693
+ }
694
+ return -1;
695
+ };
696
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: socialcast-i18n-js
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.rc5
4
+ version: 4.0.0.rc6
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-09-20 00:00:00.000000000 Z
13
+ date: 2012-09-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: i18n
17
- requirement: &2153420060 !ruby/object:Gem::Requirement
17
+ requirement: &2159287820 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2153420060
25
+ version_requirements: *2159287820
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activesupport
28
- requirement: &2153435520 !ruby/object:Gem::Requirement
28
+ requirement: &2159303320 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 3.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2153435520
36
+ version_requirements: *2159303320
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: railties
39
- requirement: &2153434760 !ruby/object:Gem::Requirement
39
+ requirement: &2159302520 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 3.0.0
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *2153434760
47
+ version_requirements: *2159302520
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: sprockets
50
- requirement: &2153434260 !ruby/object:Gem::Requirement
50
+ requirement: &2159302020 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 2.0.0
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *2153434260
58
+ version_requirements: *2159302020
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: rspec
61
- requirement: &2153433860 !ruby/object:Gem::Requirement
61
+ requirement: &2159301640 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: '0'
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *2153433860
69
+ version_requirements: *2159301640
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: rake
72
- requirement: &2153433380 !ruby/object:Gem::Requirement
72
+ requirement: &2159301140 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
- version_requirements: *2153433380
80
+ version_requirements: *2159301140
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: pry
83
- requirement: &2153432940 !ruby/object:Gem::Requirement
83
+ requirement: &2159300700 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ! '>='
@@ -88,10 +88,10 @@ dependencies:
88
88
  version: '0'
89
89
  type: :development
90
90
  prerelease: false
91
- version_requirements: *2153432940
91
+ version_requirements: *2159300700
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: awesome_print
94
- requirement: &2153432500 !ruby/object:Gem::Requirement
94
+ requirement: &2159300260 !ruby/object:Gem::Requirement
95
95
  none: false
96
96
  requirements:
97
97
  - - ! '>='
@@ -99,7 +99,7 @@ dependencies:
99
99
  version: '0'
100
100
  type: :development
101
101
  prerelease: false
102
- version_requirements: *2153432500
102
+ version_requirements: *2159300260
103
103
  description: It's a small library to provide the Rails I18n translations on the Javascript.
104
104
  email:
105
105
  - fnando.vieira@gmail.com
@@ -167,7 +167,6 @@ files:
167
167
  - spec/translator_spec.rb
168
168
  - vendor/assets/javascripts/i18n.js
169
169
  - vendor/assets/javascripts/i18n/translations.js.erb
170
- - vendor/assets/javascripts/underscore.js
171
170
  homepage: http://rubygems.org/gems/socialcast-i18n-js
172
171
  licenses: []
173
172
  post_install_message:
@@ -1,1059 +0,0 @@
1
- // Underscore.js 1.3.3
2
- // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
- // Underscore may be freely distributed 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
8
-
9
- (function() {
10
-
11
- // Baseline setup
12
- // --------------
13
-
14
- // Establish the root object, `window` in the browser, or `global` on the server.
15
- var root = this;
16
-
17
- // Save the previous value of the `_` variable.
18
- var previousUnderscore = root._;
19
-
20
- // Establish the object that gets returned to break out of a loop iteration.
21
- var breaker = {};
22
-
23
- // Save bytes in the minified (but not gzipped) version:
24
- var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
25
-
26
- // 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;
31
-
32
- // All **ECMAScript 5** native function implementations that we hope to use
33
- // are declared here.
34
- var
35
- nativeForEach = ArrayProto.forEach,
36
- nativeMap = ArrayProto.map,
37
- nativeReduce = ArrayProto.reduce,
38
- nativeReduceRight = ArrayProto.reduceRight,
39
- nativeFilter = ArrayProto.filter,
40
- nativeEvery = ArrayProto.every,
41
- nativeSome = ArrayProto.some,
42
- nativeIndexOf = ArrayProto.indexOf,
43
- nativeLastIndexOf = ArrayProto.lastIndexOf,
44
- nativeIsArray = Array.isArray,
45
- nativeKeys = Object.keys,
46
- nativeBind = FuncProto.bind;
47
-
48
- // Create a safe reference to the Underscore object for use below.
49
- var _ = function(obj) { return new wrapper(obj); };
50
-
51
- // Export the Underscore object for **Node.js**, with
52
- // backwards-compatibility for the old `require()` API. If we're in
53
- // the browser, add `_` as a global object via a string identifier,
54
- // for Closure Compiler "advanced" mode.
55
- if (typeof exports !== 'undefined') {
56
- if (typeof module !== 'undefined' && module.exports) {
57
- exports = module.exports = _;
58
- }
59
- exports._ = _;
60
- } else {
61
- root['_'] = _;
62
- }
63
-
64
- // Current version.
65
- _.VERSION = '1.3.3';
66
-
67
- // Collection Functions
68
- // --------------------
69
-
70
- // The cornerstone, an `each` implementation, aka `forEach`.
71
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
72
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
73
- var each = _.each = _.forEach = function(obj, iterator, context) {
74
- if (obj == null) return;
75
- if (nativeForEach && obj.forEach === nativeForEach) {
76
- obj.forEach(iterator, context);
77
- } else if (obj.length === +obj.length) {
78
- for (var i = 0, l = obj.length; i < l; i++) {
79
- if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
80
- }
81
- } else {
82
- for (var key in obj) {
83
- if (_.has(obj, key)) {
84
- if (iterator.call(context, obj[key], key, obj) === breaker) return;
85
- }
86
- }
87
- }
88
- };
89
-
90
- // Return the results of applying the iterator to each element.
91
- // Delegates to **ECMAScript 5**'s native `map` if available.
92
- _.map = _.collect = function(obj, iterator, context) {
93
- var results = [];
94
- if (obj == null) return results;
95
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
96
- each(obj, function(value, index, list) {
97
- results[results.length] = iterator.call(context, value, index, list);
98
- });
99
- if (obj.length === +obj.length) results.length = obj.length;
100
- return results;
101
- };
102
-
103
- // **Reduce** builds up a single result from a list of values, aka `inject`,
104
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
105
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
106
- var initial = arguments.length > 2;
107
- if (obj == null) obj = [];
108
- if (nativeReduce && obj.reduce === nativeReduce) {
109
- if (context) iterator = _.bind(iterator, context);
110
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
111
- }
112
- each(obj, function(value, index, list) {
113
- if (!initial) {
114
- memo = value;
115
- initial = true;
116
- } else {
117
- memo = iterator.call(context, memo, value, index, list);
118
- }
119
- });
120
- if (!initial) throw new TypeError('Reduce of empty array with no initial value');
121
- return memo;
122
- };
123
-
124
- // The right-associative version of reduce, also known as `foldr`.
125
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
126
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
127
- var initial = arguments.length > 2;
128
- if (obj == null) obj = [];
129
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
130
- if (context) iterator = _.bind(iterator, context);
131
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
132
- }
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);
136
- };
137
-
138
- // Return the first value which passes a truth test. Aliased as `detect`.
139
- _.find = _.detect = function(obj, iterator, context) {
140
- var result;
141
- any(obj, function(value, index, list) {
142
- if (iterator.call(context, value, index, list)) {
143
- result = value;
144
- return true;
145
- }
146
- });
147
- return result;
148
- };
149
-
150
- // Return all the elements that pass a truth test.
151
- // Delegates to **ECMAScript 5**'s native `filter` if available.
152
- // Aliased as `select`.
153
- _.filter = _.select = function(obj, iterator, context) {
154
- var results = [];
155
- if (obj == null) return results;
156
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
157
- each(obj, function(value, index, list) {
158
- if (iterator.call(context, value, index, list)) results[results.length] = value;
159
- });
160
- return results;
161
- };
162
-
163
- // Return all the elements for which a truth test fails.
164
- _.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;
171
- };
172
-
173
- // Determine whether all of the elements match a truth test.
174
- // Delegates to **ECMAScript 5**'s native `every` if available.
175
- // Aliased as `all`.
176
- _.every = _.all = function(obj, iterator, context) {
177
- var result = true;
178
- if (obj == null) return result;
179
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
180
- each(obj, function(value, index, list) {
181
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
182
- });
183
- return !!result;
184
- };
185
-
186
- // Determine if at least one element in the object matches a truth test.
187
- // Delegates to **ECMAScript 5**'s native `some` if available.
188
- // Aliased as `any`.
189
- var any = _.some = _.any = function(obj, iterator, context) {
190
- iterator || (iterator = _.identity);
191
- var result = false;
192
- if (obj == null) return result;
193
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
194
- each(obj, function(value, index, list) {
195
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
196
- });
197
- return !!result;
198
- };
199
-
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;
205
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
206
- found = any(obj, function(value) {
207
- return value === target;
208
- });
209
- return found;
210
- };
211
-
212
- // Invoke a method (with arguments) on every item in a collection.
213
- _.invoke = function(obj, method) {
214
- var args = slice.call(arguments, 2);
215
- return _.map(obj, function(value) {
216
- return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
217
- });
218
- };
219
-
220
- // Convenience version of a common use case of `map`: fetching a property.
221
- _.pluck = function(obj, key) {
222
- return _.map(obj, function(value){ return value[key]; });
223
- };
224
-
225
- // Return the maximum element or (element-based computation).
226
- _.max = function(obj, iterator, context) {
227
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
228
- if (!iterator && _.isEmpty(obj)) return -Infinity;
229
- var result = {computed : -Infinity};
230
- each(obj, function(value, index, list) {
231
- var computed = iterator ? iterator.call(context, value, index, list) : value;
232
- computed >= result.computed && (result = {value : value, computed : computed});
233
- });
234
- return result.value;
235
- };
236
-
237
- // Return the minimum element (or element-based computation).
238
- _.min = function(obj, iterator, context) {
239
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
240
- if (!iterator && _.isEmpty(obj)) return Infinity;
241
- var result = {computed : Infinity};
242
- each(obj, function(value, index, list) {
243
- var computed = iterator ? iterator.call(context, value, index, list) : value;
244
- computed < result.computed && (result = {value : value, computed : computed});
245
- });
246
- return result.value;
247
- };
248
-
249
- // Shuffle an array.
250
- _.shuffle = function(obj) {
251
- var shuffled = [], rand;
252
- each(obj, function(value, index, list) {
253
- rand = Math.floor(Math.random() * (index + 1));
254
- shuffled[index] = shuffled[rand];
255
- shuffled[rand] = value;
256
- });
257
- return shuffled;
258
- };
259
-
260
- // Sort the object's values by a criterion produced by an iterator.
261
- _.sortBy = function(obj, val, context) {
262
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
263
- return _.pluck(_.map(obj, function(value, index, list) {
264
- return {
265
- value : value,
266
- criteria : iterator.call(context, value, index, list)
267
- };
268
- }).sort(function(left, right) {
269
- var a = left.criteria, b = right.criteria;
270
- if (a === void 0) return 1;
271
- if (b === void 0) return -1;
272
- return a < b ? -1 : a > b ? 1 : 0;
273
- }), 'value');
274
- };
275
-
276
- // Groups the object's values by a criterion. Pass either a string attribute
277
- // to group by, or a function that returns the criterion.
278
- _.groupBy = function(obj, val) {
279
- var result = {};
280
- var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
281
- each(obj, function(value, index) {
282
- var key = iterator(value, index);
283
- (result[key] || (result[key] = [])).push(value);
284
- });
285
- return result;
286
- };
287
-
288
- // Use a comparator function to figure out at what index an object should
289
- // be inserted so as to maintain order. Uses binary search.
290
- _.sortedIndex = function(array, obj, iterator) {
291
- iterator || (iterator = _.identity);
292
- var low = 0, high = array.length;
293
- while (low < high) {
294
- var mid = (low + high) >> 1;
295
- iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
296
- }
297
- return low;
298
- };
299
-
300
- // Safely convert anything iterable into a real, live array.
301
- _.toArray = function(obj) {
302
- if (!obj) return [];
303
- if (_.isArray(obj)) return slice.call(obj);
304
- if (_.isArguments(obj)) return slice.call(obj);
305
- if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray();
306
- return _.values(obj);
307
- };
308
-
309
- // Return the number of elements in an object.
310
- _.size = function(obj) {
311
- return _.isArray(obj) ? obj.length : _.keys(obj).length;
312
- };
313
-
314
- // Array Functions
315
- // ---------------
316
-
317
- // Get the first element of an array. Passing **n** will return the first N
318
- // values in the array. Aliased as `head` and `take`. The **guard** check
319
- // allows it to work with `_.map`.
320
- _.first = _.head = _.take = function(array, n, guard) {
321
- return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
322
- };
323
-
324
- // Returns everything but the last entry of the array. Especcialy useful on
325
- // the arguments object. Passing **n** will return all the values in
326
- // the array, excluding the last N. The **guard** check allows it to work with
327
- // `_.map`.
328
- _.initial = function(array, n, guard) {
329
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
330
- };
331
-
332
- // Get the last element of an array. Passing **n** will return the last N
333
- // values in the array. The **guard** check allows it to work with `_.map`.
334
- _.last = function(array, n, guard) {
335
- if ((n != null) && !guard) {
336
- return slice.call(array, Math.max(array.length - n, 0));
337
- } else {
338
- return array[array.length - 1];
339
- }
340
- };
341
-
342
- // Returns everything but the first entry of the array. Aliased as `tail`.
343
- // Especially useful on the arguments object. Passing an **index** will return
344
- // the rest of the values in the array from that index onward. The **guard**
345
- // check allows it to work with `_.map`.
346
- _.rest = _.tail = function(array, index, guard) {
347
- return slice.call(array, (index == null) || guard ? 1 : index);
348
- };
349
-
350
- // Trim out all falsy values from an array.
351
- _.compact = function(array) {
352
- return _.filter(array, function(value){ return !!value; });
353
- };
354
-
355
- // Return a completely flattened version of an array.
356
- _.flatten = function(array, shallow) {
357
- return _.reduce(array, function(memo, value) {
358
- if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
359
- memo[memo.length] = value;
360
- return memo;
361
- }, []);
362
- };
363
-
364
- // Return a version of the array that does not contain the specified value(s).
365
- _.without = function(array) {
366
- return _.difference(array, slice.call(arguments, 1));
367
- };
368
-
369
- // Produce a duplicate-free version of the array. If the array has already
370
- // been sorted, you have the option of using a faster algorithm.
371
- // Aliased as `unique`.
372
- _.uniq = _.unique = function(array, isSorted, iterator) {
373
- var initial = iterator ? _.map(array, iterator) : array;
374
- var results = [];
375
- // The `isSorted` flag is irrelevant if the array only contains two elements.
376
- if (array.length < 3) isSorted = true;
377
- _.reduce(initial, function (memo, value, index) {
378
- if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
379
- memo.push(value);
380
- results.push(array[index]);
381
- }
382
- return memo;
383
- }, []);
384
- return results;
385
- };
386
-
387
- // Produce an array that contains the union: each distinct element from all of
388
- // the passed-in arrays.
389
- _.union = function() {
390
- return _.uniq(_.flatten(arguments, true));
391
- };
392
-
393
- // Produce an array that contains every item shared between all the
394
- // passed-in arrays. (Aliased as "intersect" for back-compat.)
395
- _.intersection = _.intersect = function(array) {
396
- var rest = slice.call(arguments, 1);
397
- return _.filter(_.uniq(array), function(item) {
398
- return _.every(rest, function(other) {
399
- return _.indexOf(other, item) >= 0;
400
- });
401
- });
402
- };
403
-
404
- // Take the difference between one array and a number of other arrays.
405
- // Only the elements present in just the first array will remain.
406
- _.difference = function(array) {
407
- var rest = _.flatten(slice.call(arguments, 1), true);
408
- return _.filter(array, function(value){ return !_.include(rest, value); });
409
- };
410
-
411
- // Zip together multiple lists into a single array -- elements that share
412
- // an index go together.
413
- _.zip = function() {
414
- var args = slice.call(arguments);
415
- var length = _.max(_.pluck(args, 'length'));
416
- var results = new Array(length);
417
- for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
418
- return results;
419
- };
420
-
421
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
422
- // we need this function. Return the position of the first occurrence of an
423
- // item in an array, or -1 if the item is not included in the array.
424
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
425
- // If the array is large and already in sort order, pass `true`
426
- // for **isSorted** to use binary search.
427
- _.indexOf = function(array, item, isSorted) {
428
- if (array == null) return -1;
429
- var i, l;
430
- if (isSorted) {
431
- i = _.sortedIndex(array, item);
432
- return array[i] === item ? i : -1;
433
- }
434
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
435
- for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
436
- return -1;
437
- };
438
-
439
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
440
- _.lastIndexOf = function(array, item) {
441
- if (array == null) return -1;
442
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
443
- var i = array.length;
444
- while (i--) if (i in array && array[i] === item) return i;
445
- return -1;
446
- };
447
-
448
- // Generate an integer Array containing an arithmetic progression. A port of
449
- // the native Python `range()` function. See
450
- // [the Python documentation](http://docs.python.org/library/functions.html#range).
451
- _.range = function(start, stop, step) {
452
- if (arguments.length <= 1) {
453
- stop = start || 0;
454
- start = 0;
455
- }
456
- step = arguments[2] || 1;
457
-
458
- var len = Math.max(Math.ceil((stop - start) / step), 0);
459
- var idx = 0;
460
- var range = new Array(len);
461
-
462
- while(idx < len) {
463
- range[idx++] = start;
464
- start += step;
465
- }
466
-
467
- return range;
468
- };
469
-
470
- // Function (ahem) Functions
471
- // ------------------
472
-
473
- // Reusable constructor function for prototype setting.
474
- var ctor = function(){};
475
-
476
- // Create a function bound to a given object (assigning `this`, and arguments,
477
- // optionally). Binding with arguments is also known as `curry`.
478
- // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
479
- // We check for `func.bind` first, to fail fast when `func` is undefined.
480
- _.bind = function bind(func, context) {
481
- var bound, args;
482
- if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
483
- if (!_.isFunction(func)) throw new TypeError;
484
- args = slice.call(arguments, 2);
485
- return bound = function() {
486
- if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
487
- ctor.prototype = func.prototype;
488
- var self = new ctor;
489
- var result = func.apply(self, args.concat(slice.call(arguments)));
490
- if (Object(result) === result) return result;
491
- return self;
492
- };
493
- };
494
-
495
- // Bind all of an object's methods to that object. Useful for ensuring that
496
- // all callbacks defined on an object belong to it.
497
- _.bindAll = function(obj) {
498
- var funcs = slice.call(arguments, 1);
499
- if (funcs.length == 0) funcs = _.functions(obj);
500
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
501
- return obj;
502
- };
503
-
504
- // Memoize an expensive function by storing its results.
505
- _.memoize = function(func, hasher) {
506
- var memo = {};
507
- hasher || (hasher = _.identity);
508
- return function() {
509
- var key = hasher.apply(this, arguments);
510
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
511
- };
512
- };
513
-
514
- // Delays a function for the given number of milliseconds, and then calls
515
- // it with the arguments supplied.
516
- _.delay = function(func, wait) {
517
- var args = slice.call(arguments, 2);
518
- return setTimeout(function(){ return func.apply(null, args); }, wait);
519
- };
520
-
521
- // Defers a function, scheduling it to run after the current call stack has
522
- // cleared.
523
- _.defer = function(func) {
524
- return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
525
- };
526
-
527
- // Returns a function, that, when invoked, will only be triggered at most once
528
- // during a given window of time.
529
- _.throttle = function(func, wait) {
530
- var context, args, timeout, throttling, more, result;
531
- var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
532
- return function() {
533
- context = this; args = arguments;
534
- var later = function() {
535
- timeout = null;
536
- if (more) func.apply(context, args);
537
- whenDone();
538
- };
539
- if (!timeout) timeout = setTimeout(later, wait);
540
- if (throttling) {
541
- more = true;
542
- } else {
543
- result = func.apply(context, args);
544
- }
545
- whenDone();
546
- throttling = true;
547
- return result;
548
- };
549
- };
550
-
551
- // Returns a function, that, as long as it continues to be invoked, will not
552
- // be triggered. The function will be called after it stops being called for
553
- // N milliseconds. If `immediate` is passed, trigger the function on the
554
- // leading edge, instead of the trailing.
555
- _.debounce = function(func, wait, immediate) {
556
- var timeout;
557
- return function() {
558
- var context = this, args = arguments;
559
- var later = function() {
560
- timeout = null;
561
- if (!immediate) func.apply(context, args);
562
- };
563
- if (immediate && !timeout) func.apply(context, args);
564
- clearTimeout(timeout);
565
- timeout = setTimeout(later, wait);
566
- };
567
- };
568
-
569
- // Returns a function that will be executed at most one time, no matter how
570
- // often you call it. Useful for lazy initialization.
571
- _.once = function(func) {
572
- var ran = false, memo;
573
- return function() {
574
- if (ran) return memo;
575
- ran = true;
576
- return memo = func.apply(this, arguments);
577
- };
578
- };
579
-
580
- // Returns the first function passed as an argument to the second,
581
- // allowing you to adjust arguments, run code before and after, and
582
- // conditionally execute the original function.
583
- _.wrap = function(func, wrapper) {
584
- return function() {
585
- var args = [func].concat(slice.call(arguments, 0));
586
- return wrapper.apply(this, args);
587
- };
588
- };
589
-
590
- // Returns a function that is the composition of a list of functions, each
591
- // consuming the return value of the function that follows.
592
- _.compose = function() {
593
- var funcs = arguments;
594
- return function() {
595
- var args = arguments;
596
- for (var i = funcs.length - 1; i >= 0; i--) {
597
- args = [funcs[i].apply(this, args)];
598
- }
599
- return args[0];
600
- };
601
- };
602
-
603
- // Returns a function that will only be executed after being called N times.
604
- _.after = function(times, func) {
605
- if (times <= 0) return func();
606
- return function() {
607
- if (--times < 1) { return func.apply(this, arguments); }
608
- };
609
- };
610
-
611
- // Object Functions
612
- // ----------------
613
-
614
- // Retrieve the names of an object's properties.
615
- // Delegates to **ECMAScript 5**'s native `Object.keys`
616
- _.keys = nativeKeys || function(obj) {
617
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
618
- var keys = [];
619
- for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
620
- return keys;
621
- };
622
-
623
- // Retrieve the values of an object's properties.
624
- _.values = function(obj) {
625
- return _.map(obj, _.identity);
626
- };
627
-
628
- // Return a sorted list of the function names available on the object.
629
- // Aliased as `methods`
630
- _.functions = _.methods = function(obj) {
631
- var names = [];
632
- for (var key in obj) {
633
- if (_.isFunction(obj[key])) names.push(key);
634
- }
635
- return names.sort();
636
- };
637
-
638
- // Extend a given object with all the properties in passed-in object(s).
639
- _.extend = function(obj) {
640
- each(slice.call(arguments, 1), function(source) {
641
- for (var prop in source) {
642
- obj[prop] = source[prop];
643
- }
644
- });
645
- return obj;
646
- };
647
-
648
- // Return a copy of the object only containing the whitelisted properties.
649
- _.pick = function(obj) {
650
- var result = {};
651
- each(_.flatten(slice.call(arguments, 1)), function(key) {
652
- if (key in obj) result[key] = obj[key];
653
- });
654
- return result;
655
- };
656
-
657
- // Fill in a given object with default properties.
658
- _.defaults = function(obj) {
659
- each(slice.call(arguments, 1), function(source) {
660
- for (var prop in source) {
661
- if (obj[prop] == null) obj[prop] = source[prop];
662
- }
663
- });
664
- return obj;
665
- };
666
-
667
- // Create a (shallow-cloned) duplicate of an object.
668
- _.clone = function(obj) {
669
- if (!_.isObject(obj)) return obj;
670
- return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
671
- };
672
-
673
- // Invokes interceptor with the obj, and then returns obj.
674
- // The primary purpose of this method is to "tap into" a method chain, in
675
- // order to perform operations on intermediate results within the chain.
676
- _.tap = function(obj, interceptor) {
677
- interceptor(obj);
678
- return obj;
679
- };
680
-
681
- // Internal recursive comparison function.
682
- function eq(a, b, stack) {
683
- // Identical objects are equal. `0 === -0`, but they aren't identical.
684
- // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
685
- if (a === b) return a !== 0 || 1 / a == 1 / b;
686
- // A strict comparison is necessary because `null == undefined`.
687
- if (a == null || b == null) return a === b;
688
- // Unwrap any wrapped objects.
689
- if (a._chain) a = a._wrapped;
690
- if (b._chain) b = b._wrapped;
691
- // Invoke a custom `isEqual` method if one is provided.
692
- if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
693
- if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
694
- // Compare `[[Class]]` names.
695
- var className = toString.call(a);
696
- if (className != toString.call(b)) return false;
697
- switch (className) {
698
- // Strings, numbers, dates, and booleans are compared by value.
699
- case '[object String]':
700
- // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
701
- // equivalent to `new String("5")`.
702
- return a == String(b);
703
- case '[object Number]':
704
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
705
- // other numeric values.
706
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
707
- case '[object Date]':
708
- case '[object Boolean]':
709
- // Coerce dates and booleans to numeric primitive values. Dates are compared by their
710
- // millisecond representations. Note that invalid dates with millisecond representations
711
- // of `NaN` are not equivalent.
712
- return +a == +b;
713
- // RegExps are compared by their source patterns and flags.
714
- case '[object RegExp]':
715
- return a.source == b.source &&
716
- a.global == b.global &&
717
- a.multiline == b.multiline &&
718
- a.ignoreCase == b.ignoreCase;
719
- }
720
- if (typeof a != 'object' || typeof b != 'object') return false;
721
- // Assume equality for cyclic structures. The algorithm for detecting cyclic
722
- // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
723
- var length = stack.length;
724
- while (length--) {
725
- // Linear search. Performance is inversely proportional to the number of
726
- // unique nested structures.
727
- if (stack[length] == a) return true;
728
- }
729
- // Add the first object to the stack of traversed objects.
730
- stack.push(a);
731
- var size = 0, result = true;
732
- // Recursively compare objects and arrays.
733
- if (className == '[object Array]') {
734
- // Compare array lengths to determine if a deep comparison is necessary.
735
- size = a.length;
736
- result = size == b.length;
737
- if (result) {
738
- // Deep compare the contents, ignoring non-numeric properties.
739
- while (size--) {
740
- // Ensure commutative equality for sparse arrays.
741
- if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
742
- }
743
- }
744
- } else {
745
- // Objects with different constructors are not equivalent.
746
- if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
747
- // Deep compare objects.
748
- for (var key in a) {
749
- if (_.has(a, key)) {
750
- // Count the expected number of properties.
751
- size++;
752
- // Deep compare each member.
753
- if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
754
- }
755
- }
756
- // Ensure that both objects contain the same number of properties.
757
- if (result) {
758
- for (key in b) {
759
- if (_.has(b, key) && !(size--)) break;
760
- }
761
- result = !size;
762
- }
763
- }
764
- // Remove the first object from the stack of traversed objects.
765
- stack.pop();
766
- return result;
767
- }
768
-
769
- // Perform a deep comparison to check if two objects are equal.
770
- _.isEqual = function(a, b) {
771
- return eq(a, b, []);
772
- };
773
-
774
- // Is a given array, string, or object empty?
775
- // An "empty" object has no enumerable own-properties.
776
- _.isEmpty = function(obj) {
777
- if (obj == null) return true;
778
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
779
- for (var key in obj) if (_.has(obj, key)) return false;
780
- return true;
781
- };
782
-
783
- // Is a given value a DOM element?
784
- _.isElement = function(obj) {
785
- return !!(obj && obj.nodeType == 1);
786
- };
787
-
788
- // Is a given value an array?
789
- // Delegates to ECMA5's native Array.isArray
790
- _.isArray = nativeIsArray || function(obj) {
791
- return toString.call(obj) == '[object Array]';
792
- };
793
-
794
- // Is a given variable an object?
795
- _.isObject = function(obj) {
796
- return obj === Object(obj);
797
- };
798
-
799
- // Is a given variable an arguments object?
800
- _.isArguments = function(obj) {
801
- return toString.call(obj) == '[object Arguments]';
802
- };
803
- if (!_.isArguments(arguments)) {
804
- _.isArguments = function(obj) {
805
- return !!(obj && _.has(obj, 'callee'));
806
- };
807
- }
808
-
809
- // Is a given value a function?
810
- _.isFunction = function(obj) {
811
- return toString.call(obj) == '[object Function]';
812
- };
813
-
814
- // Is a given value a string?
815
- _.isString = function(obj) {
816
- return toString.call(obj) == '[object String]';
817
- };
818
-
819
- // Is a given value a number?
820
- _.isNumber = function(obj) {
821
- return toString.call(obj) == '[object Number]';
822
- };
823
-
824
- // Is a given object a finite number?
825
- _.isFinite = function(obj) {
826
- return _.isNumber(obj) && isFinite(obj);
827
- };
828
-
829
- // Is the given value `NaN`?
830
- _.isNaN = function(obj) {
831
- // `NaN` is the only value for which `===` is not reflexive.
832
- return obj !== obj;
833
- };
834
-
835
- // Is a given value a boolean?
836
- _.isBoolean = function(obj) {
837
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
838
- };
839
-
840
- // Is a given value a date?
841
- _.isDate = function(obj) {
842
- return toString.call(obj) == '[object Date]';
843
- };
844
-
845
- // Is the given value a regular expression?
846
- _.isRegExp = function(obj) {
847
- return toString.call(obj) == '[object RegExp]';
848
- };
849
-
850
- // Is a given value equal to null?
851
- _.isNull = function(obj) {
852
- return obj === null;
853
- };
854
-
855
- // Is a given variable undefined?
856
- _.isUndefined = function(obj) {
857
- return obj === void 0;
858
- };
859
-
860
- // Has own property?
861
- _.has = function(obj, key) {
862
- return hasOwnProperty.call(obj, key);
863
- };
864
-
865
- // Utility Functions
866
- // -----------------
867
-
868
- // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
869
- // previous owner. Returns a reference to the Underscore object.
870
- _.noConflict = function() {
871
- root._ = previousUnderscore;
872
- return this;
873
- };
874
-
875
- // Keep the identity function around for default iterators.
876
- _.identity = function(value) {
877
- return value;
878
- };
879
-
880
- // Run a function **n** times.
881
- _.times = function (n, iterator, context) {
882
- for (var i = 0; i < n; i++) iterator.call(context, i);
883
- };
884
-
885
- // Escape a string for HTML interpolation.
886
- _.escape = function(string) {
887
- return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
888
- };
889
-
890
- // If the value of the named property is a function then invoke it;
891
- // otherwise, return it.
892
- _.result = function(object, property) {
893
- if (object == null) return null;
894
- var value = object[property];
895
- return _.isFunction(value) ? value.call(object) : value;
896
- };
897
-
898
- // Add your own custom functions to the Underscore object, ensuring that
899
- // they're correctly added to the OOP wrapper as well.
900
- _.mixin = function(obj) {
901
- each(_.functions(obj), function(name){
902
- addToWrapper(name, _[name] = obj[name]);
903
- });
904
- };
905
-
906
- // Generate a unique integer id (unique within the entire client session).
907
- // Useful for temporary DOM ids.
908
- var idCounter = 0;
909
- _.uniqueId = function(prefix) {
910
- var id = idCounter++;
911
- return prefix ? prefix + id : id;
912
- };
913
-
914
- // By default, Underscore uses ERB-style template delimiters, change the
915
- // following template settings to use alternative delimiters.
916
- _.templateSettings = {
917
- evaluate : /<%([\s\S]+?)%>/g,
918
- interpolate : /<%=([\s\S]+?)%>/g,
919
- escape : /<%-([\s\S]+?)%>/g
920
- };
921
-
922
- // When customizing `templateSettings`, if you don't want to define an
923
- // interpolation, evaluation or escaping regex, we need one that is
924
- // guaranteed not to match.
925
- var noMatch = /.^/;
926
-
927
- // Certain characters need to be escaped so that they can be put into a
928
- // string literal.
929
- var escapes = {
930
- '\\': '\\',
931
- "'": "'",
932
- 'r': '\r',
933
- 'n': '\n',
934
- 't': '\t',
935
- 'u2028': '\u2028',
936
- 'u2029': '\u2029'
937
- };
938
-
939
- for (var p in escapes) escapes[escapes[p]] = p;
940
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
941
- var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
942
-
943
- // Within an interpolation, evaluation, or escaping, remove HTML escaping
944
- // that had been previously added.
945
- var unescape = function(code) {
946
- return code.replace(unescaper, function(match, escape) {
947
- return escapes[escape];
948
- });
949
- };
950
-
951
- // JavaScript micro-templating, similar to John Resig's implementation.
952
- // Underscore templating handles arbitrary delimiters, preserves whitespace,
953
- // and correctly escapes quotes within interpolated code.
954
- _.template = function(text, data, settings) {
955
- settings = _.defaults(settings || {}, _.templateSettings);
956
-
957
- // Compile the template source, taking care to escape characters that
958
- // cannot be included in a string literal and then unescape them in code
959
- // blocks.
960
- var source = "__p+='" + text
961
- .replace(escaper, function(match) {
962
- return '\\' + escapes[match];
963
- })
964
- .replace(settings.escape || noMatch, function(match, code) {
965
- return "'+\n_.escape(" + unescape(code) + ")+\n'";
966
- })
967
- .replace(settings.interpolate || noMatch, function(match, code) {
968
- return "'+\n(" + unescape(code) + ")+\n'";
969
- })
970
- .replace(settings.evaluate || noMatch, function(match, code) {
971
- return "';\n" + unescape(code) + "\n;__p+='";
972
- }) + "';\n";
973
-
974
- // If a variable is not specified, place data values in local scope.
975
- if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
976
-
977
- source = "var __p='';" +
978
- "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
979
- source + "return __p;\n";
980
-
981
- var render = new Function(settings.variable || 'obj', '_', source);
982
- if (data) return render(data, _);
983
- var template = function(data) {
984
- return render.call(this, data, _);
985
- };
986
-
987
- // Provide the compiled function source as a convenience for build time
988
- // precompilation.
989
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
990
- source + '}';
991
-
992
- return template;
993
- };
994
-
995
- // Add a "chain" function, which will delegate to the wrapper.
996
- _.chain = function(obj) {
997
- return _(obj).chain();
998
- };
999
-
1000
- // The OOP Wrapper
1001
- // ---------------
1002
-
1003
- // If Underscore is called as a function, it returns a wrapped object that
1004
- // can be used OO-style. This wrapper holds altered versions of all the
1005
- // underscore functions. Wrapped objects may be chained.
1006
- var wrapper = function(obj) { this._wrapped = obj; };
1007
-
1008
- // Expose `wrapper.prototype` as `_.prototype`
1009
- _.prototype = wrapper.prototype;
1010
-
1011
- // Helper function to continue chaining intermediate results.
1012
- var result = function(obj, chain) {
1013
- return chain ? _(obj).chain() : obj;
1014
- };
1015
-
1016
- // A method to easily add functions to the OOP wrapper.
1017
- var addToWrapper = function(name, func) {
1018
- wrapper.prototype[name] = function() {
1019
- var args = slice.call(arguments);
1020
- unshift.call(args, this._wrapped);
1021
- return result(func.apply(_, args), this._chain);
1022
- };
1023
- };
1024
-
1025
- // Add all of the Underscore functions to the wrapper object.
1026
- _.mixin(_);
1027
-
1028
- // Add all mutator Array functions to the wrapper.
1029
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1030
- var method = ArrayProto[name];
1031
- wrapper.prototype[name] = function() {
1032
- var wrapped = this._wrapped;
1033
- method.apply(wrapped, arguments);
1034
- var length = wrapped.length;
1035
- if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
1036
- return result(wrapped, this._chain);
1037
- };
1038
- });
1039
-
1040
- // Add all accessor Array functions to the wrapper.
1041
- each(['concat', 'join', 'slice'], function(name) {
1042
- var method = ArrayProto[name];
1043
- wrapper.prototype[name] = function() {
1044
- return result(method.apply(this._wrapped, arguments), this._chain);
1045
- };
1046
- });
1047
-
1048
- // Start chaining a wrapped Underscore object.
1049
- wrapper.prototype.chain = function() {
1050
- this._chain = true;
1051
- return this;
1052
- };
1053
-
1054
- // Extracts the result from a wrapped and chained object.
1055
- wrapper.prototype.value = function() {
1056
- return this._wrapped;
1057
- };
1058
-
1059
- }).call(this);