UNPKG

jsonp-client

Version:

jsonp minimal client for the browser (1.4K) and Node.js

180 lines (161 loc) 5.41 kB
// jsonp-client // ----------------- // Copyright(c) 2013 Bermi Ferrer <bermi@bermilabs.com> // MIT Licensed (function (root) { 'use strict'; var // Save the previous value of the `jsonpClient` variable. previousJsonpClient = root.jsonpClient, is_browser = (typeof process !== 'undefined') ? // We are on a common js environment, we might be using browserify process.browser : (typeof window !== 'undefined'), getJsonpBrowser, getJsonp, CALLBACK_REGEXP = /[\\?|&]callback=([a-z0-9_]+)/i, // Create a safe reference to the jsonpClient object for use below. jsonpClient = function () { var args = Array.prototype.slice.apply(arguments), callback, urls = args.slice(0, -1), i = 0, error, results = [], addUrl, returnResult; // Don't allows sync calls try { callback = args.slice(-1)[0]; if (typeof callback !== 'function') { throw new Error('Callback not found'); } } catch (e) { throw new Error('jsonpClient expects a callback'); } // URL's provided as an array on the first parameter if (typeof urls[0] !== 'string') { urls = urls[0]; } // Returns the results in the right order returnResult = function () { var i = 0; results = results.sort(function (a, b) { return a.position > b.position; }); for (i = 0; results.length > i; i = i + 1) { results[i] = results[i].data; } results.unshift(null); callback.apply(null, results); }; // Adds a URL to the queue addUrl = function (url, position) { getJsonp(urls[i], function (err, data) { if (error) { return; } error = err; if (err) { return callback(err); } results.push({ data: data, position: position }); if (results.length === urls.length) { returnResult(); } }); }; // Pushes files to fetch for (i = 0; urls.length > i; i = i + 1) { addUrl(urls[i] + '', i); } }; // Run jsonpClient in *noConflict* mode, returning the `jsonpClient` // variable to its previous owner. Returns a reference to // the jsonpClient object. jsonpClient.noConflict = function () { root.jsonpClient = previousJsonpClient; return jsonpClient; }; // Browser only logic for including jsonp on the page getJsonpBrowser = function () { var getCallbackFromUrl, loadScript, head = document.getElementsByTagName('head')[0]; loadScript = function (url, callback) { var script = document.createElement('script'), done = false; script.src = url; script.async = true; script.onload = script.onreadystatechange = function () { if (!done && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { done = true; script.onload = script.onreadystatechange = null; if (script && script.parentNode) { script.parentNode.removeChild(script); } callback(); } }; head.appendChild(script); }; getCallbackFromUrl = function (url, callback) { var matches = url.match(CALLBACK_REGEXP); if (!matches) { return callback(new Error('Could not find callback on URL')); } callback(null, matches[1]); }; return function (url, callback) { getCallbackFromUrl(url, function (err, callbackName) { var data, originalCallback = window[callbackName]; if (err) { return callback(err); } window[callbackName] = function (jsonp_data) { data = jsonp_data; }; loadScript(url, function (err) { if (!err && !data) { err = new Error('Calling to ' + callbackName + ' did not returned a JSON response.' + 'Make sure the callback ' + callbackName + ' exists and is properly formatted.'); } if (originalCallback) { window[callbackName] = originalCallback; } else { // Repeated calls to the same jsonp callback should be avoided // Unique callback names should be used. // Also, the try, catch here is to support issues in IE8/IE7 where // you can not use delete on window. try { delete window[callbackName]; } catch (ex) { window[callbackName] = undefined; } } callback(err, data); }); }); }; }; getJsonp = is_browser ? getJsonpBrowser() : require('./jsonp-node.js'); // Export the jsonpClient object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `jsonpClient` as a global object via a string identifier, // for Closure Compiler 'advanced' mode. if (typeof module !== 'undefined' && module.exports) { module.exports = jsonpClient; } else { // Set jsonpClient on the browser window root.jsonpClient = jsonpClient; } // Establish the root object, `window` in the browser, or `global` on the // server. }(this));