Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /***
3 MochiKit.Async 1.4.2
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
9 ***/
11 MochiKit.Base._deps('Async', ['Base']);
13 MochiKit.Async.NAME = "MochiKit.Async";
14 MochiKit.Async.VERSION = "1.4.2";
15 MochiKit.Async.__repr__ = function () {
16 return "[" + this.NAME + " " + this.VERSION + "]";
17 };
18 MochiKit.Async.toString = function () {
19 return this.__repr__();
20 };
22 /** @id MochiKit.Async.Deferred */
23 MochiKit.Async.Deferred = function (/* optional */ canceller) {
24 this.chain = [];
25 this.id = this._nextId();
26 this.fired = -1;
27 this.paused = 0;
28 this.results = [null, null];
29 this.canceller = canceller;
30 this.silentlyCancelled = false;
31 this.chained = false;
32 };
34 MochiKit.Async.Deferred.prototype = {
35 /** @id MochiKit.Async.Deferred.prototype.repr */
36 repr: function () {
37 var state;
38 if (this.fired == -1) {
39 state = 'unfired';
40 } else if (this.fired === 0) {
41 state = 'success';
42 } else {
43 state = 'error';
44 }
45 return 'Deferred(' + this.id + ', ' + state + ')';
46 },
48 toString: MochiKit.Base.forwardCall("repr"),
50 _nextId: MochiKit.Base.counter(),
52 /** @id MochiKit.Async.Deferred.prototype.cancel */
53 cancel: function () {
54 var self = MochiKit.Async;
55 if (this.fired == -1) {
56 if (this.canceller) {
57 this.canceller(this);
58 } else {
59 this.silentlyCancelled = true;
60 }
61 if (this.fired == -1) {
62 this.errback(new self.CancelledError(this));
63 }
64 } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
65 this.results[0].cancel();
66 }
67 },
69 _resback: function (res) {
70 /***
72 The primitive that means either callback or errback
74 ***/
75 this.fired = ((res instanceof Error) ? 1 : 0);
76 this.results[this.fired] = res;
77 this._fire();
78 },
80 _check: function () {
81 if (this.fired != -1) {
82 if (!this.silentlyCancelled) {
83 throw new MochiKit.Async.AlreadyCalledError(this);
84 }
85 this.silentlyCancelled = false;
86 return;
87 }
88 },
90 /** @id MochiKit.Async.Deferred.prototype.callback */
91 callback: function (res) {
92 this._check();
93 if (res instanceof MochiKit.Async.Deferred) {
94 throw new Error("Deferred instances can only be chained if they are the result of a callback");
95 }
96 this._resback(res);
97 },
99 /** @id MochiKit.Async.Deferred.prototype.errback */
100 errback: function (res) {
101 this._check();
102 var self = MochiKit.Async;
103 if (res instanceof self.Deferred) {
104 throw new Error("Deferred instances can only be chained if they are the result of a callback");
105 }
106 if (!(res instanceof Error)) {
107 res = new self.GenericError(res);
108 }
109 this._resback(res);
110 },
112 /** @id MochiKit.Async.Deferred.prototype.addBoth */
113 addBoth: function (fn) {
114 if (arguments.length > 1) {
115 fn = MochiKit.Base.partial.apply(null, arguments);
116 }
117 return this.addCallbacks(fn, fn);
118 },
120 /** @id MochiKit.Async.Deferred.prototype.addCallback */
121 addCallback: function (fn) {
122 if (arguments.length > 1) {
123 fn = MochiKit.Base.partial.apply(null, arguments);
124 }
125 return this.addCallbacks(fn, null);
126 },
128 /** @id MochiKit.Async.Deferred.prototype.addErrback */
129 addErrback: function (fn) {
130 if (arguments.length > 1) {
131 fn = MochiKit.Base.partial.apply(null, arguments);
132 }
133 return this.addCallbacks(null, fn);
134 },
136 /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
137 addCallbacks: function (cb, eb) {
138 if (this.chained) {
139 throw new Error("Chained Deferreds can not be re-used");
140 }
141 this.chain.push([cb, eb]);
142 if (this.fired >= 0) {
143 this._fire();
144 }
145 return this;
146 },
148 _fire: function () {
149 /***
151 Used internally to exhaust the callback sequence when a result
152 is available.
154 ***/
155 var chain = this.chain;
156 var fired = this.fired;
157 var res = this.results[fired];
158 var self = this;
159 var cb = null;
160 while (chain.length > 0 && this.paused === 0) {
161 // Array
162 var pair = chain.shift();
163 var f = pair[fired];
164 if (f === null) {
165 continue;
166 }
167 try {
168 res = f(res);
169 fired = ((res instanceof Error) ? 1 : 0);
170 if (res instanceof MochiKit.Async.Deferred) {
171 cb = function (res) {
172 self._resback(res);
173 self.paused--;
174 if ((self.paused === 0) && (self.fired >= 0)) {
175 self._fire();
176 }
177 };
178 this.paused++;
179 }
180 } catch (err) {
181 fired = 1;
182 if (!(err instanceof Error)) {
183 err = new MochiKit.Async.GenericError(err);
184 }
185 res = err;
186 }
187 }
188 this.fired = fired;
189 this.results[fired] = res;
190 if (cb && this.paused) {
191 // this is for "tail recursion" in case the dependent deferred
192 // is already fired
193 res.addBoth(cb);
194 res.chained = true;
195 }
196 }
197 };
199 MochiKit.Base.update(MochiKit.Async, {
200 /** @id MochiKit.Async.evalJSONRequest */
201 evalJSONRequest: function (req) {
202 return MochiKit.Base.evalJSON(req.responseText);
203 },
205 /** @id MochiKit.Async.succeed */
206 succeed: function (/* optional */result) {
207 var d = new MochiKit.Async.Deferred();
208 d.callback.apply(d, arguments);
209 return d;
210 },
212 /** @id MochiKit.Async.fail */
213 fail: function (/* optional */result) {
214 var d = new MochiKit.Async.Deferred();
215 d.errback.apply(d, arguments);
216 return d;
217 },
219 /** @id MochiKit.Async.getXMLHttpRequest */
220 getXMLHttpRequest: function () {
221 var self = arguments.callee;
222 if (!self.XMLHttpRequest) {
223 var tryThese = [
224 function () { return new XMLHttpRequest(); },
225 function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
226 function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
227 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
228 function () {
229 throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
230 }
231 ];
232 for (var i = 0; i < tryThese.length; i++) {
233 var func = tryThese[i];
234 try {
235 self.XMLHttpRequest = func;
236 return func();
237 } catch (e) {
238 // pass
239 }
240 }
241 }
242 return self.XMLHttpRequest();
243 },
245 _xhr_onreadystatechange: function (d) {
246 // MochiKit.Logging.logDebug('this.readyState', this.readyState);
247 var m = MochiKit.Base;
248 if (this.readyState == 4) {
249 // IE SUCKS
250 try {
251 this.onreadystatechange = null;
252 } catch (e) {
253 try {
254 this.onreadystatechange = m.noop;
255 } catch (e) {
256 }
257 }
258 var status = null;
259 try {
260 status = this.status;
261 if (!status && m.isNotEmpty(this.responseText)) {
262 // 0 or undefined seems to mean cached or local
263 status = 304;
264 }
265 } catch (e) {
266 // pass
267 // MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
268 }
269 // 200 is OK, 201 is CREATED, 204 is NO CONTENT
270 // 304 is NOT MODIFIED, 1223 is apparently a bug in IE
271 if (status == 200 || status == 201 || status == 204 ||
272 status == 304 || status == 1223) {
273 d.callback(this);
274 } else {
275 var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
276 if (err.number) {
277 // XXX: This seems to happen on page change
278 d.errback(err);
279 } else {
280 // XXX: this seems to happen when the server is unreachable
281 d.errback(err);
282 }
283 }
284 }
285 },
287 _xhr_canceller: function (req) {
288 // IE SUCKS
289 try {
290 req.onreadystatechange = null;
291 } catch (e) {
292 try {
293 req.onreadystatechange = MochiKit.Base.noop;
294 } catch (e) {
295 }
296 }
297 req.abort();
298 },
301 /** @id MochiKit.Async.sendXMLHttpRequest */
302 sendXMLHttpRequest: function (req, /* optional */ sendContent) {
303 if (typeof(sendContent) == "undefined" || sendContent === null) {
304 sendContent = "";
305 }
307 var m = MochiKit.Base;
308 var self = MochiKit.Async;
309 var d = new self.Deferred(m.partial(self._xhr_canceller, req));
311 try {
312 req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
313 req, d);
314 req.send(sendContent);
315 } catch (e) {
316 try {
317 req.onreadystatechange = null;
318 } catch (ignore) {
319 // pass
320 }
321 d.errback(e);
322 }
324 return d;
326 },
328 /** @id MochiKit.Async.doXHR */
329 doXHR: function (url, opts) {
330 /*
331 Work around a Firefox bug by dealing with XHR during
332 the next event loop iteration. Maybe it's this one:
333 https://bugzilla.mozilla.org/show_bug.cgi?id=249843
334 */
335 var self = MochiKit.Async;
336 return self.callLater(0, self._doXHR, url, opts);
337 },
339 _doXHR: function (url, opts) {
340 var m = MochiKit.Base;
341 opts = m.update({
342 method: 'GET',
343 sendContent: ''
344 /*
345 queryString: undefined,
346 username: undefined,
347 password: undefined,
348 headers: undefined,
349 mimeType: undefined
350 */
351 }, opts);
352 var self = MochiKit.Async;
353 var req = self.getXMLHttpRequest();
354 if (opts.queryString) {
355 var qs = m.queryString(opts.queryString);
356 if (qs) {
357 url += "?" + qs;
358 }
359 }
360 // Safari will send undefined:undefined, so we have to check.
361 // We can't use apply, since the function is native.
362 if ('username' in opts) {
363 req.open(opts.method, url, true, opts.username, opts.password);
364 } else {
365 req.open(opts.method, url, true);
366 }
367 if (req.overrideMimeType && opts.mimeType) {
368 req.overrideMimeType(opts.mimeType);
369 }
370 req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
371 if (opts.headers) {
372 var headers = opts.headers;
373 if (!m.isArrayLike(headers)) {
374 headers = m.items(headers);
375 }
376 for (var i = 0; i < headers.length; i++) {
377 var header = headers[i];
378 var name = header[0];
379 var value = header[1];
380 req.setRequestHeader(name, value);
381 }
382 }
383 return self.sendXMLHttpRequest(req, opts.sendContent);
384 },
386 _buildURL: function (url/*, ...*/) {
387 if (arguments.length > 1) {
388 var m = MochiKit.Base;
389 var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
390 if (qs) {
391 return url + "?" + qs;
392 }
393 }
394 return url;
395 },
397 /** @id MochiKit.Async.doSimpleXMLHttpRequest */
398 doSimpleXMLHttpRequest: function (url/*, ...*/) {
399 var self = MochiKit.Async;
400 url = self._buildURL.apply(self, arguments);
401 return self.doXHR(url);
402 },
404 /** @id MochiKit.Async.loadJSONDoc */
405 loadJSONDoc: function (url/*, ...*/) {
406 var self = MochiKit.Async;
407 url = self._buildURL.apply(self, arguments);
408 var d = self.doXHR(url, {
409 'mimeType': 'text/plain',
410 'headers': [['Accept', 'application/json']]
411 });
412 d = d.addCallback(self.evalJSONRequest);
413 return d;
414 },
416 /** @id MochiKit.Async.wait */
417 wait: function (seconds, /* optional */value) {
418 var d = new MochiKit.Async.Deferred();
419 var m = MochiKit.Base;
420 if (typeof(value) != 'undefined') {
421 d.addCallback(function () { return value; });
422 }
423 var timeout = setTimeout(
424 m.bind("callback", d),
425 Math.floor(seconds * 1000));
426 d.canceller = function () {
427 try {
428 clearTimeout(timeout);
429 } catch (e) {
430 // pass
431 }
432 };
433 return d;
434 },
436 /** @id MochiKit.Async.callLater */
437 callLater: function (seconds, func) {
438 var m = MochiKit.Base;
439 var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
440 return MochiKit.Async.wait(seconds).addCallback(
441 function (res) { return pfunc(); }
442 );
443 }
444 });
447 /** @id MochiKit.Async.DeferredLock */
448 MochiKit.Async.DeferredLock = function () {
449 this.waiting = [];
450 this.locked = false;
451 this.id = this._nextId();
452 };
454 MochiKit.Async.DeferredLock.prototype = {
455 __class__: MochiKit.Async.DeferredLock,
456 /** @id MochiKit.Async.DeferredLock.prototype.acquire */
457 acquire: function () {
458 var d = new MochiKit.Async.Deferred();
459 if (this.locked) {
460 this.waiting.push(d);
461 } else {
462 this.locked = true;
463 d.callback(this);
464 }
465 return d;
466 },
467 /** @id MochiKit.Async.DeferredLock.prototype.release */
468 release: function () {
469 if (!this.locked) {
470 throw TypeError("Tried to release an unlocked DeferredLock");
471 }
472 this.locked = false;
473 if (this.waiting.length > 0) {
474 this.locked = true;
475 this.waiting.shift().callback(this);
476 }
477 },
478 _nextId: MochiKit.Base.counter(),
479 repr: function () {
480 var state;
481 if (this.locked) {
482 state = 'locked, ' + this.waiting.length + ' waiting';
483 } else {
484 state = 'unlocked';
485 }
486 return 'DeferredLock(' + this.id + ', ' + state + ')';
487 },
488 toString: MochiKit.Base.forwardCall("repr")
490 };
492 /** @id MochiKit.Async.DeferredList */
493 MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
495 // call parent constructor
496 MochiKit.Async.Deferred.apply(this, [canceller]);
498 this.list = list;
499 var resultList = [];
500 this.resultList = resultList;
502 this.finishedCount = 0;
503 this.fireOnOneCallback = fireOnOneCallback;
504 this.fireOnOneErrback = fireOnOneErrback;
505 this.consumeErrors = consumeErrors;
507 var cb = MochiKit.Base.bind(this._cbDeferred, this);
508 for (var i = 0; i < list.length; i++) {
509 var d = list[i];
510 resultList.push(undefined);
511 d.addCallback(cb, i, true);
512 d.addErrback(cb, i, false);
513 }
515 if (list.length === 0 && !fireOnOneCallback) {
516 this.callback(this.resultList);
517 }
519 };
521 MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
523 MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
524 this.resultList[index] = [succeeded, result];
525 this.finishedCount += 1;
526 if (this.fired == -1) {
527 if (succeeded && this.fireOnOneCallback) {
528 this.callback([index, result]);
529 } else if (!succeeded && this.fireOnOneErrback) {
530 this.errback(result);
531 } else if (this.finishedCount == this.list.length) {
532 this.callback(this.resultList);
533 }
534 }
535 if (!succeeded && this.consumeErrors) {
536 result = null;
537 }
538 return result;
539 };
541 /** @id MochiKit.Async.gatherResults */
542 MochiKit.Async.gatherResults = function (deferredList) {
543 var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
544 d.addCallback(function (results) {
545 var ret = [];
546 for (var i = 0; i < results.length; i++) {
547 ret.push(results[i][1]);
548 }
549 return ret;
550 });
551 return d;
552 };
554 /** @id MochiKit.Async.maybeDeferred */
555 MochiKit.Async.maybeDeferred = function (func) {
556 var self = MochiKit.Async;
557 var result;
558 try {
559 var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
560 if (r instanceof self.Deferred) {
561 result = r;
562 } else if (r instanceof Error) {
563 result = self.fail(r);
564 } else {
565 result = self.succeed(r);
566 }
567 } catch (e) {
568 result = self.fail(e);
569 }
570 return result;
571 };
574 MochiKit.Async.EXPORT = [
575 "AlreadyCalledError",
576 "CancelledError",
577 "BrowserComplianceError",
578 "GenericError",
579 "XMLHttpRequestError",
580 "Deferred",
581 "succeed",
582 "fail",
583 "getXMLHttpRequest",
584 "doSimpleXMLHttpRequest",
585 "loadJSONDoc",
586 "wait",
587 "callLater",
588 "sendXMLHttpRequest",
589 "DeferredLock",
590 "DeferredList",
591 "gatherResults",
592 "maybeDeferred",
593 "doXHR"
594 ];
596 MochiKit.Async.EXPORT_OK = [
597 "evalJSONRequest"
598 ];
600 MochiKit.Async.__new__ = function () {
601 var m = MochiKit.Base;
602 var ne = m.partial(m._newNamedError, this);
604 ne("AlreadyCalledError",
605 /** @id MochiKit.Async.AlreadyCalledError */
606 function (deferred) {
607 /***
609 Raised by the Deferred if callback or errback happens
610 after it was already fired.
612 ***/
613 this.deferred = deferred;
614 }
615 );
617 ne("CancelledError",
618 /** @id MochiKit.Async.CancelledError */
619 function (deferred) {
620 /***
622 Raised by the Deferred cancellation mechanism.
624 ***/
625 this.deferred = deferred;
626 }
627 );
629 ne("BrowserComplianceError",
630 /** @id MochiKit.Async.BrowserComplianceError */
631 function (msg) {
632 /***
634 Raised when the JavaScript runtime is not capable of performing
635 the given function. Technically, this should really never be
636 raised because a non-conforming JavaScript runtime probably
637 isn't going to support exceptions in the first place.
639 ***/
640 this.message = msg;
641 }
642 );
644 ne("GenericError",
645 /** @id MochiKit.Async.GenericError */
646 function (msg) {
647 this.message = msg;
648 }
649 );
651 ne("XMLHttpRequestError",
652 /** @id MochiKit.Async.XMLHttpRequestError */
653 function (req, msg) {
654 /***
656 Raised when an XMLHttpRequest does not complete for any reason.
658 ***/
659 this.req = req;
660 this.message = msg;
661 try {
662 // Strange but true that this can raise in some cases.
663 this.number = req.status;
664 } catch (e) {
665 // pass
666 }
667 }
668 );
671 this.EXPORT_TAGS = {
672 ":common": this.EXPORT,
673 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
674 };
676 m.nameFunctions(this);
678 };
680 MochiKit.Async.__new__();
682 MochiKit.Base._exportSymbols(this, MochiKit.Async);