Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / docs / source / Observable-more.html
1 <html>\r
2 <head>\r
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    \r
4   <title>The source code</title>\r
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
7 </head>\r
8 <body  onload="prettyPrint();">\r
9     <pre class="prettyprint lang-js">/**\r
10  * @class Ext.util.Observable\r
11  */\r
12 Ext.apply(Ext.util.Observable.prototype, function(){\r
13     // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)\r
14     // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
15     // private\r
16     function getMethodEvent(method){\r
17         var e = (this.methodEvents = this.methodEvents ||\r
18         {})[method], returnValue, v, cancel, obj = this;\r
19 \r
20         if (!e) {\r
21             this.methodEvents[method] = e = {};\r
22             e.originalFn = this[method];\r
23             e.methodName = method;\r
24             e.before = [];\r
25             e.after = [];\r
26 \r
27             var makeCall = function(fn, scope, args){\r
28                 if (!Ext.isEmpty(v = fn.apply(scope || obj, args))) {\r
29                     if (Ext.isObject(v)) {\r
30                         returnValue = !Ext.isEmpty(v.returnValue) ? v.returnValue : v;\r
31                         cancel = !!v.cancel;\r
32                     }\r
33                     else\r
34                         if (v === false) {\r
35                             cancel = true;\r
36                         }\r
37                         else {\r
38                             returnValue = v;\r
39                         }\r
40                 }\r
41             };\r
42 \r
43             this[method] = function(){\r
44                 var args = Ext.toArray(arguments);\r
45                 returnValue = v = undefined;\r
46                 cancel = false;\r
47 \r
48                 Ext.each(e.before, function(b){\r
49                     makeCall(b.fn, b.scope, args);\r
50                     if (cancel) {\r
51                         return returnValue;\r
52                     }\r
53                 });\r
54 \r
55                 if (!Ext.isEmpty(v = e.originalFn.apply(obj, args))) {\r
56                     returnValue = v;\r
57                 }\r
58                 Ext.each(e.after, function(a){\r
59                     makeCall(a.fn, a.scope, args);\r
60                     if (cancel) {\r
61                         return returnValue;\r
62                     }\r
63                 });\r
64                 return returnValue;\r
65             };\r
66         }\r
67         return e;\r
68     }\r
69 \r
70     return {\r
71         // these are considered experimental\r
72         // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
73         // adds an 'interceptor' called before the original method\r
74         beforeMethod : function(method, fn, scope){\r
75             getMethodEvent.call(this, method).before.push({\r
76                 fn: fn,\r
77                 scope: scope\r
78             });\r
79         },\r
80 \r
81         // adds a 'sequence' called after the original method\r
82         afterMethod : function(method, fn, scope){\r
83             getMethodEvent.call(this, method).after.push({\r
84                 fn: fn,\r
85                 scope: scope\r
86             });\r
87         },\r
88 \r
89         removeMethodListener: function(method, fn, scope){\r
90             var e = getMethodEvent.call(this, method), found = false;\r
91             Ext.each(e.before, function(b, i, arr){\r
92                 if (b.fn == fn && b.scope == scope) {\r
93                     arr.splice(i, 1);\r
94                     found = true;\r
95                     return false;\r
96                 }\r
97             });\r
98             if (!found) {\r
99                 Ext.each(e.after, function(a, i, arr){\r
100                     if (a.fn == fn && a.scope == scope) {\r
101                         arr.splice(i, 1);\r
102                         return false;\r
103                     }\r
104                 });\r
105             }\r
106         },\r
107 \r
108         <div id="method-Ext.util.Observable-relayEvents"></div>/**\r
109          * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.\r
110          * @param {Object} o The Observable whose events this object is to relay.\r
111          * @param {Array} events Array of event names to relay.\r
112          */\r
113         relayEvents : function(o, events){\r
114             var me = this;\r
115             function createHandler(ename){\r
116                 return function(){\r
117                     return me.fireEvent.apply(me, [ename].concat(Ext.toArray(arguments)));\r
118                 };\r
119             }\r
120             Ext.each(events, function(ename){\r
121                 me.events[ename] = me.events[ename] || true;\r
122                 o.on(ename, createHandler(ename), me);\r
123             });\r
124         },\r
125 \r
126         <div id="method-Ext.util.Observable-enableBubble"></div>/**\r
127          * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling\r
128          * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>\r
129          * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default\r
130          * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to\r
131          * access the required target more quickly.</p>\r
132          * <p>Example:</p><pre><code>\r
133 Ext.override(Ext.form.Field, {\r
134     //  Add functionality to Field&#39;s initComponent to enable the change event to bubble\r
135     initComponent : Ext.form.Field.prototype.initComponent.createSequence(function() {\r
136         this.enableBubble('change');\r
137     }),\r
138 \r
139     //  We know that we want Field&#39;s events to bubble directly to the FormPanel.\r
140     getBubbleTarget : function() {\r
141         if (!this.formPanel) {\r
142             this.formPanel = this.findParentByType('form');\r
143         }\r
144         return this.formPanel;\r
145     }\r
146 });\r
147 \r
148 var myForm = new Ext.formPanel({\r
149     title: 'User Details',\r
150     items: [{\r
151         ...\r
152     }],\r
153     listeners: {\r
154         change: function() {\r
155             // Title goes red if form has been modified.\r
156             myForm.header.setStyle('color', 'red');\r
157         }\r
158     }\r
159 });\r
160 </code></pre>\r
161          * @param {String/Array} events The event name to bubble, or an Array of event names.\r
162          */\r
163         enableBubble : function(events){\r
164             var me = this;\r
165             if(!Ext.isEmpty(events)){\r
166                 events = Ext.isArray(events) ? events : Ext.toArray(arguments);\r
167                 Ext.each(events, function(ename){\r
168                     ename = ename.toLowerCase();\r
169                     var ce = me.events[ename] || true;\r
170                     if (Ext.isBoolean(ce)) {\r
171                         ce = new Ext.util.Event(me, ename);\r
172                         me.events[ename] = ce;\r
173                     }\r
174                     ce.bubble = true;\r
175                 });\r
176             }\r
177         }\r
178     };\r
179 }());\r
180 \r
181 \r
182 <div id="method-Ext.util.Observable-Observable.capture"></div>/**\r
183  * Starts capture on the specified Observable. All events will be passed\r
184  * to the supplied function with the event name + standard signature of the event\r
185  * <b>before</b> the event is fired. If the supplied function returns false,\r
186  * the event will not fire.\r
187  * @param {Observable} o The Observable to capture events from.\r
188  * @param {Function} fn The function to call when an event is fired.\r
189  * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Observable firing the event.\r
190  * @static\r
191  */\r
192 Ext.util.Observable.capture = function(o, fn, scope){\r
193     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);\r
194 };\r
195 \r
196 \r
197 <div id="method-Ext.util.Observable-Observable.observeClass"></div>/**\r
198  * Sets observability on the passed class constructor.<p>\r
199  * <p>This makes any event fired on any instance of the passed class also fire a single event through\r
200  * the <i>class</i> allowing for central handling of events on many instances at once.</p>\r
201  * <p>Usage:</p><pre><code>\r
202 Ext.util.Observable.observeClass(Ext.data.Connection);\r
203 Ext.data.Connection.on('beforerequest', function(con, options) {\r
204     console.log('Ajax request made to ' + options.url);\r
205 });</code></pre>\r
206  * @param {Function} c The class constructor to make observable.\r
207  * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}. \r
208  * @static\r
209  */\r
210 Ext.util.Observable.observeClass = function(c, listeners){\r
211     if(c){\r
212       if(!c.fireEvent){\r
213           Ext.apply(c, new Ext.util.Observable());\r
214           Ext.util.Observable.capture(c.prototype, c.fireEvent, c);\r
215       }\r
216       if(Ext.isObject(listeners)){\r
217           c.on(listeners);\r
218       }\r
219       return c;\r
220    }\r
221 };</pre>    \r
222 </body>\r
223 </html>