/** * socket.io * Copyright(c) 2011 LearnBoost * MIT Licensed */ (function (exports, global) { /** * Utilities namespace. * * @namespace */ var util = exports.util = {}; /** * Parses an URI * * @author Steven Levithan (MIT license) * @api public */ var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor']; util.parseUri = function (str) { var m = re.exec(str || '') , uri = {} , i = 14; while (i--) { uri[parts[i]] = m[i] || ''; } return uri; }; /** * Produces a unique url that identifies a Socket.IO connection. * * @param {Object} uri * @api public */ util.uniqueUri = function (uri) { var protocol = uri.protocol , host = uri.host , port = uri.port; if ('document' in global) { host = host || document.domain; port = port || (protocol == 'https' && document.location.protocol !== 'https:' ? 443 : document.location.port); } else { host = host || 'localhost'; if (!port && protocol == 'https') { port = 443; } } return (protocol || 'http') + '://' + host + ':' + (port || 80); }; /** * Mergest 2 query strings in to once unique query string * * @param {String} base * @param {String} addition * @api public */ util.query = function (base, addition) { var query = util.chunkQuery(base || '') , components = []; util.merge(query, util.chunkQuery(addition || '')); for (var part in query) { if (query.hasOwnProperty(part)) { components.push(part + '=' + query[part]); } } return components.length ? '?' + components.join('&') : ''; }; /** * Transforms a querystring in to an object * * @param {String} qs * @api public */ util.chunkQuery = function (qs) { var query = {} , params = qs.split('&') , i = 0 , l = params.length , kv; for (; i < l; ++i) { kv = params[i].split('='); if (kv[0]) { query[kv[0]] = kv[1]; } } return query; }; /** * Executes the given function when the page is loaded. * * io.util.load(function () { console.log('page loaded'); }); * * @param {Function} fn * @api public */ var pageLoaded = false; util.load = function (fn) { if ('document' in global && document.readyState === 'complete' || pageLoaded) { return fn(); } util.on(global, 'load', fn, false); }; /** * Adds an event. * * @api private */ util.on = function (element, event, fn, capture) { if (element.attachEvent) { element.attachEvent('on' + event, fn); } else if (element.addEventListener) { element.addEventListener(event, fn, capture); } }; /** * Generates the correct `XMLHttpRequest` for regular and cross domain requests. * * @param {Boolean} [xdomain] Create a request that can be used cross domain. * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest. * @api private */ util.request = function (xdomain) { // if node var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; return new XMLHttpRequest(); // end node if (xdomain && 'undefined' != typeof XDomainRequest && !util.ua.hasCORS) { return new XDomainRequest(); } if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) { return new XMLHttpRequest(); } if (!xdomain) { try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) { } } return null; }; /** * XHR based transport constructor. * * @constructor * @api public */ /** * Change the internal pageLoaded value. */ if ('undefined' != typeof window) { util.load(function () { pageLoaded = true; }); } /** * Defers a function to ensure a spinner is not displayed by the browser * * @param {Function} fn * @api public */ util.defer = function (fn) { if (!util.ua.webkit || 'undefined' != typeof importScripts) { return fn(); } util.load(function () { setTimeout(fn, 100); }); }; /** * Merges two objects. * * @api public */ util.merge = function merge (target, additional, deep, lastseen) { var seen = lastseen || [] , depth = typeof deep == 'undefined' ? 2 : deep , prop; for (prop in additional) { if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) { if (typeof target[prop] !== 'object' || !depth) { target[prop] = additional[prop]; seen.push(additional[prop]); } else { util.merge(target[prop], additional[prop], depth - 1, seen); } } } return target; }; /** * Merges prototypes from objects * * @api public */ util.mixin = function (ctor, ctor2) { util.merge(ctor.prototype, ctor2.prototype); }; /** * Shortcut for prototypical and static inheritance. * * @api private */ util.inherit = function (ctor, ctor2) { function f() {}; f.prototype = ctor2.prototype; ctor.prototype = new f; }; /** * Checks if the given object is an Array. * * io.util.isArray([]); // true * io.util.isArray({}); // false * * @param Object obj * @api public */ util.isArray = Array.isArray || function (obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }; /** * Intersects values of two arrays into a third * * @api public */ util.intersect = function (arr, arr2) { var ret = [] , longest = arr.length > arr2.length ? arr : arr2 , shortest = arr.length > arr2.length ? arr2 : arr; for (var i = 0, l = shortest.length; i < l; i++) { if (~util.indexOf(longest, shortest[i])) ret.push(shortest[i]); } return ret; }; /** * Array indexOf compatibility. * * @see bit.ly/a5Dxa2 * @api public */ util.indexOf = function (arr, o, i) { for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0; i < j && arr[i] !== o; i++) {} return j <= i ? -1 : i; }; /** * Converts enumerables to array. * * @api public */ util.toArray = function (enu) { var arr = []; for (var i = 0, l = enu.length; i < l; i++) arr.push(enu[i]); return arr; }; /** * UA / engines detection namespace. * * @namespace */ util.ua = {}; /** * Whether the UA supports CORS for XHR. * * @api public */ util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () { try { var a = new XMLHttpRequest(); } catch (e) { return false; } return a.withCredentials != undefined; })(); /** * Detect webkit. * * @api public */ util.ua.webkit = 'undefined' != typeof navigator && /webkit/i.test(navigator.userAgent); /** * Detect iPad/iPhone/iPod. * * @api public */ util.ua.iDevice = 'undefined' != typeof navigator && /iPad|iPhone|iPod/i.test(navigator.userAgent); })('undefined' != typeof io ? io : module.exports, this);