]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dojo/_base/Deferred.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / _base / Deferred.js.uncompressed.js
diff --git a/lib/dojo/_base/Deferred.js.uncompressed.js b/lib/dojo/_base/Deferred.js.uncompressed.js
new file mode 100644 (file)
index 0000000..6dc39e9
--- /dev/null
@@ -0,0 +1,366 @@
+define("dojo/_base/Deferred", ["./kernel", "./lang"], function(dojo, lang){
+       // module:
+       //              dojo/_base/Deferred
+       // summary:
+       //              This module defines dojo.Deferred.
+
+       var mutator = function(){};
+       var freeze = Object.freeze || function(){};
+       // A deferred provides an API for creating and resolving a promise.
+       dojo.Deferred = function(/*Function?*/ canceller){
+               // summary:
+               //              Deferreds provide a generic means for encapsulating an asynchronous
+               //              operation and notifying users of the completion and result of the operation.
+               // description:
+               //              The dojo.Deferred API is based on the concept of promises that provide a
+               //              generic interface into the eventual completion of an asynchronous action.
+               //              The motivation for promises fundamentally is about creating a
+               //              separation of concerns that allows one to achieve the same type of
+               //              call patterns and logical data flow in asynchronous code as can be
+               //              achieved in synchronous code. Promises allows one
+               //              to be able to call a function purely with arguments needed for
+               //              execution, without conflating the call with concerns of whether it is
+               //              sync or async. One shouldn't need to alter a call's arguments if the
+               //              implementation switches from sync to async (or vice versa). By having
+               //              async functions return promises, the concerns of making the call are
+               //              separated from the concerns of asynchronous interaction (which are
+               //              handled by the promise).
+               //
+               //              The dojo.Deferred is a type of promise that provides methods for fulfilling the
+               //              promise with a successful result or an error. The most important method for
+               //              working with Dojo's promises is the then() method, which follows the
+               //              CommonJS proposed promise API. An example of using a Dojo promise:
+               //
+               //              |       var resultingPromise = someAsyncOperation.then(function(result){
+               //              |               ... handle result ...
+               //              |       },
+               //              |       function(error){
+               //              |               ... handle error ...
+               //              |       });
+               //
+               //              The .then() call returns a new promise that represents the result of the
+               //              execution of the callback. The callbacks will never affect the original promises value.
+               //
+               //              The dojo.Deferred instances also provide the following functions for backwards compatibility:
+               //
+               //                      * addCallback(handler)
+               //                      * addErrback(handler)
+               //                      * callback(result)
+               //                      * errback(result)
+               //
+               //              Callbacks are allowed to return promises themselves, so
+               //              you can build complicated sequences of events with ease.
+               //
+               //              The creator of the Deferred may specify a canceller.  The canceller
+               //              is a function that will be called if Deferred.cancel is called
+               //              before the Deferred fires. You can use this to implement clean
+               //              aborting of an XMLHttpRequest, etc. Note that cancel will fire the
+               //              deferred with a CancelledError (unless your canceller returns
+               //              another kind of error), so the errbacks should be prepared to
+               //              handle that error for cancellable Deferreds.
+               // example:
+               //      |       var deferred = new dojo.Deferred();
+               //      |       setTimeout(function(){ deferred.callback({success: true}); }, 1000);
+               //      |       return deferred;
+               // example:
+               //              Deferred objects are often used when making code asynchronous. It
+               //              may be easiest to write functions in a synchronous manner and then
+               //              split code using a deferred to trigger a response to a long-lived
+               //              operation. For example, instead of register a callback function to
+               //              denote when a rendering operation completes, the function can
+               //              simply return a deferred:
+               //
+               //              |       // callback style:
+               //              |       function renderLotsOfData(data, callback){
+               //              |               var success = false
+               //              |               try{
+               //              |                       for(var x in data){
+               //              |                               renderDataitem(data[x]);
+               //              |                       }
+               //              |                       success = true;
+               //              |               }catch(e){ }
+               //              |               if(callback){
+               //              |                       callback(success);
+               //              |               }
+               //              |       }
+               //
+               //              |       // using callback style
+               //              |       renderLotsOfData(someDataObj, function(success){
+               //              |               // handles success or failure
+               //              |               if(!success){
+               //              |                       promptUserToRecover();
+               //              |               }
+               //              |       });
+               //              |       // NOTE: no way to add another callback here!!
+               // example:
+               //              Using a Deferred doesn't simplify the sending code any, but it
+               //              provides a standard interface for callers and senders alike,
+               //              providing both with a simple way to service multiple callbacks for
+               //              an operation and freeing both sides from worrying about details
+               //              such as "did this get called already?". With Deferreds, new
+               //              callbacks can be added at any time.
+               //
+               //              |       // Deferred style:
+               //              |       function renderLotsOfData(data){
+               //              |               var d = new dojo.Deferred();
+               //              |               try{
+               //              |                       for(var x in data){
+               //              |                               renderDataitem(data[x]);
+               //              |                       }
+               //              |                       d.callback(true);
+               //              |               }catch(e){
+               //              |                       d.errback(new Error("rendering failed"));
+               //              |               }
+               //              |               return d;
+               //              |       }
+               //
+               //              |       // using Deferred style
+               //              |       renderLotsOfData(someDataObj).then(null, function(){
+               //              |               promptUserToRecover();
+               //              |       });
+               //              |       // NOTE: addErrback and addCallback both return the Deferred
+               //              |       // again, so we could chain adding callbacks or save the
+               //              |       // deferred for later should we need to be notified again.
+               // example:
+               //              In this example, renderLotsOfData is synchronous and so both
+               //              versions are pretty artificial. Putting the data display on a
+               //              timeout helps show why Deferreds rock:
+               //
+               //              |       // Deferred style and async func
+               //              |       function renderLotsOfData(data){
+               //              |               var d = new dojo.Deferred();
+               //              |               setTimeout(function(){
+               //              |                       try{
+               //              |                               for(var x in data){
+               //              |                                       renderDataitem(data[x]);
+               //              |                               }
+               //              |                               d.callback(true);
+               //              |                       }catch(e){
+               //              |                               d.errback(new Error("rendering failed"));
+               //              |                       }
+               //              |               }, 100);
+               //              |               return d;
+               //              |       }
+               //
+               //              |       // using Deferred style
+               //              |       renderLotsOfData(someDataObj).then(null, function(){
+               //              |               promptUserToRecover();
+               //              |       });
+               //
+               //              Note that the caller doesn't have to change his code at all to
+               //              handle the asynchronous case.
+
+               var result, finished, isError, head, nextListener;
+               var promise = (this.promise = {});
+
+               function complete(value){
+                       if(finished){
+                               throw new Error("This deferred has already been resolved");
+                       }
+                       result = value;
+                       finished = true;
+                       notify();
+               }
+               function notify(){
+                       var mutated;
+                       while(!mutated && nextListener){
+                               var listener = nextListener;
+                               nextListener = nextListener.next;
+                               if((mutated = (listener.progress == mutator))){ // assignment and check
+                                       finished = false;
+                               }
+                               var func = (isError ? listener.error : listener.resolved);
+                               if(func){
+                                       try{
+                                               var newResult = func(result);
+                                               if (newResult && typeof newResult.then === "function"){
+                                                       newResult.then(lang.hitch(listener.deferred, "resolve"), lang.hitch(listener.deferred, "reject"), lang.hitch(listener.deferred, "progress"));
+                                                       continue;
+                                               }
+                                               var unchanged = mutated && newResult === undefined;
+                                               if(mutated && !unchanged){
+                                                       isError = newResult instanceof Error;
+                                               }
+                                               listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult);
+                                       }catch(e){
+                                               listener.deferred.reject(e);
+                                       }
+                               }else{
+                                       if(isError){
+                                               listener.deferred.reject(result);
+                                       }else{
+                                               listener.deferred.resolve(result);
+                                       }
+                               }
+                       }
+               }
+               // calling resolve will resolve the promise
+               this.resolve = this.callback = function(value){
+                       // summary:
+                       //              Fulfills the Deferred instance successfully with the provide value
+                       this.fired = 0;
+                       this.results = [value, null];
+                       complete(value);
+               };
+
+
+               // calling error will indicate that the promise failed
+               this.reject = this.errback = function(error){
+                       // summary:
+                       //              Fulfills the Deferred instance as an error with the provided error
+                       isError = true;
+                       this.fired = 1;
+                       complete(error);
+                       this.results = [null, error];
+                       if(!error || error.log !== false){
+                               (dojo.config.deferredOnError || function(x){ console.error(x); })(error);
+                       }
+               };
+               // call progress to provide updates on the progress on the completion of the promise
+               this.progress = function(update){
+                       // summary:
+                       //              Send progress events to all listeners
+                       var listener = nextListener;
+                       while(listener){
+                               var progress = listener.progress;
+                               progress && progress(update);
+                               listener = listener.next;
+                       }
+               };
+               this.addCallbacks = function(callback, errback){
+                       // summary:
+                       //              Adds callback and error callback for this deferred instance.
+                       // callback: Function?
+                       //              The callback attached to this deferred object.
+                       // errback: Function?
+                       //              The error callback attached to this deferred object.
+                       // returns:
+                       //              Returns this deferred object.
+                       this.then(callback, errback, mutator);
+                       return this;    // dojo.Deferred
+               };
+               // provide the implementation of the promise
+               promise.then = this.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){
+                       // summary:
+                       //              Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
+                       //              completion of a promise. The fulfilledHandler is called when the promise
+                       //              is fulfilled. The errorHandler is called when a promise fails. The
+                       //              progressHandler is called for progress events. All arguments are optional
+                       //              and non-function values are ignored. The progressHandler is not only an
+                       //              optional argument, but progress events are purely optional. Promise
+                       //              providers are not required to ever create progress events.
+                       //
+                       //              This function will return a new promise that is fulfilled when the given
+                       //              fulfilledHandler or errorHandler callback is finished. This allows promise
+                       //              operations to be chained together. The value returned from the callback
+                       //              handler is the fulfillment value for the returned promise. If the callback
+                       //              throws an error, the returned promise will be moved to failed state.
+                       //
+                       // returns: 
+                       //              Returns a new promise that represents the result of the
+                       //              execution of the callback. The callbacks will never affect the original promises value.
+                       // example:
+                       //              An example of using a CommonJS compliant promise:
+                       //              |       asyncComputeTheAnswerToEverything().
+                       //              |               then(addTwo).
+                       //              |               then(printResult, onError);
+                       //              |       >44
+                       //
+                       var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel);
+                       var listener = {
+                               resolved: resolvedCallback,
+                               error: errorCallback,
+                               progress: progressCallback,
+                               deferred: returnDeferred
+                       };
+                       if(nextListener){
+                               head = head.next = listener;
+                       }
+                       else{
+                               nextListener = head = listener;
+                       }
+                       if(finished){
+                               notify();
+                       }
+                       return returnDeferred.promise; // Promise
+               };
+               var deferred = this;
+               promise.cancel = this.cancel = function (){
+                       // summary:
+                       //              Cancels the asynchronous operation
+                       if(!finished){
+                               var error = canceller && canceller(deferred);
+                               if(!finished){
+                                       if (!(error instanceof Error)){
+                                               error = new Error(error);
+                                       }
+                                       error.log = false;
+                                       deferred.reject(error);
+                               }
+                       }
+               };
+               freeze(promise);
+       };
+       lang.extend(dojo.Deferred, {
+               addCallback: function (/*Function*/ callback){
+                       // summary:
+                       //              Adds successful callback for this deferred instance.
+                       // returns:
+                       //              Returns this deferred object.
+                       return this.addCallbacks(lang.hitch.apply(dojo, arguments));    // dojo.Deferred
+               },
+
+               addErrback: function (/*Function*/ errback){
+                       // summary:
+                       //              Adds error callback for this deferred instance.
+                       // returns:
+                       //              Returns this deferred object.
+                       return this.addCallbacks(null, lang.hitch.apply(dojo, arguments));      // dojo.Deferred
+               },
+
+               addBoth: function (/*Function*/ callback){
+                       // summary:
+                       //              Add handler as both successful callback and error callback for this deferred instance.
+                       // returns:
+                       //              Returns this deferred object.
+                       var enclosed = lang.hitch.apply(dojo, arguments);
+                       return this.addCallbacks(enclosed, enclosed);   // dojo.Deferred
+               },
+               fired: -1
+       });
+
+       dojo.Deferred.when = dojo.when = function(promiseOrValue, /*Function?*/ callback, /*Function?*/ errback, /*Function?*/ progressHandler){
+               // summary:
+               //              This provides normalization between normal synchronous values and
+               //              asynchronous promises, so you can interact with them in a common way
+               // returns:
+               //              Returns a new promise that represents the result of the execution of callback 
+               //              when parameter "promiseOrValue" is promise.
+               //              Returns the execution result of callback when parameter "promiseOrValue" is value.
+               // example:
+               //              |       function printFirstAndLast(items){
+               //              |               dojo.when(findFirst(items), console.log);
+               //              |               dojo.when(findLast(items), console.log);
+               //              |       }
+               //              |       function findFirst(items){
+               //              |               return dojo.when(items, function(items){
+               //              |                       return items[0];
+               //              |               });
+               //              |       }
+               //              |       function findLast(items){
+               //              |               return dojo.when(items, function(items){
+               //              |                       return items[items.length - 1];
+               //              |               });
+               //              |       }
+               //              And now all three of his functions can be used sync or async.
+               //              |       printFirstAndLast([1,2,3,4]) will work just as well as
+               //              |       printFirstAndLast(dojo.xhrGet(...));
+
+               if(promiseOrValue && typeof promiseOrValue.then === "function"){
+                       return promiseOrValue.then(callback, errback, progressHandler);
+               }
+               return callback ? callback(promiseOrValue) : promiseOrValue;    // Promise
+       };
+
+       return dojo.Deferred;
+});