judge 1.5.0 → 2.0.0

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