// console.log("Loading UploadManager..."); Spontaneous.UploadManager = (function($, S) { var dom = S.Dom; var Upload = S.Upload; var WrapUpload = new JS.Class(Upload, { start: function() { var form = new FormData(); form.append('file', this.file); this.post(["/file", this.target_id].join('/'), form); } }); var ShardedWrapUpload = new JS.Class(S.ShardedUpload, { path: function() { return ["/shard", this.target_id].join('/'); }, method: "POST" }); var FormUpload = new JS.Class(Upload, { initialize: function(manager, target, form_data, size) { this.callSuper(manager, target, form_data) this.form_data = this.file; this._total = size; this.name = "Saving..."; }, start: function() { this.put(this.target.save_path(), this.form_data); } }); var UploadManager = { init: function(status_bar) { this.status_bar = status_bar; this.pending = []; this.completed = []; this.failed = []; this.current = null; this.updater = null; this.total_time = 0; this.total_data = 0; this.targets = {}; }, // call to append call for image replacement to queue add: function(target, upload) { this.pending.push(upload); this.register(target); }, register: function(target) { this.targets[target.uid()] = target; }, unregister: function(target) { delete this.targets[target.uid()]; }, replace: function(field, file) { var uploader_class = Upload; if (S.ShardedUpload.supported()) { console.log('Using sharded uploader') uploader_class = S.ShardedUpload; } this.add(field, new uploader_class(this, field, file)) if (!this.current) { this.next(); } }, // call to wrap files wrap: function(slot, files, position) { for (var i = 0, ii = files.length; i < ii; i++) { var file = files[i], upload, upload_class = WrapUpload; if (S.ShardedUpload.supported()) { console.log('Using sharded uploader') upload_class = ShardedWrapUpload; } upload = new upload_class(this, slot, file, position); this.add(slot, upload) } if (!this.current) { this.next(); } }, form: function(content, form_data, file_size) { var upload = new FormUpload(this, content, form_data, file_size); this.add(content, upload) if (!this.current) { this.next(); } }, next: function() { if (this.current) { return; } if (this.pending.length === 0) { // the download queue is complete if (this.failed.length === 0) { this.finished(); } else { var upload = this.failed.pop(), delay = Math.pow(2, upload.failure_count); console.log("UploadManager.next", "scheduling re-try of failed upload after", delay, "seconds"); this.pending.push(upload); window.setTimeout(function() { console.log("UploadManager.next", "re-trying failed upload"); this.next(); }.bind(this), delay * 1000); } return; } this.init_progress_bar(); this.current = this.pending.shift(); this.bars.name.text(this.current.name); this.current.start(); }, finished: function() { // console.log('UploadManager.finished', this.pending); this.completed = []; this.status_bar.hide(); }, init_progress_bar: function() { this.status_bar.show(); if (this.progress_showing) { return; } var c = this.status_bar.progress_container(); var outer = dom.div('#progress-bars'); var total = dom.div('#progress-total.bar'); var individual = dom.div('#progress-individual.bar'); var name = dom.div('#progress-name'); var stats = dom.div('#progress-stats'); outer.append(individual); outer.append(total); c.append(outer); c.append(name).append(stats); this.bars = { total: total, individual: individual, name: name, stats: stats }; this.progress_showing = true; }, data_total: function() { var total = 0; for (var i = 0, ii = this.completed.length; i < ii; i++) { total += this.completed[i].total(); } for (var i = 0, ii = this.pending.length; i < ii; i++) { total += this.pending[i].total(); } if (this.current) { total += this.current.total(); } return total; }, data_completed: function() { var completed = 0; for (var i = 0, ii = this.completed.length; i < ii; i++) { completed += this.completed[i].total(); } if (this.current) { completed += this.current.position(); } return completed; }, update_progress_bars: function() { var total = this.data_total(), completed = this.data_completed(); completed = Math.min(total, completed); this.set_bar_length('total', completed, total); if (this.current) { this.set_bar_length('individual', this.current.position, this.current.total); this.bars.stats.text([this.rate(), 'Kb\/s', this.time_estimate()].join(' ')); } else { this.set_bar_length('individual', 0, 0); } }, rate: function() { var t = this.total_time, d = this.total_data; if (this.current) { t += this.current.time; d += this.current.position(); } return Math.round(((d/1024)/(t/1000)*10)/10); }, time_estimate: function() { var remaining = this.data_total() - this.data_completed(); var time = (remaining/1024) / this.rate(); return (Math.round(time)) + 's'; }, set_bar_length: function(bar_name, position, total) { var bar = this.bars[bar_name], percent = (position/total) * 100; bar.css('width', percent+"%"); }, upload_progress: function(upload) { if (upload !== this.current) { console.warn("UploadManager#upload_progress", "completed upload does not match current") } var target = this.targets[upload.uid]; if (target) { target.upload_progress(upload.position(), upload.total()); } this.update_progress_bars(); }, upload_complete: function(upload, result) { if (upload !== this.current) { console.warn("UploadManager#upload_complete", "completed upload does not match current") } this.completed.push(this.current); this.total_time += this.current.time; this.total_data += this.current.position(); var target = this.targets[upload.uid]; if (target) { target.upload_complete(result); } this.current = null; this.next(); }, upload_failed: function(upload, event) { if (upload !== this.current) { console.warn("UploadManager#upload_complete", "completed upload does not match current") } this.failed.push(this.current); var target = this.targets[upload.uid]; if (target) { target.upload_failed(event); } this.current = null; console.error("UploadManager#upload_failed", upload, this.failed) this.next(); }, upload_conflict: function(upload, event) { if (upload !== this.current) { console.warn("UploadManager#upload_complete", "completed upload does not match current") } var target = this.targets[upload.uid]; if (target) { target.upload_conflict($.parseJSON(event.currentTarget.response)); } this.current = null; console.error("UploadManager#upload_conflict", upload, event) this.next(); }, FormUpload: FormUpload, WrapUpload: WrapUpload }; return UploadManager; }(jQuery, Spontaneous));