backbone-associations-rails 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
@@ -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
|
})();
|