backbone-rails 1.1.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,20 +1,35 @@
1
- // Backbone.js 1.1.0
1
+ // Backbone.js 1.1.2
2
2
 
3
- // (c) 2010-2011 Jeremy Ashkenas, DocumentCloud Inc.
4
- // (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3
+ // (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
5
4
  // Backbone may be freely distributed under the MIT license.
6
5
  // For all details and documentation:
7
6
  // http://backbonejs.org
8
7
 
9
- (function(){
8
+ (function(root, factory) {
9
+
10
+ // Set up Backbone appropriately for the environment. Start with AMD.
11
+ if (typeof define === 'function' && define.amd) {
12
+ define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
13
+ // Export global even in AMD case in case this script is loaded with
14
+ // others that may still expect a global Backbone.
15
+ root.Backbone = factory(root, exports, _, $);
16
+ });
17
+
18
+ // Next for Node.js or CommonJS. jQuery may not be needed as a module.
19
+ } else if (typeof exports !== 'undefined') {
20
+ var _ = require('underscore');
21
+ factory(root, exports, _);
22
+
23
+ // Finally, as a browser global.
24
+ } else {
25
+ root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
26
+ }
27
+
28
+ }(this, function(root, Backbone, _, $) {
10
29
 
11
30
  // Initial Setup
12
31
  // -------------
13
32
 
14
- // Save a reference to the global object (`window` in the browser, `exports`
15
- // on the server).
16
- var root = this;
17
-
18
33
  // Save the previous value of the `Backbone` variable, so that it can be
19
34
  // restored later on, if `noConflict` is used.
20
35
  var previousBackbone = root.Backbone;
@@ -25,25 +40,12 @@
25
40
  var slice = array.slice;
26
41
  var splice = array.splice;
27
42
 
28
- // The top-level namespace. All public Backbone classes and modules will
29
- // be attached to this. Exported for both the browser and the server.
30
- var Backbone;
31
- if (typeof exports !== 'undefined') {
32
- Backbone = exports;
33
- } else {
34
- Backbone = root.Backbone = {};
35
- }
36
-
37
43
  // Current version of the library. Keep in sync with `package.json`.
38
- Backbone.VERSION = '1.1.0';
39
-
40
- // Require Underscore, if we're on the server, and it's not already present.
41
- var _ = root._;
42
- if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
44
+ Backbone.VERSION = '1.1.2';
43
45
 
44
46
  // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
45
47
  // the `$` variable.
46
- Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
48
+ Backbone.$ = $;
47
49
 
48
50
  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
49
51
  // to its previous owner. Returns a reference to this Backbone object.
@@ -109,7 +111,7 @@
109
111
  var retain, ev, events, names, i, l, j, k;
110
112
  if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
111
113
  if (!name && !callback && !context) {
112
- this._events = {};
114
+ this._events = void 0;
113
115
  return this;
114
116
  }
115
117
  names = name ? [name] : _.keys(this._events);
@@ -205,7 +207,7 @@
205
207
  case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
206
208
  case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
207
209
  case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
208
- default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
210
+ default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
209
211
  }
210
212
  };
211
213
 
@@ -350,7 +352,7 @@
350
352
 
351
353
  // Trigger all relevant attribute changes.
352
354
  if (!silent) {
353
- if (changes.length) this._pending = true;
355
+ if (changes.length) this._pending = options;
354
356
  for (var i = 0, l = changes.length; i < l; i++) {
355
357
  this.trigger('change:' + changes[i], this, current[changes[i]], options);
356
358
  }
@@ -361,6 +363,7 @@
361
363
  if (changing) return this;
362
364
  if (!silent) {
363
365
  while (this._pending) {
366
+ options = this._pending;
364
367
  this._pending = false;
365
368
  this.trigger('change', this, options);
366
369
  }
@@ -528,9 +531,12 @@
528
531
  // using Backbone's restful methods, override this to change the endpoint
529
532
  // that will be called.
530
533
  url: function() {
531
- var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
534
+ var base =
535
+ _.result(this, 'urlRoot') ||
536
+ _.result(this.collection, 'url') ||
537
+ urlError();
532
538
  if (this.isNew()) return base;
533
- return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
539
+ return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
534
540
  },
535
541
 
536
542
  // **parse** converts a response into the hash of attributes to be `set` on
@@ -546,7 +552,7 @@
546
552
 
547
553
  // A model is new if it has never been saved to the server, and lacks an id.
548
554
  isNew: function() {
549
- return this.id == null;
555
+ return !this.has(this.idAttribute);
550
556
  },
551
557
 
552
558
  // Check if the model is currently in a valid state.
@@ -650,7 +656,7 @@
650
656
  options.index = index;
651
657
  model.trigger('remove', model, this, options);
652
658
  }
653
- this._removeReference(model);
659
+ this._removeReference(model, options);
654
660
  }
655
661
  return singular ? models[0] : models;
656
662
  },
@@ -676,11 +682,11 @@
676
682
  // Turn bare objects into model references, and prevent invalid models
677
683
  // from being added.
678
684
  for (i = 0, l = models.length; i < l; i++) {
679
- attrs = models[i];
685
+ attrs = models[i] || {};
680
686
  if (attrs instanceof Model) {
681
687
  id = model = attrs;
682
688
  } else {
683
- id = attrs[targetModel.prototype.idAttribute];
689
+ id = attrs[targetModel.prototype.idAttribute || 'id'];
684
690
  }
685
691
 
686
692
  // If a duplicate is found, prevent it from being added and
@@ -700,14 +706,13 @@
700
706
  model = models[i] = this._prepareModel(attrs, options);
701
707
  if (!model) continue;
702
708
  toAdd.push(model);
703
-
704
- // Listen to added models' events, and index models for lookup by
705
- // `id` and by `cid`.
706
- model.on('all', this._onModelEvent, this);
707
- this._byId[model.cid] = model;
708
- if (model.id != null) this._byId[model.id] = model;
709
+ this._addReference(model, options);
709
710
  }
710
- if (order) order.push(existing || model);
711
+
712
+ // Do not add multiple models with the same `id`.
713
+ model = existing || model;
714
+ if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
715
+ modelMap[model.id] = true;
711
716
  }
712
717
 
713
718
  // Remove nonexistent models if appropriate.
@@ -757,7 +762,7 @@
757
762
  reset: function(models, options) {
758
763
  options || (options = {});
759
764
  for (var i = 0, l = this.models.length; i < l; i++) {
760
- this._removeReference(this.models[i]);
765
+ this._removeReference(this.models[i], options);
761
766
  }
762
767
  options.previousModels = this.models;
763
768
  this._reset();
@@ -798,7 +803,7 @@
798
803
  // Get a model from the set by id.
799
804
  get: function(obj) {
800
805
  if (obj == null) return void 0;
801
- return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj];
806
+ return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
802
807
  },
803
808
 
804
809
  // Get the model at the given index.
@@ -874,7 +879,7 @@
874
879
  if (!options.wait) this.add(model, options);
875
880
  var collection = this;
876
881
  var success = options.success;
877
- options.success = function(model, resp, options) {
882
+ options.success = function(model, resp) {
878
883
  if (options.wait) collection.add(model, options);
879
884
  if (success) success(model, resp, options);
880
885
  };
@@ -904,10 +909,7 @@
904
909
  // Prepare a hash of attributes (or other model) to be added to this
905
910
  // collection.
906
911
  _prepareModel: function(attrs, options) {
907
- if (attrs instanceof Model) {
908
- if (!attrs.collection) attrs.collection = this;
909
- return attrs;
910
- }
912
+ if (attrs instanceof Model) return attrs;
911
913
  options = options ? _.clone(options) : {};
912
914
  options.collection = this;
913
915
  var model = new this.model(attrs, options);
@@ -916,8 +918,16 @@
916
918
  return false;
917
919
  },
918
920
 
921
+ // Internal method to create a model's ties to a collection.
922
+ _addReference: function(model, options) {
923
+ this._byId[model.cid] = model;
924
+ if (model.id != null) this._byId[model.id] = model;
925
+ if (!model.collection) model.collection = this;
926
+ model.on('all', this._onModelEvent, this);
927
+ },
928
+
919
929
  // Internal method to sever a model's ties to a collection.
920
- _removeReference: function(model) {
930
+ _removeReference: function(model, options) {
921
931
  if (this === model.collection) delete model.collection;
922
932
  model.off('all', this._onModelEvent, this);
923
933
  },
@@ -946,7 +956,7 @@
946
956
  'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
947
957
  'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
948
958
  'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
949
- 'lastIndexOf', 'isEmpty', 'chain'];
959
+ 'lastIndexOf', 'isEmpty', 'chain', 'sample'];
950
960
 
951
961
  // Mix in each Underscore method as a proxy to `Collection#models`.
952
962
  _.each(methods, function(method) {
@@ -958,7 +968,7 @@
958
968
  });
959
969
 
960
970
  // Underscore methods that take a property name as an argument.
961
- var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
971
+ var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
962
972
 
963
973
  // Use attributes instead of properties.
964
974
  _.each(attributeMethods, function(method) {
@@ -1180,7 +1190,9 @@
1180
1190
  return xhr;
1181
1191
  };
1182
1192
 
1183
- var noXhrPatch = typeof window !== 'undefined' && !!window.ActiveXObject && !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
1193
+ var noXhrPatch =
1194
+ typeof window !== 'undefined' && !!window.ActiveXObject &&
1195
+ !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
1184
1196
 
1185
1197
  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
1186
1198
  var methodMap = {
@@ -1239,7 +1251,7 @@
1239
1251
  var router = this;
1240
1252
  Backbone.history.route(route, function(fragment) {
1241
1253
  var args = router._extractParameters(route, fragment);
1242
- callback && callback.apply(router, args);
1254
+ router.execute(callback, args);
1243
1255
  router.trigger.apply(router, ['route:' + name].concat(args));
1244
1256
  router.trigger('route', name, args);
1245
1257
  Backbone.history.trigger('route', router, name, args);
@@ -1247,6 +1259,12 @@
1247
1259
  return this;
1248
1260
  },
1249
1261
 
1262
+ // Execute a route handler with the provided parameters. This is an
1263
+ // excellent place to do pre-route setup or post-route cleanup.
1264
+ execute: function(callback, args) {
1265
+ if (callback) callback.apply(this, args);
1266
+ },
1267
+
1250
1268
  // Simple proxy to `Backbone.history` to save a fragment into the history.
1251
1269
  navigate: function(fragment, options) {
1252
1270
  Backbone.history.navigate(fragment, options);
@@ -1271,10 +1289,10 @@
1271
1289
  route = route.replace(escapeRegExp, '\\$&')
1272
1290
  .replace(optionalParam, '(?:$1)?')
1273
1291
  .replace(namedParam, function(match, optional) {
1274
- return optional ? match : '([^\/]+)';
1292
+ return optional ? match : '([^/?]+)';
1275
1293
  })
1276
- .replace(splatParam, '(.*?)');
1277
- return new RegExp('^' + route + '$');
1294
+ .replace(splatParam, '([^?]*?)');
1295
+ return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
1278
1296
  },
1279
1297
 
1280
1298
  // Given a route, and a URL fragment that it matches, return the array of
@@ -1282,7 +1300,9 @@
1282
1300
  // treated as `null` to normalize cross-browser behavior.
1283
1301
  _extractParameters: function(route, fragment) {
1284
1302
  var params = route.exec(fragment).slice(1);
1285
- return _.map(params, function(param) {
1303
+ return _.map(params, function(param, i) {
1304
+ // Don't decode the search params.
1305
+ if (i === params.length - 1) return param || null;
1286
1306
  return param ? decodeURIComponent(param) : null;
1287
1307
  });
1288
1308
  }
@@ -1320,8 +1340,8 @@
1320
1340
  // Cached regex for removing a trailing slash.
1321
1341
  var trailingSlash = /\/$/;
1322
1342
 
1323
- // Cached regex for stripping urls of hash and query.
1324
- var pathStripper = /[?#].*$/;
1343
+ // Cached regex for stripping urls of hash.
1344
+ var pathStripper = /#.*$/;
1325
1345
 
1326
1346
  // Has the history handling already been started?
1327
1347
  History.started = false;
@@ -1333,6 +1353,11 @@
1333
1353
  // twenty times a second.
1334
1354
  interval: 50,
1335
1355
 
1356
+ // Are we at the app root?
1357
+ atRoot: function() {
1358
+ return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
1359
+ },
1360
+
1336
1361
  // Gets the true hash value. Cannot use location.hash directly due to bug
1337
1362
  // in Firefox where location.hash will always be decoded.
1338
1363
  getHash: function(window) {
@@ -1345,7 +1370,7 @@
1345
1370
  getFragment: function(fragment, forcePushState) {
1346
1371
  if (fragment == null) {
1347
1372
  if (this._hasPushState || !this._wantsHashChange || forcePushState) {
1348
- fragment = this.location.pathname;
1373
+ fragment = decodeURI(this.location.pathname + this.location.search);
1349
1374
  var root = this.root.replace(trailingSlash, '');
1350
1375
  if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
1351
1376
  } else {
@@ -1376,7 +1401,8 @@
1376
1401
  this.root = ('/' + this.root + '/').replace(rootStripper, '/');
1377
1402
 
1378
1403
  if (oldIE && this._wantsHashChange) {
1379
- this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
1404
+ var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
1405
+ this.iframe = frame.hide().appendTo('body')[0].contentWindow;
1380
1406
  this.navigate(fragment);
1381
1407
  }
1382
1408
 
@@ -1394,7 +1420,6 @@
1394
1420
  // opened by a non-pushState browser.
1395
1421
  this.fragment = fragment;
1396
1422
  var loc = this.location;
1397
- var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
1398
1423
 
1399
1424
  // Transition from hashChange to pushState or vice versa if both are
1400
1425
  // requested.
@@ -1402,17 +1427,17 @@
1402
1427
 
1403
1428
  // If we've started off with a route from a `pushState`-enabled
1404
1429
  // browser, but we're currently in a browser that doesn't support it...
1405
- if (!this._hasPushState && !atRoot) {
1430
+ if (!this._hasPushState && !this.atRoot()) {
1406
1431
  this.fragment = this.getFragment(null, true);
1407
- this.location.replace(this.root + this.location.search + '#' + this.fragment);
1432
+ this.location.replace(this.root + '#' + this.fragment);
1408
1433
  // Return immediately as browser will do redirect to new url
1409
1434
  return true;
1410
1435
 
1411
1436
  // Or if we've started out with a hash-based route, but we're currently
1412
1437
  // in a browser where it could be `pushState`-based instead...
1413
- } else if (this._hasPushState && atRoot && loc.hash) {
1438
+ } else if (this._hasPushState && this.atRoot() && loc.hash) {
1414
1439
  this.fragment = this.getHash().replace(routeStripper, '');
1415
- this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
1440
+ this.history.replaceState({}, document.title, this.root + this.fragment);
1416
1441
  }
1417
1442
 
1418
1443
  }
@@ -1424,7 +1449,7 @@
1424
1449
  // but possibly useful for unit testing Routers.
1425
1450
  stop: function() {
1426
1451
  Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
1427
- clearInterval(this._checkUrlInterval);
1452
+ if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
1428
1453
  History.started = false;
1429
1454
  },
1430
1455
 
@@ -1472,7 +1497,7 @@
1472
1497
 
1473
1498
  var url = this.root + (fragment = this.getFragment(fragment || ''));
1474
1499
 
1475
- // Strip the fragment of the query and hash for matching.
1500
+ // Strip the hash for matching.
1476
1501
  fragment = fragment.replace(pathStripper, '');
1477
1502
 
1478
1503
  if (this.fragment === fragment) return;
@@ -1578,4 +1603,6 @@
1578
1603
  };
1579
1604
  };
1580
1605
 
1581
- }).call(this);
1606
+ return Backbone;
1607
+
1608
+ }));
@@ -1,6 +1,6 @@
1
- // Underscore.js 1.5.2
1
+ // Underscore.js 1.6.0
2
2
  // http://underscorejs.org
3
- // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3
+ // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
4
  // Underscore may be freely distributed under the MIT license.
5
5
 
6
6
  (function() {
@@ -65,7 +65,7 @@
65
65
  }
66
66
 
67
67
  // Current version.
68
- _.VERSION = '1.5.2';
68
+ _.VERSION = '1.6.0';
69
69
 
70
70
  // Collection Functions
71
71
  // --------------------
@@ -74,7 +74,7 @@
74
74
  // Handles objects with the built-in `forEach`, arrays, and raw objects.
75
75
  // Delegates to **ECMAScript 5**'s native `forEach` if available.
76
76
  var each = _.each = _.forEach = function(obj, iterator, context) {
77
- if (obj == null) return;
77
+ if (obj == null) return obj;
78
78
  if (nativeForEach && obj.forEach === nativeForEach) {
79
79
  obj.forEach(iterator, context);
80
80
  } else if (obj.length === +obj.length) {
@@ -87,6 +87,7 @@
87
87
  if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
88
88
  }
89
89
  }
90
+ return obj;
90
91
  };
91
92
 
92
93
  // Return the results of applying the iterator to each element.
@@ -152,10 +153,10 @@
152
153
  };
153
154
 
154
155
  // Return the first value which passes a truth test. Aliased as `detect`.
155
- _.find = _.detect = function(obj, iterator, context) {
156
+ _.find = _.detect = function(obj, predicate, context) {
156
157
  var result;
157
158
  any(obj, function(value, index, list) {
158
- if (iterator.call(context, value, index, list)) {
159
+ if (predicate.call(context, value, index, list)) {
159
160
  result = value;
160
161
  return true;
161
162
  }
@@ -166,33 +167,33 @@
166
167
  // Return all the elements that pass a truth test.
167
168
  // Delegates to **ECMAScript 5**'s native `filter` if available.
168
169
  // Aliased as `select`.
169
- _.filter = _.select = function(obj, iterator, context) {
170
+ _.filter = _.select = function(obj, predicate, context) {
170
171
  var results = [];
171
172
  if (obj == null) return results;
172
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
173
+ if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
173
174
  each(obj, function(value, index, list) {
174
- if (iterator.call(context, value, index, list)) results.push(value);
175
+ if (predicate.call(context, value, index, list)) results.push(value);
175
176
  });
176
177
  return results;
177
178
  };
178
179
 
179
180
  // Return all the elements for which a truth test fails.
180
- _.reject = function(obj, iterator, context) {
181
+ _.reject = function(obj, predicate, context) {
181
182
  return _.filter(obj, function(value, index, list) {
182
- return !iterator.call(context, value, index, list);
183
+ return !predicate.call(context, value, index, list);
183
184
  }, context);
184
185
  };
185
186
 
186
187
  // Determine whether all of the elements match a truth test.
187
188
  // Delegates to **ECMAScript 5**'s native `every` if available.
188
189
  // Aliased as `all`.
189
- _.every = _.all = function(obj, iterator, context) {
190
- iterator || (iterator = _.identity);
190
+ _.every = _.all = function(obj, predicate, context) {
191
+ predicate || (predicate = _.identity);
191
192
  var result = true;
192
193
  if (obj == null) return result;
193
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
194
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
194
195
  each(obj, function(value, index, list) {
195
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
196
+ if (!(result = result && predicate.call(context, value, index, list))) return breaker;
196
197
  });
197
198
  return !!result;
198
199
  };
@@ -200,13 +201,13 @@
200
201
  // Determine if at least one element in the object matches a truth test.
201
202
  // Delegates to **ECMAScript 5**'s native `some` if available.
202
203
  // Aliased as `any`.
203
- var any = _.some = _.any = function(obj, iterator, context) {
204
- iterator || (iterator = _.identity);
204
+ var any = _.some = _.any = function(obj, predicate, context) {
205
+ predicate || (predicate = _.identity);
205
206
  var result = false;
206
207
  if (obj == null) return result;
207
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
208
+ if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
208
209
  each(obj, function(value, index, list) {
209
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
210
+ if (result || (result = predicate.call(context, value, index, list))) return breaker;
210
211
  });
211
212
  return !!result;
212
213
  };
@@ -232,25 +233,19 @@
232
233
 
233
234
  // Convenience version of a common use case of `map`: fetching a property.
234
235
  _.pluck = function(obj, key) {
235
- return _.map(obj, function(value){ return value[key]; });
236
+ return _.map(obj, _.property(key));
236
237
  };
237
238
 
238
239
  // Convenience version of a common use case of `filter`: selecting only objects
239
240
  // containing specific `key:value` pairs.
240
- _.where = function(obj, attrs, first) {
241
- if (_.isEmpty(attrs)) return first ? void 0 : [];
242
- return _[first ? 'find' : 'filter'](obj, function(value) {
243
- for (var key in attrs) {
244
- if (attrs[key] !== value[key]) return false;
245
- }
246
- return true;
247
- });
241
+ _.where = function(obj, attrs) {
242
+ return _.filter(obj, _.matches(attrs));
248
243
  };
249
244
 
250
245
  // Convenience version of a common use case of `find`: getting the first object
251
246
  // containing specific `key:value` pairs.
252
247
  _.findWhere = function(obj, attrs) {
253
- return _.where(obj, attrs, true);
248
+ return _.find(obj, _.matches(attrs));
254
249
  };
255
250
 
256
251
  // Return the maximum element or (element-based computation).
@@ -260,13 +255,15 @@
260
255
  if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
261
256
  return Math.max.apply(Math, obj);
262
257
  }
263
- if (!iterator && _.isEmpty(obj)) return -Infinity;
264
- var result = {computed : -Infinity, value: -Infinity};
258
+ var result = -Infinity, lastComputed = -Infinity;
265
259
  each(obj, function(value, index, list) {
266
260
  var computed = iterator ? iterator.call(context, value, index, list) : value;
267
- computed > result.computed && (result = {value : value, computed : computed});
261
+ if (computed > lastComputed) {
262
+ result = value;
263
+ lastComputed = computed;
264
+ }
268
265
  });
269
- return result.value;
266
+ return result;
270
267
  };
271
268
 
272
269
  // Return the minimum element (or element-based computation).
@@ -274,17 +271,19 @@
274
271
  if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
275
272
  return Math.min.apply(Math, obj);
276
273
  }
277
- if (!iterator && _.isEmpty(obj)) return Infinity;
278
- var result = {computed : Infinity, value: Infinity};
274
+ var result = Infinity, lastComputed = Infinity;
279
275
  each(obj, function(value, index, list) {
280
276
  var computed = iterator ? iterator.call(context, value, index, list) : value;
281
- computed < result.computed && (result = {value : value, computed : computed});
277
+ if (computed < lastComputed) {
278
+ result = value;
279
+ lastComputed = computed;
280
+ }
282
281
  });
283
- return result.value;
282
+ return result;
284
283
  };
285
284
 
286
285
  // Shuffle an array, using the modern version of the
287
- // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
286
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/FisherYates_shuffle).
288
287
  _.shuffle = function(obj) {
289
288
  var rand;
290
289
  var index = 0;
@@ -297,11 +296,12 @@
297
296
  return shuffled;
298
297
  };
299
298
 
300
- // Sample **n** random values from an array.
301
- // If **n** is not specified, returns a single random element from the array.
299
+ // Sample **n** random values from a collection.
300
+ // If **n** is not specified, returns a single random element.
302
301
  // The internal `guard` argument allows it to work with `map`.
303
302
  _.sample = function(obj, n, guard) {
304
- if (arguments.length < 2 || guard) {
303
+ if (n == null || guard) {
304
+ if (obj.length !== +obj.length) obj = _.values(obj);
305
305
  return obj[_.random(obj.length - 1)];
306
306
  }
307
307
  return _.shuffle(obj).slice(0, Math.max(0, n));
@@ -309,12 +309,14 @@
309
309
 
310
310
  // An internal function to generate lookup iterators.
311
311
  var lookupIterator = function(value) {
312
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
312
+ if (value == null) return _.identity;
313
+ if (_.isFunction(value)) return value;
314
+ return _.property(value);
313
315
  };
314
316
 
315
317
  // Sort the object's values by a criterion produced by an iterator.
316
- _.sortBy = function(obj, value, context) {
317
- var iterator = lookupIterator(value);
318
+ _.sortBy = function(obj, iterator, context) {
319
+ iterator = lookupIterator(iterator);
318
320
  return _.pluck(_.map(obj, function(value, index, list) {
319
321
  return {
320
322
  value: value,
@@ -334,9 +336,9 @@
334
336
 
335
337
  // An internal function used for aggregate "group by" operations.
336
338
  var group = function(behavior) {
337
- return function(obj, value, context) {
339
+ return function(obj, iterator, context) {
338
340
  var result = {};
339
- var iterator = value == null ? _.identity : lookupIterator(value);
341
+ iterator = lookupIterator(iterator);
340
342
  each(obj, function(value, index) {
341
343
  var key = iterator.call(context, value, index, obj);
342
344
  behavior(result, key, value);
@@ -348,7 +350,7 @@
348
350
  // Groups the object's values by a criterion. Pass either a string attribute
349
351
  // to group by, or a function that returns the criterion.
350
352
  _.groupBy = group(function(result, key, value) {
351
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
353
+ _.has(result, key) ? result[key].push(value) : result[key] = [value];
352
354
  });
353
355
 
354
356
  // Indexes the object's values by a criterion, similar to `groupBy`, but for
@@ -367,7 +369,7 @@
367
369
  // Use a comparator function to figure out the smallest index at which
368
370
  // an object should be inserted so as to maintain order. Uses binary search.
369
371
  _.sortedIndex = function(array, obj, iterator, context) {
370
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
372
+ iterator = lookupIterator(iterator);
371
373
  var value = iterator.call(context, obj);
372
374
  var low = 0, high = array.length;
373
375
  while (low < high) {
@@ -399,7 +401,9 @@
399
401
  // allows it to work with `_.map`.
400
402
  _.first = _.head = _.take = function(array, n, guard) {
401
403
  if (array == null) return void 0;
402
- return (n == null) || guard ? array[0] : slice.call(array, 0, n);
404
+ if ((n == null) || guard) return array[0];
405
+ if (n < 0) return [];
406
+ return slice.call(array, 0, n);
403
407
  };
404
408
 
405
409
  // Returns everything but the last entry of the array. Especially useful on
@@ -414,11 +418,8 @@
414
418
  // values in the array. The **guard** check allows it to work with `_.map`.
415
419
  _.last = function(array, n, guard) {
416
420
  if (array == null) return void 0;
417
- if ((n == null) || guard) {
418
- return array[array.length - 1];
419
- } else {
420
- return slice.call(array, Math.max(array.length - n, 0));
421
- }
421
+ if ((n == null) || guard) return array[array.length - 1];
422
+ return slice.call(array, Math.max(array.length - n, 0));
422
423
  };
423
424
 
424
425
  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
@@ -459,6 +460,16 @@
459
460
  return _.difference(array, slice.call(arguments, 1));
460
461
  };
461
462
 
463
+ // Split an array into two arrays: one whose elements all satisfy the given
464
+ // predicate, and one whose elements all do not satisfy the predicate.
465
+ _.partition = function(array, predicate) {
466
+ var pass = [], fail = [];
467
+ each(array, function(elem) {
468
+ (predicate(elem) ? pass : fail).push(elem);
469
+ });
470
+ return [pass, fail];
471
+ };
472
+
462
473
  // Produce a duplicate-free version of the array. If the array has already
463
474
  // been sorted, you have the option of using a faster algorithm.
464
475
  // Aliased as `unique`.
@@ -492,7 +503,7 @@
492
503
  var rest = slice.call(arguments, 1);
493
504
  return _.filter(_.uniq(array), function(item) {
494
505
  return _.every(rest, function(other) {
495
- return _.indexOf(other, item) >= 0;
506
+ return _.contains(other, item);
496
507
  });
497
508
  });
498
509
  };
@@ -507,7 +518,7 @@
507
518
  // Zip together multiple lists into a single array -- elements that share
508
519
  // an index go together.
509
520
  _.zip = function() {
510
- var length = _.max(_.pluck(arguments, "length").concat(0));
521
+ var length = _.max(_.pluck(arguments, 'length').concat(0));
511
522
  var results = new Array(length);
512
523
  for (var i = 0; i < length; i++) {
513
524
  results[i] = _.pluck(arguments, '' + i);
@@ -613,19 +624,27 @@
613
624
  };
614
625
 
615
626
  // Partially apply a function by creating a version that has had some of its
616
- // arguments pre-filled, without changing its dynamic `this` context.
627
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
628
+ // as a placeholder, allowing any combination of arguments to be pre-filled.
617
629
  _.partial = function(func) {
618
- var args = slice.call(arguments, 1);
630
+ var boundArgs = slice.call(arguments, 1);
619
631
  return function() {
620
- return func.apply(this, args.concat(slice.call(arguments)));
632
+ var position = 0;
633
+ var args = boundArgs.slice();
634
+ for (var i = 0, length = args.length; i < length; i++) {
635
+ if (args[i] === _) args[i] = arguments[position++];
636
+ }
637
+ while (position < arguments.length) args.push(arguments[position++]);
638
+ return func.apply(this, args);
621
639
  };
622
640
  };
623
641
 
624
- // Bind all of an object's methods to that object. Useful for ensuring that
625
- // all callbacks defined on an object belong to it.
642
+ // Bind a number of an object's methods to that object. Remaining arguments
643
+ // are the method names to be bound. Useful for ensuring that all callbacks
644
+ // defined on an object belong to it.
626
645
  _.bindAll = function(obj) {
627
646
  var funcs = slice.call(arguments, 1);
628
- if (funcs.length === 0) throw new Error("bindAll must be passed function names");
647
+ if (funcs.length === 0) throw new Error('bindAll must be passed function names');
629
648
  each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
630
649
  return obj;
631
650
  };
@@ -664,12 +683,13 @@
664
683
  var previous = 0;
665
684
  options || (options = {});
666
685
  var later = function() {
667
- previous = options.leading === false ? 0 : new Date;
686
+ previous = options.leading === false ? 0 : _.now();
668
687
  timeout = null;
669
688
  result = func.apply(context, args);
689
+ context = args = null;
670
690
  };
671
691
  return function() {
672
- var now = new Date;
692
+ var now = _.now();
673
693
  if (!previous && options.leading === false) previous = now;
674
694
  var remaining = wait - (now - previous);
675
695
  context = this;
@@ -679,6 +699,7 @@
679
699
  timeout = null;
680
700
  previous = now;
681
701
  result = func.apply(context, args);
702
+ context = args = null;
682
703
  } else if (!timeout && options.trailing !== false) {
683
704
  timeout = setTimeout(later, remaining);
684
705
  }
@@ -692,24 +713,33 @@
692
713
  // leading edge, instead of the trailing.
693
714
  _.debounce = function(func, wait, immediate) {
694
715
  var timeout, args, context, timestamp, result;
716
+
717
+ var later = function() {
718
+ var last = _.now() - timestamp;
719
+ if (last < wait) {
720
+ timeout = setTimeout(later, wait - last);
721
+ } else {
722
+ timeout = null;
723
+ if (!immediate) {
724
+ result = func.apply(context, args);
725
+ context = args = null;
726
+ }
727
+ }
728
+ };
729
+
695
730
  return function() {
696
731
  context = this;
697
732
  args = arguments;
698
- timestamp = new Date();
699
- var later = function() {
700
- var last = (new Date()) - timestamp;
701
- if (last < wait) {
702
- timeout = setTimeout(later, wait - last);
703
- } else {
704
- timeout = null;
705
- if (!immediate) result = func.apply(context, args);
706
- }
707
- };
733
+ timestamp = _.now();
708
734
  var callNow = immediate && !timeout;
709
735
  if (!timeout) {
710
736
  timeout = setTimeout(later, wait);
711
737
  }
712
- if (callNow) result = func.apply(context, args);
738
+ if (callNow) {
739
+ result = func.apply(context, args);
740
+ context = args = null;
741
+ }
742
+
713
743
  return result;
714
744
  };
715
745
  };
@@ -731,11 +761,7 @@
731
761
  // allowing you to adjust arguments, run code before and after, and
732
762
  // conditionally execute the original function.
733
763
  _.wrap = function(func, wrapper) {
734
- return function() {
735
- var args = [func];
736
- push.apply(args, arguments);
737
- return wrapper.apply(this, args);
738
- };
764
+ return _.partial(wrapper, func);
739
765
  };
740
766
 
741
767
  // Returns a function that is the composition of a list of functions, each
@@ -765,8 +791,9 @@
765
791
 
766
792
  // Retrieve the names of an object's properties.
767
793
  // Delegates to **ECMAScript 5**'s native `Object.keys`
768
- _.keys = nativeKeys || function(obj) {
769
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
794
+ _.keys = function(obj) {
795
+ if (!_.isObject(obj)) return [];
796
+ if (nativeKeys) return nativeKeys(obj);
770
797
  var keys = [];
771
798
  for (var key in obj) if (_.has(obj, key)) keys.push(key);
772
799
  return keys;
@@ -921,7 +948,8 @@
921
948
  // from different frames are.
922
949
  var aCtor = a.constructor, bCtor = b.constructor;
923
950
  if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
924
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
951
+ _.isFunction(bCtor) && (bCtor instanceof bCtor))
952
+ && ('constructor' in a && 'constructor' in b)) {
925
953
  return false;
926
954
  }
927
955
  // Add the first object to the stack of traversed objects.
@@ -1061,6 +1089,30 @@
1061
1089
  return value;
1062
1090
  };
1063
1091
 
1092
+ _.constant = function(value) {
1093
+ return function () {
1094
+ return value;
1095
+ };
1096
+ };
1097
+
1098
+ _.property = function(key) {
1099
+ return function(obj) {
1100
+ return obj[key];
1101
+ };
1102
+ };
1103
+
1104
+ // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
1105
+ _.matches = function(attrs) {
1106
+ return function(obj) {
1107
+ if (obj === attrs) return true; //avoid comparing an object to itself.
1108
+ for (var key in attrs) {
1109
+ if (attrs[key] !== obj[key])
1110
+ return false;
1111
+ }
1112
+ return true;
1113
+ }
1114
+ };
1115
+
1064
1116
  // Run a function **n** times.
1065
1117
  _.times = function(n, iterator, context) {
1066
1118
  var accum = Array(Math.max(0, n));
@@ -1077,6 +1129,9 @@
1077
1129
  return min + Math.floor(Math.random() * (max - min + 1));
1078
1130
  };
1079
1131
 
1132
+ // A (possibly faster) way to get the current timestamp as an integer.
1133
+ _.now = Date.now || function() { return new Date().getTime(); };
1134
+
1080
1135
  // List of HTML entities for escaping.
1081
1136
  var entityMap = {
1082
1137
  escape: {
@@ -1273,4 +1328,16 @@
1273
1328
 
1274
1329
  });
1275
1330
 
1331
+ // AMD registration happens at the end for compatibility with AMD loaders
1332
+ // that may not enforce next-turn semantics on modules. Even though general
1333
+ // practice for AMD registration is to be anonymous, underscore registers
1334
+ // as a named module because, like jQuery, it is a base library that is
1335
+ // popular enough to be bundled in a third party lib, but not be part of
1336
+ // an AMD load request. Those cases could generate an error when an
1337
+ // anonymous define() is called outside of a loader request.
1338
+ if (typeof define === 'function' && define.amd) {
1339
+ define('underscore', [], function() {
1340
+ return _;
1341
+ });
1342
+ }
1276
1343
  }).call(this);
metadata CHANGED
@@ -1,27 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backbone-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Alexander Flatter
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-01-29 00:00:00.000000000 Z
12
+ date: 2014-06-11 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rails
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: 3.0.0
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: 3.0.0
27
30
  description: Ships backbone and underscore to your Rails 3.1 application through the
@@ -44,25 +47,26 @@ files:
44
47
  - README.md
45
48
  homepage: https://github.com/aflatter/backbone-rails
46
49
  licenses: []
47
- metadata: {}
48
50
  post_install_message:
49
51
  rdoc_options: []
50
52
  require_paths:
51
53
  - lib
52
54
  required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
53
56
  requirements:
54
- - - '>='
57
+ - - ! '>='
55
58
  - !ruby/object:Gem::Version
56
59
  version: '0'
57
60
  required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
58
62
  requirements:
59
- - - '>='
63
+ - - ! '>='
60
64
  - !ruby/object:Gem::Version
61
65
  version: 1.3.6
62
66
  requirements: []
63
67
  rubyforge_project:
64
- rubygems_version: 2.0.7
68
+ rubygems_version: 1.8.23
65
69
  signing_key:
66
- specification_version: 4
70
+ specification_version: 3
67
71
  summary: backbone and underscore for Rails
68
72
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 1915d7968e842a3fb966a315c8746acdc28d5478
4
- data.tar.gz: 29859b0847514c85434204e33060bf08c8c6b3c6
5
- SHA512:
6
- metadata.gz: 7f81db49eb8c5c109d1ae6b4d75efe120f1d5447a66dbb8a18cf028c0d2d618a2a0629e7a9b219ca694d6d9dd0ae650f805c089385432b259cee2cbaba033385
7
- data.tar.gz: 731a21c6332295da0dc143a3c5454bc3dd117d9dad3879640290620465f5e57c6e8edd1dbba8809f8b7ad5f436a3036cb3b7998ccc004372ae6a0b72b9c23ecc