summaryrefslogtreecommitdiff
path: root/frontend/delta/js/MochiKit/Async.js
Unidiff
Diffstat (limited to 'frontend/delta/js/MochiKit/Async.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/MochiKit/Async.js733
1 files changed, 733 insertions, 0 deletions
diff --git a/frontend/delta/js/MochiKit/Async.js b/frontend/delta/js/MochiKit/Async.js
new file mode 100644
index 0000000..a76aaa2
--- a/dev/null
+++ b/frontend/delta/js/MochiKit/Async.js
@@ -0,0 +1,733 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24/***
25
26MochiKit.Async 1.5
27
28See <http://mochikit.com/> for documentation, downloads, license, etc.
29
30(c) 2005 Bob Ippolito. All rights Reserved.
31
32***/
33
34MochiKit.Base.module(MochiKit, 'Async', '1.5', ['Base']);
35
36/** @id MochiKit.Async.Deferred */
37MochiKit.Async.Deferred = function (/* optional */ canceller) {
38 this.chain = [];
39 this.id = this._nextId();
40 this.fired = -1;
41 this.paused = 0;
42 this.results = [null, null];
43 this.canceller = canceller;
44 this.silentlyCancelled = false;
45 this.chained = false;
46 this.finalized = false;
47};
48
49MochiKit.Async.Deferred.prototype = {
50 /** @id MochiKit.Async.Deferred.prototype.repr */
51 repr: function () {
52 return 'Deferred(' + this.id + ', ' + this.state() + ')';
53 },
54
55 toString: MochiKit.Base.forwardCall("repr"),
56
57 _nextId: MochiKit.Base.counter(),
58
59 /** @id MochiKit.Async.Deferred.prototype.state */
60 state: function () {
61 if (this.fired == -1) {
62 return 'unfired';
63 } else if (this.fired === 0) {
64 return 'success';
65 } else {
66 return 'error';
67 }
68 },
69
70 /** @id MochiKit.Async.Deferred.prototype.cancel */
71 cancel: function (e) {
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 if (typeof(e) === 'string') {
81 e = new self.GenericError(e);
82 } else if (!(e instanceof Error)) {
83 e = new self.CancelledError(this);
84 }
85 this.errback(e);
86 }
87 } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
88 this.results[0].cancel(e);
89 }
90 },
91
92 _resback: function (res) {
93 /***
94
95 The primitive that means either callback or errback
96
97 ***/
98 this.fired = ((res instanceof Error) ? 1 : 0);
99 this.results[this.fired] = res;
100 if (this.paused === 0) {
101 this._fire();
102 }
103 },
104
105 _check: function () {
106 if (this.fired != -1) {
107 if (!this.silentlyCancelled) {
108 throw new MochiKit.Async.AlreadyCalledError(this);
109 }
110 this.silentlyCancelled = false;
111 return;
112 }
113 },
114
115 /** @id MochiKit.Async.Deferred.prototype.callback */
116 callback: function (res) {
117 this._check();
118 if (res instanceof MochiKit.Async.Deferred) {
119 throw new Error("Deferred instances can only be chained if they are the result of a callback");
120 }
121 this._resback(res);
122 },
123
124 /** @id MochiKit.Async.Deferred.prototype.errback */
125 errback: function (res) {
126 this._check();
127 var self = MochiKit.Async;
128 if (res instanceof self.Deferred) {
129 throw new Error("Deferred instances can only be chained if they are the result of a callback");
130 }
131 if (!(res instanceof Error)) {
132 res = new self.GenericError(res);
133 }
134 this._resback(res);
135 },
136
137 /** @id MochiKit.Async.Deferred.prototype.addBoth */
138 addBoth: function (fn) {
139 if (arguments.length > 1) {
140 fn = MochiKit.Base.partial.apply(null, arguments);
141 }
142 return this.addCallbacks(fn, fn);
143 },
144
145 /** @id MochiKit.Async.Deferred.prototype.addCallback */
146 addCallback: function (fn) {
147 if (arguments.length > 1) {
148 fn = MochiKit.Base.partial.apply(null, arguments);
149 }
150 return this.addCallbacks(fn, null);
151 },
152
153 /** @id MochiKit.Async.Deferred.prototype.addErrback */
154 addErrback: function (fn) {
155 if (arguments.length > 1) {
156 fn = MochiKit.Base.partial.apply(null, arguments);
157 }
158 return this.addCallbacks(null, fn);
159 },
160
161 /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
162 addCallbacks: function (cb, eb) {
163 if (this.chained) {
164 throw new Error("Chained Deferreds can not be re-used");
165 }
166 if (this.finalized) {
167 throw new Error("Finalized Deferreds can not be re-used");
168 }
169 this.chain.push([cb, eb]);
170 if (this.fired >= 0) {
171 this._fire();
172 }
173 return this;
174 },
175
176 /** @id MochiKit.Async.Deferred.prototype.setFinalizer */
177 setFinalizer: function (fn) {
178 if (this.chained) {
179 throw new Error("Chained Deferreds can not be re-used");
180 }
181 if (this.finalized) {
182 throw new Error("Finalized Deferreds can not be re-used");
183 }
184 if (arguments.length > 1) {
185 fn = MochiKit.Base.partial.apply(null, arguments);
186 }
187 this._finalizer = fn;
188 if (this.fired >= 0) {
189 this._fire();
190 }
191 return this;
192 },
193
194 _fire: function () {
195 /***
196
197 Used internally to exhaust the callback sequence when a result
198 is available.
199
200 ***/
201 var chain = this.chain;
202 var fired = this.fired;
203 var res = this.results[fired];
204 var self = this;
205 var cb = null;
206 while (chain.length > 0 && this.paused === 0) {
207 // Array
208 var pair = chain.shift();
209 var f = pair[fired];
210 if (f === null) {
211 continue;
212 }
213 try {
214 res = f(res);
215 fired = ((res instanceof Error) ? 1 : 0);
216 if (res instanceof MochiKit.Async.Deferred) {
217 cb = function (res) {
218 self.paused--;
219 self._resback(res);
220 };
221 this.paused++;
222 }
223 } catch (err) {
224 fired = 1;
225 if (!(err instanceof Error)) {
226 err = new MochiKit.Async.GenericError(err);
227 }
228 res = err;
229 }
230 }
231 this.fired = fired;
232 this.results[fired] = res;
233 if (this.chain.length == 0 && this.paused === 0 && this._finalizer) {
234 this.finalized = true;
235 this._finalizer(res);
236 }
237 if (cb && this.paused) {
238 // this is for "tail recursion" in case the dependent deferred
239 // is already fired
240 res.addBoth(cb);
241 res.chained = true;
242 }
243 }
244};
245
246MochiKit.Base.update(MochiKit.Async, {
247 /** @id MochiKit.Async.evalJSONRequest */
248 evalJSONRequest: function (req) {
249 return MochiKit.Base.evalJSON(req.responseText);
250 },
251
252 /** @id MochiKit.Async.succeed */
253 succeed: function (/* optional */result) {
254 var d = new MochiKit.Async.Deferred();
255 d.callback.apply(d, arguments);
256 return d;
257 },
258
259 /** @id MochiKit.Async.fail */
260 fail: function (/* optional */result) {
261 var d = new MochiKit.Async.Deferred();
262 d.errback.apply(d, arguments);
263 return d;
264 },
265
266 /** @id MochiKit.Async.getXMLHttpRequest */
267 getXMLHttpRequest: function () {
268 var self = arguments.callee;
269 if (!self.XMLHttpRequest) {
270 var tryThese = [
271 function () { return new XMLHttpRequest(); },
272 function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
273 function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
274 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
275 function () {
276 throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
277 }
278 ];
279 for (var i = 0; i < tryThese.length; i++) {
280 var func = tryThese[i];
281 try {
282 self.XMLHttpRequest = func;
283 return func();
284 } catch (e) {
285 // pass
286 }
287 }
288 }
289 return self.XMLHttpRequest();
290 },
291
292 _xhr_onreadystatechange: function (d) {
293 // MochiKit.Logging.logDebug('this.readyState', this.readyState);
294 var m = MochiKit.Base;
295 if (this.readyState == 4) {
296 // IE SUCKS
297 try {
298 this.onreadystatechange = null;
299 } catch (e) {
300 try {
301 this.onreadystatechange = m.noop;
302 } catch (e) {
303 }
304 }
305 var status = null;
306 try {
307 status = this.status;
308 if (!status && (this.response || m.isNotEmpty(this.responseText))) {
309 // 0 or undefined seems to mean cached or local
310 status = 304;
311 }
312 } catch (e) {
313 // pass
314 // MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
315 }
316 // 200 is OK, 201 is CREATED, 204 is NO CONTENT
317 // 304 is NOT MODIFIED, 1223 is apparently a bug in IE
318 if (status == 200 || status == 201 || status == 204 ||
319 status == 304 || status == 1223) {
320 d.callback(this);
321 } else {
322 var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
323 if (err.number) {
324 // XXX: This seems to happen on page change
325 d.errback(err);
326 } else {
327 // XXX: this seems to happen when the server is unreachable
328 d.errback(err);
329 }
330 }
331 }
332 },
333
334 _xhr_canceller: function (req) {
335 // IE SUCKS
336 try {
337 req.onreadystatechange = null;
338 } catch (e) {
339 try {
340 req.onreadystatechange = MochiKit.Base.noop;
341 } catch (e) {
342 }
343 }
344 req.abort();
345 },
346
347
348 /** @id MochiKit.Async.sendXMLHttpRequest */
349 sendXMLHttpRequest: function (req, /* optional */ sendContent) {
350 if (typeof(sendContent) == "undefined" || sendContent === null) {
351 sendContent = "";
352 }
353
354 var m = MochiKit.Base;
355 var self = MochiKit.Async;
356 var d = new self.Deferred(m.partial(self._xhr_canceller, req));
357
358 try {
359 req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
360 req, d);
361 req.send(sendContent);
362 } catch (e) {
363 try {
364 req.onreadystatechange = null;
365 } catch (ignore) {
366 // pass
367 }
368 d.errback(e);
369 }
370
371 return d;
372
373 },
374
375 /** @id MochiKit.Async.doXHR */
376 doXHR: function (url, opts) {
377 /*
378 Work around a Firefox bug by dealing with XHR during
379 the next event loop iteration. Maybe it's this one:
380 https://bugzilla.mozilla.org/show_bug.cgi?id=249843
381 */
382 var self = MochiKit.Async;
383 return self.callLater(0, self._doXHR, url, opts);
384 },
385
386 _doXHR: function (url, opts) {
387 var m = MochiKit.Base;
388 opts = m.update({
389 method: 'GET',
390 sendContent: ''
391 /*
392 queryString: undefined,
393 username: undefined,
394 password: undefined,
395 headers: undefined,
396 mimeType: undefined,
397 responseType: undefined,
398 withCredentials: undefined
399 */
400 }, opts);
401 var self = MochiKit.Async;
402 var req = self.getXMLHttpRequest();
403 if (opts.queryString) {
404 var qs = m.queryString(opts.queryString);
405 if (qs) {
406 url += "?" + qs;
407 }
408 }
409 // Safari will send undefined:undefined, so we have to check.
410 // We can't use apply, since the function is native.
411 if ('username' in opts) {
412 req.open(opts.method, url, true, opts.username, opts.password);
413 } else {
414 req.open(opts.method, url, true);
415 }
416 if (req.overrideMimeType && opts.mimeType) {
417 req.overrideMimeType(opts.mimeType);
418 }
419 req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
420 if (opts.headers) {
421 var headers = opts.headers;
422 if (!m.isArrayLike(headers)) {
423 headers = m.items(headers);
424 }
425 for (var i = 0; i < headers.length; i++) {
426 var header = headers[i];
427 var name = header[0];
428 var value = header[1];
429 req.setRequestHeader(name, value);
430 }
431 }
432 if ("responseType" in opts && "responseType" in req) {
433 req.responseType = opts.responseType;
434 }
435 if (opts.withCredentials) {
436 req.withCredentials = 'true';
437 }
438 return self.sendXMLHttpRequest(req, opts.sendContent);
439 },
440
441 _buildURL: function (url/*, ...*/) {
442 if (arguments.length > 1) {
443 var m = MochiKit.Base;
444 var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
445 if (qs) {
446 return url + "?" + qs;
447 }
448 }
449 return url;
450 },
451
452 /** @id MochiKit.Async.doSimpleXMLHttpRequest */
453 doSimpleXMLHttpRequest: function (url/*, ...*/) {
454 var self = MochiKit.Async;
455 url = self._buildURL.apply(self, arguments);
456 return self.doXHR(url);
457 },
458
459 /** @id MochiKit.Async.loadJSONDoc */
460 loadJSONDoc: function (url/*, ...*/) {
461 var self = MochiKit.Async;
462 url = self._buildURL.apply(self, arguments);
463 var d = self.doXHR(url, {
464 'mimeType': 'text/plain',
465 'headers': [['Accept', 'application/json']]
466 });
467 d = d.addCallback(self.evalJSONRequest);
468 return d;
469 },
470
471 /** @id MochiKit.Async.loadScript */
472 loadScript: function (url) {
473 var d = new MochiKit.Async.Deferred();
474 var script = document.createElement("script");
475 script.type = "text/javascript";
476 script.src = url;
477 script.onload = function () {
478 script.onload = null;
479 script.onerror = null;
480 script.onreadystatechange = null;
481 script = null;
482 d.callback();
483 };
484 script.onerror = function (msg) {
485 script.onload = null;
486 script.onerror = null;
487 script.onreadystatechange = null;
488 script = null;
489 msg = "Failed to load script at " + url + ": " + msg;
490 d.errback(new URIError(msg, url));
491 }
492 script.onreadystatechange = function () {
493 if (script.readyState == "loaded" || script.readyState == "complete") {
494 script.onload();
495 } else {
496 // IE doesn't bother to report errors...
497 MochiKit.Async.callLater(10, script.onerror, "Script loading timed out")
498 }
499 };
500 document.getElementsByTagName("head")[0].appendChild(script);
501 return d;
502 },
503
504 /** @id MochiKit.Async.wait */
505 wait: function (seconds, /* optional */value) {
506 var d = new MochiKit.Async.Deferred();
507 var cb = MochiKit.Base.bind("callback", d, value);
508 var timeout = setTimeout(cb, Math.floor(seconds * 1000));
509 d.canceller = function () {
510 try {
511 clearTimeout(timeout);
512 } catch (e) {
513 // pass
514 }
515 };
516 return d;
517 },
518
519 /** @id MochiKit.Async.callLater */
520 callLater: function (seconds, func) {
521 var m = MochiKit.Base;
522 var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
523 return MochiKit.Async.wait(seconds).addCallback(
524 function (res) { return pfunc(); }
525 );
526 }
527});
528
529
530/** @id MochiKit.Async.DeferredLock */
531MochiKit.Async.DeferredLock = function () {
532 this.waiting = [];
533 this.locked = false;
534 this.id = this._nextId();
535};
536
537MochiKit.Async.DeferredLock.prototype = {
538 __class__: MochiKit.Async.DeferredLock,
539 /** @id MochiKit.Async.DeferredLock.prototype.acquire */
540 acquire: function () {
541 var d = new MochiKit.Async.Deferred();
542 if (this.locked) {
543 this.waiting.push(d);
544 } else {
545 this.locked = true;
546 d.callback(this);
547 }
548 return d;
549 },
550 /** @id MochiKit.Async.DeferredLock.prototype.release */
551 release: function () {
552 if (!this.locked) {
553 throw TypeError("Tried to release an unlocked DeferredLock");
554 }
555 this.locked = false;
556 if (this.waiting.length > 0) {
557 this.locked = true;
558 this.waiting.shift().callback(this);
559 }
560 },
561 _nextId: MochiKit.Base.counter(),
562 repr: function () {
563 var state;
564 if (this.locked) {
565 state = 'locked, ' + this.waiting.length + ' waiting';
566 } else {
567 state = 'unlocked';
568 }
569 return 'DeferredLock(' + this.id + ', ' + state + ')';
570 },
571 toString: MochiKit.Base.forwardCall("repr")
572
573};
574
575/** @id MochiKit.Async.DeferredList */
576MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
577
578 // call parent constructor
579 MochiKit.Async.Deferred.apply(this, [canceller]);
580
581 this.list = list;
582 var resultList = [];
583 this.resultList = resultList;
584
585 this.finishedCount = 0;
586 this.fireOnOneCallback = fireOnOneCallback;
587 this.fireOnOneErrback = fireOnOneErrback;
588 this.consumeErrors = consumeErrors;
589
590 var cb = MochiKit.Base.bind(this._cbDeferred, this);
591 for (var i = 0; i < list.length; i++) {
592 var d = list[i];
593 resultList.push(undefined);
594 d.addCallback(cb, i, true);
595 d.addErrback(cb, i, false);
596 }
597
598 if (list.length === 0 && !fireOnOneCallback) {
599 this.callback(this.resultList);
600 }
601
602};
603
604MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
605MochiKit.Async.DeferredList.prototype.constructor = MochiKit.Async.DeferredList;
606
607MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
608 this.resultList[index] = [succeeded, result];
609 this.finishedCount += 1;
610 if (this.fired == -1) {
611 if (succeeded && this.fireOnOneCallback) {
612 this.callback([index, result]);
613 } else if (!succeeded && this.fireOnOneErrback) {
614 this.errback(result);
615 } else if (this.finishedCount == this.list.length) {
616 this.callback(this.resultList);
617 }
618 }
619 if (!succeeded && this.consumeErrors) {
620 result = null;
621 }
622 return result;
623};
624
625/** @id MochiKit.Async.gatherResults */
626MochiKit.Async.gatherResults = function (deferredList) {
627 var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
628 d.addCallback(function (results) {
629 var ret = [];
630 for (var i = 0; i < results.length; i++) {
631 ret.push(results[i][1]);
632 }
633 return ret;
634 });
635 return d;
636};
637
638/** @id MochiKit.Async.maybeDeferred */
639MochiKit.Async.maybeDeferred = function (func) {
640 var self = MochiKit.Async;
641 var result;
642 try {
643 var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
644 if (r instanceof self.Deferred) {
645 result = r;
646 } else if (r instanceof Error) {
647 result = self.fail(r);
648 } else {
649 result = self.succeed(r);
650 }
651 } catch (e) {
652 result = self.fail(e);
653 }
654 return result;
655};
656
657
658MochiKit.Async.__new__ = function () {
659 var m = MochiKit.Base;
660 var ne = m.partial(m._newNamedError, this);
661
662 ne("AlreadyCalledError",
663 /** @id MochiKit.Async.AlreadyCalledError */
664 function (deferred) {
665 /***
666
667 Raised by the Deferred if callback or errback happens
668 after it was already fired.
669
670 ***/
671 this.deferred = deferred;
672 }
673 );
674
675 ne("CancelledError",
676 /** @id MochiKit.Async.CancelledError */
677 function (deferred) {
678 /***
679
680 Raised by the Deferred cancellation mechanism.
681
682 ***/
683 this.deferred = deferred;
684 }
685 );
686
687 ne("BrowserComplianceError",
688 /** @id MochiKit.Async.BrowserComplianceError */
689 function (msg) {
690 /***
691
692 Raised when the JavaScript runtime is not capable of performing
693 the given function. Technically, this should really never be
694 raised because a non-conforming JavaScript runtime probably
695 isn't going to support exceptions in the first place.
696
697 ***/
698 this.message = msg;
699 }
700 );
701
702 ne("GenericError",
703 /** @id MochiKit.Async.GenericError */
704 function (msg) {
705 this.message = msg;
706 }
707 );
708
709 ne("XMLHttpRequestError",
710 /** @id MochiKit.Async.XMLHttpRequestError */
711 function (req, msg) {
712 /***
713
714 Raised when an XMLHttpRequest does not complete for any reason.
715
716 ***/
717 this.req = req;
718 this.message = msg;
719 try {
720 // Strange but true that this can raise in some cases.
721 this.number = req.status;
722 } catch (e) {
723 // pass
724 }
725 }
726 );
727
728 m.nameFunctions(this);
729};
730
731MochiKit.Async.__new__();
732
733MochiKit.Base._exportSymbols(this, MochiKit.Async);