UNPKG

7.54 kBJavaScriptView Raw
1
2/**
3 * socket.io
4 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
5 * MIT Licensed
6 */
7
8(function (exports, global) {
9
10 /**
11 * Utilities namespace.
12 *
13 * @namespace
14 */
15
16 var util = exports.util = {};
17
18 /**
19 * Parses an URI
20 *
21 * @author Steven Levithan <stevenlevithan.com> (MIT license)
22 * @api public
23 */
24
25 var re = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
26
27 var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',
28 'host', 'port', 'relative', 'path', 'directory', 'file', 'query',
29 'anchor'];
30
31 util.parseUri = function (str) {
32 var m = re.exec(str || '')
33 , uri = {}
34 , i = 14;
35
36 while (i--) {
37 uri[parts[i]] = m[i] || '';
38 }
39
40 return uri;
41 };
42
43 /**
44 * Produces a unique url that identifies a Socket.IO connection.
45 *
46 * @param {Object} uri
47 * @api public
48 */
49
50 util.uniqueUri = function (uri) {
51 var protocol = uri.protocol
52 , host = uri.host
53 , port = uri.port;
54
55 if ('document' in global) {
56 host = host || document.domain;
57 port = port || (protocol == 'https'
58 && document.location.protocol !== 'https:' ? 443 : document.location.port);
59 } else {
60 host = host || 'localhost';
61
62 if (!port && protocol == 'https') {
63 port = 443;
64 }
65 }
66
67 return (protocol || 'http') + '://' + host + ':' + (port || 80);
68 };
69
70 /**
71 * Mergest 2 query strings in to once unique query string
72 *
73 * @param {String} base
74 * @param {String} addition
75 * @api public
76 */
77
78 util.query = function (base, addition) {
79 var query = util.chunkQuery(base || '')
80 , components = [];
81
82 util.merge(query, util.chunkQuery(addition || ''));
83 for (var part in query) {
84 if (query.hasOwnProperty(part)) {
85 components.push(part + '=' + query[part]);
86 }
87 }
88
89 return components.length ? '?' + components.join('&') : '';
90 };
91
92 /**
93 * Transforms a querystring in to an object
94 *
95 * @param {String} qs
96 * @api public
97 */
98
99 util.chunkQuery = function (qs) {
100 var query = {}
101 , params = qs.split('&')
102 , i = 0
103 , l = params.length
104 , kv;
105
106 for (; i < l; ++i) {
107 kv = params[i].split('=');
108 if (kv[0]) {
109 query[kv[0]] = decodeURIComponent(kv[1]);
110 }
111 }
112
113 return query;
114 };
115
116 /**
117 * Executes the given function when the page is loaded.
118 *
119 * io.util.load(function () { console.log('page loaded'); });
120 *
121 * @param {Function} fn
122 * @api public
123 */
124
125 var pageLoaded = false;
126
127 util.load = function (fn) {
128 if ('document' in global && document.readyState === 'complete' || pageLoaded) {
129 return fn();
130 }
131
132 util.on(global, 'load', fn, false);
133 };
134
135 /**
136 * Adds an event.
137 *
138 * @api private
139 */
140
141 util.on = function (element, event, fn, capture) {
142 if (element.attachEvent) {
143 element.attachEvent('on' + event, fn);
144 } else if (element.addEventListener) {
145 element.addEventListener(event, fn, capture);
146 }
147 };
148
149 /**
150 * Generates the correct `XMLHttpRequest` for regular and cross domain requests.
151 *
152 * @param {Boolean} [xdomain] Create a request that can be used cross domain.
153 * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.
154 * @api private
155 */
156
157 util.request = function (xdomain) {
158 // if node
159 var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
160 return new XMLHttpRequest();
161 // end node
162
163 if ('undefined' != typeof window) {
164 if (xdomain && window.XDomainRequest) {
165 return new XDomainRequest();
166 }
167
168 if (window.XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {
169 return new XMLHttpRequest();
170 }
171
172 if (!xdomain) {
173 try {
174 return new window.ActiveXObject('Microsoft.XMLHTTP');
175 } catch(e) { }
176 }
177 }
178
179 return null;
180 };
181
182 /**
183 * XHR based transport constructor.
184 *
185 * @constructor
186 * @api public
187 */
188
189 /**
190 * Change the internal pageLoaded value.
191 */
192
193 if ('undefined' != typeof window) {
194 util.load(function () {
195 pageLoaded = true;
196 });
197 }
198
199 /**
200 * Defers a function to ensure a spinner is not displayed by the browser
201 *
202 * @param {Function} fn
203 * @api public
204 */
205
206 util.defer = function (fn) {
207 if (!util.ua.webkit) {
208 return fn();
209 }
210
211 util.load(function () {
212 setTimeout(fn, 100);
213 });
214 };
215
216 /**
217 * Merges two objects.
218 *
219 * @api public
220 */
221
222 util.merge = function merge (target, additional, deep, lastseen) {
223 var seen = lastseen || []
224 , depth = typeof deep == 'undefined' ? 2 : deep
225 , prop;
226
227 for (prop in additional) {
228 if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {
229 if (typeof target[prop] !== 'object' || !depth) {
230 target[prop] = additional[prop];
231 seen.push(additional[prop]);
232 } else {
233 util.merge(target[prop], additional[prop], depth - 1, seen);
234 }
235 }
236 }
237
238 return target;
239 };
240
241 /**
242 * Merges prototypes from objects
243 *
244 * @api public
245 */
246
247 util.mixin = function (ctor, ctor2) {
248 util.merge(ctor.prototype, ctor2.prototype);
249 };
250
251 /**
252 * Shortcut for prototypical and static inheritance.
253 *
254 * @api private
255 */
256
257 util.inherit = function (ctor, ctor2) {
258 function f() {};
259 f.prototype = ctor2.prototype;
260 ctor.prototype = new f;
261 };
262
263 /**
264 * Checks if the given object is an Array.
265 *
266 * io.util.isArray([]); // true
267 * io.util.isArray({}); // false
268 *
269 * @param Object obj
270 * @api public
271 */
272
273 util.isArray = Array.isArray || function (obj) {
274 return Object.prototype.toString.call(obj) === '[object Array]';
275 };
276
277 /**
278 * Intersects values of two arrays into a third
279 *
280 * @api public
281 */
282
283 util.intersect = function (arr, arr2) {
284 var ret = []
285 , longest = arr.length > arr2.length ? arr : arr2
286 , shortest = arr.length > arr2.length ? arr2 : arr;
287
288 for (var i = 0, l = shortest.length; i < l; i++) {
289 if (~util.indexOf(longest, shortest[i]))
290 ret.push(shortest[i]);
291 }
292
293 return ret;
294 }
295
296 /**
297 * Array indexOf compatibility.
298 *
299 * @see bit.ly/a5Dxa2
300 * @api public
301 */
302
303 util.indexOf = function (arr, o, i) {
304 if (Array.prototype.indexOf) {
305 return Array.prototype.indexOf.call(arr, o, i);
306 }
307
308 for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;
309 i < j && arr[i] !== o; i++);
310
311 return j <= i ? -1 : i;
312 };
313
314 /**
315 * Converts enumerables to array.
316 *
317 * @api public
318 */
319
320 util.toArray = function (enu) {
321 var arr = [];
322
323 for (var i = 0, l = enu.length; i < l; i++)
324 arr.push(enu[i]);
325
326 return arr;
327 };
328
329 /**
330 * UA / engines detection namespace.
331 *
332 * @namespace
333 */
334
335 util.ua = {};
336
337 /**
338 * Whether the UA supports CORS for XHR.
339 *
340 * @api public
341 */
342
343 util.ua.hasCORS = 'undefined' != typeof window && window.XMLHttpRequest &&
344 (function () {
345 try {
346 var a = new XMLHttpRequest();
347 } catch (e) {
348 return false;
349 }
350
351 return a.withCredentials != undefined;
352 })();
353
354 /**
355 * Detect webkit.
356 *
357 * @api public
358 */
359
360 util.ua.webkit = 'undefined' != typeof navigator
361 && /webkit/i.test(navigator.userAgent);
362
363})(
364 'undefined' != typeof window ? io : module.exports
365 , this
366);