Skip to content

Commit 67f70d6

Browse files
committed
feat(options): target, query, headers can be functions
If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean
1 parent 05e2f30 commit 67f70d6

3 files changed

Lines changed: 50 additions & 18 deletions

File tree

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,17 @@ The object is loaded with a configuration options:
9797

9898
Available configuration options are:
9999

100-
* `target` The target URL for the multipart POST request. (Default: `/`)
100+
* `target` The target URL for the multipart POST request. This can be a string or a function. If a
101+
function, it will be passed a FlowFile, a FlowChunk and isTest boolean (Default: `/`)
101102
* `singleFile` Enable single file upload. Once one file is uploaded, second file will overtake existing one, first one will be canceled. (Default: false)
102103
* `chunkSize` The size in bytes of each uploaded chunk of data. The last uploaded chunk will be at least this size and up to two the size, see [Issue #51](https://github.com/23/resumable.js/issues/51) for details and reasons. (Default: `1*1024*1024`)
103104
* `forceChunkSize` Force all chunks to be less or equal than chunkSize. Otherwise, the last chunk will be greater than or equal to `chunkSize`. (Default: `false`)
104105
* `simultaneousUploads` Number of simultaneous uploads (Default: `3`)
105106
* `fileParameterName` The name of the multipart POST parameter to use for the file chunk (Default: `file`)
106-
* `query` Extra parameters to include in the multipart POST with data. This can be an object or a function. If a function, it will be passed a FlowFile and a FlowChunk object (Default: `{}`)
107-
* `headers` Extra headers to include in the multipart POST with data (Default: `{}`)
107+
* `query` Extra parameters to include in the multipart POST with data. This can be an object or a
108+
function. If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean
109+
(Default: `{}`)
110+
* `headers` Extra headers to include in the multipart POST with data. If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean (Default: `{}`)
108111
* `withCredentials` Standard CORS requests do not send or set any cookies by default. In order to
109112
include cookies as part of the request, you need to set the `withCredentials` property to true.
110113
(Default: `false`)

src/flow.js

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
* @param {number} [opts.progressCallbacksInterval]
1616
* @param {number} [opts.speedSmoothingFactor]
1717
* @param {Object|Function} [opts.query]
18-
* @param {Object} [opts.headers]
18+
* @param {Object|Function} [opts.headers]
1919
* @param {bool} [opts.withCredentials]
2020
* @param {Function} [opts.preprocess]
2121
* @param {string} [opts.method]
2222
* @param {bool} [opts.prioritizeFirstAndLastChunk]
23-
* @param {string} [opts.target]
23+
* @param {string|Function} [opts.target]
2424
* @param {number} [opts.maxChunkRetries]
2525
* @param {number} [opts.chunkRetryInterval]
2626
* @param {Array.<number>} [opts.permanentErrors]
@@ -1174,8 +1174,7 @@
11741174
* @param params
11751175
* @returns {string}
11761176
*/
1177-
getTarget: function(params){
1178-
var target = this.flowObj.opts.target;
1177+
getTarget: function(target, params){
11791178
if(target.indexOf('?') < 0) {
11801179
target += '?';
11811180
} else {
@@ -1194,7 +1193,7 @@
11941193
this.xhr = new XMLHttpRequest();
11951194
this.xhr.addEventListener("load", this.testHandler, false);
11961195
this.xhr.addEventListener("error", this.testHandler, false);
1197-
var data = this.prepareXhrRequest('GET');
1196+
var data = this.prepareXhrRequest('GET', true);
11981197
this.xhr.send(data);
11991198
},
12001199

@@ -1246,8 +1245,7 @@
12461245
this.xhr.addEventListener("load", this.doneHandler, false);
12471246
this.xhr.addEventListener("error", this.doneHandler, false);
12481247

1249-
var data = this.prepareXhrRequest('POST', this.flowObj.opts.method, bytes);
1250-
1248+
var data = this.prepareXhrRequest('POST', false, this.flowObj.opts.method, bytes);
12511249
this.xhr.send(data);
12521250
},
12531251

@@ -1342,27 +1340,25 @@
13421340
/**
13431341
* Prepare Xhr request. Set query, headers and data
13441342
* @param {string} method GET or POST
1343+
* @param {bool} isTest is this a test request
13451344
* @param {string} [paramsMethod] octet or form
13461345
* @param {Blob} [blob] to send
13471346
* @returns {FormData|Blob|Null} data to send
13481347
*/
1349-
prepareXhrRequest: function(method, paramsMethod, blob) {
1348+
prepareXhrRequest: function(method, isTest, paramsMethod, blob) {
13501349
// Add data from the query options
1351-
var query = this.flowObj.opts.query;
1352-
if (typeof query === "function") {
1353-
query = query(this.fileObj, this);
1354-
}
1350+
var query = evalOpts(this.flowObj.opts.query, this.fileObj, this, isTest);
13551351
query = extend(this.getParams(), query);
13561352

1357-
var target = this.flowObj.opts.target;
1353+
var target = evalOpts(this.flowObj.opts.target, this.fileObj, this, isTest);
13581354
var data = null;
13591355
if (method === 'GET' || paramsMethod === 'octet') {
13601356
// Add data from the query options
13611357
var params = [];
13621358
each(query, function (v, k) {
13631359
params.push([encodeURIComponent(k), encodeURIComponent(v)].join('='));
13641360
});
1365-
target = this.getTarget(params);
1361+
target = this.getTarget(target, params);
13661362
data = blob || null;
13671363
} else {
13681364
// Add data from the query options
@@ -1377,7 +1373,7 @@
13771373
this.xhr.withCredentials = this.flowObj.opts.withCredentials;
13781374

13791375
// Add data from header options
1380-
each(this.flowObj.opts.headers, function (v, k) {
1376+
each(evalOpts(this.flowObj.opts.headers, this.fileObj, this, isTest), function (v, k) {
13811377
this.xhr.setRequestHeader(k, v);
13821378
}, this);
13831379

@@ -1397,6 +1393,22 @@
13971393
}
13981394
}
13991395

1396+
/**
1397+
* If option is a function, evaluate it with given params
1398+
* @param {*} data
1399+
* @param {...} args arguments of a callback
1400+
* @returns {*}
1401+
*/
1402+
function evalOpts(data, args) {
1403+
if (typeof data === "function") {
1404+
// `arguments` is an object, not array, in FF, so:
1405+
args = Array.prototype.slice.call(arguments);
1406+
data = data.apply(null, args.slice(1));
1407+
}
1408+
return data;
1409+
}
1410+
Flow.evalOpts = evalOpts;
1411+
14001412
/**
14011413
* Execute function asynchronously
14021414
* @param fn

test/evalOptsSpec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
describe('evalOpts', function () {
2+
3+
it('should return same object for non functions', function() {
4+
var obj = {};
5+
expect(Flow.evalOpts(obj)).toBe(obj);
6+
});
7+
it('should return same type for non functions', function() {
8+
expect(Flow.evalOpts(5)).toBe(5);
9+
});
10+
it('should evaluate function', function() {
11+
expect(Flow.evalOpts(function () {return 5;})).toBe(5);
12+
});
13+
it('should evaluate function with given arguments', function() {
14+
var obj = {};
15+
expect(Flow.evalOpts(function (a) {return a;}, obj)).toBe(obj);
16+
});
17+
});

0 commit comments

Comments
 (0)