Skip to content

Commit 3c6e1fe

Browse files
authored
Merge pull request #83 from sunpietro/ezp-27100-pass-custom-request-callbacks
EZP-27100: Allow to pass custom XHR callbacks with REST requests
2 parents 195cb05 + 8099e6e commit 3c6e1fe

File tree

6 files changed

+304
-14
lines changed

6 files changed

+304
-14
lines changed

src/ConnectionManager.js

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,41 +33,80 @@ define(["structures/Response", "structures/Request", "structures/CAPIError"],
3333
* @param [url="/"] {String} requested REST resource
3434
* @param [body=""] {String} a string which should be passed in request body to the REST service
3535
* @param [headers={}] {object} object literal describing request headers
36+
* @param [requestEventHandlers] {Object} a set of callbacks to apply on a specific XHR event like onload, onerror, onprogress, etc.
3637
* @param callback {Function} function, which will be executed on request success
38+
* @example
39+
* var connectionManager = jsCAPI.getConnectionManager();
40+
*
41+
* connectionManager.request(
42+
* 'GET',
43+
* '/endpoint',
44+
* '',
45+
* {Accept: 'application/json'},
46+
* {
47+
* upload: {
48+
* onloadstart: someUploadCallback,
49+
* onload: someUploadCallback,
50+
* onloadend: someUploadCallback,
51+
* onprogress: someUploadCallback,
52+
* onabort: someUploadCallback,
53+
* onerror: someUploadCallback,
54+
* ontimeout: someUploadCallback,
55+
* },
56+
* onloadstart: someCallback,
57+
* onload: someCallback,
58+
* onloadend: someCallback,
59+
* onprogress: someCallback,
60+
* onabort: someCallback,
61+
* onerror: someCallback,
62+
* ontimeout: someCallback,
63+
* },
64+
* callback
65+
* );
3766
*/
38-
ConnectionManager.prototype.request = function (method, url, body, headers, callback) {
67+
ConnectionManager.prototype.request = function (method, url, body, headers, requestEventHandlers, callback) {
3968
var that = this,
4069
request,
4170
nextRequest,
4271
defaultMethod = "GET",
4372
defaultUrl = "/",
4473
defaultBody = "",
45-
defaultHeaders = {};
74+
defaultHeaders = {},
75+
defaultRequestEventHandlers = {};
4676

4777
// default values for omitted parameters (if any)
48-
if (arguments.length < 5) {
49-
if (typeof method == "function") {
50-
//no optional parameteres are passed
78+
if (arguments.length < 6) {
79+
if (typeof method === 'function') {
80+
// no optional parameteres are passed
5181
callback = method;
5282
method = defaultMethod;
5383
url = defaultUrl;
5484
body = defaultBody;
5585
headers = defaultHeaders;
56-
} else if (typeof url == "function") {
86+
requestEventHandlers = defaultRequestEventHandlers;
87+
} else if (typeof url === 'function') {
5788
// only first 1 optional parameter is passed
89+
requestEventHandlers = body;
5890
callback = url;
5991
url = defaultUrl;
6092
body = defaultBody;
6193
headers = defaultHeaders;
62-
} else if (typeof body == "function") {
94+
requestEventHandlers = defaultRequestEventHandlers;
95+
} else if (typeof body === 'function') {
6396
// only first 2 optional parameters are passed
6497
callback = body;
6598
body = defaultBody;
6699
headers = defaultHeaders;
67-
} else {
100+
requestEventHandlers = defaultRequestEventHandlers;
101+
} else if (typeof headers === 'function') {
68102
// only first 3 optional parameters are passed
69103
callback = headers;
70104
headers = defaultHeaders;
105+
requestEventHandlers = defaultRequestEventHandlers;
106+
} else if (typeof requestEventHandlers === 'function') {
107+
// only first 4 optional parameters are passed
108+
callback = requestEventHandlers;
109+
requestEventHandlers = defaultRequestEventHandlers;
71110
}
72111
}
73112

@@ -124,7 +163,7 @@ define(["structures/Response", "structures/Request", "structures/CAPIError"],
124163
console.dir(request);
125164
}
126165
// Main goal
127-
that._connectionFactory.createConnection().execute(authenticatedRequest, callback);
166+
that._connectionFactory.createConnection().execute(authenticatedRequest, requestEventHandlers, callback);
128167
}
129168
);
130169
} // while

src/connections/XmlHttpRequestConnection.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,37 @@ define(["structures/Response", "structures/CAPIError"], function (Response, CAPI
1010
* @constructor
1111
*/
1212
var XmlHttpRequestConnection = function () {
13-
this._xhr = new XMLHttpRequest();
14-
};
13+
this._xhr = new XMLHttpRequest();
14+
},
15+
_assignCallback = function(xhr, eventName, callback) {
16+
if (typeof callback !== 'function') {
17+
return xhr;
18+
}
19+
20+
xhr[eventName] = callback;
21+
22+
return xhr;
23+
};
1524

1625
/**
1726
* Basic request implemented via XHR technique
1827
*
1928
* @method execute
2029
* @param request {Request} structure containing all needed params and data
30+
* @param [requestEventHandlers] {Object} a set of callbacks to apply on a specific XHR event like onload, onerror, onprogress, etc.
2131
* @param callback {Function} function, which will be executed on request success
2232
*/
23-
XmlHttpRequestConnection.prototype.execute = function (request, callback) {
33+
XmlHttpRequestConnection.prototype.execute = function (request, requestEventHandlers, callback) {
2434
var XHR = this._xhr,
2535
headerType,
2636
method = request.method,
2737
standardMethods = {"OPTIONS": 1, "GET": 1, "HEAD": 1, "POST": 1, "PUT": 1, "DELETE": 1, "TRACE": 1};
2838

39+
if (typeof requestEventHandlers === 'function') {
40+
callback = requestEventHandlers;
41+
requestEventHandlers = {};
42+
}
43+
2944
// Create the state change handler:
3045
XHR.onreadystatechange = function () {
3146
var response;
@@ -54,6 +69,26 @@ define(["structures/Response", "structures/CAPIError"], function (Response, CAPI
5469
method = "POST";
5570
}
5671

72+
if (requestEventHandlers && Object.keys(requestEventHandlers).length) {
73+
if (requestEventHandlers.upload && Object.keys(requestEventHandlers.upload).length) {
74+
_assignCallback(XHR.upload, 'onloadstart', requestEventHandlers.upload.onloadstart);
75+
_assignCallback(XHR.upload, 'onload', requestEventHandlers.upload.onload);
76+
_assignCallback(XHR.upload, 'onloadend', requestEventHandlers.upload.onloadend);
77+
_assignCallback(XHR.upload, 'onprogress', requestEventHandlers.upload.onprogress);
78+
_assignCallback(XHR.upload, 'onabort', requestEventHandlers.upload.onabort);
79+
_assignCallback(XHR.upload, 'onerror', requestEventHandlers.upload.onerror);
80+
_assignCallback(XHR.upload, 'ontimeout', requestEventHandlers.upload.ontimeout);
81+
}
82+
83+
_assignCallback(XHR, 'onloadstart', requestEventHandlers.onloadstart);
84+
_assignCallback(XHR, 'onload', requestEventHandlers.onload);
85+
_assignCallback(XHR, 'onloadend', requestEventHandlers.onloadend);
86+
_assignCallback(XHR, 'onprogress', requestEventHandlers.onprogress);
87+
_assignCallback(XHR, 'onabort', requestEventHandlers.onabort);
88+
_assignCallback(XHR, 'onerror', requestEventHandlers.onerror);
89+
_assignCallback(XHR, 'ontimeout', requestEventHandlers.ontimeout);
90+
}
91+
5792
if (request.httpBasicAuth) {
5893
XHR.open(method, request.url, true, request.login, request.password);
5994
} else {

src/services/ContentService.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,46 @@ define(["structures/ContentCreateStruct", "structures/ContentUpdateStruct", "str
388388
*
389389
* @method createContent
390390
* @param contentCreateStruct {ContentCreateStruct} object describing content to be created
391+
* @param [requestEventHandlers] {Object} a set of callbacks to apply on a specific XHR event like onload, onerror, onprogress, etc.
391392
* @param callback {Function} callback executed after performing the request (see
392393
* {{#crossLink "ContentService"}}Note on the callbacks usage{{/crossLink}} for more info)
394+
* @example
395+
* var contentService = jsCAPI.getContentService();
396+
*
397+
* contentService.createContent(
398+
* {
399+
* body: '',
400+
* headers: {}
401+
* },
402+
* {
403+
* upload: {
404+
* onloadstart: someUploadCallback,
405+
* onload: someUploadCallback,
406+
* onloadend: someUploadCallback,
407+
* onprogress: someUploadCallback,
408+
* onabort: someUploadCallback,
409+
* onerror: someUploadCallback,
410+
* ontimeout: someUploadCallback,
411+
* },
412+
* onloadstart: someCallback,
413+
* onload: someCallback,
414+
* onloadend: someCallback,
415+
* onprogress: someCallback,
416+
* onabort: someCallback,
417+
* onerror: someCallback,
418+
* ontimeout: someCallback,
419+
* },
420+
* callback
421+
* );
393422
*/
394-
ContentService.prototype.createContent = function (contentCreateStruct, callback) {
423+
ContentService.prototype.createContent = function (contentCreateStruct, requestEventHandlers, callback) {
395424
var that = this;
396425

426+
if (typeof requestEventHandlers === 'function') {
427+
callback = requestEventHandlers;
428+
requestEventHandlers = {};
429+
}
430+
397431
this._discoveryService.getInfoObject(
398432
"content",
399433
function (error, contentObjects) {
@@ -407,6 +441,7 @@ define(["structures/ContentCreateStruct", "structures/ContentUpdateStruct", "str
407441
contentObjects._href,
408442
JSON.stringify(contentCreateStruct.body),
409443
contentCreateStruct.headers,
444+
requestEventHandlers,
410445
callback
411446
);
412447
}
@@ -1111,7 +1146,7 @@ define(["structures/ContentCreateStruct", "structures/ContentUpdateStruct", "str
11111146
if ( viewCreateStruct.getCriteria() && Object.keys(viewCreateStruct.getCriteria()).length !== 0 ) {
11121147
console.warn('[DEPRECATED] virtual property Criteria is deprecated');
11131148
}
1114-
1149+
11151150
that._connectionManager.request(
11161151
"POST",
11171152
views._href,

test/ConnectionManager.tests.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ define(function (require) {
8888
expect(mockConnectionFactory.createConnection).toHaveBeenCalled();
8989
expect(mockConnection.execute).toHaveBeenCalledWith(
9090
jasmine.any(Request),
91+
{},
9192
mockCallback
9293
);
9394

@@ -117,6 +118,7 @@ define(function (require) {
117118
);
118119
expect(mockConnection.execute).toHaveBeenCalledWith(
119120
jasmine.any(Request),
121+
{},
120122
mockCallback
121123
);
122124
expect(console.dir).toHaveBeenCalledWith(jasmine.any(Request));
@@ -143,6 +145,7 @@ define(function (require) {
143145
);
144146
expect(mockConnection.execute).toHaveBeenCalledWith(
145147
jasmine.any(Request),
148+
{},
146149
mockCallback
147150
);
148151

@@ -169,6 +172,7 @@ define(function (require) {
169172
);
170173
expect(mockConnection.execute).toHaveBeenCalledWith(
171174
jasmine.any(Request),
175+
{},
172176
mockCallback
173177
);
174178

@@ -196,6 +200,7 @@ define(function (require) {
196200
);
197201
expect(mockConnection.execute).toHaveBeenCalledWith(
198202
jasmine.any(Request),
203+
{},
199204
mockCallback
200205
);
201206

@@ -207,6 +212,41 @@ define(function (require) {
207212
});
208213
});
209214

215+
it("request (with 5 optional arguments)", function () {
216+
var requestEventHandlers = {
217+
upload: { onerror: function () {}},
218+
onerror: function () {}
219+
},
220+
requestHeaders = {};
221+
222+
connectionManager.request(
223+
"GET",
224+
rootId,
225+
"",
226+
requestHeaders,
227+
requestEventHandlers,
228+
mockCallback
229+
);
230+
231+
expect(mockAuthenticationAgent.ensureAuthentication).toHaveBeenCalled();
232+
expect(mockAuthenticationAgent.authenticateRequest).toHaveBeenCalledWith(
233+
jasmine.any(Request),
234+
jasmine.any(Function)
235+
);
236+
expect(mockConnection.execute).toHaveBeenCalledWith(
237+
jasmine.any(Request),
238+
requestEventHandlers,
239+
mockCallback
240+
);
241+
242+
expect(mockConnection.execute).toHaveBeenCalledWithObject({
243+
method: "GET",
244+
url: endPointUrl + rootId,
245+
body: "",
246+
headers: requestHeaders
247+
});
248+
});
249+
210250
it("request (and stores request in queue while authentication is still in progress)", function (){
211251

212252
connectionManager._authInProgress = true;
@@ -369,6 +409,7 @@ define(function (require) {
369409
expect(mockConnectionFactory.createConnection).toHaveBeenCalled();
370410
expect(mockConnection.execute).toHaveBeenCalledWith(
371411
jasmine.any(Request),
412+
{},
372413
mockCallback
373414
);
374415

test/ContentService.tests.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,39 @@ define(function (require) {
287287
describe("Content management request:", function () {
288288

289289
it("createContent", function () {
290+
var locationCreateStruct = contentService.newLocationCreateStruct("/api/ezp/v2/content/locations/1/2/118"),
291+
contentCreateStruct = contentService.newContentCreateStruct(
292+
"/api/ezp/v2/content/types/18",
293+
locationCreateStruct,
294+
"eng-US",
295+
"DummyUser"
296+
),
297+
fieldInfo = {
298+
"fieldDefinitionIdentifier": "title",
299+
"languageCode": "eng-US",
300+
"fieldValue": "This is a title"
301+
};
302+
303+
contentCreateStruct.body.ContentCreate.fields.field.push(fieldInfo);
304+
305+
contentService.createContent(
306+
contentCreateStruct,
307+
mockCallback
308+
);
309+
310+
expect(mockDiscoveryService.getInfoObject).toHaveBeenCalledWith("content", jasmine.any(Function));
311+
312+
expect(mockConnectionManager.request).toHaveBeenCalledWith(
313+
"POST",
314+
testContentObjects,
315+
JSON.stringify(contentCreateStruct.body),
316+
contentCreateStruct.headers,
317+
{},
318+
mockCallback
319+
);
320+
});
290321

322+
it("createContent with optional request callbacks", function () {
291323
var locationCreateStruct = contentService.newLocationCreateStruct("/api/ezp/v2/content/locations/1/2/118"),
292324
contentCreateStruct = contentService.newContentCreateStruct(
293325
"/api/ezp/v2/content/types/18",
@@ -299,12 +331,17 @@ define(function (require) {
299331
"fieldDefinitionIdentifier": "title",
300332
"languageCode": "eng-US",
301333
"fieldValue": "This is a title"
334+
},
335+
requestCallbacks = {
336+
upload: {},
337+
onerror: function () {}
302338
};
303339

304340
contentCreateStruct.body.ContentCreate.fields.field.push(fieldInfo);
305341

306342
contentService.createContent(
307343
contentCreateStruct,
344+
requestCallbacks,
308345
mockCallback
309346
);
310347

@@ -315,6 +352,7 @@ define(function (require) {
315352
testContentObjects,
316353
JSON.stringify(contentCreateStruct.body),
317354
contentCreateStruct.headers,
355+
requestCallbacks,
318356
mockCallback
319357
);
320358
});

0 commit comments

Comments
 (0)