]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/aspect.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dojo / aspect.js.uncompressed.js
1 define("dojo/aspect", [], function(){
2
3 // module:
4 // dojo/aspect
5
6 "use strict";
7 var undefined, nextId = 0;
8 function advise(dispatcher, type, advice, receiveArguments){
9 var previous = dispatcher[type];
10 var around = type == "around";
11 var signal;
12 if(around){
13 var advised = advice(function(){
14 return previous.advice(this, arguments);
15 });
16 signal = {
17 remove: function(){
18 signal.cancelled = true;
19 },
20 advice: function(target, args){
21 return signal.cancelled ?
22 previous.advice(target, args) : // cancelled, skip to next one
23 advised.apply(target, args); // called the advised function
24 }
25 };
26 }else{
27 // create the remove handler
28 signal = {
29 remove: function(){
30 var previous = signal.previous;
31 var next = signal.next;
32 if(!next && !previous){
33 delete dispatcher[type];
34 }else{
35 if(previous){
36 previous.next = next;
37 }else{
38 dispatcher[type] = next;
39 }
40 if(next){
41 next.previous = previous;
42 }
43 }
44 },
45 id: nextId++,
46 advice: advice,
47 receiveArguments: receiveArguments
48 };
49 }
50 if(previous && !around){
51 if(type == "after"){
52 // add the listener to the end of the list
53 // note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bug
54 while(previous.next && (previous = previous.next)){}
55 previous.next = signal;
56 signal.previous = previous;
57 }else if(type == "before"){
58 // add to beginning
59 dispatcher[type] = signal;
60 signal.next = previous;
61 previous.previous = signal;
62 }
63 }else{
64 // around or first one just replaces
65 dispatcher[type] = signal;
66 }
67 return signal;
68 }
69 function aspect(type){
70 return function(target, methodName, advice, receiveArguments){
71 var existing = target[methodName], dispatcher;
72 if(!existing || existing.target != target){
73 // no dispatcher in place
74 target[methodName] = dispatcher = function(){
75 var executionId = nextId;
76 // before advice
77 var args = arguments;
78 var before = dispatcher.before;
79 while(before){
80 args = before.advice.apply(this, args) || args;
81 before = before.next;
82 }
83 // around advice
84 if(dispatcher.around){
85 var results = dispatcher.around.advice(this, args);
86 }
87 // after advice
88 var after = dispatcher.after;
89 while(after && after.id < executionId){
90 if(after.receiveArguments){
91 var newResults = after.advice.apply(this, args);
92 // change the return value only if a new value was returned
93 results = newResults === undefined ? results : newResults;
94 }else{
95 results = after.advice.call(this, results, args);
96 }
97 after = after.next;
98 }
99 return results;
100 };
101 if(existing){
102 dispatcher.around = {advice: function(target, args){
103 return existing.apply(target, args);
104 }};
105 }
106 dispatcher.target = target;
107 }
108 var results = advise((dispatcher || existing), type, advice, receiveArguments);
109 advice = null;
110 return results;
111 };
112 }
113
114 // TODOC: after/before/around return object
115
116 var after = aspect("after");
117 /*=====
118 after = function(target, methodName, advice, receiveArguments){
119 // summary:
120 // The "after" export of the aspect module is a function that can be used to attach
121 // "after" advice to a method. This function will be executed after the original method
122 // is executed. By default the function will be called with a single argument, the return
123 // value of the original method, or the the return value of the last executed advice (if a previous one exists).
124 // The fourth (optional) argument can be set to true to so the function receives the original
125 // arguments (from when the original method was called) rather than the return value.
126 // If there are multiple "after" advisors, they are executed in the order they were registered.
127 // target: Object
128 // This is the target object
129 // methodName: String
130 // This is the name of the method to attach to.
131 // advice: Function
132 // This is function to be called after the original method
133 // receiveArguments: Boolean?
134 // If this is set to true, the advice function receives the original arguments (from when the original mehtod
135 // was called) rather than the return value of the original/previous method.
136 // returns:
137 // A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will
138 // stop the advice function from being executed.
139 };
140 =====*/
141
142 var before = aspect("before");
143 /*=====
144 before = function(target, methodName, advice){
145 // summary:
146 // The "before" export of the aspect module is a function that can be used to attach
147 // "before" advice to a method. This function will be executed before the original method
148 // is executed. This function will be called with the arguments used to call the method.
149 // This function may optionally return an array as the new arguments to use to call
150 // the original method (or the previous, next-to-execute before advice, if one exists).
151 // If the before method doesn't return anything (returns undefined) the original arguments
152 // will be preserved.
153 // If there are multiple "before" advisors, they are executed in the reverse order they were registered.
154 // target: Object
155 // This is the target object
156 // methodName: String
157 // This is the name of the method to attach to.
158 // advice: Function
159 // This is function to be called before the original method
160 };
161 =====*/
162
163 var around = aspect("around");
164 /*=====
165 around = function(target, methodName, advice){
166 // summary:
167 // The "around" export of the aspect module is a function that can be used to attach
168 // "around" advice to a method. The advisor function is immediately executed when
169 // the around() is called, is passed a single argument that is a function that can be
170 // called to continue execution of the original method (or the next around advisor).
171 // The advisor function should return a function, and this function will be called whenever
172 // the method is called. It will be called with the arguments used to call the method.
173 // Whatever this function returns will be returned as the result of the method call (unless after advise changes it).
174 // example:
175 // If there are multiple "around" advisors, the most recent one is executed first,
176 // which can then delegate to the next one and so on. For example:
177 // | around(obj, "foo", function(originalFoo){
178 // | return function(){
179 // | var start = new Date().getTime();
180 // | var results = originalFoo.apply(this, arguments); // call the original
181 // | var end = new Date().getTime();
182 // | console.log("foo execution took " + (end - start) + " ms");
183 // | return results;
184 // | };
185 // | });
186 // target: Object
187 // This is the target object
188 // methodName: String
189 // This is the name of the method to attach to.
190 // advice: Function
191 // This is function to be called around the original method
192 };
193 =====*/
194
195 return {
196 // summary:
197 // provides aspect oriented programming functionality, allowing for
198 // one to add before, around, or after advice on existing methods.
199 // example:
200 // | define(["dojo/aspect"], function(aspect){
201 // | var signal = aspect.after(targetObject, "methodName", function(someArgument){
202 // | this will be called when targetObject.methodName() is called, after the original function is called
203 // | });
204 //
205 // example:
206 // The returned signal object can be used to cancel the advice.
207 // | signal.remove(); // this will stop the advice from being executed anymore
208 // | aspect.before(targetObject, "methodName", function(someArgument){
209 // | // this will be called when targetObject.methodName() is called, before the original function is called
210 // | });
211
212 before: before,
213 around: around,
214 after: after
215 };
216 });