Last active
October 10, 2015 12:59
-
-
Save ksprwhite/a720bcf74dbd55ec3ab8 to your computer and use it in GitHub Desktop.
This file contains 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 FileUploader = (function($global) { | |
var defaults = { | |
'wrapperStyle': '', | |
'url': null, | |
'chooseText': 'Seleccionar archivos' | |
}, | |
context = null; | |
function Uploader(element, settings) { | |
context = this; | |
this.settings = settings; | |
this.defaults = defaults; | |
this.init(this.element = element); | |
} | |
Uploader.prototype = { | |
formData: new FormData(), | |
additionalFields: {}, | |
form: false, | |
submitted: false, | |
wrapper: null, | |
callbacks: { | |
'progress': null, | |
'error': null, | |
'complete': null, | |
'success': null, | |
'choose': null | |
}, | |
/* inicializamos */ | |
init: function(element) { | |
var parent; | |
this.instance.element = element; | |
/* check parent form */ | |
parent = element; | |
do { | |
parent = parent.parentNode; | |
if (parent.tagName == 'FORM') { | |
this.form = parent; | |
break; | |
} | |
} while (parent); | |
if (this.form) { | |
this.form.onsubmit = function() { | |
context.upload(); | |
return false; | |
}; | |
} | |
/* check multiple attribute */ | |
if (!this.element.multiple) { | |
this.element.multiple = true; | |
} | |
this.prepareSettings(); | |
this.setWrapper(); | |
}, | |
prepareSettings: function() { | |
for (var _default in this.defaults) { | |
if (!(_default in this.settings)) { | |
this.settings[_default] = this.defaults[_default]; | |
} | |
} | |
for (var setting in this.settings) { | |
var value = this.settings[setting]; | |
switch (setting) { | |
case 'additional': | |
// check aditional inputs | |
if (Object.prototype.toString.call(value) == '[object Object]') { | |
for (var key in this.settings.additional) { | |
if (!this.settings.additional.hasOwnProperty(key)) { | |
continue; | |
} | |
this.additionalFields[key] = value; | |
} | |
} else if (Object.prototype.toString.call(value) == '[object String]' && | |
document.querySelector(value)) { | |
[].forEach.call(document.querySelector(value).children, function(element, index) { | |
if (element === context.element || | |
element.tagName !== 'INPUT' || | |
!element.getAttribute('name')) { | |
return; | |
} | |
context.additionalFields[element.getAttribute('name')] = element.value; | |
}); | |
} | |
break; | |
case 'url': | |
if (!value && this.form && this.form.getAttribute('action')) { | |
this.settings[setting] = this.form.getAttribute('action'); | |
} else if (!value) { | |
this.settings[settings] = ''; | |
} | |
break; | |
} | |
} | |
}, | |
reset: function() { | |
// clear input value | |
this.element.value = ''; | |
if (this.element.value) { | |
this.element.type = 'text'; | |
this.element.type = 'file'; | |
} | |
this.element.disabled = false; | |
// clear additional inputs | |
this.additionalFields = {}; | |
// reset formData | |
this.formData = new FormData(); | |
// enable submit | |
this.submitted = false; | |
// set defaults and settings | |
this.prepareSettings(); | |
// reset wrapper | |
this.setWrapper(); | |
}, | |
upload: function() { | |
if (!this.element.files.length && !this.additionalFields.length) | |
return false; | |
if (this.submitted) { | |
return false; | |
} else { | |
this.wrapper.className = [this.wrapper.className, 'disabled'].join(' '); | |
this.element.disabled = true; | |
this.submitted = true; | |
} | |
// add files | |
[].forEach.call(this.element.files, function(file, index) { | |
context.formData.append(context.element.getAttribute('name'), file); | |
}); | |
// add extra fields | |
Object.keys(this.additionalFields).forEach(function(key) { | |
context.formData.append(key, context.additionalFields[key]); | |
}); | |
// create XMLHttpRequest object | |
var xhr = new XMLHttpRequest(); | |
// handle progress | |
xhr.upload.addEventListener('progress', function(event) { | |
if (event.lengthComputable) { | |
var progress = (event.loaded / event.total) * 100; | |
context.performCallback('progress', [progress, event]); | |
} | |
}, false); | |
// handle complete callback | |
xhr.upload.addEventListener('load', function(event) { | |
context.performCallback('complete', [event]); | |
}, false); | |
// handle error | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState === 4) { | |
if (xhr.status !== 200) { | |
context.performCallback('error', [xhr]); | |
} else { | |
context.performCallback('success', [xhr]); | |
} | |
} | |
}; | |
// open and send data | |
xhr.open('POST', this.settings.url, true); | |
xhr.send(this.formData); | |
}, | |
setCallback: function(callback, handler) { | |
if (!(callback in this.callbacks)) | |
return false; | |
this.callbacks[callback] = handler; | |
}, | |
performCallback: function(callback, args) { | |
if (this.callbacks[callback]) { | |
this.callbacks[callback].apply(this.instance, args); | |
} | |
}, | |
setWrapper: function() { | |
var parent = this.form ? this.form : this.element.parentNode, | |
wrapper = document.createElement('div'), | |
button = document.createElement('a'), | |
info = document.createElement('div'); | |
if (this.wrapper) { | |
this.element.parentNode.removeChild(this.wrapper); | |
} | |
this.wrapper = wrapper; | |
this.element.style.display = 'none'; | |
button.className = 'button'; | |
button.innerHTML = this.settings.chooseText; | |
button.href = '#'; | |
info.className = 'info'; | |
this.wrapper.className = this.settings.wrapperStyle; | |
this.wrapper.appendChild(button); | |
this.wrapper.appendChild(info); | |
button.addEventListener('click', function(event) { | |
context.element.click(); | |
event.preventDefault(); | |
return false; | |
}); | |
this.element.addEventListener('change', function() { | |
info.innerHTML = context.element.files.length + ' archivos selecionados'; | |
context.performCallback('choose', [context.element.files]); | |
}); | |
if (this.element.files.length) { | |
info.innerHTML = this.element.files.length + ' archivos selecionados'; | |
} | |
parent.insertBefore(this.wrapper, this.element); | |
}, | |
instance: { | |
element: null, | |
upload: function() { | |
context.upload(); | |
return this; | |
}, | |
reset: function() { | |
context.reset(); | |
return this; | |
}, | |
on: function(callback, handler) { | |
context.setCallback(callback, handler); | |
return this; | |
} | |
} | |
}; | |
return (function(selector, settings) { | |
var element; | |
$global._UploaderInstances = $global._UploaderInstances || {}; | |
if (!(element = document.querySelector(selector))) { | |
throw new Error(['[', selector, ']', ' element is undefined.'].join('')); | |
} else if (element.nodeName !== 'INPUT' || element.type !== 'file') { | |
throw new Error(['[', selector, ']', ' input must be file type.'].join('')); | |
} else if (!$global._UploaderInstances[element]) { | |
return $global._UploaderInstances[element] = new Uploader(element, settings).instance; | |
} else { | |
return $global._UploaderInstances[element]; | |
} | |
}); | |
}(window)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment