Skip to content

Instantly share code, notes, and snippets.

@Asmod4n
Created May 23, 2014 04:15
Show Gist options
  • Save Asmod4n/28e5440fd47af471da9c to your computer and use it in GitHub Desktop.
Save Asmod4n/28e5440fd47af471da9c to your computer and use it in GitHub Desktop.
//= require external/crypto-js/build/rollups/sha512.js
//= require external/crypto-js/build/components/lib-typedarrays.js
messageHandler = (event) ->
if 'cmd' of event.data
switch event.data.cmd
when 'localStorage.push'
if storedFiles = localStorage.getItem(event.data.key)
storedFiles = JSON.parse(storedFiles)
storedFiles.push event.data.value
localStorage.setItem event.data.key, JSON.stringify(storedFiles)
else
localStorage.setItem event.data.key, JSON.stringify([event.data.value])
when 'localStorage.del' then localStorage.removeItem event.data.key
when 'print' then console.log event.data.message
$('form').submit (event) ->
event.preventDefault()
worker = new Worker("<%= javascript_path('form_worker.js') %>")
worker.addEventListener 'message', messageHandler, false
form = new Array()
$(this).find('input, textarea, select').each (index, element) ->
if element.type is 'file'
form.push
name: element.name
type: element.type
data: element.files
else
form.push
name: element.name
type: element.type
data: $(this).val()
worker.postMessage
cmd: 'tryit'
form: form
#= require internal/js/crypto.js
#= require internal/js/xhr2-FormData.js
chunkUpload = (file, length, sha512, formUUID, chunkCount, chunk) ->
formData = new FormData()
formData.append 'ffl.file', JSON.stringify(
name: file.name
size: file.size
type: file.type
length: length
sha512: sha512
formUUID: formUUID
chunkNumber: chunkCount.currentNumber
numOfChunks: chunkCount.numOfChunks
)
formData.append 'ffl.chunk', chunk
xhr = new XMLHttpRequest()
xhr.open 'POST', '/application/', false
xhr.setRequestHeader 'Accept', 'application/json'
xhr.setRequestHeader 'X-Form-UUID', formUUID
xhr.send formData
postMessage
cmd: 'print'
message: JSON.stringify(xhr.response)
if xhr.status < 400
response = JSON.parse(xhr.response)
if response.success is true
postMessage
cmd: 'localStorage.push'
key: sha512
value: chunkCount.currentNumber
chunkCount.numOfUploadedChunks++
if chunkCount.numOfUploadedChunks is chunkCount.numOfChunks
postMessage
cmd: 'localStorage.del'
key: sha512
upload = (file, length, sha512, formUUID) ->
chunkSize = 1024 * 512
chunkCount =
currentNumber: 1
numOfChunks: Math.ceil(file.size / chunkSize)
numOfUploadedChunks: 0
chunkStart = 0
chunkEnd = chunkSize
while chunkStart < file.size
if file.slice
currentChunk = file.slice(chunkStart, chunkEnd)
else if file.mozSlice
currentChunk = file.mozSlice(chunkStart, chunkEnd)
else currentChunk = file.webkitSlice(chunkStart, chunkEnd) if file.webkitSlice
chunkUpload file, length, sha512, formUUID, chunkCount, currentChunk
chunkCount.currentNumber++
chunkStart = chunkEnd
chunkEnd = chunkEnd + chunkSize
UUID = ->
uuid = ''
i = 0
while i < 32
random = Math.random() * 16 | 0
uuid += '-' if i is 8 or i is 12 or i is 16 or i is 20
uuid += ((if i is 12 then 4 else ((if i is 16 then (random & 3 | 8) else random)))).toString(16)
i++
uuid
uploadFiles = (files, formUUID) ->
reader = new FileReaderSync()
i = 0
while i < files.length
upload files[i], files.length, CryptoJS.SHA512(CryptoJS.lib.WordArray.create(reader.readAsArrayBuffer(files[i]))).toString(CryptoJS.enc.Hex), formUUID
i++
uploadForm = (form) ->
formUUID = UUID()
postMessage
cmd: 'print'
message: formUUID
formData = new FormData()
form.forEach (element, index, array) ->
if element.type is 'file'
array.splice index, 1
uploadFiles element.data, formUUID
else
formData.append element.name, element.data
xhr = new XMLHttpRequest()
xhr.open 'POST', '/application/', false
xhr.setRequestHeader 'Accept', 'application/json'
xhr.setRequestHeader 'X-Form-UUID', formUUID
xhr.send formData
postMessage
cmd: 'print'
message: JSON.stringify(xhr.response)
self.close()
self.addEventListener 'message', ((event) ->
if 'cmd' of event.data
switch event.data.cmd
when 'tryit'
uploadForm event.data.form
), false
/*
* FormData for XMLHttpRequest 2 - Polyfill for Web Worker (c) 2012 Rob W
* License: Creative Commons BY - http://creativecommons.org/licenses/by/3.0/
* - append(name, value[, filename])
* - toString: Returns an ArrayBuffer object
*
* Specification: http://www.w3.org/TR/XMLHttpRequest/#formdata
* http://www.w3.org/TR/XMLHttpRequest/#the-send-method
* The .append() implementation also accepts Uint8Array and ArrayBuffer objects
* Web Workers do not natively support FormData:
* http://dev.w3.org/html5/workers/#apis-available-to-workers
**/
(function() {
// Export variable to the global scope
(this == undefined ? self : this)['FormData'] = FormData;
var ___send$rw = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype['send'] = function(data) {
if (data instanceof FormData) {
if (!data.__endedMultipart) data.__append('--' + data.boundary + '--\r\n');
data.__endedMultipart = true;
this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + data.boundary);
data = new Uint8Array(data.data).buffer;
}
// Invoke original XHR.send
return ___send$rw.call(this, data);
};
function FormData() {
// Force a Constructor
if (!(this instanceof FormData)) return new FormData();
// Generate a random boundary - This must be unique with respect to the form's contents.
this.boundary = '------RWWorkerFormDataBoundary' + Math.random().toString(36);
var internal_data = this.data = [];
/**
* Internal method.
* @param inp String | ArrayBuffer | Uint8Array Input
*/
this.__append = function(inp) {
var i=0, len;
if (typeof inp === 'string') {
for (len=inp.length; i<len; i++)
internal_data.push(inp.charCodeAt(i) & 0xff);
} else if (inp && inp.byteLength) {/*If ArrayBuffer or typed array */
if (!('byteOffset' in inp)) /* If ArrayBuffer, wrap in view */
inp = new Uint8Array(inp);
for (len=inp.byteLength; i<len; i++)
internal_data.push(inp[i] & 0xff);
}
};
}
/**
* @param name String Key name
* @param value String|Blob|File|Uint8Array|ArrayBuffer Value
* @param filename String Optional File name (when value is not a string).
**/
FormData.prototype['append'] = function(name, value, filename) {
if (this.__endedMultipart) {
// Truncate the closing boundary
this.data.length -= this.boundary.length + 6;
this.__endedMultipart = false;
}
var valueType = Object.prototype.toString.call(value),
part = '--' + this.boundary + '\r\n' +
'Content-Disposition: form-data; name="' + name + '"';
if (/^\[object (?:Blob|File)(?:Constructor)?\]$/.test(valueType)) {
return this.append(name,
new Uint8Array(new FileReaderSync().readAsArrayBuffer(value)),
filename || value.name);
} else if (/^\[object (?:Uint8Array|ArrayBuffer)(?:Constructor)?\]$/.test(valueType)) {
part += '; filename="'+ (filename || 'blob').replace(/"/g,'%22') +'"\r\n';
part += 'Content-Type: application/octet-stream\r\n\r\n';
this.__append(part);
this.__append(value);
part = '\r\n';
} else {
part += '\r\n\r\n' + value + '\r\n';
}
this.__append(part);
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment