summaryrefslogtreecommitdiff
path: root/js/cheesesteak.js
diff options
context:
space:
mode:
authorPeter Lejeck <peter.lejeck@gmail.com>2013-10-31 12:56:48 +0100
committerPeter Lejeck <peter.lejeck@gmail.com>2013-10-31 12:56:48 +0100
commit1792788f5fc16f8b497351a5361649f5ce131891 (patch)
tree981b02855329027996b9dd333dea51916a7615ec /js/cheesesteak.js
parent152c0257a8ef9a8da7e45717a65578c340a7c178 (diff)
Move JS into js/, replace with uncompressed
Diffstat (limited to 'js/cheesesteak.js')
-rw-r--r--js/cheesesteak.js168
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)
+ }
+})()