function UploadQueue(options) { this.queue = options.queue_element; this.preview_area = options.preview_area; this.upload_progress = []; this.upload_url = options.upload_url; this.submit = options.submit_button; this.addEvents(); } UploadQueue.prototype.addEvents = function() { var that = this; that.queue.addEventListener('change', function() { that.showSpinner(that.queue, "Generating previews (not uploading yet!)"); that.clearPreviews(); for (var i = 0; i < that.queue.files.length; i++) { var callback = (i !== that.queue.files.length - 1) ? null : function() { that.hideSpinner(); }; that.addPreviewForFile(that.queue.files[i], i, callback); }; }); that.submit.addEventListener('click', function(e) { e.preventDefault(); that.process(); }); }; UploadQueue.prototype.clearPreviews = function() { this.preview_area.innerHTML = ''; } UploadQueue.prototype.addPreviewForFile = function(file, index, callback) { if (!file) { return false; } var preview = document.createElement('img'); preview.title = file.name; preview.style.maxHeight = '150px'; var preview_box = document.createElement('div'); preview_box.id = 'upload_preview_' + index; preview_box.appendChild(preview); var reader = new FileReader(); var that = this; var appendMe = function() { preview.src = reader.result; if (callback) { preview.addEventListener('load', function() { callback(); }); } that.preview_area.appendChild(preview_box); }; var waitForMe = function() { var previews = that.preview_area.childNodes; if (previews.length === 0 || previews[previews.length - 1].id === 'upload_preview_' + (index - 1)) { appendMe(); } else { setTimeout(waitForMe, 10); } }; reader.addEventListener('load', waitForMe, false); reader.readAsDataURL(file); }; UploadQueue.prototype.process = function() { this.showSpinner(this.submit, "Preparing to upload files..."); var files = this.queue.files; for (var i = 0; i < files.length; i++) { this.setSpinnerLabel("Uploading file " + (i + 1) + " out of " + files.length); var callback = (i !== files.length - 1) ? null : function() { this.hideSpinner(); }; this.sendFile(files[i], i, callback); }; }; UploadQueue.prototype.sendFile = function(file, index, callback) { // Prepare the request. var that = this; var request = new XMLHttpRequest(); request.addEventListener('error', function(event) { that.updateProgress(index, -1); }); request.addEventListener('progress', function(event) { that.updateProgress(index, event.loaded / event.total); }); request.addEventListener('load', function(event) { that.updateProgress(index, 1); if (request.responseText !== null && request.status === 200) { var obj = JSON.parse(request.responseText); if (obj.error) { alert(obj.error); return; } else if (callback) { callback.call(that, obj); } } }); var data = new FormData(); data.append('uploads', file, file.name); request.open('POST', this.upload_url, true); request.send(data); }; UploadQueue.prototype.addProgressBar = function(index) { if (index in this.upload_progress) { return; } var progress_container = document.createElement('div'); progress_container.className = 'progress'; var progress = document.createElement('div'); progress_container.appendChild(progress); var preview_box = document.getElementById('upload_preview_' + index); preview_box.appendChild(progress_container); this.upload_progress[index] = progress; }; UploadQueue.prototype.updateProgress = function(index, progress) { if (!(index in this.upload_progress)) { this.addProgressBar(index); } var bar = this.upload_progress[index]; if (progress >= 0) { bar.style.width = Math.ceil(progress * 100) + '%'; } else { bar.style.width = ""; if (progress === -1) { bar.className = "error"; } } }; UploadQueue.prototype.showSpinner = function(sibling, label) { if (this.spinner) { return; } this.spinner = document.createElement('div'); this.spinner.className = 'spinner'; sibling.parentNode.appendChild(this.spinner); if (label) { this.spinner_label = document.createElement('span'); this.spinner_label.className = 'spinner_label'; this.spinner_label.innerHTML = label; sibling.parentNode.appendChild(this.spinner_label); } }; UploadQueue.prototype.setSpinnerLabel = function(label) { if (this.spinner_label) { this.spinner_label.innerHTML = label; } } UploadQueue.prototype.hideSpinner = function() { if (this.spinner) { this.spinner.parentNode.removeChild(this.spinner); this.spinner = null; } if (this.spinner_label) { this.spinner_label.parentNode.removeChild(this.spinner_label); this.spinner_label = null; } };