123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682 |
- /***
- MochiKit.Async 1.4
- See <http://mochikit.com/> for documentation, downloads, license, etc.
- (c) 2005 Bob Ippolito. All rights Reserved.
- ***/
- if (typeof(dojo) != 'undefined') {
- dojo.provide("MochiKit.Async");
- dojo.require("MochiKit.Base");
- }
- if (typeof(JSAN) != 'undefined') {
- JSAN.use("MochiKit.Base", []);
- }
- try {
- if (typeof(MochiKit.Base) == 'undefined') {
- throw "";
- }
- } catch (e) {
- throw "MochiKit.Async depends on MochiKit.Base!";
- }
- if (typeof(MochiKit.Async) == 'undefined') {
- MochiKit.Async = {};
- }
- MochiKit.Async.NAME = "MochiKit.Async";
- MochiKit.Async.VERSION = "1.4";
- MochiKit.Async.__repr__ = function () {
- return "[" + this.NAME + " " + this.VERSION + "]";
- };
- MochiKit.Async.toString = function () {
- return this.__repr__();
- };
- /** @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;
- };
- 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 + ')';
- },
- toString: MochiKit.Base.forwardCall("repr"),
- _nextId: MochiKit.Base.counter(),
- /** @id MochiKit.Async.Deferred.prototype.cancel */
- cancel: function () {
- 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));
- }
- } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
- this.results[0].cancel();
- }
- },
-
- _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();
- },
- _check: function () {
- if (this.fired != -1) {
- if (!this.silentlyCancelled) {
- throw new MochiKit.Async.AlreadyCalledError(this);
- }
- this.silentlyCancelled = false;
- return;
- }
- },
- /** @id MochiKit.Async.Deferred.prototype.callback */
- callback: function (res) {
- this._check();
- if (res instanceof MochiKit.Async.Deferred) {
- throw new Error("Deferred instances can only be chained if they are the result of a callback");
- }
- this._resback(res);
- },
- /** @id MochiKit.Async.Deferred.prototype.errback */
- errback: function (res) {
- this._check();
- var self = MochiKit.Async;
- if (res instanceof self.Deferred) {
- throw new Error("Deferred instances can only be chained if they are the result of a callback");
- }
- if (!(res instanceof Error)) {
- res = new self.GenericError(res);
- }
- this._resback(res);
- },
- /** @id MochiKit.Async.Deferred.prototype.addBoth */
- addBoth: function (fn) {
- if (arguments.length > 1) {
- fn = MochiKit.Base.partial.apply(null, arguments);
- }
- return this.addCallbacks(fn, fn);
- },
- /** @id MochiKit.Async.Deferred.prototype.addCallback */
- addCallback: function (fn) {
- if (arguments.length > 1) {
- fn = MochiKit.Base.partial.apply(null, arguments);
- }
- return this.addCallbacks(fn, null);
- },
- /** @id MochiKit.Async.Deferred.prototype.addErrback */
- 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");
- }
- this.chain.push([cb, eb]);
- 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();
- }
- };
- 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 (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 */) {
- return eval('(' + arguments[0].responseText + ')');
- },
- /** @id MochiKit.Async.succeed */
- succeed: function (/* optional */result) {
- var d = new MochiKit.Async.Deferred();
- d.callback.apply(d, arguments);
- return d;
- },
- /** @id MochiKit.Async.fail */
- fail: function (/* optional */result) {
- var d = new MochiKit.Async.Deferred();
- d.errback.apply(d, arguments);
- return d;
- },
- /** @id MochiKit.Async.getXMLHttpRequest */
- getXMLHttpRequest: function () {
- var self = arguments.callee;
- if (!self.XMLHttpRequest) {
- var tryThese = [
- function () { return new XMLHttpRequest(); },
- function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
- function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
- function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
- function () {
- throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
- }
- ];
- for (var i = 0; i < tryThese.length; i++) {
- var func = tryThese[i];
- try {
- self.XMLHttpRequest = func;
- return func();
- } catch (e) {
- // pass
- }
- }
- }
- return self.XMLHttpRequest();
- },
- _xhr_onreadystatechange: function (d) {
- // MochiKit.Logging.logDebug('this.readyState', this.readyState);
- var m = MochiKit.Base;
- if (this.readyState == 4) {
- // 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)) {
- // 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, 304 is NOT_MODIFIED
- if (status == 200 || status == 304) { // OK
- d.callback(this);
- } else {
- var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
- if (err.number) {
- // XXX: This seems to happen on page change
- d.errback(err);
- } else {
- // XXX: this seems to happen when the server is unreachable
- d.errback(err);
- }
- }
- }
- },
- _xhr_canceller: function (req) {
- // IE SUCKS
- try {
- req.onreadystatechange = null;
- } catch (e) {
- try {
- req.onreadystatechange = MochiKit.Base.noop;
- } catch (e) {
- }
- }
- req.abort();
- },
-
- /** @id MochiKit.Async.sendXMLHttpRequest */
- sendXMLHttpRequest: function (req, /* optional */ sendContent) {
- if (typeof(sendContent) == "undefined" || sendContent === null) {
- sendContent = "";
- }
- var m = MochiKit.Base;
- var self = MochiKit.Async;
- var d = new self.Deferred(m.partial(self._xhr_canceller, req));
-
- try {
- req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
- req, d);
- req.send(sendContent);
- } catch (e) {
- try {
- req.onreadystatechange = null;
- } catch (ignore) {
- // pass
- }
- d.errback(e);
- }
- return d;
- },
- /** @id MochiKit.Async.doXHR */
- doXHR: function (url, opts) {
- var m = MochiKit.Base;
- opts = m.update({
- method: 'GET',
- sendContent: ''
- /*
- queryString: undefined,
- username: undefined,
- password: undefined,
- headers: undefined,
- mimeType: undefined
- */
- }, opts);
- var self = MochiKit.Async;
- var req = self.getXMLHttpRequest();
- if (opts.queryString) {
- var qs = m.queryString(opts.queryString);
- if (qs) {
- url += "?" + qs;
- }
- }
- req.open(opts.method, url, true, opts.username, opts.password);
- if (req.overrideMimeType && opts.mimeType) {
- req.overrideMimeType(opts.mimeType);
- }
- 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);
- }
- }
- 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;
- },
-
- /** @id MochiKit.Async.doSimpleXMLHttpRequest */
- doSimpleXMLHttpRequest: function (url/*, ...*/) {
- var self = MochiKit.Async;
- url = self._buildURL.apply(self, arguments);
- return self.doXHR(url);
- },
- /** @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.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));
- d.canceller = function () {
- try {
- clearTimeout(timeout);
- } catch (e) {
- // pass
- }
- };
- return d;
- },
- /** @id MochiKit.Async.callLater */
- callLater: function (seconds, func) {
- var m = MochiKit.Base;
- var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
- return MochiKit.Async.wait(seconds).addCallback(
- function (res) { return pfunc(); }
- );
- }
- });
- /** @id MochiKit.Async.DeferredLock */
- MochiKit.Async.DeferredLock = function () {
- this.waiting = [];
- this.locked = false;
- this.id = this._nextId();
- };
- MochiKit.Async.DeferredLock.prototype = {
- __class__: MochiKit.Async.DeferredLock,
- /** @id MochiKit.Async.DeferredLock.prototype.acquire */
- acquire: function () {
- var d = new MochiKit.Async.Deferred();
- if (this.locked) {
- this.waiting.push(d);
- } else {
- this.locked = true;
- d.callback(this);
- }
- return d;
- },
- /** @id MochiKit.Async.DeferredLock.prototype.release */
- release: function () {
- if (!this.locked) {
- throw TypeError("Tried to release an unlocked DeferredLock");
- }
- this.locked = false;
- if (this.waiting.length > 0) {
- this.locked = true;
- this.waiting.shift().callback(this);
- }
- },
- _nextId: MochiKit.Base.counter(),
- repr: function () {
- var state;
- if (this.locked) {
- state = 'locked, ' + this.waiting.length + ' waiting';
- } else {
- state = 'unlocked';
- }
- return 'DeferredLock(' + this.id + ', ' + state + ')';
- },
- toString: MochiKit.Base.forwardCall("repr")
- };
- /** @id MochiKit.Async.DeferredList */
- MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
- // call parent constructor
- MochiKit.Async.Deferred.apply(this, [canceller]);
-
- this.list = list;
- var resultList = [];
- this.resultList = resultList;
- this.finishedCount = 0;
- this.fireOnOneCallback = fireOnOneCallback;
- this.fireOnOneErrback = fireOnOneErrback;
- this.consumeErrors = consumeErrors;
- var cb = MochiKit.Base.bind(this._cbDeferred, this);
- for (var i = 0; i < list.length; i++) {
- var d = list[i];
- 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._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);
- }
- }
- if (!succeeded && this.consumeErrors) {
- result = null;
- }
- return result;
- };
- /** @id MochiKit.Async.gatherResults */
- MochiKit.Async.gatherResults = function (deferredList) {
- var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
- d.addCallback(function (results) {
- var ret = [];
- for (var i = 0; i < results.length; i++) {
- ret.push(results[i][1]);
- }
- return ret;
- });
- return d;
- };
- /** @id MochiKit.Async.maybeDeferred */
- MochiKit.Async.maybeDeferred = function (func) {
- var self = MochiKit.Async;
- var result;
- try {
- var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
- if (r instanceof self.Deferred) {
- result = r;
- } else if (r instanceof Error) {
- result = self.fail(r);
- } else {
- result = self.succeed(r);
- }
- } catch (e) {
- result = self.fail(e);
- }
- return result;
- };
- MochiKit.Async.EXPORT = [
- "AlreadyCalledError",
- "CancelledError",
- "BrowserComplianceError",
- "GenericError",
- "XMLHttpRequestError",
- "Deferred",
- "succeed",
- "fail",
- "getXMLHttpRequest",
- "doSimpleXMLHttpRequest",
- "loadJSONDoc",
- "wait",
- "callLater",
- "sendXMLHttpRequest",
- "DeferredLock",
- "DeferredList",
- "gatherResults",
- "maybeDeferred",
- "doXHR"
- ];
-
- MochiKit.Async.EXPORT_OK = [
- "evalJSONRequest"
- ];
- MochiKit.Async.__new__ = function () {
- var m = MochiKit.Base;
- var ne = m.partial(m._newNamedError, this);
-
- ne("AlreadyCalledError",
- /** @id MochiKit.Async.AlreadyCalledError */
- function (deferred) {
- /***
- Raised by the Deferred if callback or errback happens
- after it was already fired.
- ***/
- this.deferred = deferred;
- }
- );
- ne("CancelledError",
- /** @id MochiKit.Async.CancelledError */
- function (deferred) {
- /***
- Raised by the Deferred cancellation mechanism.
- ***/
- this.deferred = deferred;
- }
- );
- ne("BrowserComplianceError",
- /** @id MochiKit.Async.BrowserComplianceError */
- function (msg) {
- /***
- Raised when the JavaScript runtime is not capable of performing
- the given function. Technically, this should really never be
- raised because a non-conforming JavaScript runtime probably
- isn't going to support exceptions in the first place.
- ***/
- this.message = msg;
- }
- );
- ne("GenericError",
- /** @id MochiKit.Async.GenericError */
- function (msg) {
- this.message = msg;
- }
- );
- ne("XMLHttpRequestError",
- /** @id MochiKit.Async.XMLHttpRequestError */
- function (req, msg) {
- /***
- Raised when an XMLHttpRequest does not complete for any reason.
- ***/
- this.req = req;
- this.message = msg;
- try {
- // Strange but true that this can raise in some cases.
- this.number = req.status;
- } catch (e) {
- // pass
- }
- }
- );
- this.EXPORT_TAGS = {
- ":common": this.EXPORT,
- ":all": m.concat(this.EXPORT, this.EXPORT_OK)
- };
- m.nameFunctions(this);
- };
- MochiKit.Async.__new__();
- MochiKit.Base._exportSymbols(this, MochiKit.Async);
|