Skip to content
This repository was archived by the owner on Apr 20, 2018. It is now read-only.

Commit d550430

Browse files
Merge pull request #13 from sergi/fix_jsonp
Allow static JSONP callbacks
2 parents bcabf9d + f9b4083 commit d550430

File tree

3 files changed

+111
-44
lines changed

3 files changed

+111
-44
lines changed

doc/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ Rx.DOM.Request.jsonpRequest(settings);
235235
1. `settings` *(Object)*: An object with the following properties:
236236
- `url` *(String)*: URL of the request
237237
- `jsonp` *(String)*: The named callback parameter for the JSONP call
238+
- `jsonpCallback` *(String)*: Name of the function in the root object that JSONP will call. This is useful for when the JSONP callback is hardcoded and can't be changed
238239

239240
#### Returns
240241
*(Observable)*: A hot observable containing the results from the JSONP call.

src/jsonp.js

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,60 +22,71 @@
2222
* An object with the following properties
2323
* - url: URL of the request
2424
* - jsonp: The named callback parameter for the JSONP call
25+
* - jsonpCallback: Callback to execute. For when the JSONP callback can't be changed
2526
*
2627
* @returns {Observable} A cold observable containing the results from the JSONP call.
2728
*/
2829
var getJSONPRequestCold = ajax.jsonpRequestCold = (function () {
29-
var uniqueId = 0;
30-
return function (settings) {
31-
return new AnonymousObservable(function (observer) {
30+
var uniqueId = 0;
31+
var defaultCallback = function _defaultCallback(observer, data) {
32+
observer.onNext(data);
33+
observer.onCompleted();
34+
};
3235

33-
if (typeof settings === 'string') {
34-
settings = { url: settings }
35-
}
36-
if (!settings.jsonp) {
37-
settings.jsonp = 'JSONPCallback';
38-
}
36+
return function (settings) {
37+
return new AnonymousObservable(function (observer) {
38+
39+
if (typeof settings === 'string') {
40+
settings = { url: settings };
41+
}
42+
if (!settings.jsonp) {
43+
settings.jsonp = 'JSONPCallback';
44+
}
3945

40-
var head = document.getElementsByTagName('head')[0] || document.documentElement,
41-
tag = document.createElement('script'),
42-
handler = 'rxjscallback' + uniqueId++;
46+
var head = document.getElementsByTagName('head')[0] || document.documentElement,
47+
tag = document.createElement('script'),
48+
handler = 'rxjscallback' + uniqueId++;
49+
50+
var prevFn;
51+
if (typeof settings.jsonpCallback === 'string') {
52+
handler = settings.jsonpCallback;
53+
prevFn = root[handler];
54+
}
4355

44-
settings.url = settings.url.replace('=' + settings.jsonp, '=' + handler);
56+
settings.url = settings.url.replace('=' + settings.jsonp, '=' + handler);
4557

46-
root[handler] = function (data) {
47-
observer.onNext(data);
48-
observer.onCompleted();
49-
};
58+
root[handler] = function(data) {
59+
if (prevFn && typeof prevFn === 'function') {
60+
prevFn(observer, data);
61+
} else {
62+
defaultCallback(observer, data);
63+
}
64+
};
5065

51-
tag.src = settings.url;
52-
tag.async = true;
53-
tag.onload = tag.onreadystatechange = function (_, abort) {
54-
if ( abort || !tag.readyState || /loaded|complete/.test(tag.readyState) ) {
55-
tag.onload = tag.onreadystatechange = null;
56-
if (head && tag.parentNode) {
57-
destroy(tag);
58-
}
59-
tag = undefined;
60-
root[handler] = undefined;
61-
delete root[handler];
62-
}
63-
};
64-
head.insertBefore(tag, head.firstChild);
66+
var cleanup = function _cleanup() {
67+
tag.onload = tag.onreadystatechange = null;
68+
if (head && tag.parentNode) {
69+
destroy(tag);
70+
}
71+
tag = undefined;
72+
root[handler] = prevFn;
73+
};
6574

66-
return function () {
67-
if (!tag) { return; }
68-
tag.onload = tag.onreadystatechange = null;
69-
if (head && tag.parentNode) {
70-
destroy(tag);
71-
}
72-
tag = undefined;
73-
root[handler] = undefined;
74-
delete root[handler];
75-
};
76-
});
77-
};
75+
tag.src = settings.url;
76+
tag.async = true;
77+
tag.onload = tag.onreadystatechange = function (_, abort) {
78+
if ( abort || !tag.readyState || /loaded|complete/.test(tag.readyState) ) {
79+
cleanup();
80+
}
81+
};
82+
head.insertBefore(tag, head.firstChild);
7883

84+
return function () {
85+
if (!tag) { return; }
86+
cleanup();
87+
};
88+
});
89+
};
7990
})();
8091

8192
/**

tests/tests.ajax.js

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var xhr, requests
1+
var xhr, requests;
22

33
module('Ajax Tests', {
44
setup: function () {
@@ -590,4 +590,59 @@ test('getJSON failure', function () {
590590
);
591591

592592
requests[0].respond(500, { 'Content-Type': 'application/json' }, 'error');
593+
});
594+
595+
asyncTest('jsonpRequest with jsonp callback success', function () {
596+
window.testCallback = function(observer, data) {
597+
data[0].correct = true;
598+
observer.onNext(data);
599+
observer.onCompleted();
600+
};
601+
602+
var fakeScript = "data:text/javascript;base64," + btoa(
603+
'testCallback([{ "id": 123 }])'
604+
);
605+
606+
var source = Rx.DOM.Request.jsonpRequest({
607+
url: fakeScript,
608+
jsonpCallback: 'testCallback'
609+
});
610+
611+
source.subscribe(
612+
function (x) {
613+
equal(123, x[0].id);
614+
equal(true, x[0].correct);
615+
},
616+
function (e) {
617+
ok(false);
618+
},
619+
function () {
620+
ok(true);
621+
QUnit.start();
622+
}
623+
);
624+
});
625+
626+
asyncTest('jsonpRequest without jsonp callback success', function () {
627+
var fakeScript = "data:text/javascript;base64," + btoa(
628+
'testCallback([{ "id": 123 }])'
629+
);
630+
631+
var source = Rx.DOM.Request.jsonpRequest({
632+
url: fakeScript,
633+
jsonpCallback: 'testCallback'
634+
});
635+
636+
source.subscribe(
637+
function (x) {
638+
equal(123, x[0].id);
639+
},
640+
function (e) {
641+
ok(false);
642+
},
643+
function () {
644+
ok(true);
645+
QUnit.start();
646+
}
647+
);
593648
});

0 commit comments

Comments
 (0)