addon/utils/ember-uploader.js
// this file contains source code from https://github.com/benefitcloud/ember-uploader
// thanks to this great project
import { get, set } from '@ember/object';
import EmberObject from '@ember/object';
import Evented from '@ember/object/evented';
import { isArray } from '@ember/array';
import { Promise } from 'rsvp';
import { run } from '@ember/runloop';
import $ from 'jquery';
/**
EmberUploader class
@module utils
@namespace utils
@class EmberUploader
@constructor
*/
export default EmberObject.extend(Evented, {
/**
* upload url
*
* @property {String} url
*
*/
url: null,
paramNamespace: null,
/**
* upload file parameter name
*
* @property {String} paramName
* @default 'file'
*/
paramName: 'file',
/**
* ajax request settings traditional, by default false
*
* @property {Boolean} traditional
* @default true
*/
traditional: true,
/**
* ajax request status
*
* @property {Boolean} isUploading
* @default false
*/
isUploading: false,
/**
* ajax request type (method), by default it will be POST
*
* @property {String} type
* @default 'POST'
*/
type: 'POST',
/**
* Start upload of files and extra data
*
* @param {object|array} files One file object or one array of files object
* @param {array} extra
* @return {object} jquery promise from ajax object
*/
upload: function(files, extra) {
extra = extra || {};
var data = this.setupFormData(files, extra);
var url = get(this, 'url');
var type = get(this, 'type');
set(this, 'isUploading', true);
return this.ajax(url, data, type);
},
setupFormData: function(files, extra) {
var formData = new FormData();
for (var prop in extra) {
if (extra.hasOwnProperty(prop)) {
formData.append(this.toNamespacedParam(prop), extra[prop]);
}
}
// if is a array of files ...
if (isArray(files)) {
var paramName;
for (var i = files.length - 1; i >= 0; i--) {
if(get(this, 'traditional')){
paramName = this.toNamespacedParam(this.paramName);
}else {
paramName = this.toNamespacedParam(this.paramName) + '[' + i + ']';
}
formData.append(paramName , files[i]);
}
} else {
// if has only one file object ...
formData.append(this.toNamespacedParam(this.paramName), files);
}
return formData;
},
toNamespacedParam: function(name) {
if (this.paramNamespace) {
return this.paramNamespace + '[' + name + ']';
}
return name;
},
didUpload: function(data) {
set(this, 'isUploading', false);
this.trigger('didUpload', data);
return data;
},
didError: function(jqXHR, textStatus, errorThrown) {
set(this, 'isUploading', false);
// Borrowed from Ember Data
var isObject = jqXHR !== null && typeof jqXHR === 'object';
if (isObject) {
jqXHR.then = null;
if (!jqXHR.errorThrown) {
if (typeof errorThrown === 'string') {
jqXHR.errorThrown = new Error(errorThrown);
} else {
jqXHR.errorThrown = errorThrown;
}
}
}
this.trigger('didError', jqXHR, textStatus, errorThrown);
return jqXHR;
},
didProgress: function(e) {
e.percent = e.loaded / e.total * 100;
this.trigger('progress', e);
},
abort: function() {
set(this, 'isUploading', false);
this.trigger('isAborting');
},
ajaxSettings: function(url, params, method) {
var self = this;
return {
url: url,
type: method || 'POST',
contentType: false,
processData: false,
traditional: get(self, 'traditional'),
dataType: 'json',
xhr: function() {
var xhr = $.ajaxSettings.xhr();
xhr.upload.onprogress = function(e) {
self.didProgress(e);
};
self.one('isAborting', function() { xhr.abort(); });
return xhr;
},
data: params
};
},
ajax: function(url, params, method) {
return this._ajax(this.ajaxSettings(url, params, method));
},
_ajax: function(settings) {
var self = this;
return new Promise(function(resolve, reject) {
settings.success = function(data) {
run(null, resolve, self.didUpload(data));
};
settings.error = function(jqXHR, responseText, errorThrown) {
run(null, reject, self.didError(jqXHR, responseText, errorThrown));
};
$.ajax(settings);
});
}
});