js_stack 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5dba30cdf10a542fc2075be0e211dc211082f1f4
4
- data.tar.gz: 672fe6206d90b5f212b986b0b768016046a89960
3
+ metadata.gz: 14ebafa9d5b48ce3adf24eb32eaf3669f1b1c3cc
4
+ data.tar.gz: bc8aecf8b725ee74693d41cacba95a5f384e6ffa
5
5
  SHA512:
6
- metadata.gz: b9fd43d12fa92b7d590a572d9d9d2ec13bd4d27f6f3d1577e1fc299ed3a9c6e4432791e32d5d50bfca63cae6749c84d25825fcdd4c5a62ece74973afd927682e
7
- data.tar.gz: fd9ca35a353a30a01aa33fbfcab7323ee7e4255d98169613b3769a0196b9592678daca64aa0ce74203972ab48303fe47e5376cb329f2b0f1215f4727d416e51d
6
+ metadata.gz: c118177073fba0f56a3007cb853d3f716bb31314d466e002cd145a1eae1456ff47d22c737349f1117a1169f91aa27c499490605e7a807667c00f7d39eda0cfd8
7
+ data.tar.gz: fbbbf80f1f6dcaf65851e9e125c84cb47491314ebb1f53084b9b526b9cc04515d6e21899be0e933e98799d997b89c8b332ec47e5362c92662a007456cac57674
data/CHANGELOG.md CHANGED
@@ -11,6 +11,16 @@
11
11
  * backbone.deepmodel - [changelog](https://github.com/powmedia/backbone-deep-model#changelog)
12
12
  * backbone-virtualcollection - [changelog](https://github.com/p3drosola/Backbone.VirtualCollection#changelog)
13
13
 
14
+ ## master
15
+
16
+ ## v0.3.0
17
+
18
+ * updated marionette 1.4.1 -> 1.5.1 [@gvl]
19
+ * updated backbone.validation 0.9.0 -> 0.9.1 [@gvl]
20
+ * updated backbone-pageable 1.4.3 -> 1.4.5 [@gvl]
21
+ * bump momentjs-rails 2.4.0 -> 2.5.0 [@gvl]
22
+ * updated backbone-associations 0.5.4 -> 0.5.5 [@gvl]
23
+
14
24
  ## v0.2.0
15
25
 
16
26
  * updated *backbone-stickit* 0.6.3 -> 0.7.0 [@gvl]
data/README.md CHANGED
@@ -42,7 +42,7 @@ http://backbonejs.org/
42
42
  #= require js_stack/backbone
43
43
  ```
44
44
 
45
- ### marionette.js 1.4.1
45
+ ### marionette.js 1.5.1
46
46
 
47
47
  https://github.com/marionettejs/backbone.marionette/tree/master/docs
48
48
 
@@ -58,7 +58,7 @@ http://nytimes.github.io/backbone.stickit/
58
58
  #= require js_stack/backbone.stickit
59
59
  ```
60
60
 
61
- ### backbone.validation 0.9.0
61
+ ### backbone.validation 0.9.1
62
62
 
63
63
  https://github.com/thedersen/backbone.validation
64
64
 
@@ -67,7 +67,7 @@ https://github.com/thedersen/backbone.validation
67
67
  #= require js_stack/backbone.validation
68
68
  ```
69
69
 
70
- ### backbone-associations 0.5.4
70
+ ### backbone-associations 0.5.5
71
71
 
72
72
  http://dhruvaray.github.io/backbone-associations/
73
73
 
@@ -75,7 +75,7 @@ http://dhruvaray.github.io/backbone-associations/
75
75
  #= require js_stack/backbone.associations
76
76
  ```
77
77
 
78
- ### backbone-pageable 1.4.3
78
+ ### backbone-pageable 1.4.5
79
79
 
80
80
  https://github.com/wyuenho/backbone-pageable
81
81
 
@@ -108,7 +108,7 @@ https://github.com/netzpirat/haml_coffee_assets
108
108
  #= require js_stack/hamlcoffee
109
109
  ```
110
110
 
111
- ### momentjs 2.4.0
111
+ ### momentjs 2.5.0
112
112
 
113
113
  https://github.com/derekprior/momentjs-rails
114
114
 
data/js_stack.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'js_stack/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "js_stack"
8
8
  spec.version = JsStack::VERSION
9
- spec.authors = ["Tomasz Pewiński"]
10
- spec.email = ["pewniak747@gmail.com"]
9
+ spec.authors = ["Tomasz Pewiński", "Igor Dominiak"]
10
+ spec.email = ["pewniak747@gmail.com", "dominiak.igor@gmail.com"]
11
11
  spec.description = "standard SPA stack used at netguru.co"
12
12
  spec.summary = "standard SPA stack used at netguru.co"
13
13
  spec.homepage = "https://github.com/netguru/js_stack"
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "haml_coffee_assets", "~> 1.16"
22
- spec.add_dependency "momentjs-rails", "~> 2.4.0"
22
+ spec.add_dependency "momentjs-rails", "~> 2.5.0"
23
23
  spec.add_dependency "js-routes", "~> 0.9.6"
24
24
 
25
25
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -1,3 +1,3 @@
1
1
  module JsStack
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,581 @@
1
+ //
2
+ // Backbone-associations.js 0.5.5
3
+ //
4
+ // (c) 2013 Dhruva Ray, Jaynti Kanani, Persistent Systems Ltd.
5
+ // Backbone-associations may be freely distributed under the MIT license.
6
+ // For all details and documentation:
7
+ // https://github.com/dhruvaray/backbone-associations/
8
+ //
9
+
10
+ // Initial Setup
11
+ // --------------
12
+ (function () {
13
+ "use strict";
14
+
15
+ // Save a reference to the global object (`window` in the browser, `exports`
16
+ // on the server).
17
+ var root = this;
18
+
19
+ // The top-level namespace. All public Backbone classes and modules will be attached to this.
20
+ // Exported for the browser and CommonJS.
21
+ var _, Backbone, BackboneModel, BackboneCollection, ModelProto,
22
+ CollectionProto, AssociatedModel, pathChecker,
23
+ delimiters, pathSeparator, source;
24
+
25
+ if (typeof exports !== 'undefined') {
26
+ _ = require('underscore');
27
+ Backbone = require('backbone');
28
+ if (typeof module !== 'undefined' && module.exports) {
29
+ module.exports = Backbone;
30
+ }
31
+ exports = Backbone;
32
+ } else {
33
+ _ = root._;
34
+ Backbone = root.Backbone;
35
+ }
36
+ // Create local reference `Model` prototype.
37
+ BackboneModel = Backbone.Model;
38
+ BackboneCollection = Backbone.Collection;
39
+ ModelProto = BackboneModel.prototype;
40
+ CollectionProto = BackboneCollection.prototype;
41
+
42
+ Backbone.Associations = {
43
+ VERSION: "0.5.5"
44
+ };
45
+
46
+ // Define `getter` and `setter` for `separator`
47
+ var getSeparator = function() {
48
+ return pathSeparator;
49
+ };
50
+ // Define `setSeperator`
51
+ var setSeparator = function(value) {
52
+ if (!_.isString(value) || _.size(value) < 1) {
53
+ value = ".";
54
+ }
55
+ // set private properties
56
+ pathSeparator = value;
57
+ pathChecker = new RegExp("[\\" + pathSeparator + "\\[\\]]+", "g");
58
+ delimiters = new RegExp("[^\\" + pathSeparator + "\\[\\]]+", "g");
59
+ };
60
+
61
+ try {
62
+ // Define `SEPERATOR` property to Backbone.Associations
63
+ Object.defineProperty(Backbone.Associations, 'SEPARATOR', {
64
+ enumerable: true,
65
+ get: getSeparator,
66
+ set: setSeparator
67
+ });
68
+ } catch (e) {}
69
+
70
+ // Backbone.AssociatedModel
71
+ // --------------
72
+
73
+ //Add `Many` and `One` relations to Backbone Object.
74
+ Backbone.Associations.Many = Backbone.Many = "Many";
75
+ Backbone.Associations.One = Backbone.One = "One";
76
+ Backbone.Associations.Self = Backbone.Self = "Self";
77
+ // Set default separator
78
+ Backbone.Associations.SEPARATOR = ".";
79
+ Backbone.Associations.getSeparator = getSeparator;
80
+ Backbone.Associations.setSeparator = setSeparator;
81
+
82
+ Backbone.Associations.EVENTS_BUBBLE = true;
83
+ Backbone.Associations.EVENTS_WILDCARD = true;
84
+ Backbone.Associations.EVENTS_NC = true;
85
+
86
+
87
+ setSeparator();
88
+
89
+ // Define `AssociatedModel` (Extends Backbone.Model).
90
+ AssociatedModel = Backbone.AssociatedModel = Backbone.Associations.AssociatedModel = BackboneModel.extend({
91
+ // Define relations with Associated Model.
92
+ relations:undefined,
93
+ // Define `Model` property which can keep track of already fired `events`,
94
+ // and prevent redundant event to be triggered in case of cyclic model graphs.
95
+ _proxyCalls:undefined,
96
+
97
+
98
+ // Get the value of an attribute.
99
+ get:function (attr) {
100
+ var obj = ModelProto.get.call(this, attr);
101
+ return obj ? obj : this._getAttr.apply(this, arguments);
102
+ },
103
+
104
+ // Set a hash of model attributes on the Backbone Model.
105
+ set:function (key, value, options) {
106
+ var attributes, result;
107
+ // Duplicate backbone's behavior to allow separate key/value parameters,
108
+ // instead of a single 'attributes' object.
109
+ if (_.isObject(key) || key == null) {
110
+ attributes = key;
111
+ options = value;
112
+ } else {
113
+ attributes = {};
114
+ attributes[key] = value;
115
+ }
116
+ result = this._set(attributes, options);
117
+ // Trigger events which have been blocked until the entire object graph is updated.
118
+ this._processPendingEvents();
119
+ return result;
120
+
121
+ },
122
+
123
+ // Works with an attribute hash and options + fully qualified paths
124
+ _set:function (attributes, options) {
125
+ var attr, modelMap, modelId, obj, result = this;
126
+ if (!attributes) return this;
127
+ for (attr in attributes) {
128
+ //Create a map for each unique object whose attributes we want to set
129
+ modelMap || (modelMap = {});
130
+ if (attr.match(pathChecker)) {
131
+ var pathTokens = getPathArray(attr), initials = _.initial(pathTokens),
132
+ last = pathTokens[pathTokens.length - 1],
133
+ parentModel = this.get(initials);
134
+ if (parentModel instanceof AssociatedModel) {
135
+ obj = modelMap[parentModel.cid] || (modelMap[parentModel.cid] = {'model':parentModel, 'data':{}});
136
+ obj.data[last] = attributes[attr];
137
+ }
138
+ } else {
139
+ obj = modelMap[this.cid] || (modelMap[this.cid] = {'model':this, 'data':{}});
140
+ obj.data[attr] = attributes[attr];
141
+ }
142
+ }
143
+
144
+ if (modelMap) {
145
+ for (modelId in modelMap) {
146
+ obj = modelMap[modelId];
147
+ this._setAttr.call(obj.model, obj.data, options) || (result = false);
148
+
149
+ }
150
+ } else {
151
+ result = this._setAttr.call(this, attributes, options);
152
+ }
153
+ return result;
154
+
155
+ },
156
+
157
+ // Set a hash of model attributes on the object,
158
+ // fire Backbone `event` with options.
159
+ // It maintains relations between models during the set operation.
160
+ // It also bubbles up child events to the parent.
161
+ _setAttr:function (attributes, options) {
162
+ var attr;
163
+ // Extract attributes and options.
164
+ options || (options = {});
165
+ if (options.unset) for (attr in attributes) attributes[attr] = void 0;
166
+ this.parents = this.parents || [];
167
+
168
+ if (this.relations) {
169
+ // Iterate over `this.relations` and `set` model and collection values
170
+ // if `relations` are available.
171
+ _.each(this.relations, function (relation) {
172
+ var relationKey = relation.key,
173
+ relatedModel = relation.relatedModel,
174
+ collectionType = relation.collectionType,
175
+ activationContext = relation.scope || root,
176
+ map = relation.map,
177
+ currVal = this.attributes[relationKey],
178
+ idKey = currVal && currVal.idAttribute,
179
+ val, relationOptions, data, relationValue, newCtx = false;
180
+
181
+ // Call function if relatedModel is implemented as a function
182
+ if (relatedModel && !(relatedModel.prototype instanceof BackboneModel))
183
+ relatedModel = _.isFunction(relatedModel) ?
184
+ relatedModel.call(this, relation, attributes) :
185
+ relatedModel;
186
+
187
+ // Get class if relation and map is stored as a string.
188
+ if (relatedModel && _.isString(relatedModel)) {
189
+ relatedModel = (relatedModel === Backbone.Self) ?
190
+ this.constructor :
191
+ map2Scope(relatedModel, activationContext);
192
+ }
193
+ collectionType && _.isString(collectionType) &&
194
+ (collectionType = map2Scope(collectionType, activationContext));
195
+ map && _.isString(map) && (map = map2Scope(map, activationContext));
196
+ // Merge in `options` specific to this relation.
197
+ relationOptions = relation.options ? _.extend({}, relation.options, options) : options;
198
+
199
+ if ((!relatedModel) && (!collectionType))
200
+ throw new Error('specify either a relatedModel or collectionType');
201
+
202
+ if (attributes[relationKey]) {
203
+ // Get value of attribute with relation key in `val`.
204
+ val = _.result(attributes, relationKey);
205
+ // Map `val` if a transformation function is provided.
206
+ val = map ? map.call(this, val, collectionType ? collectionType : relatedModel) : val;
207
+
208
+ // If `relation.type` is `Backbone.Many`,
209
+ // Create `Backbone.Collection` with passed data and perform Backbone `set`.
210
+ if (relation.type === Backbone.Many) {
211
+ // `collectionType` of defined `relation` should be instance of `Backbone.Collection`.
212
+ if (collectionType && !collectionType.prototype instanceof BackboneCollection) {
213
+ throw new Error('collectionType must inherit from Backbone.Collection');
214
+ }
215
+
216
+ if (currVal) {
217
+ // Setting this flag will prevent events from firing immediately. That way clients
218
+ // will not get events until the entire object graph is updated.
219
+ currVal._deferEvents = true;
220
+
221
+ // Use Backbone.Collection's `reset` or smart `set` method
222
+ currVal[relationOptions.reset ? 'reset' : 'set'](
223
+ val instanceof BackboneCollection ? val.models : val, relationOptions);
224
+
225
+ data = currVal;
226
+
227
+ } else {
228
+ newCtx = true;
229
+
230
+ if (val instanceof BackboneCollection) {
231
+ data = val;
232
+ } else {
233
+ data = collectionType ?
234
+ new collectionType() : this._createCollection(relatedModel, activationContext);
235
+ data[relationOptions.reset ? 'reset' : 'set'](val, relationOptions);
236
+ }
237
+ }
238
+
239
+ } else if (relation.type === Backbone.One) {
240
+
241
+ if (!relatedModel)
242
+ throw new Error('specify a relatedModel for Backbone.One type');
243
+
244
+ if (!(relatedModel.prototype instanceof Backbone.AssociatedModel))
245
+ throw new Error('specify an AssociatedModel for Backbone.One type');
246
+
247
+ data = val instanceof AssociatedModel ? val : new relatedModel(val, relationOptions);
248
+ //Is the passed in data for the same key?
249
+ if (currVal && data.attributes[idKey] &&
250
+ currVal.attributes[idKey] === data.attributes[idKey]) {
251
+ // Setting this flag will prevent events from firing immediately. That way clients
252
+ // will not get events until the entire object graph is updated.
253
+ currVal._deferEvents = true;
254
+ // Perform the traditional `set` operation
255
+ currVal._set(val instanceof AssociatedModel ? val.attributes : val, relationOptions);
256
+ data = currVal;
257
+ } else {
258
+ newCtx = true;
259
+ }
260
+
261
+ } else {
262
+ throw new Error('type attribute must be specified and have the values Backbone.One or Backbone.Many');
263
+ }
264
+
265
+
266
+ attributes[relationKey] = data;
267
+ relationValue = data;
268
+
269
+ // Add proxy events to respective parents.
270
+ // Only add callback if not defined or new Ctx has been identified.
271
+ if (newCtx || (relationValue && !relationValue._proxyCallback)) {
272
+ relationValue._proxyCallback = function () {
273
+ return Backbone.Associations.EVENTS_BUBBLE &&
274
+ this._bubbleEvent.call(this, relationKey, relationValue, arguments);
275
+ };
276
+ relationValue.on("all", relationValue._proxyCallback, this);
277
+ }
278
+
279
+ }
280
+ //Distinguish between the value of undefined versus a set no-op
281
+ if (attributes.hasOwnProperty(relationKey)) {
282
+ //Maintain reverse pointers - a.k.a parents
283
+ var updated = attributes[relationKey];
284
+ var original = this.attributes[relationKey];
285
+ if (updated) {
286
+ updated.parents = updated.parents || [];
287
+ (_.indexOf(updated.parents, this) == -1) && updated.parents.push(this);
288
+ } else if (original && original.parents.length > 0) { // New value is undefined
289
+ original.parents = _.difference(original.parents, [this]);
290
+ // Don't bubble to this parent anymore
291
+ original._proxyCallback && original.off("all", original._proxyCallback, this);
292
+ }
293
+ }
294
+ }, this);
295
+ }
296
+ // Return results for `BackboneModel.set`.
297
+ return ModelProto.set.call(this, attributes, options);
298
+ },
299
+
300
+
301
+ // Bubble-up event to `parent` Model
302
+ _bubbleEvent:function (relationKey, relationValue, eventArguments) {
303
+ var args = eventArguments,
304
+ opt = args[0].split(":"),
305
+ eventType = opt[0],
306
+ catch_all = args[0] == "nested-change",
307
+ isChangeEvent = eventType === "change",
308
+ eventObject = args[1],
309
+ indexEventObject = -1,
310
+ _proxyCalls = relationValue._proxyCalls,
311
+ cargs,
312
+ eventPath = opt[1],
313
+ basecolEventPath;
314
+
315
+
316
+ // Short circuit the listen in to the nested-graph event
317
+ if (catch_all) return;
318
+
319
+ // Short circuit the listen in to the wild-card event
320
+ if (Backbone.Associations.EVENTS_WILDCARD) {
321
+ if (/\[\*\]/g.test(eventPath)) return this;
322
+ }
323
+
324
+ if (relationValue instanceof BackboneCollection && (isChangeEvent || eventPath)) {
325
+ // O(n) search :(
326
+ indexEventObject = relationValue.indexOf(source || eventObject);
327
+ }
328
+
329
+ if (this instanceof BackboneModel) {
330
+ // A quicker way to identify the model which caused an update inside the collection (while bubbling up)
331
+ source = this;
332
+ }
333
+ // Manipulate `eventPath`.
334
+ eventPath = relationKey + ((indexEventObject !== -1 && (isChangeEvent || eventPath)) ?
335
+ "[" + indexEventObject + "]" : "") + (eventPath ? pathSeparator + eventPath : "");
336
+
337
+ // Short circuit collection * events
338
+
339
+ if (Backbone.Associations.EVENTS_WILDCARD) {
340
+ basecolEventPath = eventPath.replace(/\[\d+\]/g, '[*]');
341
+ }
342
+
343
+ cargs = [];
344
+ cargs.push.apply(cargs, args);
345
+ cargs[0] = eventType + ":" + eventPath;
346
+
347
+ // Create a collection modified event with wild-card
348
+ if (Backbone.Associations.EVENTS_WILDCARD && eventPath !== basecolEventPath) {
349
+ cargs[0] = cargs[0] + " " + eventType + ":" + basecolEventPath;
350
+ }
351
+
352
+ // If event has been already triggered as result of same source `eventPath`,
353
+ // no need to re-trigger event to prevent cycle.
354
+ _proxyCalls = relationValue._proxyCalls = (_proxyCalls || {});
355
+ if (this._isEventAvailable.call(this, _proxyCalls, eventPath)) return this;
356
+
357
+ // Add `eventPath` in `_proxyCalls` to keep track of already triggered `event`.
358
+ _proxyCalls[eventPath] = true;
359
+
360
+
361
+ // Set up previous attributes correctly.
362
+ if (isChangeEvent) {
363
+ this._previousAttributes[relationKey] = relationValue._previousAttributes;
364
+ this.changed[relationKey] = relationValue;
365
+ }
366
+
367
+ // Bubble up event to parent `model` with new changed arguments.
368
+
369
+ this.trigger.apply(this, cargs);
370
+
371
+ //Only fire for change. Not change:attribute
372
+ if (Backbone.Associations.EVENTS_NC && isChangeEvent && this.get(eventPath) != args[2]) {
373
+ var ncargs = ["nested-change", eventPath, args[1]];
374
+ args[2] && ncargs.push(args[2]); //args[2] will be options if present
375
+ this.trigger.apply(this, ncargs);
376
+ }
377
+
378
+ // Remove `eventPath` from `_proxyCalls`,
379
+ // if `eventPath` and `_proxyCalls` are available,
380
+ // which allow event to be triggered on for next operation of `set`.
381
+ if (_proxyCalls && eventPath) delete _proxyCalls[eventPath];
382
+
383
+ source = undefined;
384
+
385
+ return this;
386
+ },
387
+
388
+ // Has event been fired from this source. Used to prevent event recursion in cyclic graphs
389
+ _isEventAvailable:function (_proxyCalls, path) {
390
+ return _.find(_proxyCalls, function (value, eventKey) {
391
+ return path.indexOf(eventKey, path.length - eventKey.length) !== -1;
392
+ });
393
+ },
394
+
395
+ // Returns New `collection` of type `relation.relatedModel`.
396
+ _createCollection: function (type, context) {
397
+ var collection, relatedModel = type;
398
+ _.isString(relatedModel) && (relatedModel = map2Scope(relatedModel, context));
399
+ // Creates new `Backbone.Collection` and defines model class.
400
+ if (relatedModel && (relatedModel.prototype instanceof AssociatedModel) || _.isFunction(relatedModel)) {
401
+ collection = new BackboneCollection();
402
+ collection.model = relatedModel;
403
+ } else {
404
+ throw new Error('type must inherit from Backbone.AssociatedModel');
405
+ }
406
+ return collection;
407
+ },
408
+
409
+ // Process all pending events after the entire object graph has been updated
410
+ _processPendingEvents:function () {
411
+ if (!this._processedEvents) {
412
+ this._processedEvents = true;
413
+
414
+ this._deferEvents = false;
415
+
416
+ // Trigger all pending events
417
+ _.each(this._pendingEvents, function (e) {
418
+ e.c.trigger.apply(e.c, e.a);
419
+ });
420
+
421
+ this._pendingEvents = [];
422
+
423
+ // Traverse down the object graph and call process pending events on sub-trees
424
+ _.each(this.relations, function (relation) {
425
+ var val = this.attributes[relation.key];
426
+ val && val._processPendingEvents();
427
+ }, this);
428
+
429
+ delete this._processedEvents;
430
+ }
431
+ },
432
+
433
+ // Override trigger to defer events in the object graph.
434
+ trigger:function (name) {
435
+ // Defer event processing
436
+ if (this._deferEvents) {
437
+ this._pendingEvents = this._pendingEvents || [];
438
+ // Maintain a queue of pending events to trigger after the entire object graph is updated.
439
+ this._pendingEvents.push({c:this, a:arguments});
440
+ } else {
441
+ ModelProto.trigger.apply(this, arguments);
442
+ }
443
+ },
444
+
445
+ // The JSON representation of the model.
446
+ toJSON:function (options) {
447
+ var json = {}, aJson;
448
+ json[this.idAttribute] = this.id;
449
+ if (!this.visited) {
450
+ this.visited = true;
451
+ // Get json representation from `BackboneModel.toJSON`.
452
+ json = ModelProto.toJSON.apply(this, arguments);
453
+ // If `this.relations` is defined, iterate through each `relation`
454
+ // and added it's json representation to parents' json representation.
455
+ if (this.relations) {
456
+ _.each(this.relations, function (relation) {
457
+ var key = relation.key,
458
+ remoteKey = relation.remoteKey,
459
+ attr = this.attributes[key],
460
+ serialize = !relation.isTransient;
461
+
462
+ // Remove default Backbone serialization for associations.
463
+ delete json[key];
464
+
465
+ //Assign to remoteKey if specified. Otherwise use the default key.
466
+ //Only for non-transient relationships
467
+ if (serialize) {
468
+ aJson = attr && attr.toJSON ? attr.toJSON(options) : attr;
469
+ json[remoteKey || key] = _.isArray(aJson) ? _.compact(aJson) : aJson;
470
+ }
471
+
472
+ }, this);
473
+ }
474
+ delete this.visited;
475
+ }
476
+ return json;
477
+ },
478
+
479
+ // Create a new model with identical attributes to this one.
480
+ clone:function () {
481
+ return new this.constructor(this.toJSON());
482
+ },
483
+
484
+ // Call this if you want to set an `AssociatedModel` to a falsy value like undefined/null directly.
485
+ // Not calling this will leak memory and have wrong parents.
486
+ // See test case "parent relations"
487
+ cleanup:function () {
488
+ _.each(this.relations, function (relation) {
489
+ var val = this.attributes[relation.key];
490
+ val && (val.parents = _.difference(val.parents, [this]));
491
+ }, this);
492
+ this.off();
493
+ },
494
+
495
+ // Navigate the path to the leaf object in the path to query for the attribute value
496
+ _getAttr:function (path) {
497
+
498
+ var result = this,
499
+ //Tokenize the path
500
+ attrs = getPathArray(path),
501
+ key,
502
+ i;
503
+ if (_.size(attrs) < 1) return;
504
+ for (i = 0; i < attrs.length; i++) {
505
+ key = attrs[i];
506
+ if (!result) break;
507
+ //Navigate the path to get to the result
508
+ result = result instanceof BackboneCollection
509
+ ? (isNaN(key) ? undefined : result.at(key))
510
+ : result.attributes[key];
511
+ }
512
+ return result;
513
+ }
514
+ });
515
+
516
+ // Tokenize the fully qualified event path
517
+ var getPathArray = function (path) {
518
+ if (path === '') return [''];
519
+ return _.isString(path) ? (path.match(delimiters)) : path || [];
520
+ };
521
+
522
+ var map2Scope = function (path, context) {
523
+ return _.reduce(path.split(pathSeparator), function (memo, elem) {
524
+ return memo[elem];
525
+ }, context);
526
+ };
527
+
528
+ //Infer the relation from the collection's parents and find the appropriate map for the passed in `models`
529
+ var map2models = function (parents, target, models) {
530
+ var relation, surrogate;
531
+ //Iterate over collection's parents
532
+ _.find(parents, function (parent) {
533
+ //Iterate over relations
534
+ relation = _.find(parent.relations, function (rel) {
535
+ return parent.get(rel.key) === target;
536
+ }, this);
537
+ if (relation) {
538
+ surrogate = parent;//surrogate for transformation
539
+ return true;//break;
540
+ }
541
+ }, this);
542
+
543
+ //If we found a relation and it has a mapping function
544
+ if (relation && relation.map) {
545
+ return relation.map.call(surrogate, models, target);
546
+ }
547
+ return models;
548
+ };
549
+
550
+ var proxies = {};
551
+ // Proxy Backbone collection methods
552
+ _.each(['set', 'remove', 'reset'], function (method) {
553
+ proxies[method] = BackboneCollection.prototype[method];
554
+
555
+ CollectionProto[method] = function (models, options) {
556
+ //Short-circuit if this collection doesn't hold `AssociatedModels`
557
+ if (this.model.prototype instanceof AssociatedModel && this.parents) {
558
+ //Find a map function if available and perform a transformation
559
+ arguments[0] = map2models(this.parents, this, models);
560
+ }
561
+ return proxies[method].apply(this, arguments);
562
+ }
563
+ });
564
+
565
+ // Override trigger to defer events in the object graph.
566
+ proxies['trigger'] = CollectionProto['trigger'];
567
+ CollectionProto['trigger'] = function (name) {
568
+ if (this._deferEvents) {
569
+ this._pendingEvents = this._pendingEvents || [];
570
+ // Maintain a queue of pending events to trigger after the entire object graph is updated.
571
+ this._pendingEvents.push({c:this, a:arguments});
572
+ } else {
573
+ proxies['trigger'].apply(this, arguments);
574
+ }
575
+ };
576
+
577
+ // Attach process pending event functionality on collections as well. Re-use from `AssociatedModel`
578
+ CollectionProto._processPendingEvents = AssociatedModel.prototype._processPendingEvents;
579
+
580
+
581
+ }).call(this);
@@ -1 +1 @@
1
- //= require js_stack/backbone.associations/backbone.associations-0.5.4
1
+ //= require js_stack/backbone.associations/backbone.associations-0.5.5