Scott Baker | b7aba68 | 2014-07-07 21:30:52 -0700 | [diff] [blame] | 1 | /** |
| 2 | * Backbone-tastypie.js 0.1 |
| 3 | * (c) 2011 Paul Uithol |
| 4 | * |
| 5 | * Backbone-tastypie may be freely distributed under the MIT license. |
| 6 | * Add or override Backbone.js functionality, for compatibility with django-tastypie. |
| 7 | */ |
| 8 | (function( undefined ) { |
| 9 | var Backbone = this.Backbone; |
| 10 | |
| 11 | /** |
| 12 | * Override Backbone's sync function, to do a GET upon receiving a HTTP CREATED. |
| 13 | * This requires 2 requests to do a create, so you may want to use some other method in production. |
| 14 | * Modified from http://joshbohde.com/blog/backbonejs-and-django |
| 15 | */ |
| 16 | Backbone.oldSync = Backbone.sync; |
| 17 | Backbone.sync = function( method, model, options ) { |
| 18 | if ( method === 'create' ) { |
| 19 | var dfd = new $.Deferred(); |
| 20 | |
| 21 | // Set up 'success' handling |
| 22 | dfd.done( options.success ); |
| 23 | options.success = function( resp, status, xhr ) { |
| 24 | // If create is successful but doesn't return a response, fire an extra GET. |
| 25 | // Otherwise, resolve the deferred (which triggers the original 'success' callbacks). |
| 26 | if ( xhr.status === 201 && !resp ) { // 201 CREATED; response null or empty. |
| 27 | var location = xhr.getResponseHeader( 'Location' ); |
| 28 | return $.ajax( { |
| 29 | url: location, |
| 30 | success: dfd.resolve, |
| 31 | error: dfd.reject |
| 32 | }); |
| 33 | } |
| 34 | else { |
| 35 | return dfd.resolveWith( options.context || options, [ resp, status, xhr ] ); |
| 36 | } |
| 37 | }; |
| 38 | |
| 39 | // Set up 'error' handling |
| 40 | dfd.fail( options.error ); |
| 41 | options.error = dfd.reject; |
| 42 | |
| 43 | // Make the request, make it accessibly by assigning it to the 'request' property on the deferred |
| 44 | dfd.request = Backbone.oldSync( method, model, options ); |
| 45 | return dfd; |
| 46 | } |
| 47 | |
| 48 | return Backbone.oldSync( method, model, options ); |
| 49 | }; |
| 50 | |
| 51 | Backbone.Model.prototype.idAttribute = 'resource_uri'; |
| 52 | |
| 53 | Backbone.Model.prototype.url = function() { |
| 54 | // Use the id if possible |
| 55 | var url = this.id; |
| 56 | |
| 57 | // If there's no idAttribute, try to have the collection construct a url. Fallback to 'urlRoot'. |
| 58 | if ( !url ) { |
| 59 | url = this.collection && ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url ); |
| 60 | url = url || this.urlRoot; |
| 61 | } |
| 62 | |
| 63 | url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' ); |
| 64 | |
| 65 | return url; |
| 66 | }; |
| 67 | |
| 68 | /** |
| 69 | * Return 'data.objects' if it exists and is an array, or else just plain 'data'. |
| 70 | */ |
| 71 | Backbone.Model.prototype.parse = function( data ) { |
| 72 | return data && data.objects && ( _.isArray( data.objects ) ? data.objects[ 0 ] : data.objects ) || data; |
| 73 | }; |
| 74 | |
| 75 | Backbone.Collection.prototype.parse = function( data ) { |
| 76 | return data && data.objects; |
| 77 | }; |
| 78 | |
| 79 | Backbone.Collection.prototype.url = function( models ) { |
| 80 | var url = this.urlRoot || ( models && models.length && models[0].urlRoot ); |
| 81 | url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' ); |
| 82 | |
| 83 | // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute |
| 84 | // (set to 'resource_uri') contains the model's id. |
| 85 | if ( models && models.length ) { |
| 86 | var ids = _.map( models, function( model ) { |
| 87 | var parts = _.compact( model.id.split('/') ); |
| 88 | return parts[ parts.length - 1 ]; |
| 89 | }); |
| 90 | url += 'set/' + ids.join(';') + '/'; |
| 91 | } |
| 92 | |
| 93 | return url; |
| 94 | }; |
| 95 | })(); |