Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Use FormBuilder as a fallback from lacking support for FileReader and…
… multipart posts in Safari. Closes jejacks0n#37.
  • Loading branch information
mixonic committed Mar 15, 2012
1 parent f286c3a commit 171ca36
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 32 deletions.
52 changes: 34 additions & 18 deletions public/mercury/javascripts/mercury.js
Expand Up @@ -16357,7 +16357,8 @@ Showdown.converter = function() {

}).call(this);
(function() {
var __hasProp = Object.prototype.hasOwnProperty;
var __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = Object.prototype.hasOwnProperty;

this.Mercury.uploader = function(file, options) {
if (Mercury.config.uploading.enabled) Mercury.uploader.show(file, options);
Expand All @@ -16384,9 +16385,8 @@ Showdown.converter = function() {
return this.initialized = true;
},
supported: function() {
var fileReader, xhr;
var xhr;
xhr = new XMLHttpRequest;
fileReader = window.FileReader;
if (window.Uint8Array && window.ArrayBuffer && !XMLHttpRequest.prototype.sendAsBinary) {
XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
var data, index, ui8a, _len;
Expand All @@ -16398,7 +16398,13 @@ Showdown.converter = function() {
return this.send(ui8a.buffer);
};
}
return !!(xhr.upload && xhr.sendAsBinary && fileReader);
return !!(xhr.upload && xhr.sendAsBinary && (Mercury.uploader.fileReaderSupported() || Mercury.uploader.formDataSupported()));
},
fileReaderSupported: function() {
return !!(__indexOf.call(window, 'FileReader') >= 0);
},
formDataSupported: function() {
return !!(__indexOf.call(window, 'FormData') >= 0);
},
build: function() {
var _ref, _ref2;
Expand Down Expand Up @@ -16456,15 +16462,19 @@ Showdown.converter = function() {
},
loadImage: function() {
var _this = this;
return this.file.readAsDataURL(function(result) {
_this.element.find('.mercury-uploader-preview b').html(jQuery('<img>', {
src: result
}));
return _this.upload();
});
if (Mercury.uploader.fileReaderSupported()) {
return this.file.readAsDataURL(function(result) {
_this.element.find('.mercury-uploader-preview b').html(jQuery('<img>', {
src: result
}));
return _this.upload();
});
} else {
return this.upload();
}
},
upload: function() {
var xhr,
var formData, xhr,
_this = this;
xhr = new XMLHttpRequest;
jQuery.each(['onloadstart', 'onprogress', 'onload', 'onabort', 'onerror'], function(index, eventName) {
Expand Down Expand Up @@ -16501,13 +16511,19 @@ Showdown.converter = function() {
xhr.setRequestHeader('Accept', 'application/json, text/javascript, text/html, application/xml, text/xml, */*');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader(Mercury.config.csrfHeader, Mercury.csrfToken);
return this.file.readAsBinaryString(function(result) {
var multipart;
multipart = new Mercury.uploader.MultiPartPost(Mercury.config.uploading.inputName, _this.file, result);
_this.file.updateSize(multipart.delta);
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + multipart.boundary);
return xhr.sendAsBinary(multipart.body);
});
if (Mercury.uploader.fileReaderSupported()) {
return this.file.readAsBinaryString(function(result) {
var multipart;
multipart = new Mercury.uploader.MultiPartPost(Mercury.config.uploading.inputName, _this.file, result);
_this.file.updateSize(multipart.delta);
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + multipart.boundary);
return xhr.sendAsBinary(multipart.body);
});
} else {
formData = new FormData();
formData.append(Mercury.config.uploading.inputName, this.file.file, this.file.file.name);
return xhr.send(formData);
}
},
updateStatus: function(message, loaded) {
var percent;
Expand Down
4 changes: 2 additions & 2 deletions public/mercury/javascripts/mercury.min.js

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions spec/javascripts/mercury/uploader_spec.js.coffee
Expand Up @@ -4,6 +4,8 @@ describe "Mercury.uploader", ->

beforeEach ->
Mercury.config.uploading.enabled = true
@fileReaderSupport = spyOn(Mercury.uploader, 'fileReaderSupported')
@fileReaderSupport.andCallFake(=> true)
$.fx.off = true
@mockFile = {
size: 1024
Expand Down Expand Up @@ -220,6 +222,7 @@ describe "Mercury.uploader", ->
Mercury.uploader.file = new Mercury.uploader.File(@mockFile)
Mercury.uploader.build()
spyOn(FileReader.prototype, 'readAsBinaryString').andCallFake(=>)
@fileReaderSupport.andCallFake(=> true)
@readAsDataURLSpy = spyOn(Mercury.uploader.File.prototype, 'readAsDataURL').andCallFake((callback) => callback('data-url'))

it "calls file.readAsDataURL", ->
Expand All @@ -235,6 +238,19 @@ describe "Mercury.uploader", ->
Mercury.uploader.loadImage()
expect(spy.callCount).toEqual(1)

describe "#loadImage with FileReader", ->

beforeEach ->
Mercury.uploader.options = {appendTo: '#test'}
Mercury.uploader.file = new Mercury.uploader.File(@mockFile)
Mercury.uploader.build()
@fileReaderSupport.andCallFake(=> false)

it "calls upload", ->
spy = spyOn(Mercury.uploader, 'upload').andCallFake(=>)
Mercury.uploader.loadImage()
expect(spy.callCount).toEqual(1)


describe "#upload", ->

Expand Down
43 changes: 31 additions & 12 deletions vendor/assets/javascripts/mercury/uploader.js.coffee
Expand Up @@ -25,16 +25,20 @@ jQuery.extend Mercury.uploader,

supported: ->
xhr = new XMLHttpRequest
fileReader = window.FileReader

if window.Uint8Array && window.ArrayBuffer && !XMLHttpRequest.prototype.sendAsBinary
XMLHttpRequest::sendAsBinary = (datastr) ->
ui8a = new Uint8Array(datastr.length)
ui8a[index] = (datastr.charCodeAt(index) & 0xff) for data, index in datastr
@send(ui8a.buffer)

return !!(xhr.upload && xhr.sendAsBinary && fileReader)
return !!(xhr.upload && xhr.sendAsBinary && (Mercury.uploader.fileReaderSupported() || Mercury.uploader.formDataSupported()))

fileReaderSupported: ->
!!('FileReader' in window)

formDataSupported: ->
!!('FormData' in window)

build: ->
@element = jQuery('<div>', {class: 'mercury-uploader', style: 'display:none'})
Expand Down Expand Up @@ -86,8 +90,11 @@ jQuery.extend Mercury.uploader,


loadImage: ->
@file.readAsDataURL (result) =>
@element.find('.mercury-uploader-preview b').html(jQuery('<img>', {src: result}))
if Mercury.uploader.fileReaderSupported()
@file.readAsDataURL (result) =>
@element.find('.mercury-uploader-preview b').html(jQuery('<img>', {src: result}))
@upload()
else
@upload()


Expand Down Expand Up @@ -121,16 +128,28 @@ jQuery.extend Mercury.uploader,
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
xhr.setRequestHeader(Mercury.config.csrfHeader, Mercury.csrfToken)

@file.readAsBinaryString (result) =>
# build the multipart post string
multipart = new Mercury.uploader.MultiPartPost(Mercury.config.uploading.inputName, @file, result)
# Homespun multipart uploads. Chrome 18, Firefox 11.
#
if Mercury.uploader.fileReaderSupported()
@file.readAsBinaryString (result) =>

multipart = new Mercury.uploader.MultiPartPost(Mercury.config.uploading.inputName, @file, result)

# update the content size so we can calculate
@file.updateSize(multipart.delta)
# update the content size so we can calculate
@file.updateSize(multipart.delta)

# set the content type and send
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + multipart.boundary)
xhr.sendAsBinary(multipart.body)

# FormData based. Safari 5.1.2.
#
else
formData = new FormData()
formData.append(Mercury.config.uploading.inputName, @file.file, @file.file.name)

xhr.send(formData)

# set the content type and send
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + multipart.boundary)
xhr.sendAsBinary(multipart.body)


updateStatus: (message, loaded) ->
Expand Down

0 comments on commit 171ca36

Please sign in to comment.