Files
socket.io/lib/util.js
2013-03-16 09:19:48 -07:00

290 lines
5.3 KiB
JavaScript

/**
* Status of page load.
*/
var pageLoaded = false;
/**
* Returns the global object
*
* @api private
*/
exports.global = function () {
return 'undefined' != typeof window ? window : global;
};
/**
* Inheritance.
*
* @param {Function} ctor a
* @param {Function} ctor b
* @api private
*/
exports.inherits = function inherits (a, b) {
function c () { }
c.prototype = b.prototype;
a.prototype = new c;
};
/**
* Object.keys
*/
exports.keys = Object.keys || function (obj) {
var ret = [];
var has = Object.prototype.hasOwnProperty;
for (var i in obj) {
if (has.call(obj, i)) {
ret.push(i);
}
}
return ret;
};
/**
* Adds an event.
*
* @api private
*/
exports.on = function (element, event, fn, capture) {
if (element.attachEvent) {
element.attachEvent('on' + event, fn);
} else if (element.addEventListener) {
element.addEventListener(event, fn, capture);
}
};
/**
* Load utility.
*
* @api private
*/
exports.load = function (fn) {
var global = exports.global();
if (global.document && document.readyState === 'complete' || pageLoaded) {
return fn();
}
exports.on(global, 'load', fn, false);
};
/**
* Change the internal pageLoaded value.
*/
if ('undefined' != typeof window) {
exports.load(function () {
pageLoaded = true;
});
}
/**
* Defers a function to ensure a spinner is not displayed by the browser.
*
* @param {Function} fn
* @api private
*/
exports.defer = function (fn) {
if (!exports.ua.webkit || 'undefined' != typeof importScripts) {
return fn();
}
exports.load(function () {
setTimeout(fn, 100);
});
};
/**
* JSON parse.
*
* @see Based on jQuery#parseJSON (MIT) and JSON2
* @api private
*/
var rvalidchars = /^[\],:{}\s]*$/;
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
var rtrimLeft = /^\s+/;
var rtrimRight = /\s+$/;
exports.parseJSON = function (data) {
var global = exports.global();
if ('string' != typeof data || !data) {
return null;
}
data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
// Attempt to parse using the native JSON parser first
if (global.JSON && JSON.parse) {
return JSON.parse(data);
}
if (rvalidchars.test(data.replace(rvalidescape, '@')
.replace(rvalidtokens, ']')
.replace(rvalidbraces, ''))) {
return (new Function('return ' + data))();
}
};
/**
* UA / engines detection namespace.
*
* @namespace
*/
exports.ua = {};
/**
* Whether the UA supports CORS for XHR.
*
* @api private
*/
exports.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
var a;
try {
a = new XMLHttpRequest();
} catch (e) {
return false;
}
return a.withCredentials != undefined;
})();
/**
* Detect webkit.
*
* @api private
*/
exports.ua.webkit = 'undefined' != typeof navigator &&
/webkit/i.test(navigator.userAgent);
/**
* Detect gecko.
*
* @api private
*/
exports.ua.gecko = 'undefined' != typeof navigator &&
/gecko/i.test(navigator.userAgent);
/**
* Detect android;
*/
exports.ua.android = 'undefined' != typeof navigator &&
/android/i.test(navigator.userAgent);
/**
* Detect iOS.
*/
exports.ua.ios = 'undefined' != typeof navigator &&
/^(iPad|iPhone|iPod)$/.test(navigator.platform);
exports.ua.ios6 = exports.ua.ios && /OS 6_/.test(navigator.userAgent);
/**
* XHR request helper.
*
* @param {Boolean} whether we need xdomain
* @api private
*/
exports.request = function request (xdomain) {
if ('undefined' == typeof window) {
var _XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
return new _XMLHttpRequest();
}
if (xdomain && 'undefined' != typeof XDomainRequest && !exports.ua.hasCORS) {
return new XDomainRequest();
}
// XMLHttpRequest can be disabled on IE
try {
if ('undefined' != typeof XMLHttpRequest && (!xdomain || exports.ua.hasCORS)) {
return new XMLHttpRequest();
}
} catch (e) { }
if (!xdomain) {
try {
return new ActiveXObject('Microsoft.XMLHTTP');
} catch(e) { }
}
};
/**
* Parses an URI
*
* @author Steven Levithan <stevenlevithan.com> (MIT license)
* @api private
*/
var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
var parts = [
'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
, 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];
exports.parseUri = function (str) {
var m = re.exec(str || '')
, uri = {}
, i = 14;
while (i--) {
uri[parts[i]] = m[i] || '';
}
return uri;
};
/**
* Compiles a querystring
*
* @param {Object}
* @api private
*/
exports.qs = function (obj) {
var str = '';
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
if (str.length) str += '&';
str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
}
}
return str;
};
/**
* Parses a simple querystring.
*
* @param {String} qs
* @api private
*/
exports.qsParse = function(qs){
var qry = {};
var pairs = qs.split('&');
for (var i = 0, l = pairs.length; i < l; i++) {
var pair = pairs[i].split('=');
qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return qry;
};