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
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
9 ***/
11 if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.Async");
13 dojo.require("MochiKit.Base");
14 }
15 if (typeof(JSAN) != 'undefined') {
16 JSAN.use("MochiKit.Base", []);
17 }
19 try {
20 if (typeof(MochiKit.Base) == 'undefined') {
21 throw "";
22 }
23 } catch (e) {
24 throw "MochiKit.Async depends on MochiKit.Base!";
25 }
27 if (typeof(MochiKit.Async) == 'undefined') {
28 MochiKit.Async = {};
29 }
31 MochiKit.Async.NAME = "MochiKit.Async";
32 MochiKit.Async.VERSION = "1.4";
33 MochiKit.Async.__repr__ = function () {
34 return "[" + this.NAME + " " + this.VERSION + "]";
35 };
36 MochiKit.Async.toString = function () {
37 return this.__repr__();
38 };
40 /** @id MochiKit.Async.Deferred */
41 MochiKit.Async.Deferred = function (/* optional */ canceller) {
42 this.chain = [];
43 this.id = this._nextId();
44 this.fired = -1;
45 this.paused = 0;
46 this.results = [null, null];
47 this.canceller = canceller;
48 this.silentlyCancelled = false;
49 this.chained = false;
50 };
52 MochiKit.Async.Deferred.prototype = {
53 /** @id MochiKit.Async.Deferred.prototype.repr */
54 repr: function () {
55 var state;
56 if (this.fired == -1) {
57 state = 'unfired';
58 } else if (this.fired === 0) {
59 state = 'success';
60 } else {
61 state = 'error';
62 }
63 return 'Deferred(' + this.id + ', ' + state + ')';
64 },
66 toString: MochiKit.Base.forwardCall("repr"),
68 _nextId: MochiKit.Base.counter(),
70 /** @id MochiKit.Async.Deferred.prototype.cancel */
71 cancel: function () {
72 var self = MochiKit.Async;
73 if (this.fired == -1) {
74 if (this.canceller) {
75 this.canceller(this);
76 } else {
77 this.silentlyCancelled = true;
78 }
79 if (this.fired == -1) {
80 this.errback(new self.CancelledError(this));
81 }
82 } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
83 this.results[0].cancel();
84 }
85 },
87 _resback: function (res) {
88 /***
90 The primitive that means either callback or errback
92 ***/
93 this.fired = ((res instanceof Error) ? 1 : 0);
94 this.results[this.fired] = res;
95 this._fire();
96 },
98 _check: function () {
99 if (this.fired != -1) {
100 if (!this.silentlyCancelled) {
101 throw new MochiKit.Async.AlreadyCalledError(this);
102 }
103 this.silentlyCancelled = false;
104 return;
105 }
106 },
108 /** @id MochiKit.Async.Deferred.prototype.callback */
109 callback: function (res) {
110 this._check();
111 if (res instanceof MochiKit.Async.Deferred) {
112 throw new Error("Deferred instances can only be chained if they are the result of a callback");
113 }
114 this._resback(res);
115 },
117 /** @id MochiKit.Async.Deferred.prototype.errback */
118 errback: function (res) {
119 this._check();
120 var self = MochiKit.Async;
121 if (res instanceof self.Deferred) {
122 throw new Error("Deferred instances can only be chained if they are the result of a callback");
123 }
124 if (!(res instanceof Error)) {
125 res = new self.GenericError(res);
126 }
127 this._resback(res);
128 },
130 /** @id MochiKit.Async.Deferred.prototype.addBoth */
131 addBoth: function (fn) {
132 if (arguments.length > 1) {
133 fn = MochiKit.Base.partial.apply(null, arguments);
134 }
135 return this.addCallbacks(fn, fn);
136 },
138 /** @id MochiKit.Async.Deferred.prototype.addCallback */
139 addCallback: function (fn) {
140 if (arguments.length > 1) {
141 fn = MochiKit.Base.partial.apply(null, arguments);
142 }
143 return this.addCallbacks(fn, null);
144 },
146 /** @id MochiKit.Async.Deferred.prototype.addErrback */
147 addErrback: function (fn) {
148 if (arguments.length > 1) {
149 fn = MochiKit.Base.partial.apply(null, arguments);
150 }
151 return this.addCallbacks(null, fn);
152 },
154 /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
155 addCallbacks: function (cb, eb) {
156 if (this.chained) {
157 throw new Error("Chained Deferreds can not be re-used");
158 }
159 this.chain.push([cb, eb]);
160 if (this.fired >= 0) {
161 this._fire();
162 }
163 return this;
164 },
166 _fire: function () {
167 /***
169 Used internally to exhaust the callback sequence when a result
170 is available.
172 ***/
173 var chain = this.chain;
174 var fired = this.fired;
175 var res = this.results[fired];
176 var self = this;
177 var cb = null;
178 while (chain.length > 0 && this.paused === 0) {
179 // Array
180 var pair = chain.shift();
181 var f = pair[fired];
182 if (f === null) {
183 continue;
184 }
185 try {
186 res = f(res);
187 fired = ((res instanceof Error) ? 1 : 0);
188 if (res instanceof MochiKit.Async.Deferred) {
189 cb = function (res) {
190 self._resback(res);
191 self.paused--;
192 if ((self.paused === 0) && (self.fired >= 0)) {
193 self._fire();
194 }
195 };
196 this.paused++;
197 }
198 } catch (err) {
199 fired = 1;
200 if (!(err instanceof Error)) {
201 err = new MochiKit.Async.GenericError(err);
202 }
203 res = err;
204 }
205 }
206 this.fired = fired;
207 this.results[fired] = res;
208 if (cb && this.paused) {
209 // this is for "tail recursion" in case the dependent deferred
210 // is already fired
211 res.addBoth(cb);
212 res.chained = true;
213 }
214 }
215 };
217 MochiKit.Base.update(MochiKit.Async, {
218 /** @id MochiKit.Async.evalJSONRequest */
219 evalJSONRequest: function (/* req */) {
220 return eval('(' + arguments[0].responseText + ')');
221 },
223 /** @id MochiKit.Async.succeed */
224 succeed: function (/* optional */result) {
225 var d = new MochiKit.Async.Deferred();
226 d.callback.apply(d, arguments);
227 return d;
228 },
230 /** @id MochiKit.Async.fail */
231 fail: function (/* optional */result) {
232 var d = new MochiKit.Async.Deferred();
233 d.errback.apply(d, arguments);
234 return d;
235 },
237 /** @id MochiKit.Async.getXMLHttpRequest */
238 getXMLHttpRequest: function () {
239 var self = arguments.callee;
240 if (!self.XMLHttpRequest) {
241 var tryThese = [
242 function () { return new XMLHttpRequest(); },
243 function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
244 function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
245 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
246 function () {
247 throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
248 }
249 ];
250 for (var i = 0; i < tryThese.length; i++) {
251 var func = tryThese[i];
252 try {
253 self.XMLHttpRequest = func;
254 return func();
255 } catch (e) {
256 // pass
257 }
258 }
259 }
260 return self.XMLHttpRequest();
261 },
263 _xhr_onreadystatechange: function (d) {
264 // MochiKit.Logging.logDebug('this.readyState', this.readyState);
265 var m = MochiKit.Base;
266 if (this.readyState == 4) {
267 // IE SUCKS
268 try {
269 this.onreadystatechange = null;
270 } catch (e) {
271 try {
272 this.onreadystatechange = m.noop;
273 } catch (e) {
274 }
275 }
276 var status = null;
277 try {
278 status = this.status;
279 if (!status && m.isNotEmpty(this.responseText)) {
280 // 0 or undefined seems to mean cached or local
281 status = 304;
282 }
283 } catch (e) {
284 // pass
285 // MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
286 }
287 // 200 is OK, 304 is NOT_MODIFIED
288 if (status == 200 || status == 304) { // OK
289 d.callback(this);
290 } else {
291 var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
292 if (err.number) {
293 // XXX: This seems to happen on page change
294 d.errback(err);
295 } else {
296 // XXX: this seems to happen when the server is unreachable
297 d.errback(err);
298 }
299 }
300 }
301 },
303 _xhr_canceller: function (req) {
304 // IE SUCKS
305 try {
306 req.onreadystatechange = null;
307 } catch (e) {
308 try {
309 req.onreadystatechange = MochiKit.Base.noop;
310 } catch (e) {
311 }
312 }
313 req.abort();
314 },
317 /** @id MochiKit.Async.sendXMLHttpRequest */
318 sendXMLHttpRequest: function (req, /* optional */ sendContent) {
319 if (typeof(sendContent) == "undefined" || sendContent === null) {
320 sendContent = "";
321 }
323 var m = MochiKit.Base;
324 var self = MochiKit.Async;
325 var d = new self.Deferred(m.partial(self._xhr_canceller, req));
327 try {
328 req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
329 req, d);
330 req.send(sendContent);
331 } catch (e) {
332 try {
333 req.onreadystatechange = null;
334 } catch (ignore) {
335 // pass
336 }
337 d.errback(e);
338 }
340 return d;
342 },
344 /** @id MochiKit.Async.doXHR */
345 doXHR: function (url, opts) {
346 var m = MochiKit.Base;
347 opts = m.update({
348 method: 'GET',
349 sendContent: ''
350 /*
351 queryString: undefined,
352 username: undefined,
353 password: undefined,
354 headers: undefined,
355 mimeType: undefined
356 */
357 }, opts);
358 var self = MochiKit.Async;
359 var req = self.getXMLHttpRequest();
360 if (opts.queryString) {
361 var qs = m.queryString(opts.queryString);
362 if (qs) {
363 url += "?" + qs;
364 }
365 }
366 req.open(opts.method, url, true, opts.username, opts.password);
367 if (req.overrideMimeType && opts.mimeType) {
368 req.overrideMimeType(opts.mimeType);
369 }
370 if (opts.headers) {
371 var headers = opts.headers;
372 if (!m.isArrayLike(headers)) {
373 headers = m.items(headers);
374 }
375 for (var i = 0; i < headers.length; i++) {
376 var header = headers[i];
377 var name = header[0];
378 var value = header[1];
379 req.setRequestHeader(name, value);
380 }
381 }
382 return self.sendXMLHttpRequest(req, opts.sendContent);
383 },
385 _buildURL: function (url/*, ...*/) {
386 if (arguments.length > 1) {
387 var m = MochiKit.Base;
388 var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
389 if (qs) {
390 return url + "?" + qs;
391 }
392 }
393 return url;
394 },
396 /** @id MochiKit.Async.doSimpleXMLHttpRequest */
397 doSimpleXMLHttpRequest: function (url/*, ...*/) {
398 var self = MochiKit.Async;
399 url = self._buildURL.apply(self, arguments);
400 return self.doXHR(url);
401 },
403 /** @id MochiKit.Async.loadJSONDoc */
404 loadJSONDoc: function (url/*, ...*/) {
405 var self = MochiKit.Async;
406 url = self._buildURL.apply(self, arguments);
407 var d = self.doXHR(url, {
408 'mimeType': 'text/plain',
409 'headers': [['Accept', 'application/json']]
410 });
411 d = d.addCallback(self.evalJSONRequest);
412 return d;
413 },
415 /** @id MochiKit.Async.wait */
416 wait: function (seconds, /* optional */value) {
417 var d = new MochiKit.Async.Deferred();
418 var m = MochiKit.Base;
419 if (typeof(value) != 'undefined') {
420 d.addCallback(function () { return value; });
421 }
422 var timeout = setTimeout(
423 m.bind("callback", d),
424 Math.floor(seconds * 1000));
425 d.canceller = function () {
426 try {
427 clearTimeout(timeout);
428 } catch (e) {
429 // pass
430 }
431 };
432 return d;
433 },
435 /** @id MochiKit.Async.callLater */
436 callLater: function (seconds, func) {
437 var m = MochiKit.Base;
438 var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
439 return MochiKit.Async.wait(seconds).addCallback(
440 function (res) { return pfunc(); }
441 );
442 }
443 });
446 /** @id MochiKit.Async.DeferredLock */
447 MochiKit.Async.DeferredLock = function () {
448 this.waiting = [];
449 this.locked = false;
450 this.id = this._nextId();
451 };
453 MochiKit.Async.DeferredLock.prototype = {
454 __class__: MochiKit.Async.DeferredLock,
455 /** @id MochiKit.Async.DeferredLock.prototype.acquire */
456 acquire: function () {
457 var d = new MochiKit.Async.Deferred();
458 if (this.locked) {
459 this.waiting.push(d);
460 } else {
461 this.locked = true;
462 d.callback(this);
463 }
464 return d;
465 },
466 /** @id MochiKit.Async.DeferredLock.prototype.release */
467 release: function () {
468 if (!this.locked) {
469 throw TypeError("Tried to release an unlocked DeferredLock");
470 }
471 this.locked = false;
472 if (this.waiting.length > 0) {
473 this.locked = true;
474 this.waiting.shift().callback(this);
475 }
476 },
477 _nextId: MochiKit.Base.counter(),
478 repr: function () {
479 var state;
480 if (this.locked) {
481 state = 'locked, ' + this.waiting.length + ' waiting';
482 } else {
483 state = 'unlocked';
484 }
485 return 'DeferredLock(' + this.id + ', ' + state + ')';
486 },
487 toString: MochiKit.Base.forwardCall("repr")
489 };
491 /** @id MochiKit.Async.DeferredList */
492 MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
494 // call parent constructor
495 MochiKit.Async.Deferred.apply(this, [canceller]);
497 this.list = list;
498 var resultList = [];
499 this.resultList = resultList;
501 this.finishedCount = 0;
502 this.fireOnOneCallback = fireOnOneCallback;
503 this.fireOnOneErrback = fireOnOneErrback;
504 this.consumeErrors = consumeErrors;
506 var cb = MochiKit.Base.bind(this._cbDeferred, this);
507 for (var i = 0; i < list.length; i++) {
508 var d = list[i];
509 resultList.push(undefined);
510 d.addCallback(cb, i, true);
511 d.addErrback(cb, i, false);
512 }
514 if (list.length === 0 && !fireOnOneCallback) {
515 this.callback(this.resultList);
516 }
518 };
520 MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
522 MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
523 this.resultList[index] = [succeeded, result];
524 this.finishedCount += 1;
525 if (this.fired == -1) {
526 if (succeeded && this.fireOnOneCallback) {
527 this.callback([index, result]);
528 } else if (!succeeded && this.fireOnOneErrback) {
529 this.errback(result);
530 } else if (this.finishedCount == this.list.length) {
531 this.callback(this.resultList);
532 }
533 }
534 if (!succeeded && this.consumeErrors) {
535 result = null;
536 }
537 return result;
538 };
540 /** @id MochiKit.Async.gatherResults */
541 MochiKit.Async.gatherResults = function (deferredList) {
542 var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
543 d.addCallback(function (results) {
544 var ret = [];
545 for (var i = 0; i < results.length; i++) {
546 ret.push(results[i][1]);
547 }
548 return ret;
549 });
550 return d;
551 };
553 /** @id MochiKit.Async.maybeDeferred */
554 MochiKit.Async.maybeDeferred = function (func) {
555 var self = MochiKit.Async;
556 var result;
557 try {
558 var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
559 if (r instanceof self.Deferred) {
560 result = r;
561 } else if (r instanceof Error) {
562 result = self.fail(r);
563 } else {
564 result = self.succeed(r);
565 }
566 } catch (e) {
567 result = self.fail(e);
568 }
569 return result;
570 };
573 MochiKit.Async.EXPORT = [
574 "AlreadyCalledError",
575 "CancelledError",
576 "BrowserComplianceError",
577 "GenericError",
578 "XMLHttpRequestError",
579 "Deferred",
580 "succeed",
581 "fail",
582 "getXMLHttpRequest",
583 "doSimpleXMLHttpRequest",
584 "loadJSONDoc",
585 "wait",
586 "callLater",
587 "sendXMLHttpRequest",
588 "DeferredLock",
589 "DeferredList",
590 "gatherResults",
591 "maybeDeferred",
592 "doXHR"
593 ];
595 MochiKit.Async.EXPORT_OK = [
596 "evalJSONRequest"
597 ];
599 MochiKit.Async.__new__ = function () {
600 var m = MochiKit.Base;
601 var ne = m.partial(m._newNamedError, this);
603 ne("AlreadyCalledError",
604 /** @id MochiKit.Async.AlreadyCalledError */
605 function (deferred) {
606 /***
608 Raised by the Deferred if callback or errback happens
609 after it was already fired.
611 ***/
612 this.deferred = deferred;
613 }
614 );
616 ne("CancelledError",
617 /** @id MochiKit.Async.CancelledError */
618 function (deferred) {
619 /***
621 Raised by the Deferred cancellation mechanism.
623 ***/
624 this.deferred = deferred;
625 }
626 );
628 ne("BrowserComplianceError",
629 /** @id MochiKit.Async.BrowserComplianceError */
630 function (msg) {
631 /***
633 Raised when the JavaScript runtime is not capable of performing
634 the given function. Technically, this should really never be
635 raised because a non-conforming JavaScript runtime probably
636 isn't going to support exceptions in the first place.
638 ***/
639 this.message = msg;
640 }
641 );
643 ne("GenericError",
644 /** @id MochiKit.Async.GenericError */
645 function (msg) {
646 this.message = msg;
647 }
648 );
650 ne("XMLHttpRequestError",
651 /** @id MochiKit.Async.XMLHttpRequestError */
652 function (req, msg) {
653 /***
655 Raised when an XMLHttpRequest does not complete for any reason.
657 ***/
658 this.req = req;
659 this.message = msg;
660 try {
661 // Strange but true that this can raise in some cases.
662 this.number = req.status;
663 } catch (e) {
664 // pass
665 }
666 }
667 );
670 this.EXPORT_TAGS = {
671 ":common": this.EXPORT,
672 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
673 };
675 m.nameFunctions(this);
677 };
679 MochiKit.Async.__new__();
681 MochiKit.Base._exportSymbols(this, MochiKit.Async);