Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Safari uploads, closes #37. Please help review. #184

Merged
merged 7 commits into from

3 participants

@mixonic

Wow, what a night!

In Safari, FileReader was dropped in 5.1.something. There is also some problem with multi-part uploads in Safari 5. FileReader looks like it's probably on the way out anyway (in the next few years).

Anyway, this uses FormBuilder and Safari's native binary data ajax posts.

I considered the alternative of just building jQuery-File-Upload into Mercury. Honestly, I think that or plupload would be a great idea instead of rolling something custom. With jQuery-File-Upload, we also get a lightweight way to offer upload forms instead of just the tough-to-discover-and-learn drag and drop.

This is good in Chrome 18, Firefox 11, and Safari 5.1. Please, give it a test in another browser and see if any other version does not work properly.

@DaveTsunami

Good job! I confirm this works in mentioned Chrome and Safari versions on both Mac and Windows. Latest Safari 5.3 and Chrome 19.0.1 dev OK. The problem with Firefox from #145 still persists even though I upgraded to version 11.

@DaveTsunami

Now it works in Firefox without problems. I even spinned up by old Windows XP PC and tried it on Firefox 6. Everything works fine. Remarkably good work. A big thank to you @mixonic!

@jejacks0n
Owner

Thanks man!

@jejacks0n jejacks0n merged commit e435ad6 into from
@mixonic

w00t!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 12, 2012
  1. @mixonic

    Build js files for #180

    mixonic authored
Commits on Mar 14, 2012
  1. @mixonic
Commits on Mar 15, 2012
  1. @mixonic

    Use FormBuilder as a fallback from lacking support for FileReader and…

    mixonic authored
    … multipart posts in Safari. Closes #37.
  2. @mixonic
  3. @mixonic
  4. @mixonic

    Update mercury js files

    mixonic authored
Commits on Mar 16, 2012
  1. @mixonic
This page is out of date. Refresh to see the latest.
View
58 public/mercury/javascripts/mercury.js
@@ -16384,9 +16384,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;
@@ -16398,7 +16397,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 !!window.FileReader;
+ },
+ formDataSupported: function() {
+ return !!window.FormData;
},
build: function() {
var _ref, _ref2;
@@ -16456,15 +16461,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) {
@@ -16501,13 +16510,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;
@@ -16573,11 +16588,10 @@ Showdown.converter = function() {
function File(file) {
var errors;
this.file = file;
- this.size = this.file.size;
- this.fullSize = this.file.size;
- this.readableSize = this.file.size.toBytes();
- this.name = this.file.fileName;
- this.type = this.file.type;
+ this.fullSize = this.size = this.file.size || this.file.fileSize;
+ this.readableSize = this.size.toBytes();
+ this.name = this.file.name || this.file.fileName;
+ this.type = this.file.type || this.file.fileType;
errors = [];
if (this.size >= Mercury.config.uploading.maxFileSize) {
errors.push(Mercury.I18n('Too large'));
View
4 public/mercury/javascripts/mercury.min.js
2 additions, 2 deletions not shown
View
16 spec/javascripts/mercury/uploader_spec.js.coffee
@@ -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
@@ -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", ->
@@ -235,6 +238,19 @@ describe "Mercury.uploader", ->
Mercury.uploader.loadImage()
expect(spy.callCount).toEqual(1)
+ describe "#loadImage without 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", ->
View
52 vendor/assets/javascripts/mercury/uploader.js.coffee
@@ -25,7 +25,6 @@ jQuery.extend Mercury.uploader,
supported: ->
xhr = new XMLHttpRequest
- fileReader = window.FileReader
if window.Uint8Array && window.ArrayBuffer && !XMLHttpRequest.prototype.sendAsBinary
XMLHttpRequest::sendAsBinary = (datastr) ->
@@ -33,8 +32,13 @@ jQuery.extend Mercury.uploader,
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: ->
+ !!(window.FileReader)
+
+ formDataSupported: ->
+ !!(window.FormData)
build: ->
@element = jQuery('<div>', {class: 'mercury-uploader', style: 'display:none'})
@@ -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()
@@ -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) ->
@@ -180,11 +199,10 @@ jQuery.extend Mercury.uploader,
class Mercury.uploader.File
constructor: (@file) ->
- @size = @file.size
- @fullSize = @file.size
- @readableSize = @file.size.toBytes()
- @name = @file.fileName
- @type = @file.type
+ @fullSize = @size = @file.size || @file.fileSize
+ @readableSize = @size.toBytes()
+ @name = @file.name || @file.fileName
+ @type = @file.type || @file.fileType
# add any errors if we need to
errors = []
Something went wrong with that request. Please try again.