modelName in xos models, log window, deferred display of detail when collection not...
[plstackapi.git] / planetstack / core / xoslib / static / js / xoslib / xos-backbone.js
1 if (! window.XOSLIB_LOADED ) {
2     window.XOSLIB_LOADED=true;
3
4     SLIVER_API = "/plstackapi/slivers/";
5     SLICE_API = "/plstackapi/slices/";
6     SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
7     SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
8     SLICEROLE_API = "/plstackapi/slice_roles/";
9     NODE_API = "/plstackapi/nodes/";
10     SITE_API = "/plstackapi/sites/";
11     USER_API = "/plstackapi/users/";
12     USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
13     DEPLOYMENT_API = "/plstackapi/deployments/";
14     IMAGE_API = "/plstackapi/images/";
15     NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
16     NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";
17     NETWORK_API = "/plstackapi/networks/";
18     NETWORKSLIVER_API = "/plstackapi/networkslivers/";
19     SERVICE_API = "/plstackapi/services/";
20
21     SLICEPLUS_API = "/xoslib/slicesplus/";
22
23     XOSModel = Backbone.Model.extend({
24         /* from backbone-tastypie.js */
25         //idAttribute: 'resource_uri',
26
27         /* from backbone-tastypie.js */
28         url: function() {
29                     var url = this.attributes.resource_uri;
30
31                     if (!url) {
32                         url = this.urlRoot + this.id;
33                     }
34
35                     if (!url) {
36                         // XXX I'm not sure this does anything useful
37                         url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
38                         url = url || this.urlRoot;
39                     }
40
41                     // remove any existing query parameters
42                     url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );
43
44                     url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
45
46                     url && ( url += "?no_hyperlinks=1" );
47
48                     return url;
49             },
50
51             listMethods: function() {
52                 var res = [];\r
53                 for(var m in this) {\r
54                     if(typeof this[m] == "function") {\r
55                         res.push(m)\r
56                     }\r
57                 }\r
58                 return res;\r
59             }
60     });
61
62     XOSCollection = Backbone.Collection.extend({
63         objects: function() {
64                     return this.models.map(function(element) { return element.attributes; });
65                  },
66
67         initialize: function(){
68           this.isLoaded = false;
69           this.sortVar = 'name';\r
70           this.sortOrder = 'asc';\r
71           this.on( "sort", this.sorted );\r
72         },\r
73 \r
74         relatedCollections: [],\r
75         foreignCollections: [],\r
76 \r
77         sorted: function() {\r
78             this.isLoaded = true;\r
79         },\r
80 \r
81         simpleComparator: function( model ){\r
82           parts=this.sortVar.split(".");\r
83           result = model.get(parts[0]);\r
84           for (index=1; index<parts.length; ++index) {\r
85               result=result[parts[index]];\r
86           }\r
87           return result;\r
88         },\r
89 \r
90         comparator: function (left, right) {\r
91             var l = this.simpleComparator(left);\r
92             var r = this.simpleComparator(right);\r
93 \r
94             if (l === void 0) return -1;\r
95             if (r === void 0) return 1;\r
96 \r
97             if (this.sortOrder=="desc") {\r
98                 return l < r ? 1 : l > r ? -1 : 0;\r
99             } else {\r
100                 return l < r ? -1 : l > r ? 1 : 0;\r
101             }\r
102         },\r
103 \r
104         startPolling: function() {\r
105             if (!this._polling) {\r
106                 var collection=this;
107                 setInterval(function() { collection.fetch(); }, 10000);
108                 this._polling=true;
109                 this.fetch();
110             }
111         },
112
113         maybeFetch: function(options){
114                 // Helper function to fetch only if this collection has not been fetched before.
115             if(this._fetched){
116                     // If this has already been fetched, call the success, if it exists
117                 options.success && options.success();
118                 console.log("alreadyFetched");
119                 return;
120             }
121
122                 // when the original success function completes mark this collection as fetched
123             var self = this,
124             successWrapper = function(success){
125                 return function(){
126                     self._fetched = true;
127                     success && success.apply(this, arguments);
128                 };
129             };
130             options.success = successWrapper(options.success);
131             console.log("call fetch");
132             this.fetch(options);
133         },
134
135         getOrFetch: function(id, options){
136                 // Helper function to use this collection as a cache for models on the server
137             var model = this.get(id);
138
139             if(model){
140                 options.success && options.success(model);
141                 return;
142             }
143
144             model = new this.model({
145                 resource_uri: id
146             });
147
148             model.fetch(options);
149         },
150
151         filterBy: function(fieldName, value) {
152              filtered = this.filter(function(obj) {
153                  return obj.get(fieldName) == value;
154                  });
155              return new this.constructor(filtered);
156         },
157
158         /* from backbone-tastypie.js */
159         url: function( models ) {
160                     var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
161                     url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
162
163                     // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
164                     // (set to 'resource_uri') contains the model's id.
165                     if ( models && models.length ) {
166                             var ids = _.map( models, function( model ) {
167                                             var parts = _.compact( model.id.split('/') );
168                                             return parts[ parts.length - 1 ];
169                                     });
170                             url += 'set/' + ids.join(';') + '/';
171                     }
172
173                     url && ( url += "?no_hyperlinks=1" );
174
175                     return url;
176             },
177
178         listMethods: function() {
179                 var res = [];\r
180                 for(var m in this) {\r
181                     if(typeof this[m] == "function") {\r
182                         res.push(m)\r
183                     }\r
184                 }\r
185                 return res;\r
186             },
187     });
188
189     function xoslib() {
190         // basic REST
191         this.sliver = XOSModel.extend({ urlRoot: SLIVER_API, modelName: "sliver" });
192         this.sliverCollection = XOSCollection.extend({ urlRoot: SLIVER_API,
193                                                        relatedCollections: {"networkSlivers": "sliver"},
194                                                        foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
195                                                        model: this.sliver});
196         this.slivers = new this.sliverCollection();
197
198         this.slice = XOSModel.extend({ urlRoot: SLICE_API, modelName: "slice" });
199         this.sliceCollection = XOSCollection.extend({ urlRoot: SLICE_API,
200                                                        relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice"},
201                                                        foreignCollections: ["services", "sites"],
202                                                        model: this.slice});
203         this.slices = new this.sliceCollection();
204
205         this.sliceDeployment = XOSModel.extend({ urlRoot: SLICEDEPLOYMENT_API, modelName: "sliceDeployment" });
206         this.sliceDeploymentCollection = XOSCollection.extend({ urlRoot: SLICEDEPLOYMENT_API,
207                                                        foreignCollections: ["slices", "deployments"],
208                                                        model: this.slice});
209         this.sliceDeployments = new this.sliceDeploymentCollection();
210
211         this.slicePrivilege = XOSModel.extend({ urlRoot: SLICEPRIVILEGE_API, modelName: "slicePrivilege" });
212         this.slicePrivilegeCollection = XOSCollection.extend({ urlRoot: SLICEPRIVILEGE_API,
213                                                        foreignCollections: ["slices", "users", "sliceRoles"],
214                                                        model: this.slice});
215         this.slicePrivileges = new this.slicePrivilegeCollection();
216
217         this.sliceRole = XOSModel.extend({ urlRoot: SLICEROLE_API, modelName: "sliceRole" });
218         this.sliceRoleCollection = XOSCollection.extend({ urlRoot: SLICEROLE_API,
219                                                        model: this.slice});
220         this.sliceRoles = new this.sliceRoleCollection();
221
222         this.node = XOSModel.extend({ urlRoot: NODE_API, modelName: "node" });
223         this.nodeCollection = XOSCollection.extend({ urlRoot: NODE_API,
224                                                        foreignCollections: ["sites", "deployments"],
225                                                        model: this.node});
226         this.nodes = new this.nodeCollection();
227
228         this.site = XOSModel.extend({ urlRoot: SITE_API, modelName: "site" });
229         this.siteCollection = XOSCollection.extend({ urlRoot: SITE_API,
230                                                        model: this.site});
231         this.sites = new this.siteCollection();
232
233         this.user = XOSModel.extend({ urlRoot: USER_API, modelName: "user" });
234         this.userCollection = XOSCollection.extend({ urlRoot: USER_API,
235                                                        relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
236                                                        foreignCollections: ["sites"],
237                                                        model: this.user});
238         this.users = new this.userCollection();
239
240         this.userDeployment = XOSModel.extend({ urlRoot: USERDEPLOYMENT_API, modelName: "userDeployment" });
241         this.userDeploymentCollection = XOSCollection.extend({ urlRoot: USERDEPLOYMENT_API,
242                                                        foreignCollections: ["users","deployments"],
243                                                        model: this.user});
244         this.userDeployments = new this.userDeploymentCollection();
245
246         this.deployment = XOSModel.extend({ urlRoot: DEPLOYMENT_API, modelName: "deployment" });
247         this.deploymentCollection = XOSCollection.extend({ urlRoot: DEPLOYMENT_API,
248                                                            relatedCollections: {"slivers": "deployment", "networkDeployments": "deployment", "userDeployments": "deployment"},
249                                                            model: this.deployment});
250         this.deployments = new this.deploymentCollection();
251
252         this.image = XOSModel.extend({ urlRoot: IMAGE_API, modelName: "image" });
253         this.imageCollection = XOSCollection.extend({ urlRoot: IMAGE_API,
254                                                            model: this.image});
255         this.images = new this.imageCollection();
256
257         this.networkTemplate = XOSModel.extend({ urlRoot: NETWORKTEMPLATE_API, modelName: "networkTemplate" });
258         this.networkTemplateCollection = XOSCollection.extend({ urlRoot: NETWORKTEMPLATE_API,
259                                                            model: this.networkTemplate});
260         this.networkTemplates = new this.networkTemplateCollection();
261
262         this.network = XOSModel.extend({ urlRoot: NETWORK_API, modelName: "network" });
263         this.networkCollection = XOSCollection.extend({ urlRoot: NETWORK_API,
264                                                            relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
265                                                            foreignCollections: ["slices", "networkTemplates"],
266                                                            model: this.network});
267         this.networks = new this.networkCollection();
268
269         this.networkSliver = XOSModel.extend({ urlRoot: NETWORKSLIVER_API, modelName: "networkSliver" });
270         this.networkSliverCollection = XOSCollection.extend({ urlRoot: NETWORKSLIVER_API,
271                                                            model: this.networkSliver});
272         this.networkSlivers = new this.networkSliverCollection();
273
274         this.networkDeployment = XOSModel.extend({ urlRoot: NETWORKDEPLOYMENT_API, modelName: "networkDeployment" });
275         this.networkDeploymentCollection = XOSCollection.extend({ urlRoot: NETWORKDEPLOYMENT_API,
276                                                            model: this.networkDeployment});
277         this.networkDeployments = new this.networkDeploymentCollection();
278
279         this.service = XOSModel.extend({ urlRoot: SERVICE_API, modelName: "sliver" });
280         this.serviceCollection = XOSCollection.extend({ urlRoot: SERVICE_API,
281                                                        model: this.service});
282         this.services = new this.serviceCollection();
283
284         // enhanced REST
285         this.slicePlus = XOSModel.extend({ urlRoot: SLICEPLUS_API, modelName: "slicePlus" });
286         this.slicePlusCollection = XOSCollection.extend({ urlRoot: SLICEPLUS_API,
287                                                           relatedCollections: {'slivers': "slice"},
288                                                           model: this.slicePlus});
289         this.slicesPlus = new this.slicePlusCollection();
290
291         this.listObjects = function() { return ["slivers", "slices", "nodes", "sites", "users", "deployments"]; };
292     };
293
294     xos = new xoslib();
295
296     function getCookie(name) {
297         var cookieValue = null;\r
298         if (document.cookie && document.cookie != '') {\r
299             var cookies = document.cookie.split(';');\r
300             for (var i = 0; i < cookies.length; i++) {\r
301                 var cookie = jQuery.trim(cookies[i]);\r
302                 // Does this cookie string begin with the name we want?\r
303                 if (cookie.substring(0, name.length + 1) == (name + '=')) {\r
304                     cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\r
305                     break;\r
306                 }\r
307             }\r
308         }\r
309         return cookieValue;\r
310     }
311
312     (function() {
313       var _sync = Backbone.sync;\r
314       Backbone.sync = function(method, model, options){\r
315         options.beforeSend = function(xhr){\r
316           var token = getCookie("csrftoken");\r
317           xhr.setRequestHeader('X-CSRFToken', token);\r
318         };\r
319         return _sync(method, model, options);\r
320       };\r
321     })();
322 }