diff options
| author | Peter Lejeck <peter.lejeck@gmail.com> | 2013-10-31 12:56:48 +0100 |
|---|---|---|
| committer | Peter Lejeck <peter.lejeck@gmail.com> | 2013-10-31 12:56:48 +0100 |
| commit | 1792788f5fc16f8b497351a5361649f5ce131891 (patch) | |
| tree | 981b02855329027996b9dd333dea51916a7615ec /js/cheesesteak.js | |
| parent | 152c0257a8ef9a8da7e45717a65578c340a7c178 (diff) | |
Move JS into js/, replace with uncompressed
Diffstat (limited to 'js/cheesesteak.js')
| -rw-r--r-- | js/cheesesteak.js | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/js/cheesesteak.js b/js/cheesesteak.js new file mode 100644 index 0000000..378c6e8 --- /dev/null +++ b/js/cheesesteak.js @@ -0,0 +1,168 @@ +;(function () { + /* Lightweight EventEmitter implementation */ + EventEmitter = function () {} + EventEmitter.prototype.on = function (evt, fn) { + this._events = this._events || {} + this._events[evt] = this._events[evt] || [] + this._events[evt].push(fn) + } + EventEmitter.prototype.off = function (evt, fn) { + if (!this.hasOwnProperty('_events')) return + if (evt in this._events === false) return + this._events[evt].splice(this._events[evt].indexOf(fn), 1) + } + EventEmitter.prototype.emit = function (evt) { + if (!this.hasOwnProperty('_events')) return + if (evt in this._events === false) return + + for (var i = 0, l = this._events[evt].length; i < l; i++) { + this._events[evt][i].apply(this, Array.prototype.slice.call(arguments, 1)) + } + } + + /* Copy the stuff from Array to FileList */ + FileList.prototype.forEach = Array.prototype.forEach + FileList.prototype.every = Array.prototype.every + FileList.prototype.some = Array.prototype.some + FileList.prototype.filter = Array.prototype.filter + FileList.prototype.map = Array.prototype.map + FileList.prototype.reduce = Array.prototype.reduce + FileList.prototype.reduceRight = Array.prototype.reduceRight + + Object.defineProperty(FileList.prototype, "size", { + get: function getSize () { + return this.reduce(function (prev, curr) { + return prev + curr.size + }, 0) + } + }) + + /* Utility to convert bytes into human units */ + var humanSize = { + get: function humanSize () { + var units = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"] + var e = Math.floor(Math.log(this.size) / Math.log(1024)) + return (this.size / Math.pow(1024, e)).toFixed(2) + " " + units[e] + } + } + Object.defineProperty(FileList.prototype, "humanSize", humanSize) + Object.defineProperty(File.prototype, "humanSize", humanSize) + + var percentUploaded = { + get: function percentUploaded () { + return this.uploadedSize / this.size + } + } + Object.defineProperty(FileList.prototype, "percentUploaded", percentUploaded) + Object.defineProperty(File.prototype, "percentUploaded", percentUploaded) + + Object.defineProperty(FileList.prototype, "uploadedSize", { + get: function getUploadedSize () { + return this.reduce(function (prev, curr) { + return prev + (curr.uploadedSize || 0) + }, 0) + } + }) + + /* Object URL stuff */ + Object.defineProperty(File.prototype, "url", { + get: function getURL () { + return window.URL.createObjectURL(this); + } + }) + File.revokeURL = function revokeURL (url) { + window.URL.revokeObjectURL(url) + } + + // We manipulate this instead of files, because the fucking geniuses at + // Mozilla interpreted the spec to mean that HTMLInputElement.prototype.files + // is read-only. It isn't, read for yourself: + // http://www.w3.org/html/wg/drafts/html/master/forms.html#dom-input-files + //HTMLInputElement.prototype.filelist = Object.create(FileList); + /* + Object.defineProperty(HTMLInputElement.prototype, "filelist", { + get: function getFileList () { + return this.filelist = this._filelist || this.files + }, + set: function (files) { + r + } + })*/ + +/* HTMLInputElement.prototype.addEventListener("change", function (e) { + this.filelist = e.target.files + })*/ + + // b gets merged as defaults for a + var defaults = function (a, b) { + var out = {} + for (var key in b) { + out[key] = (a[key] === void 0) ? b[key] : a[key] + } + return out + } + + var FileListUploader = function (url, files, opts) { + this.url = url + this.files = files + + opts = opts || {} + + this.opts = defaults(opts, { + 'field': 'files[]', + 'method': 'POST' + }) + } + FileListUploader.prototype = Object.create(EventEmitter.prototype) + FileListUploader.prototype.upload = function (cb) { + if (cb) this.on('uploadcomplete', cb) + + var opts = this.opts + var files = this.files + var events = this + + var data = new FormData() + files.forEach(function (file) { + data.append(opts.field, file) + }) + + var xhr = new XMLHttpRequest() + + xhr.open(opts.method, this.url, true) + xhr.upload.addEventListener('loadstart', function (e) { + for (var i = 0, l = files.length; i < l; i++) { + files[i].uploadedSize = 0 + } + }) + xhr.upload.addEventListener('progress', function (e) { + if (e.lengthComputable) { + size = e.loaded + // We know the size of the files, the order they're in, and how + // much we've uploaded. Based on this data, we can do some magic + // to figure out which file we're on, and how much we've uploaded + // of that file. + // TODO: This math has trouble on later uploads. Leak somewhere + for (var i = 0, l = files.length; i < l; i++) { + files[i].uploadedSize = Math.min(size, files[i].size) + size -= files[i].uploadedSize + if (size <= 0) { + files.current = files[i] + size = 0 + } + } + } + events.emit('uploadprogress', e, files) + }, false) + xhr.upload.addEventListener('loadstart', function (e) { events.emit('uploadstart', e) }) + xhr.upload.addEventListener('load', function (e) { events.emit('uploadcomplete', e) }) + xhr.addEventListener('progress', function (e) { events.emit('progress', e) }) + xhr.addEventListener('load', function (e) { events.emit('load', e, xhr.responseText) }) + + xhr.send(data) + /* TODO: Add more event passthroughs, maybe abstract it into a helper? */ + } + + FileList.prototype.upload = function uploadFileList (url, opts) { + return new FileListUploader(url, this, opts) + } +})() |
