6 var pageLoaded = false;
12 var global = 'undefined' != typeof window ? window : global;
17 * @param {Function} ctor a
18 * @param {Function} ctor b
22 exports.inherits = function inherits (a, b) {
24 c.prototype = b.prototype;
32 exports.keys = Object.keys || function (obj) {
34 var has = Object.prototype.hasOwnProperty;
37 if (has.call(obj, i)) {
51 exports.on = function (element, event, fn, capture) {
52 if (element.attachEvent) {
53 element.attachEvent('on' + event, fn);
54 } else if (element.addEventListener) {
55 element.addEventListener(event, fn, capture);
65 exports.load = function (fn) {
66 if (global.document && document.readyState === 'complete' || pageLoaded) {
70 exports.on(global, 'load', fn, false);
74 * Change the internal pageLoaded value.
77 if ('undefined' != typeof window) {
78 exports.load(function () {
84 * Defers a function to ensure a spinner is not displayed by the browser.
86 * @param {Function} fn
90 exports.defer = function (fn) {
91 if (!exports.ua.webkit || 'undefined' != typeof importScripts) {
95 exports.load(function () {
103 * @see Based on jQuery#parseJSON (MIT) and JSON2
107 var rvalidchars = /^[\],:{}\s]*$/
108 , rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g
109 , rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g
110 , rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g
112 , rtrimRight = /\s+$/
114 exports.parseJSON = function (data) {
115 if ('string' != typeof data || !data) {
119 data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
121 // Attempt to parse using the native JSON parser first
122 if (global.JSON && JSON.parse) {
123 return JSON.parse(data);
126 if (rvalidchars.test(data.replace(rvalidescape, '@')
127 .replace(rvalidtokens, ']')
128 .replace(rvalidbraces, ''))) {
129 return (new Function('return ' + data))();
134 * UA / engines detection namespace.
142 * Whether the UA supports CORS for XHR.
147 exports.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {
149 var a = new XMLHttpRequest();
154 return a.withCredentials != undefined;
163 exports.ua.webkit = 'undefined' != typeof navigator &&
164 /webkit/i.test(navigator.userAgent);
172 exports.ua.gecko = 'undefined' != typeof navigator &&
173 /gecko/i.test(navigator.userAgent);
179 exports.ua.android = 'undefined' != typeof navigator &&
180 /android/i.test(navigator.userAgent);
186 exports.ua.ios = 'undefined' != typeof navigator &&
187 /^(iPad|iPhone|iPod)$/.test(navigator.platform);
188 exports.ua.ios6 = exports.ua.ios && /OS 6_/.test(navigator.userAgent);
191 * XHR request helper.
193 * @param {Boolean} whether we need xdomain
197 exports.request = function request (xdomain) {
198 if ('undefined' != typeof process) {
199 var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
200 return new XMLHttpRequest();
203 if (xdomain && 'undefined' != typeof XDomainRequest && !exports.ua.hasCORS) {
204 return new XDomainRequest();
207 // XMLHttpRequest can be disabled on IE
209 if ('undefined' != typeof XMLHttpRequest && (!xdomain || exports.ua.hasCORS)) {
210 return new XMLHttpRequest();
216 return new ActiveXObject('Microsoft.XMLHTTP');
224 * @author Steven Levithan <stevenlevithan.com> (MIT license)
228 var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
231 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host'
232 , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
235 exports.parseUri = function (str) {
236 var m = re.exec(str || '')
241 uri[parts[i]] = m[i] || '';
248 * Compiles a querystring
254 exports.qs = function (obj) {
258 if (obj.hasOwnProperty(i)) {
259 if (str.length) str += '&';
260 str += i + '=' + encodeURIComponent(obj[i]);