Skip to content

Commit

Permalink
add ability to store files in outbox (fixes #22)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheppard committed May 23, 2015
1 parent 26d2aa5 commit af62e67
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 79 deletions.
71 changes: 45 additions & 26 deletions js/wq/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,34 +841,53 @@ function _handleForm(evt) {
var outboxId = $form.data('wq-outbox-id');
var url = $form.attr('action').replace(app.base_url + "/", "");
var conf = _getConfByUrl(url);

var vals = {};
var $files = $form.find('input[type=file]');
var has_files = ($files.length > 0 && $files.val().length > 0);
if (!app['native'] && has_files) {
// Files present and we're not running in Cordova.
if (window.FormData && window.Blob) {
// Modern browser; use FormData to upload files via AJAX.
// FIXME: localStorage version of outbox item will be unusable.
// Can we serialize this object somehow?
vals.data = new FormData(this);
} else {
// Looks like we're in a an old browser and we can't upload files
// via AJAX or Cordova... Bypass store and assume server is
// configured to accept regular form posts.
return;
}
} else {
// No files, or we're running in Cordova.
// Use a simple dictionary for values, which is better for outbox
// serialization. store will automatically use Cordova FileUpload iff
// there is a form field named 'fileupload'.
$.each($form.serializeArray(), function(i, v) {
vals[v.name] = v.value;
});
var ready;

if (has_files && !window.Blob) {
// Files present but there's no Blob API. Looks like we're in a an old
// browser that can't upload files via AJAX. Bypass wq/outbox.js
// entirely and hope server is able to respond to regular form posts
// with HTML (hint: wq.db is).
return;
}
// Skip regular form submission, we're saving this via store

// Modern browser and/or no files present; skip regular form submission,
// we're saving this via wq/outbox.js
evt.preventDefault();

// Use a simple JSON structure for values, which is better for outbox
// serialization.
ready = Promise.resolve();
$.each($form.serializeArray(), function(i, v) {
vals[v.name] = v.value;
});
// Handle <input type=file>. Use HTML JSON form-style objects, but
// with Blob instead of base64 encoding to represent the actual file.
if (has_files) {
$files.each(function() {
var name = this.name;
// FIXME: Handle multiple files
var file = this.files && this.files.length && this.files[0];
if (!file) {
return;
}
vals[name] = {
'type': file.type,
'name': file.name,
// Convert to blob for better serialization
'body': file.slice(0, file.size, file.type)
};
});
}
// Handle Cordova files
if (app['native']) {
$files = $form.find('input[data-wq-type=file]');
// FIXME
}

if ($submitVal) {
$submitVal.remove();
}
Expand All @@ -881,9 +900,9 @@ function _handleForm(evt) {
}

vals.modelConf = conf;
$('.error').html('');
ds.get('csrf_token').then(function(csrftoken) {
vals.csrftoken = csrftoken;
$form.find('.error').html('');
Promise.all([ds.get('csrf_token'), ready]).then(function(results) {
vals.csrftoken = results[0];
outbox.save(vals, outboxId, true).then(function(item) {
if (backgroundSync) {
// Send user to next screen while app syncs in background
Expand Down
80 changes: 35 additions & 45 deletions js/wq/outbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
* https://wq.io/license
*/

/* global FileUploadOptions */
/* global FileTransfer */
/* global Promise */

define(['jquery', './store', './model', './online', './json', './console'],
function($, ds, model, ol, json, console) {
define(['jquery', 'localforage', './store', './model',
'./online', './json', './console'],
function($, lf, ds, model, ol, json, console) {

var _outboxes = {};
var outbox = new _Outbox(ds);
Expand Down Expand Up @@ -127,8 +126,6 @@ function _Outbox(store) {
var url = self.service;
var method = self.syncMethod;
var data = json.extend({}, item.data);
var contenttype;
var processdata;
var headers = {};
if (data.hasOwnProperty('url')) {
url = url + '/' + data.url;
Expand All @@ -153,53 +150,46 @@ function _Outbox(store) {
url += '?' + json.param(defaults);
}

if (data.data) {
data = data.data;
contenttype = processdata = false;
}

if (self.debugNetwork) {
console.log("Sending item to " + url);
if (self.debugValues) {
console.log(data);
}
}

if (data.fileupload) {
var opts = new FileUploadOptions();
opts.fileKey = data.fileupload;
opts.fileName = data[data.fileupload];
delete data[data.fileupload];
delete data.fileupload;
opts.params = data;
var ft = new FileTransfer();
return Promise(function(resolve) {
ft.upload(opts.fileName, url,
function(res) {
var response = JSON.parse(
decodeURIComponent(res.response)
);
resolve(success(response));
},
function(res) {
resolve(error(
{responseText: 'Error uploading file: ' + res.code}
));
}, opts
);
});
} else {
return Promise.resolve($.ajax(url, {
data: data,
type: method,
dataType: "json",
contentType: contenttype,
processData: processdata,
async: true,
headers: headers
})).then(success, error);
// If files/blobs are present, use a FormData object to submit
var formData = new FormData();
var useFormData = false;
var key, val, blob;
for (key in data) {
val = data[key];
if (val && val.name && val.type && val.body) {
// File (Blob) record; add with filename
blob = val.body;
if (!blob.type) {
// Serialized blobs lose their type
blob = blob.slice(0, blob.size, val.type);
}
formData.append(key, blob, val.name);
useFormData = true;
}
}
if (useFormData) {
// Add regular form fields
for (key in data) {
formData.append(key, data[key]);
}
}

return Promise.resolve($.ajax(url, {
data: useFormData ? formData : data,
type: method,
dataType: "json",
processData: !useFormData,
async: true,
headers: headers
})).then(success, error);

function success(result) {
if (self.debugNetwork) {
console.log("Item successfully sent to " + url);
Expand All @@ -223,7 +213,7 @@ function _Outbox(store) {
item.error = jqxhr.responseText;
}
} else {
item.error = jqxhr.statusCode;
item.error = jqxhr.status;
}
if (once) {
item.locked = true;
Expand Down
Loading

0 comments on commit af62e67

Please sign in to comment.