author | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2013-08-30 15:56:53 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2013-08-30 21:23:42 (UTC) |
commit | 20bea94ab6b91c85b171dcf86baba0a64169d508 (patch) (unidiff) | |
tree | 6e38e91498dcdb861620eba1e237d1026fe79cc5 /frontend/delta/js/MochiKit/Async.js | |
parent | bde3c7b98523112ade9c5bbf7390c4ecb494cd2e (diff) | |
download | clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.zip clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.tar.gz clipperz-20bea94ab6b91c85b171dcf86baba0a64169d508.tar.bz2 |
First release of /delta version
Diffstat (limited to 'frontend/delta/js/MochiKit/Async.js') (more/less context) (show whitespace changes)
-rw-r--r-- | frontend/delta/js/MochiKit/Async.js | 733 |
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 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
26 | MochiKit.Async 1.5 | ||
27 | |||
28 | See <http://mochikit.com/> for documentation, downloads, license, etc. | ||
29 | |||
30 | (c) 2005 Bob Ippolito. All rights Reserved. | ||
31 | |||
32 | ***/ | ||
33 | |||
34 | MochiKit.Base.module(MochiKit, 'Async', '1.5', ['Base']); | ||
35 | |||
36 | /** @id MochiKit.Async.Deferred */ | ||
37 | MochiKit.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 | |||
49 | MochiKit.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 | |||
246 | MochiKit.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 */ | ||
531 | MochiKit.Async.DeferredLock = function () { | ||
532 | this.waiting = []; | ||
533 | this.locked = false; | ||
534 | this.id = this._nextId(); | ||
535 | }; | ||
536 | |||
537 | MochiKit.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 */ | ||
576 | MochiKit.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 | |||
604 | MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred(); | ||
605 | MochiKit.Async.DeferredList.prototype.constructor = MochiKit.Async.DeferredList; | ||
606 | |||
607 | MochiKit.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 */ | ||
626 | MochiKit.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 */ | ||
639 | MochiKit.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 | |||
658 | MochiKit.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 | |||
731 | MochiKit.Async.__new__(); | ||
732 | |||
733 | MochiKit.Base._exportSymbols(this, MochiKit.Async); | ||