]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dojo/aspect.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / aspect.js.uncompressed.js
diff --git a/lib/dojo/aspect.js.uncompressed.js b/lib/dojo/aspect.js.uncompressed.js
new file mode 100644 (file)
index 0000000..506c4ca
--- /dev/null
@@ -0,0 +1,207 @@
+define("dojo/aspect", [], function(){
+
+// TODOC: after/before/around return object
+// TODOC: after/before/around param types. 
+
+/*=====
+       dojo.aspect = {
+               // summary: provides aspect oriented programming functionality, allowing for
+               //              one to add before, around, or after advice on existing methods.
+               //
+               // example:
+               //      |       define(["dojo/aspect"], function(aspect){
+               //      |               var signal = aspect.after(targetObject, "methodName", function(someArgument){
+               //      |                       this will be called when targetObject.methodName() is called, after the original function is called
+               //      |               });
+               //
+               // example:
+               //      The returned signal object can be used to cancel the advice.
+               //      |       signal.remove(); // this will stop the advice from being executed anymore
+               //      |       aspect.before(targetObject, "methodName", function(someArgument){
+               //      |               // this will be called when targetObject.methodName() is called, before the original function is called
+               //      |        });
+               
+               after: function(target, methodName, advice, receiveArguments){
+                       // summary: The "after" export of the aspect module is a function that can be used to attach
+                       //              "after" advice to a method. This function will be executed after the original method
+                       //              is executed. By default the function will be called with a single argument, the return
+                       //              value of the original method, or the the return value of the last executed advice (if a previous one exists).
+                       //              The fourth (optional) argument can be set to true to so the function receives the original
+                       //              arguments (from when the original method was called) rather than the return value.
+                       //              If there are multiple "after" advisors, they are executed in the order they were registered.
+                       // target: Object
+                       //              This is the target object
+                       // methodName: String
+                       //              This is the name of the method to attach to.
+                       // advice: Function
+                       //              This is function to be called after the original method
+                       // receiveArguments: Boolean?
+                       //              If this is set to true, the advice function receives the original arguments (from when the original mehtod
+                       //              was called) rather than the return value of the original/previous method.
+                       // returns:
+                       //              A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will
+                       //              stop the advice function from being executed.
+               },
+               
+               before: function(target, methodName, advice){
+                       // summary: The "before" export of the aspect module is a function that can be used to attach
+                       //              "before" advice to a method. This function will be executed before the original method
+                       //              is executed. This function will be called with the arguments used to call the method.
+                       //              This function may optionally return an array as the new arguments to use to call
+                       //              the original method (or the previous, next-to-execute before advice, if one exists).
+                       //              If the before method doesn't return anything (returns undefined) the original arguments
+                       //              will be preserved.
+                       //              If there are multiple "before" advisors, they are executed in the reverse order they were registered.
+                       //
+                       // target: Object
+                       //              This is the target object
+                       // methodName: String
+                       //              This is the name of the method to attach to.
+                       // advice: Function
+                       //              This is function to be called before the original method         
+               },
+
+               around: function(target, methodName, advice){
+                       // summary: The "around" export of the aspect module is a function that can be used to attach
+                       //              "around" advice to a method. The advisor function is immediately executed when
+                       //              the around() is called, is passed a single argument that is a function that can be
+                       //              called to continue execution of the original method (or the next around advisor).
+                       //              The advisor function should return a function, and this function will be called whenever
+                       //              the method is called. It will be called with the arguments used to call the method.
+                       //              Whatever this function returns will be returned as the result of the method call (unless after advise changes it).
+                       //
+                       // example:
+                       //              If there are multiple "around" advisors, the most recent one is executed first,
+                       //              which can then delegate to the next one and so on. For example:
+                       //              |       around(obj, "foo", function(originalFoo){
+                       //              |               return function(){
+                       //              |                       var start = new Date().getTime();
+                       //              |                       var results = originalFoo.apply(this, arguments); // call the original
+                       //              |                       var end = new Date().getTime();
+                       //              |                       console.log("foo execution took " + (end - start) + " ms");
+                       //              |                       return results;
+                       //              |               };
+                       //              |       });
+                       //
+                       // target: Object
+                       //              This is the target object
+                       // methodName: String
+                       //              This is the name of the method to attach to.
+                       // advice: Function
+                       //              This is function to be called around the original method
+               }
+
+       };
+=====*/
+
+       "use strict";
+       var nextId = 0;
+       function advise(dispatcher, type, advice, receiveArguments){
+               var previous = dispatcher[type];
+               var around = type == "around";
+               var signal;
+               if(around){
+                       var advised = advice(function(){
+                               return previous.advice(this, arguments);
+                       });
+                       signal = {
+                               remove: function(){
+                                       signal.cancelled = true;
+                               },
+                               advice: function(target, args){
+                                       return signal.cancelled ?
+                                               previous.advice(target, args) : // cancelled, skip to next one
+                                               advised.apply(target, args);    // called the advised function
+                               }
+                       };
+               }else{
+                       // create the remove handler
+                       signal = {
+                               remove: function(){
+                                       var previous = signal.previous;
+                                       var next = signal.next;
+                                       if(!next && !previous){
+                                               delete dispatcher[type];
+                                       }else{
+                                               if(previous){
+                                                       previous.next = next;
+                                               }else{
+                                                       dispatcher[type] = next;
+                                               }
+                                               if(next){
+                                                       next.previous = previous;
+                                               }
+                                       }
+                               },
+                               id: nextId++,
+                               advice: advice,
+                               receiveArguments: receiveArguments
+                       };
+               }
+               if(previous && !around){
+                       if(type == "after"){
+                               // add the listener to the end of the list
+                               var next = previous;
+                               while(next){
+                                       previous = next;
+                                       next = next.next;
+                               }
+                               previous.next = signal;
+                               signal.previous = previous;
+                       }else if(type == "before"){
+                               // add to beginning
+                               dispatcher[type] = signal;
+                               signal.next = previous;
+                               previous.previous = signal;
+                       }
+               }else{
+                       // around or first one just replaces
+                       dispatcher[type] = signal;
+               }
+               return signal;
+       }
+       function aspect(type){
+               return function(target, methodName, advice, receiveArguments){
+                       var existing = target[methodName], dispatcher;
+                       if(!existing || existing.target != target){
+                               // no dispatcher in place
+                               target[methodName] = dispatcher = function(){
+                                       var executionId = nextId;
+                                       // before advice
+                                       var args = arguments;
+                                       var before = dispatcher.before;
+                                       while(before){
+                                               args = before.advice.apply(this, args) || args;
+                                               before = before.next;
+                                       }
+                                       // around advice
+                                       if(dispatcher.around){
+                                               var results = dispatcher.around.advice(this, args);
+                                       }
+                                       // after advice
+                                       var after = dispatcher.after;
+                                       while(after && after.id < executionId){
+                                               results = after.receiveArguments ? after.advice.apply(this, args) || results :
+                                                               after.advice.call(this, results);
+                                               after = after.next;
+                                       }
+                                       return results;
+                               };
+                               if(existing){
+                                       dispatcher.around = {advice: function(target, args){
+                                               return existing.apply(target, args);
+                                       }};
+                               }
+                               dispatcher.target = target;
+                       }
+                       var results = advise((dispatcher || existing), type, advice, receiveArguments);
+                       advice = null;
+                       return results;
+               };
+       }
+       return {
+               before: aspect("before"),
+               around: aspect("around"),
+               after: aspect("after")
+       };
+});