master
1// Backbone.Model File Upload v0.1
2// by Joe Vu - joe.vu@homeslicesolutions.com
3// For all details and documentation:
4// https://github.com/homeslicesolutions/backbone-model-file-upload
5
6!function(_, Backbone){
7 // Clone the original Backbone.Model.prototype
8 var backboneModelClone = _.clone( Backbone.Model.prototype );
9
10 // Extending out
11 _.extend(Backbone.Model.prototype, {
12
13 // ! Default file attribute - can be overwritten
14 fileAttribute: 'file',
15
16 // @ Save - overwritten
17 save: function(key, val, options) {
18
19 // Variables
20 var attrs, attributes = this.attributes;
21
22 // Signature parsing - taken directly from original Backbone.Model.save
23 // and it states: 'Handle both "key", value and {key: value} -style arguments.'
24 if (key == null || typeof key === 'object') {
25 attrs = key;
26 options = val;
27 } else {
28 (attrs = {})[key] = val;
29 }
30
31 // Validate & wait options - taken directly from original Backbone.Model.save
32 options = _.extend({validate: true}, options);
33 if (attrs && !options.wait) {
34 if (!this.set(attrs, options)) return false;
35 } else {
36 if (!this._validate(attrs, options)) return false;
37 }
38 if (attrs && options.wait) {
39 this.attributes = _.extend({}, attributes, attrs);
40 }
41
42 // Check for "formData" flag and check for if file exist.
43 if ( options.formData === true
44 || options.formData !== false
45 && this.attributes[ this.fileAttribute ]
46 && this.attributes[ this.fileAttribute ] instanceof File ) {
47
48 // Flatten Attributes reapplying File Object
49 var formAttrs = _.clone( this.attributes ),
50 fileAttr = this.attributes[ this.fileAttribute ];
51 formAttrs = this._flatten( formAttrs );
52 formAttrs[ this.fileAttribute ] = fileAttr;
53
54 // Converting Attributes to Form Data
55 var formData = new FormData();
56 _.each( formAttrs, function( value, key ){
57 formData.append( key, value );
58 });
59
60 // Set options for AJAX call
61 options = options || {};
62 options.data = formData;
63 options.processData = false;
64 options.contentType = false;
65
66 // Apply custom XHR for processing status & listen to "progress"
67 var that = this;
68 options.xhr = function() {
69 var xhr = $.ajaxSettings.xhr();
70 xhr.upload.addEventListener('progress', function(){
71
72 that._progressHandler.apply(that, arguments);
73 }, false);
74 return xhr;
75 }
76 }
77
78 // Resume back to original state
79 if (attrs && options.wait) this.attributes = attributes;
80
81 // Continue to call the existing "save" method
82 return backboneModelClone.save.call(this, attrs, options);
83 },
84
85 // _ FlattenObject gist by "penguinboy". Thank You!
86 // https://gist.github.com/penguinboy/762197
87 _flatten: function( obj ) {
88 var output = {};
89 for (var i in obj) {
90 if (!obj.hasOwnProperty(i)) continue;
91 if (typeof obj[i] == 'object') {
92 var flatObject = this._flatten(obj[i]);
93 for (var x in flatObject) {
94 if (!flatObject.hasOwnProperty(x)) continue;
95 output[i + '.' + x] = flatObject[x];
96 }
97 } else {
98 output[i] = obj[i];
99 }
100 }
101 return output;
102
103 },
104
105 // _ Get the Progress of the uploading file
106 _progressHandler: function( event ) {
107 console.log(event);
108 if (event.lengthComputable) {
109 var percentComplete = event.loaded / event.total;
110 console.log("triggering... " + percentComplete);
111 this.trigger( 'progress', percentComplete );
112 }
113 }
114 });
115}(_, Backbone);