mirror of
https://github.com/viq/NewsBlur.git
synced 2025-08-05 16:49:45 +00:00
356 lines
7.2 KiB
JavaScript
356 lines
7.2 KiB
JavaScript
/**
|
|
* socket.io
|
|
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
(function (exports, global) {
|
|
|
|
/**
|
|
* Utilities namespace.
|
|
*
|
|
* @namespace
|
|
*/
|
|
|
|
var util = exports.util = {};
|
|
|
|
/**
|
|
* Parses an URI
|
|
*
|
|
* @author Steven Levithan <stevenlevithan.com> (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) {
|
|
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);
|
|
|
|
})('undefined' != typeof io ? io : module.exports, this);
|