Files
socket.io/lib/util.js
Raynos eb4d91bde9 Do not shadow global XMLHttpRequest
If you use the XMLHttpRequest variable name then the if
typeof XMLHttpRequest === 'undefined' check will always
return false and the XHR polling method is never used.

This is needed because JSONP polling is buggy and doesn't emit
close when server shutsdown. JSONP should be fixed / disabled.
2013-01-06 17:03:52 -08:00

273 lines
5.0 KiB
JavaScript

/**
* Status of page load.
*/
var pageLoaded = false;
/**
* 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]*$/
, rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g
, rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g
, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g
, rtrimLeft = /^\s+/
, 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 () {
try {
var 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 += i + '=' + encodeURIComponent(obj[i]);
}
}
return str;
};
/**
* Returns the global object
*
* @api private
*/
exports.global = function () {
return 'undefined' != typeof window ? window : global;
};