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