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