jsonp.js revision d7e90d3fc2c10a1da144394576dd4fe2c63ef086
472cb5998fc636f7d3cb6e3780dba7986a75e912Luke Smithvar isFunction = Y.Lang.isFunction;
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore/**
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * <p>Provides a JSONPRequest class for repeated JSONP calls, and a convenience
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * method Y.jsonp(url, callback) to instantiate and send a JSONP request.</p>
0a9c6f9f30a66e52ec4ea4ed93504580b3a5669aAdam Moore *
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * <p>Both the constructor as well as the convenience function take two
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * parameters: a url string and a callback.</p>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore *
0a9c6f9f30a66e52ec4ea4ed93504580b3a5669aAdam Moore * <p>The url provided must include the placeholder string
6a3faa9e0e4639febffbd7018ce47b861626d0baAdam Moore * &quot;{callback}&quot; which will be replaced by a dynamically
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * generated routing function to pass the data to your callback function.
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * An example url might look like
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * &quot;http://example.com/service?callback={callback}&quot;.</p>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore *
a4a12866ef14f142b1a799fc246a542d69af602bLuke Smith * <p>The second parameter can be a callback function that accepts the JSON
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * payload as its argument, or a configuration object supporting the keys:</p>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * <ul>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * <li>on - map of callback subscribers
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * <ul>
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * <li>success - function handler for successful transmission</li>
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * <li>failure - function handler for failed transmission</li>
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * <li>timeout - function handler for transactions that timeout</li>
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * </ul>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * </li>
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * <li>format - override function for inserting the proxy name in the url</li>
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * <li>timeout - the number of milliseconds to wait before giving up</li>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * <li>context - becomes <code>this</code> in the callbacks</li>
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * <li>args - array of subsequent parameters to pass to the callbacks</li>
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * </ul>
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore *
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @module jsonp
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @submodule jsonp-base
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @class JSONPRequest
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * @constructor
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * @param url {String} the url of the JSONP service
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * @param callback {Object|Function} the default callback configuration or
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * success handler
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith */
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smithfunction JSONPRequest() {
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith this._init.apply(this, arguments);
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith}
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke SmithJSONPRequest.prototype = {
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith /**
f0a82c6a29c12f3a85bdc740203affbbe75ce665Luke Smith * Set up the success and failure handlers and the regex pattern used
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * to insert the temporary callback name in the url.
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith *
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * @method _init
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * @param url {String} the url of the JSONP service
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * @param callback {Object|Function} Optional success callback or config
7a213507f399e32bf880bd234a6265b6807f8ee6Luke Smith * object containing success and failure functions and
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * the url regex.
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @protected
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore */
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore _init : function (url, callback) {
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore this.url = url;
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore // Accept a function, an object, or nothing
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore callback = (isFunction(callback)) ?
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore { on: { success: callback } } :
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore callback || {};
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore var subs = callback.on || {};
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore if (!subs.success) {
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore subs.success = this._defaultCallback(url, callback);
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore }
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore // Apply defaults and store
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore this._config = Y.merge({
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore context: this,
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore args : [],
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore format : this._format
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore }, callback, { on: subs });
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore },
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore /**
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * Override this method to provide logic to default the success callback if
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * it is not provided at construction. This is overridden by jsonp-url to
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * parse the callback from the url string.
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore *
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * @method _defaultCallback
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @param url {String} the url passed at construction
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @param config {Object} (optional) the config object passed at
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * construction
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @return {Function}
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore */
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore _defaultCallback: function () {},
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore /**
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * Issues the JSONP request.
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore *
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @method send
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @chainable
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore */
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore send : function () {
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore var proxy = Y.guid(),
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore config = this._config,
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore url = config.format.call(this,
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore this.url, 'YUI.Env.JSONP.' + proxy);
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore if (!config.on.success) {
057b95e2faede12bf00a82837632ae67e03ad0fcAdam Moore Y.log("No success handler defined. Aborting JSONP request.", "warn", "jsonp");
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore return this;
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore }
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore function wrap(fn) {
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore return (isFunction(fn)) ?
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore function (data) {
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore delete YUI.Env.JSONP[proxy];
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore fn.apply(config.context, [data].concat(config.args));
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore } :
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore null;
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore }
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore // Temporary un-sandboxed function alias
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore // TODO: queuing
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore YUI.Env.JSONP[proxy] = wrap(config.on.success);
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore Y.Get.script(url, {
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore onFailure: wrap(config.on.failure),
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore onTimeout: wrap(config.on.timeout),
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore timeout : config.timeout
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore });
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore return this;
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore },
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore
057b95e2faede12bf00a82837632ae67e03ad0fcAdam Moore /**
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * Default url formatter. Looks for callback= in the url and appends it
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * if not present. The supplied proxy name will be assigned to the query
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * param. Override this method by passing a function as the
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * &quot;format&quot; property in the config object to the constructor.
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore *
e69255aa5a65f8406ba2fabaf69fe4e1d05daf69Adam Moore * @method _format
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @param url { String } the original url
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore * @param proxy {String} the function name that will be used as a proxy to
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * the configured callback methods.
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @return {String} fully qualified JSONP url
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @protected
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore */
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore _format: function (url, proxy) {
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore return url.replace(/\{callback\}/, proxy);
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore }
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore};
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam MooreY.JSONPRequest = JSONPRequest;
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
057b95e2faede12bf00a82837632ae67e03ad0fcAdam Moore/**
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore *
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @method Y.jsonp
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @param url {String} the url of the JSONP service with the {callback}
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * placeholder where the callback function name typically goes.
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @param c {Function|Object} Callback function accepting the JSON payload
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * as its argument, or a configuration object (see above).
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @return {JSONPRequest}
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore * @static
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore */
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam MooreY.jsonp = function (url,c) {
772f655fcf57e58b97fa46b6a8d3fc772b83f743Adam Moore return new Y.JSONPRequest(url,c).send();
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore};
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Mooreif (!YUI.Env.JSONP) {
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore YUI.Env.JSONP = {};
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore}
3641f0baf10c9737e4ac6aac1566bfeaca00eeffAdam Moore