Created
April 1, 2016 15:14
-
-
Save blia/ec42096f778fcf601da1bb35167be436 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Uploader = Ember.Object.extend(Ember.Evented, { | |
url: null, | |
paramNamespace: null, | |
paramName: 'file', | |
isUploading: false, | |
/** | |
* ajax request type (method), by default it will be POST | |
* | |
* @property type | |
*/ | |
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'); | |
var self = this; | |
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 (Ember.isArray(files)) { | |
var paramName; | |
for (var i = files.length - 1; i >= 0; i--) { | |
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'); | |
}, | |
ajax: function(url, params, method) { | |
var self = this; | |
var settings = { | |
url: url, | |
type: method || 'POST', | |
contentType: false, | |
processData: false, | |
xhr: function() { | |
var xhr = Ember.$.ajaxSettings.xhr(); | |
xhr.upload.onprogress = function(e) { | |
self.didProgress(e); | |
}; | |
self.one('isAborting', function() { xhr.abort(); }); | |
return xhr; | |
}, | |
data: params | |
}; | |
return this._ajax(settings); | |
}, | |
_ajax: function(settings) { | |
var self = this; | |
return new Ember.RSVP.Promise(function(resolve, reject) { | |
settings.success = function(data) { | |
Ember.run(null, resolve, self.didUpload(data)); | |
}; | |
settings.error = function(jqXHR, responseText, errorThrown) { | |
Ember.run(null, reject, self.didError(jqXHR, responseText, errorThrown)); | |
}; | |
Ember.$.ajax(settings); | |
}); | |
} | |
}); | |
/** | |
* @namespace Uploader | |
*/ | |
export var eventManager = Ember.Object.extend({ | |
_elements: Ember.$(), | |
dragEnter: function (evt, view) { | |
if (this.get('_elements.length') === 0) { | |
this.uploader.trigger('filesDragStart', evt, view) | |
} | |
if (view.$().hasClass('uploader-zone')) { | |
Ember.$('.uploader-zone').removeClass('active') | |
view.$().addClass('active') | |
} else { | |
Ember.$('.uploader-zone').removeClass('active') | |
} | |
this.set('_elements', this.get('_elements').add(evt.target)) | |
}, | |
dragLeave: function (evt, view) { | |
this.set('_elements', this.get('_elements').not(evt.target)) | |
if (this.get('_elements.length') === 0) { | |
this.uploader.trigger('filesDragStop', evt, view) | |
Ember.$('.uploader-zone').removeClass('active') | |
} | |
}, | |
dragOver: function (evt, view) { | |
evt.stopPropagation(); | |
evt.preventDefault(); | |
}, | |
drop: function (evt, view) { | |
this.set('_elements', Ember.$()) | |
evt.stopPropagation(); | |
evt.preventDefault(); | |
this.uploader.trigger('filesDrop', evt, view) | |
} | |
}); | |
/** | |
* Uploader service helps you to uplad any files in your Ember app | |
* | |
* @class Service | |
* @memberof Uploader | |
*/ | |
export var Service = Ember.Object.extend(Ember.Evented, { | |
forbiddenUpload: true, | |
filesTypeUnacceptable: false, | |
filesSizeUnacceptable: false, | |
readyToUpload: false, | |
uploading: false, | |
limitError: false, | |
dataTransfer: null, | |
_handlers: 0, | |
uploadProgress: 0, | |
processing: false, | |
noHandlers: Ember.computed.not('_handlers'), | |
files: [], | |
rejected: Ember.computed.any('forbiddenUpload', 'noHandlers', 'filesTypeUnacceptable', 'filesSizeUnacceptable'), | |
/** | |
* Check user permissions to upload files | |
* | |
* @method userCan | |
* @memberof Service | |
*/ | |
userCan: function () { | |
this.set('forbiddenUpload', false) | |
return true | |
}, | |
handlersExist: function () { | |
return !this.get('noHandlers') | |
}, | |
_filesDragStartHandler: function (evt, view) { | |
this.trigger('show') | |
if (this.userCan()) { | |
if (this.handlersExist()) { | |
this.trigger('dragStart') | |
} | |
} | |
}, | |
_filesDragStopHandler: function (evt, view) { | |
this.trigger('hide') | |
this.set('forbiddenUpload', false) | |
this.set('filesTypeUnacceptable', false) | |
this.set('limitError', false) | |
this.set('filesSizeUnacceptable', false) | |
}, | |
_filesDropHandler: function (evt, view) { | |
this.set('dataTransfer', evt.dataTransfer) | |
if (typeof view.handleFiles === 'function') { | |
view.handleFiles(this.get('dataTransfer.files')) | |
} else { | |
// missed drop | |
1; | |
} | |
}, | |
_showHandler: function () { | |
this.set('readyToUpload', true) | |
}, | |
_hideHandler: function () { | |
this.set('readyToUpload', false) | |
}, | |
_initEventHandlers: function () { | |
this.on('filesDragStart', this._filesDragStartHandler) | |
this.on('filesDragStop', this._filesDragStopHandler) | |
this.on('filesDrop', this._filesDropHandler) | |
this.on('show', this._showHandler) | |
this.on('hide', this._hideHandler) | |
}, | |
init: function () { | |
this._initEventHandlers() | |
}, | |
addHandler: function () { | |
this.set('_handlers', this.get('_handlers') + 1) | |
}, | |
removeHandler: function () { | |
this.set('_handlers', this.get('_handlers') - 1) | |
}, | |
uploadFiles: function (endPoint) { | |
var self = this | |
var uploader = Uploader.create({ url: endPoint }) | |
this.set('uploading', true) | |
this.set('readyToUpload', false) | |
this.set('uploadProgress', 0) | |
uploader.on('progress', function (e) { | |
self.set('uploadProgress', Math.round(e.percent)) | |
if (Math.round(e.percent) === 100) { | |
self.set('uploading', false) | |
self.set('processing', true) | |
} | |
}) | |
uploader.on('didUpload', function (data) { | |
self.set('uploading', false) | |
self.set('processing', false) | |
}) | |
return uploader.upload(this.get('files')) | |
} | |
}); | |
/** | |
* Uploader Component adds dnd uploader view to your ember app. | |
* | |
* @class UploaderComponent | |
*/ | |
export var Component = Ember.Component.extend({ | |
tagName: 'section', | |
classNames: ['uploader-zone'], | |
classNameBindings: ['opened', 'error'], | |
opened: Ember.computed.alias('uploader.readyToUpload'), | |
error: Ember.computed.alias('uploader.rejected'), | |
active: false, | |
defaults: { | |
acceptTypes: "*", | |
multiple: true, | |
maximumFileSize: 0, | |
maximumSummarySize: 0, | |
filesLimit: 0, | |
autoUpload: true, | |
autoUploadSingle: true, | |
endPoint: ENV.cdnPrefix | |
}, | |
/** | |
* Uploader options | |
* | |
* Default options: | |
* - acceptTypes: "*" | |
* - multiple: true | |
* - maximumFileSize: 0 | |
* - maximumSummarySize: 0 | |
* - filesLimit: 0 | |
* - autoUpload: true | |
* - autoUploadSingle: true | |
* - endPoint: '/cdn/' | |
* | |
* @type {Array} | |
*/ | |
options: [], | |
init: function () { | |
this._super() | |
this.uploader.addHandler() | |
}, | |
willDestroy: function () { | |
this._super() | |
this.uploader.removeHandler() | |
}, | |
finishUpload: function (data) { | |
var uploader = this.uploader | |
var options = _.defaults(this.get('options'), this.get('defaults')) | |
var file | |
uploader.set('files', []) | |
// console.log(data.length, this.uploader.get('files.length')); | |
this.uploader.trigger('hide') | |
this.sendAction('action', data) | |
}, | |
handleFiles: function (FileList) { | |
var length = FileList.length | |
var uploader = this.uploader | |
var options = _.defaults(this.get('options'), this.get('defaults')) | |
var acceptedByType = [] | |
var acceptedBySize = [] | |
var files = [] | |
// check for multiple | |
if (!options.multiple && length > 1) { | |
uploader.set('limit', 1) | |
uploader.set('limitError', true) | |
} | |
// check length | |
if (options.filesLimit !== 0 && length > options.filesLimit) { | |
uploader.set('limit', options.filesLimit) | |
uploader.set('limitError', true) | |
} | |
for (var i = 0; i < length; i++) { | |
var file = FileList.item(i) | |
// check types | |
if (options.acceptTypes !== '*') { | |
// RegExp | |
if (_.isRegExp(options.acceptTypes) && options.acceptTypes.test(file.type)) { | |
acceptedByType.push(file) | |
} else | |
// string | |
if (_.isString(options.acceptTypes) && options.acceptTypes === file.type) { | |
acceptedByType.push(file) | |
} else | |
// array | |
if (_.isArray(options.acceptTypes) && options.acceptTypes.indexOf(file.type) !== -1) { | |
acceptedByType.push(file) | |
} else { | |
file.badType = true | |
} | |
} else { | |
acceptedByType.push(file) | |
} | |
// check sizes | |
if (options.maximumFileSize !== 0) { | |
if (options.maximumFileSize < file.size) { | |
file.badSize = true | |
} else { | |
acceptedBySize.push(file) | |
} | |
} else { | |
acceptedBySize.push(file) | |
} | |
// TODO check comuted size | |
// images | |
// if (/image\/.*/.test(file.type)) { | |
// console.log('image', file); | |
// file.kind = 'image' | |
// var img = document.createElement("img") | |
// img.file = file | |
// var reader = new FileReader(); | |
// reader.onload = (function(aImg) { return function(e) { | |
// aImg.src = e.target.result; | |
// | |
// }; })(img); | |
// reader.readAsDataURL(file); | |
// console.log("%O", img); | |
// } | |
file.checked = true | |
files.push(file) | |
} | |
if (acceptedByType.length === 0) { | |
uploader.set('filesTypeUnacceptable', true) | |
this.set('error', true) | |
return | |
} | |
if (acceptedBySize.length === 0) { | |
uploader.set('filesSizeUnacceptable', true) | |
this.set('error', true) | |
return | |
} | |
uploader.set('files', files) | |
if (length === 1 && options.autoUploadSingle) { | |
uploader.uploadFiles(options.endPoint) | |
.then(Ember.run.bind(this, 'finishUpload')) | |
} else if (options.autoUpload) { | |
uploader.uploadFiles(options.endPoint) | |
.then(Ember.run.bind(this, 'finishUpload')) | |
} else { | |
uploader.showFileList() | |
} | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment