3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 YUI.add('jsonp', function(Y) {
9 var isFunction = Y.Lang.isFunction;
12 * <p>Provides a JSONPRequest class for repeated JSONP calls, and a convenience
13 * method Y.jsonp(url, callback) to instantiate and send a JSONP request.</p>
15 * <p>Both the constructor as well as the convenience function take two
16 * parameters: a url string and a callback.</p>
18 * <p>The url provided must include the placeholder string
19 * "{callback}" which will be replaced by a dynamically
20 * generated routing function to pass the data to your callback function.
21 * An example url might look like
22 * "http://example.com/service?callback={callback}".</p>
24 * <p>The second parameter can be a callback function that accepts the JSON
25 * payload as its argument, or a configuration object supporting the keys:</p>
27 * <li>on - map of callback subscribers
29 * <li>success - function handler for successful transmission</li>
30 * <li>failure - function handler for failed transmission</li>
31 * <li>timeout - function handler for transactions that timeout</li>
34 * <li>format - override function for inserting the proxy name in the url</li>
35 * <li>timeout - the number of milliseconds to wait before giving up</li>
36 * <li>context - becomes <code>this</code> in the callbacks</li>
37 * <li>args - array of subsequent parameters to pass to the callbacks</li>
38 * <li>allowCache - use the same proxy name for all requests? (boolean)</li>
44 * @param url {String} the url of the JSONP service
45 * @param callback {Object|Function} the default callback configuration or
48 function JSONPRequest() {
49 this._init.apply(this, arguments);
52 JSONPRequest.prototype = {
54 * Set up the success and failure handlers and the regex pattern used
55 * to insert the temporary callback name in the url.
58 * @param url {String} the url of the JSONP service
59 * @param callback {Object|Function} Optional success callback or config
60 * object containing success and failure functions and
64 _init : function (url, callback) {
68 * Map of the number of requests currently pending responses per
69 * generated proxy. Used to ensure the proxy is not flushed if the
70 * request times out and there is a timeout handler and success
71 * handler, and used by connections configured to allowCache to make
72 * sure the proxy isn't deleted until the last response has returned.
81 * Map of the number of timeouts received from the destination url
82 * by generated proxy. Used to ensure the proxy is not flushed if the
83 * request times out and there is a timeout handler and success
84 * handler, and used by connections configured to allowCache to make
85 * sure the proxy isn't deleted until the last response has returned.
93 // Accept a function, an object, or nothing
94 callback = (isFunction(callback)) ?
95 { on: { success: callback } } :
98 var subs = callback.on || {};
101 subs.success = this._defaultCallback(url, callback);
104 // Apply defaults and store
105 this._config = Y.merge({
108 format : this._format,
110 }, callback, { on: subs });
114 * Override this method to provide logic to default the success callback if
115 * it is not provided at construction. This is overridden by jsonp-url to
116 * parse the callback from the url string.
118 * @method _defaultCallback
119 * @param url {String} the url passed at construction
120 * @param config {Object} (optional) the config object passed at
124 _defaultCallback: function () {},
127 * Issues the JSONP request.
130 * @param args* {any} any additional arguments to pass to the url formatter
131 * beyond the base url and the proxy function name
136 args = Y.Array(arguments, 0, true),
137 config = self._config,
138 proxy = self._proxy || Y.guid(),
141 // TODO: support allowCache as time value
142 if (config.allowCache) {
146 if (self._requests[proxy] === undefined) {
147 self._requests[proxy] = 0;
149 if (self._timeouts[proxy] === undefined) {
150 self._timeouts[proxy] = 0;
152 self._requests[proxy]++;
154 Y.log('sending ' + proxy);
156 args.unshift(self.url, 'YUI.Env.JSONP.' + proxy);
157 url = config.format.apply(self, args);
159 if (!config.on.success) {
160 Y.log("No success handler defined. Aborting JSONP request.", "warn", "jsonp");
164 function wrap(fn, isTimeout) {
165 return (isFunction(fn)) ?
168 counter = '_requests';
170 //if (config.allowCache) {
171 // A lot of wrangling to make sure timeouts result in
172 // fewer success callbacks, but the proxy is properly
175 ++self._timeouts[proxy];
176 --self._requests[proxy];
177 Y.log(proxy + ' timed out - timeouts(' + self._timeouts[proxy] + ') requests(' + self._requests[proxy] + ')');
179 if (!self._requests[proxy]) {
181 counter = '_timeouts';
183 --self[counter][proxy];
184 Y.log(proxy + ' response received - timeouts(' + self._timeouts[proxy] + ') requests(' + self._requests[proxy] + ')');
188 if (!self._requests[proxy] && !self._timeouts[proxy]) {
189 Y.log('deleting ' + proxy);
190 delete YUI.Env.JSONP[proxy];
194 fn.apply(config.context, [data].concat(config.args));
200 // Temporary un-sandboxed function alias
202 YUI.Env.JSONP[proxy] = wrap(config.on.success);
205 onFailure : wrap(config.on.failure),
206 onTimeout : wrap(config.on.timeout, true),
207 timeout : config.timeout,
208 charset : config.charset,
209 attributes: config.attributes
216 * Default url formatter. Looks for callback= in the url and appends it
217 * if not present. The supplied proxy name will be assigned to the query
218 * param. Override this method by passing a function as the
219 * "format" property in the config object to the constructor.
222 * @param url { String } the original url
223 * @param proxy {String} the function name that will be used as a proxy to
224 * the configured callback methods.
225 * @param args* {any} additional args passed to send()
226 * @return {String} fully qualified JSONP url
229 _format: function (url, proxy) {
230 return url.replace(/\{callback\}/, proxy);
234 Y.JSONPRequest = JSONPRequest;
239 * @param url {String} the url of the JSONP service with the {callback}
240 * placeholder where the callback function name typically goes.
241 * @param c {Function|Object} Callback function accepting the JSON payload
242 * as its argument, or a configuration object (see above).
243 * @param args* {any} additional arguments to pass to send()
244 * @return {JSONPRequest}
248 Y.jsonp = function (url,c) {
249 var req = new Y.JSONPRequest(url,c);
250 return req.send.apply(req, Y.Array(arguments, 2, true));
253 if (!YUI.Env.JSONP) {
258 }, '3.5.1' ,{requires:['get','oop']});