Diffstat (limited to 'frontend/gamma/js/MochiKit/Async.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/gamma/js/MochiKit/Async.js | 120 |
1 files changed, 93 insertions, 27 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,80 +1,91 @@ /*** MochiKit.Async 1.5 See <http://mochikit.com/> for documentation, downloads, license, etc. (c) 2005 Bob Ippolito. All rights Reserved. ***/ -MochiKit.Base._module('Async', '1.5', ['Base']); +MochiKit.Base.module(MochiKit, 'Async', '1.5', ['Base']); /** @id MochiKit.Async.Deferred */ MochiKit.Async.Deferred = function (/* optional */ canceller) { this.chain = []; this.id = this._nextId(); this.fired = -1; this.paused = 0; this.results = [null, null]; this.canceller = canceller; this.silentlyCancelled = false; this.chained = false; + this.finalized = false; }; MochiKit.Async.Deferred.prototype = { /** @id MochiKit.Async.Deferred.prototype.repr */ repr: function () { - var state; - if (this.fired == -1) { - state = 'unfired'; - } else if (this.fired === 0) { - state = 'success'; - } else { - state = 'error'; - } - return 'Deferred(' + this.id + ', ' + state + ')'; + return 'Deferred(' + this.id + ', ' + this.state() + ')'; }, toString: MochiKit.Base.forwardCall("repr"), _nextId: MochiKit.Base.counter(), + /** @id MochiKit.Async.Deferred.prototype.state */ + state: function () { + if (this.fired == -1) { + return 'unfired'; + } else if (this.fired === 0) { + return 'success'; + } else { + return 'error'; + } + }, + /** @id MochiKit.Async.Deferred.prototype.cancel */ - cancel: function () { + cancel: function (e) { var self = MochiKit.Async; if (this.fired == -1) { if (this.canceller) { this.canceller(this); } else { this.silentlyCancelled = true; } if (this.fired == -1) { - this.errback(new self.CancelledError(this)); + if (typeof(e) === 'string') { + e = new self.GenericError(e); + } else if (!(e instanceof Error)) { + e = new self.CancelledError(this); + } + this.errback(e); } } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) { - this.results[0].cancel(); + this.results[0].cancel(e); } }, _resback: function (res) { /*** The primitive that means either callback or errback ***/ this.fired = ((res instanceof Error) ? 1 : 0); this.results[this.fired] = res; - this._fire(); + if (this.paused === 0) { + this._fire(); + } }, _check: function () { if (this.fired != -1) { if (!this.silentlyCancelled) { throw new MochiKit.Async.AlreadyCalledError(this); } this.silentlyCancelled = false; return; } }, @@ -120,73 +131,95 @@ MochiKit.Async.Deferred.prototype = { addErrback: function (fn) { if (arguments.length > 1) { fn = MochiKit.Base.partial.apply(null, arguments); } return this.addCallbacks(null, fn); }, /** @id MochiKit.Async.Deferred.prototype.addCallbacks */ addCallbacks: function (cb, eb) { if (this.chained) { throw new Error("Chained Deferreds can not be re-used"); } + if (this.finalized) { + throw new Error("Finalized Deferreds can not be re-used"); + } this.chain.push([cb, eb]); if (this.fired >= 0) { this._fire(); } return this; }, + /** @id MochiKit.Async.Deferred.prototype.setFinalizer */ + setFinalizer: function (fn) { + if (this.chained) { + throw new Error("Chained Deferreds can not be re-used"); + } + if (this.finalized) { + throw new Error("Finalized Deferreds can not be re-used"); + } + if (arguments.length > 1) { + fn = MochiKit.Base.partial.apply(null, arguments); + } + this._finalizer = fn; + if (this.fired >= 0) { + this._fire(); + } + return this; + }, + _fire: function () { /*** Used internally to exhaust the callback sequence when a result is available. ***/ var chain = this.chain; var fired = this.fired; var res = this.results[fired]; var self = this; var cb = null; while (chain.length > 0 && this.paused === 0) { // Array var pair = chain.shift(); var f = pair[fired]; if (f === null) { continue; } try { res = f(res); fired = ((res instanceof Error) ? 1 : 0); if (res instanceof MochiKit.Async.Deferred) { cb = function (res) { - self._resback(res); self.paused--; - if ((self.paused === 0) && (self.fired >= 0)) { - self._fire(); - } + self._resback(res); }; this.paused++; } } catch (err) { fired = 1; if (!(err instanceof Error)) { err = new MochiKit.Async.GenericError(err); } res = err; } } this.fired = fired; this.results[fired] = res; + if (this.chain.length == 0 && this.paused === 0 && this._finalizer) { + this.finalized = true; + this._finalizer(res); + } if (cb && this.paused) { // this is for "tail recursion" in case the dependent deferred // is already fired res.addBoth(cb); res.chained = true; } } }; MochiKit.Base.update(MochiKit.Async, { /** @id MochiKit.Async.evalJSONRequest */ evalJSONRequest: function (req) { @@ -240,25 +273,25 @@ MochiKit.Base.update(MochiKit.Async, { // IE SUCKS try { this.onreadystatechange = null; } catch (e) { try { this.onreadystatechange = m.noop; } catch (e) { } } var status = null; try { status = this.status; - if (!status && m.isNotEmpty(this.responseText)) { + if (!status && (this.response || m.isNotEmpty(this.responseText))) { // 0 or undefined seems to mean cached or local status = 304; } } catch (e) { // pass // MochiKit.Logging.logDebug('error getting status?', repr(items(e))); } // 200 is OK, 201 is CREATED, 204 is NO CONTENT // 304 is NOT MODIFIED, 1223 is apparently a bug in IE if (status == 200 || status == 201 || status == 204 || status == 304 || status == 1223) { d.callback(this); @@ -328,25 +361,26 @@ MochiKit.Base.update(MochiKit.Async, { }, _doXHR: function (url, opts) { var m = MochiKit.Base; opts = m.update({ method: 'GET', sendContent: '' /* queryString: undefined, username: undefined, password: undefined, headers: undefined, - mimeType: undefined + mimeType: undefined, + responseType: undefined */ }, opts); var self = MochiKit.Async; var req = self.getXMLHttpRequest(); if (opts.queryString) { var qs = m.queryString(opts.queryString); if (qs) { url += "?" + qs; } } // Safari will send undefined:undefined, so we have to check. // We can't use apply, since the function is native. @@ -362,24 +396,27 @@ MochiKit.Base.update(MochiKit.Async, { if (opts.headers) { var headers = opts.headers; if (!m.isArrayLike(headers)) { headers = m.items(headers); } for (var i = 0; i < headers.length; i++) { var header = headers[i]; var name = header[0]; var value = header[1]; req.setRequestHeader(name, value); } } + if ("responseType" in opts && "responseType" in req) { + req.responseType = opts.responseType; + } return self.sendXMLHttpRequest(req, opts.sendContent); }, _buildURL: function (url/*, ...*/) { if (arguments.length > 1) { var m = MochiKit.Base; var qs = m.queryString.apply(null, m.extend(null, arguments, 1)); if (qs) { return url + "?" + qs; } } return url; @@ -395,34 +432,62 @@ MochiKit.Base.update(MochiKit.Async, { /** @id MochiKit.Async.loadJSONDoc */ loadJSONDoc: function (url/*, ...*/) { var self = MochiKit.Async; url = self._buildURL.apply(self, arguments); var d = self.doXHR(url, { 'mimeType': 'text/plain', 'headers': [['Accept', 'application/json']] }); d = d.addCallback(self.evalJSONRequest); return d; }, + /** @id MochiKit.Async.loadScript */ + loadScript: function (url) { + var d = new MochiKit.Async.Deferred(); + var script = document.createElement("script"); + script.type = "text/javascript"; + script.src = url; + script.onload = function () { + script.onload = null; + script.onerror = null; + script.onreadystatechange = null; + script = null; + d.callback(); + }; + script.onerror = function (msg) { + script.onload = null; + script.onerror = null; + script.onreadystatechange = null; + script = null; + msg = "Failed to load script at " + url + ": " + msg; + d.errback(new URIError(msg, url)); + } + script.onreadystatechange = function () { + if (script.readyState == "loaded" || script.readyState == "complete") { + script.onload(); + } else { + // IE doesn't bother to report errors... + MochiKit.Async.callLater(10, script.onerror, "Script loading timed out") + } + }; + document.getElementsByTagName("head")[0].appendChild(script); + return d; + }, + /** @id MochiKit.Async.wait */ wait: function (seconds, /* optional */value) { var d = new MochiKit.Async.Deferred(); - var m = MochiKit.Base; - if (typeof(value) != 'undefined') { - d.addCallback(function () { return value; }); - } - var timeout = setTimeout( - m.bind("callback", d), - Math.floor(seconds * 1000)); + var cb = MochiKit.Base.bind("callback", d, value); + var timeout = setTimeout(cb, Math.floor(seconds * 1000)); d.canceller = function () { try { clearTimeout(timeout); } catch (e) { // pass } }; return d; }, /** @id MochiKit.Async.callLater */ callLater: function (seconds, func) { @@ -501,24 +566,25 @@ MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, f resultList.push(undefined); d.addCallback(cb, i, true); d.addErrback(cb, i, false); } if (list.length === 0 && !fireOnOneCallback) { this.callback(this.resultList); } }; MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred(); +MochiKit.Async.DeferredList.prototype.constructor = MochiKit.Async.DeferredList; MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) { this.resultList[index] = [succeeded, result]; this.finishedCount += 1; if (this.fired == -1) { if (succeeded && this.fireOnOneCallback) { this.callback([index, result]); } else if (!succeeded && this.fireOnOneErrback) { this.errback(result); } else if (this.finishedCount == this.list.length) { this.callback(this.resultList); } |