summaryrefslogtreecommitdiff
path: root/frontend/beta/js/MochiKit/Async.js
Unidiff
Diffstat (limited to 'frontend/beta/js/MochiKit/Async.js') (more/less context) (show whitespace changes)
-rw-r--r--frontend/beta/js/MochiKit/Async.js683
1 files changed, 683 insertions, 0 deletions
diff --git a/frontend/beta/js/MochiKit/Async.js b/frontend/beta/js/MochiKit/Async.js
new file mode 100644
index 0000000..7f575aa
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Async.js
@@ -0,0 +1,683 @@
1/***
2
3MochiKit.Async 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito. All rights Reserved.
8
9***/
10
11if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.Async");
13 dojo.require("MochiKit.Base");
14}
15if (typeof(JSAN) != 'undefined') {
16 JSAN.use("MochiKit.Base", []);
17}
18
19try {
20 if (typeof(MochiKit.Base) == 'undefined') {
21 throw "";
22 }
23} catch (e) {
24 throw "MochiKit.Async depends on MochiKit.Base!";
25}
26
27if (typeof(MochiKit.Async) == 'undefined') {
28 MochiKit.Async = {};
29}
30
31MochiKit.Async.NAME = "MochiKit.Async";
32MochiKit.Async.VERSION = "1.4";
33MochiKit.Async.__repr__ = function () {
34 return "[" + this.NAME + " " + this.VERSION + "]";
35};
36MochiKit.Async.toString = function () {
37 return this.__repr__();
38};
39
40/** @id MochiKit.Async.Deferred */
41MochiKit.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};
51
52MochiKit.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 },
65
66 toString: MochiKit.Base.forwardCall("repr"),
67
68 _nextId: MochiKit.Base.counter(),
69
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 },
86
87 _resback: function (res) {
88 /***
89
90 The primitive that means either callback or errback
91
92 ***/
93 this.fired = ((res instanceof Error) ? 1 : 0);
94 this.results[this.fired] = res;
95 this._fire();
96 },
97
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 },
107
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 },
116
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 },
129
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 },
137
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 },
145
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 },
153
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 },
165
166 _fire: function () {
167 /***
168
169 Used internally to exhaust the callback sequence when a result
170 is available.
171
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};
216
217MochiKit.Base.update(MochiKit.Async, {
218 /** @id MochiKit.Async.evalJSONRequest */
219 evalJSONRequest: function (/* req */) {
220 return eval('(' + arguments[0].responseText + ')');
221 },
222
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 },
229
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 },
236
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 },
262
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, 201 is CREATED, 204 is NO CONTENT
288 // 304 is NOT MODIFIED, 1223 is apparently a bug in IE
289 if (status == 200 || status == 201 || status == 204 ||
290 status == 304 || status == 1223) {
291 d.callback(this);
292 } else {
293 var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
294 if (err.number) {
295 // XXX: This seems to happen on page change
296 d.errback(err);
297 } else {
298 // XXX: this seems to happen when the server is unreachable
299 d.errback(err);
300 }
301 }
302 }
303 },
304
305 _xhr_canceller: function (req) {
306 // IE SUCKS
307 try {
308 req.onreadystatechange = null;
309 } catch (e) {
310 try {
311 req.onreadystatechange = MochiKit.Base.noop;
312 } catch (e) {
313 }
314 }
315 req.abort();
316 },
317
318
319 /** @id MochiKit.Async.sendXMLHttpRequest */
320 sendXMLHttpRequest: function (req, /* optional */ sendContent) {
321 if (typeof(sendContent) == "undefined" || sendContent === null) {
322 sendContent = "";
323 }
324
325 var m = MochiKit.Base;
326 var self = MochiKit.Async;
327 var d = new self.Deferred(m.partial(self._xhr_canceller, req));
328
329 try {
330 req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
331 req, d);
332 req.send(sendContent);
333 } catch (e) {
334 try {
335 req.onreadystatechange = null;
336 } catch (ignore) {
337 // pass
338 }
339 d.errback(e);
340 }
341
342 return d;
343
344 },
345
346 /** @id MochiKit.Async.doXHR */
347 doXHR: function (url, opts) {
348 var m = MochiKit.Base;
349 opts = m.update({
350 method: 'GET',
351 sendContent: ''
352 /*
353 queryString: undefined,
354 username: undefined,
355 password: undefined,
356 headers: undefined,
357 mimeType: undefined
358 */
359 }, opts);
360 var self = MochiKit.Async;
361 var req = self.getXMLHttpRequest();
362 if (opts.queryString) {
363 var qs = m.queryString(opts.queryString);
364 if (qs) {
365 url += "?" + qs;
366 }
367 }
368 req.open(opts.method, url, true, opts.username, opts.password);
369 if (req.overrideMimeType && opts.mimeType) {
370 req.overrideMimeType(opts.mimeType);
371 }
372 if (opts.headers) {
373 var headers = opts.headers;
374 if (!m.isArrayLike(headers)) {
375 headers = m.items(headers);
376 }
377 for (var i = 0; i < headers.length; i++) {
378 var header = headers[i];
379 var name = header[0];
380 var value = header[1];
381 req.setRequestHeader(name, value);
382 }
383 }
384 return self.sendXMLHttpRequest(req, opts.sendContent);
385 },
386
387 _buildURL: function (url/*, ...*/) {
388 if (arguments.length > 1) {
389 var m = MochiKit.Base;
390 var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
391 if (qs) {
392 return url + "?" + qs;
393 }
394 }
395 return url;
396 },
397
398 /** @id MochiKit.Async.doSimpleXMLHttpRequest */
399 doSimpleXMLHttpRequest: function (url/*, ...*/) {
400 var self = MochiKit.Async;
401 url = self._buildURL.apply(self, arguments);
402 return self.doXHR(url);
403 },
404
405 /** @id MochiKit.Async.loadJSONDoc */
406 loadJSONDoc: function (url/*, ...*/) {
407 var self = MochiKit.Async;
408 url = self._buildURL.apply(self, arguments);
409 var d = self.doXHR(url, {
410 'mimeType': 'text/plain',
411 'headers': [['Accept', 'application/json']]
412 });
413 d = d.addCallback(self.evalJSONRequest);
414 return d;
415 },
416
417 /** @id MochiKit.Async.wait */
418 wait: function (seconds, /* optional */value) {
419 var d = new MochiKit.Async.Deferred();
420 var m = MochiKit.Base;
421 if (typeof(value) != 'undefined') {
422 d.addCallback(function () { return value; });
423 }
424 var timeout = setTimeout(
425 m.bind("callback", d),
426 Math.floor(seconds * 1000));
427 d.canceller = function () {
428 try {
429 clearTimeout(timeout);
430 } catch (e) {
431 // pass
432 }
433 };
434 return d;
435 },
436
437 /** @id MochiKit.Async.callLater */
438 callLater: function (seconds, func) {
439 var m = MochiKit.Base;
440 var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
441 return MochiKit.Async.wait(seconds).addCallback(
442 function (res) { return pfunc(); }
443 );
444 }
445});
446
447
448/** @id MochiKit.Async.DeferredLock */
449MochiKit.Async.DeferredLock = function () {
450 this.waiting = [];
451 this.locked = false;
452 this.id = this._nextId();
453};
454
455MochiKit.Async.DeferredLock.prototype = {
456 __class__: MochiKit.Async.DeferredLock,
457 /** @id MochiKit.Async.DeferredLock.prototype.acquire */
458 acquire: function () {
459 var d = new MochiKit.Async.Deferred();
460 if (this.locked) {
461 this.waiting.push(d);
462 } else {
463 this.locked = true;
464 d.callback(this);
465 }
466 return d;
467 },
468 /** @id MochiKit.Async.DeferredLock.prototype.release */
469 release: function () {
470 if (!this.locked) {
471 throw TypeError("Tried to release an unlocked DeferredLock");
472 }
473 this.locked = false;
474 if (this.waiting.length > 0) {
475 this.locked = true;
476 this.waiting.shift().callback(this);
477 }
478 },
479 _nextId: MochiKit.Base.counter(),
480 repr: function () {
481 var state;
482 if (this.locked) {
483 state = 'locked, ' + this.waiting.length + ' waiting';
484 } else {
485 state = 'unlocked';
486 }
487 return 'DeferredLock(' + this.id + ', ' + state + ')';
488 },
489 toString: MochiKit.Base.forwardCall("repr")
490
491};
492
493/** @id MochiKit.Async.DeferredList */
494MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
495
496 // call parent constructor
497 MochiKit.Async.Deferred.apply(this, [canceller]);
498
499 this.list = list;
500 var resultList = [];
501 this.resultList = resultList;
502
503 this.finishedCount = 0;
504 this.fireOnOneCallback = fireOnOneCallback;
505 this.fireOnOneErrback = fireOnOneErrback;
506 this.consumeErrors = consumeErrors;
507
508 var cb = MochiKit.Base.bind(this._cbDeferred, this);
509 for (var i = 0; i < list.length; i++) {
510 var d = list[i];
511 resultList.push(undefined);
512 d.addCallback(cb, i, true);
513 d.addErrback(cb, i, false);
514 }
515
516 if (list.length === 0 && !fireOnOneCallback) {
517 this.callback(this.resultList);
518 }
519
520};
521
522MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
523
524MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
525 this.resultList[index] = [succeeded, result];
526 this.finishedCount += 1;
527 if (this.fired == -1) {
528 if (succeeded && this.fireOnOneCallback) {
529 this.callback([index, result]);
530 } else if (!succeeded && this.fireOnOneErrback) {
531 this.errback(result);
532 } else if (this.finishedCount == this.list.length) {
533 this.callback(this.resultList);
534 }
535 }
536 if (!succeeded && this.consumeErrors) {
537 result = null;
538 }
539 return result;
540};
541
542/** @id MochiKit.Async.gatherResults */
543MochiKit.Async.gatherResults = function (deferredList) {
544 var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
545 d.addCallback(function (results) {
546 var ret = [];
547 for (var i = 0; i < results.length; i++) {
548 ret.push(results[i][1]);
549 }
550 return ret;
551 });
552 return d;
553};
554
555/** @id MochiKit.Async.maybeDeferred */
556MochiKit.Async.maybeDeferred = function (func) {
557 var self = MochiKit.Async;
558 var result;
559 try {
560 var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
561 if (r instanceof self.Deferred) {
562 result = r;
563 } else if (r instanceof Error) {
564 result = self.fail(r);
565 } else {
566 result = self.succeed(r);
567 }
568 } catch (e) {
569 result = self.fail(e);
570 }
571 return result;
572};
573
574
575MochiKit.Async.EXPORT = [
576 "AlreadyCalledError",
577 "CancelledError",
578 "BrowserComplianceError",
579 "GenericError",
580 "XMLHttpRequestError",
581 "Deferred",
582 "succeed",
583 "fail",
584 "getXMLHttpRequest",
585 "doSimpleXMLHttpRequest",
586 "loadJSONDoc",
587 "wait",
588 "callLater",
589 "sendXMLHttpRequest",
590 "DeferredLock",
591 "DeferredList",
592 "gatherResults",
593 "maybeDeferred",
594 "doXHR"
595];
596
597MochiKit.Async.EXPORT_OK = [
598 "evalJSONRequest"
599];
600
601MochiKit.Async.__new__ = function () {
602 var m = MochiKit.Base;
603 var ne = m.partial(m._newNamedError, this);
604
605 ne("AlreadyCalledError",
606 /** @id MochiKit.Async.AlreadyCalledError */
607 function (deferred) {
608 /***
609
610 Raised by the Deferred if callback or errback happens
611 after it was already fired.
612
613 ***/
614 this.deferred = deferred;
615 }
616 );
617
618 ne("CancelledError",
619 /** @id MochiKit.Async.CancelledError */
620 function (deferred) {
621 /***
622
623 Raised by the Deferred cancellation mechanism.
624
625 ***/
626 this.deferred = deferred;
627 }
628 );
629
630 ne("BrowserComplianceError",
631 /** @id MochiKit.Async.BrowserComplianceError */
632 function (msg) {
633 /***
634
635 Raised when the JavaScript runtime is not capable of performing
636 the given function. Technically, this should really never be
637 raised because a non-conforming JavaScript runtime probably
638 isn't going to support exceptions in the first place.
639
640 ***/
641 this.message = msg;
642 }
643 );
644
645 ne("GenericError",
646 /** @id MochiKit.Async.GenericError */
647 function (msg) {
648 this.message = msg;
649 }
650 );
651
652 ne("XMLHttpRequestError",
653 /** @id MochiKit.Async.XMLHttpRequestError */
654 function (req, msg) {
655 /***
656
657 Raised when an XMLHttpRequest does not complete for any reason.
658
659 ***/
660 this.req = req;
661 this.message = msg;
662 try {
663 // Strange but true that this can raise in some cases.
664 this.number = req.status;
665 } catch (e) {
666 // pass
667 }
668 }
669 );
670
671
672 this.EXPORT_TAGS = {
673 ":common": this.EXPORT,
674 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
675 };
676
677 m.nameFunctions(this);
678
679};
680
681MochiKit.Async.__new__();
682
683MochiKit.Base._exportSymbols(this, MochiKit.Async);