backbone-associations-rails 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
|
|
1
1
|
//
|
2
|
-
// Backbone-associations.js 0.
|
2
|
+
// Backbone-associations.js 0.4.0
|
3
3
|
//
|
4
4
|
// (c) 2013 Dhruva Ray, Jaynti Kanani
|
5
5
|
// Backbone-associations may be freely distributed under the MIT license;
|
@@ -12,6 +12,7 @@
|
|
12
12
|
(function () {
|
13
13
|
"use strict";
|
14
14
|
|
15
|
+
|
15
16
|
// The top-level namespace. All public Backbone classes and modules will be attached to this.
|
16
17
|
// Exported for the browser and CommonJS.
|
17
18
|
var _, Backbone, BackboneModel, BackboneCollection, ModelProto,
|
@@ -31,7 +32,7 @@
|
|
31
32
|
|
32
33
|
// Built-in Backbone `events`.
|
33
34
|
defaultEvents = ["change", "add", "remove", "reset", "destroy",
|
34
|
-
|
35
|
+
"sync", "error", "sort", "request"];
|
35
36
|
|
36
37
|
// Backbone.AssociatedModel
|
37
38
|
// --------------
|
@@ -42,22 +43,19 @@
|
|
42
43
|
// Define `AssociatedModel` (Extends Backbone.Model).
|
43
44
|
AssociatedModel = Backbone.AssociatedModel = BackboneModel.extend({
|
44
45
|
// Define relations with Associated Model.
|
45
|
-
relations:
|
46
|
+
relations:undefined,
|
46
47
|
// Define `Model` property which can keep track of already fired `events`,
|
47
48
|
// and prevent redundant event to be triggered in case of circular model graph.
|
48
|
-
_proxyCalls:
|
49
|
+
_proxyCalls:undefined,
|
49
50
|
|
50
51
|
// Get the value of an attribute.
|
51
|
-
get:
|
52
|
+
get:function (attr) {
|
52
53
|
return this.getAttr.apply(this, arguments);
|
53
54
|
},
|
54
55
|
|
55
|
-
// Set a hash of model attributes on the
|
56
|
-
|
57
|
-
|
58
|
-
// It also bubbles up child events to the parent.
|
59
|
-
set: function (key, value, options) {
|
60
|
-
var attributes, processedRelations, tbp, attr;
|
56
|
+
// Set a hash of model attributes on the Backbone Model.
|
57
|
+
set:function (key, value, options) {
|
58
|
+
var attributes, attr, modelMap, modelId, obj, result = this;
|
61
59
|
// Duplicate backbone's behavior to allow separate key/value parameters,
|
62
60
|
// instead of a single 'attributes' object.
|
63
61
|
if (_.isObject(key) || key == null) {
|
@@ -67,9 +65,36 @@
|
|
67
65
|
attributes = {};
|
68
66
|
attributes[key] = value;
|
69
67
|
}
|
68
|
+
if (!attributes) return this;
|
69
|
+
for (attr in attributes) {
|
70
|
+
var pathTokens = getPathArray(attr), initials = _.initial(pathTokens), last = _.last(pathTokens),
|
71
|
+
root = this, parentModel = this.get(initials);
|
72
|
+
|
73
|
+
modelMap || (modelMap = {});
|
74
|
+
if ((!parentModel && _.size(initials) > 0) || parentModel instanceof BackboneCollection) continue;
|
75
|
+
parentModel instanceof AssociatedModel && (root = parentModel);
|
76
|
+
obj = modelMap[root.cid] || (modelMap[root.cid] = {'model':root, 'data':{}});
|
77
|
+
obj.data[last] = attributes[attr];
|
78
|
+
}
|
79
|
+
if (modelMap) {
|
80
|
+
for (modelId in modelMap) {
|
81
|
+
obj = modelMap[modelId];
|
82
|
+
this.setAttr.call(obj.model, obj.data, options) || (result = false);
|
83
|
+
}
|
84
|
+
} else {
|
85
|
+
result = this.setAttr.call(this, attributes, options);
|
86
|
+
}
|
87
|
+
return result;
|
88
|
+
},
|
89
|
+
|
90
|
+
// Set a hash of model attributes on the object,
|
91
|
+
// fire Backbone `event` with options.
|
92
|
+
// It maintains relations between models during the set operation.
|
93
|
+
// It also bubbles up child events to the parent.
|
94
|
+
setAttr:function (attributes, options) {
|
95
|
+
var processedRelations, tbp, attr;
|
70
96
|
// Extract attributes and options.
|
71
97
|
options || (options = {});
|
72
|
-
if (!attributes) return this;
|
73
98
|
if (options.unset) for (attr in attributes) attributes[attr] = void 0;
|
74
99
|
|
75
100
|
if (this.relations) {
|
@@ -151,7 +176,7 @@
|
|
151
176
|
return ModelProto.set.call(this, tbp, options);
|
152
177
|
},
|
153
178
|
// Bubble-up event to `parent` Model
|
154
|
-
_bubbleEvent:
|
179
|
+
_bubbleEvent:function (relationKey, eventArguments) {
|
155
180
|
var args = eventArguments,
|
156
181
|
opt = args[0].split(":"),
|
157
182
|
eventType = opt[0],
|
@@ -168,13 +193,13 @@
|
|
168
193
|
if (relationValue instanceof BackboneCollection && "change" === eventType && eventObject) {
|
169
194
|
//indexEventObject = _.indexOf(relationValue.models, eventObject);
|
170
195
|
var pathTokens = getPathArray(eventPath),
|
171
|
-
initialTokens = _.initial(pathTokens),
|
172
|
-
|
196
|
+
initialTokens = _.initial(pathTokens), colModel;
|
197
|
+
|
173
198
|
colModel = relationValue.find(function (model) {
|
174
199
|
var changedModel = model.get(pathTokens);
|
175
|
-
return eventObject ===
|
176
|
-
|
177
|
-
|
200
|
+
return eventObject === (changedModel instanceof AssociatedModel
|
201
|
+
|| changedModel instanceof BackboneCollection)
|
202
|
+
? changedModel : (model.get(initialTokens) || model);
|
178
203
|
});
|
179
204
|
colModel && (indexEventObject = relationValue.indexOf(colModel));
|
180
205
|
}
|
@@ -209,7 +234,7 @@
|
|
209
234
|
return this;
|
210
235
|
},
|
211
236
|
// Returns New `collection` of type `relation.relatedModel`.
|
212
|
-
_createCollection:
|
237
|
+
_createCollection:function (type) {
|
213
238
|
var collection, relatedModel = type;
|
214
239
|
_.isString(relatedModel) && (relatedModel = eval(relatedModel));
|
215
240
|
// Creates new `Backbone.Collection` and defines model class.
|
@@ -222,7 +247,7 @@
|
|
222
247
|
return collection;
|
223
248
|
},
|
224
249
|
// Has the model changed. Traverse the object hierarchy to compute dirtyness.
|
225
|
-
hasChanged:
|
250
|
+
hasChanged:function (attr) {
|
226
251
|
var isDirty, relation, attrValue, i, dirtyObjects;
|
227
252
|
// To prevent cycles, check if this node is visited.
|
228
253
|
if (!this.visitedHC) {
|
@@ -253,7 +278,7 @@
|
|
253
278
|
return !!isDirty;
|
254
279
|
},
|
255
280
|
// Returns a hash of the changed attributes.
|
256
|
-
changedAttributes:
|
281
|
+
changedAttributes:function (diff) {
|
257
282
|
var delta, relation, attrValue, changedCollection, i;
|
258
283
|
// To prevent cycles, check if this node is visited.
|
259
284
|
if (!this.visited) {
|
@@ -284,7 +309,7 @@
|
|
284
309
|
return !delta ? false : delta;
|
285
310
|
},
|
286
311
|
// Returns the hash of the previous attributes of the graph.
|
287
|
-
previousAttributes:
|
312
|
+
previousAttributes:function () {
|
288
313
|
var pa, attrValue, pattrValue, pattrJSON;
|
289
314
|
// To prevent cycles, check if this node is visited.
|
290
315
|
if (!this.visited) {
|
@@ -314,12 +339,12 @@
|
|
314
339
|
return pa;
|
315
340
|
},
|
316
341
|
// Return the previous value of the passed in attribute.
|
317
|
-
previous:
|
342
|
+
previous:function (attr) {
|
318
343
|
return this.previousAttributes()[attr];
|
319
344
|
},
|
320
345
|
|
321
346
|
// The JSON representation of the model.
|
322
|
-
toJSON:
|
347
|
+
toJSON:function (options) {
|
323
348
|
var json, aJson;
|
324
349
|
if (!this.visited) {
|
325
350
|
this.visited = true;
|
@@ -342,16 +367,17 @@
|
|
342
367
|
},
|
343
368
|
|
344
369
|
// Create a new model with identical attributes to this one.
|
345
|
-
clone:
|
346
|
-
|
370
|
+
clone:function () {
|
371
|
+
return new this.constructor(this.toJSON());
|
347
372
|
},
|
348
373
|
|
349
374
|
// Get `reduced` result using passed `path` array or string.
|
350
|
-
getAttr:
|
375
|
+
getAttr:function (path, iterator) {
|
351
376
|
var result = this,
|
352
377
|
attrs = getPathArray(path),
|
353
378
|
key,
|
354
379
|
i;
|
380
|
+
if (_.size(attrs) < 1) return;
|
355
381
|
iterator || (iterator = function (memo, key) {
|
356
382
|
return memo instanceof BackboneCollection && _.isNumber(key) ? memo.at(key) : memo.attributes[key];
|
357
383
|
});
|
@@ -364,16 +390,17 @@
|
|
364
390
|
}
|
365
391
|
});
|
366
392
|
|
393
|
+
var _index = /^\d+$/;
|
394
|
+
var _pathTokenizer = /[^\.\[\]]+/g;
|
395
|
+
|
367
396
|
// Get Path `attrs` as Array
|
368
|
-
// Example:
|
369
|
-
// 'employee.works_for.locations[2].name' -> ['employee', 'works_for', 'locations', 2, 'name']
|
370
397
|
var getPathArray = function (path, iterator, context) {
|
371
398
|
if (_.isString(path)) {
|
372
399
|
iterator || (iterator = function (value) {
|
373
|
-
return value.match(
|
400
|
+
return value.match(_index) ? parseInt(value, 10) : value;
|
374
401
|
});
|
375
|
-
return _.map(path.match(
|
402
|
+
return _.map(path.match(_pathTokenizer) || [''], iterator, context);
|
376
403
|
}
|
377
|
-
return path || [];
|
404
|
+
return path || [''];
|
378
405
|
}
|
379
406
|
})();
|