Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Observable.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-util-Observable'>/**
19 </span> * Base class that provides a common interface for publishing events. Subclasses are expected to to have a property
20  * &quot;events&quot; with all the events defined, and, optionally, a property &quot;listeners&quot; with configured listeners defined.
21  *
22  * For example:
23  *
24  *     Ext.define('Employee', {
25  *         extend: 'Ext.util.Observable',
26  *         constructor: function(config){
27  *             this.name = config.name;
28  *             this.addEvents({
29  *                 &quot;fired&quot; : true,
30  *                 &quot;quit&quot; : true
31  *             });
32  *
33  *             // Copy configured listeners into *this* object so that the base class's
34  *             // constructor will add them.
35  *             this.listeners = config.listeners;
36  *
37  *             // Call our superclass constructor to complete construction process.
38  *             this.callParent(arguments)
39  *         }
40  *     });
41  *
42  * This could then be used like this:
43  *
44  *     var newEmployee = new Employee({
45  *         name: employeeName,
46  *         listeners: {
47  *             quit: function() {
48  *                 // By default, &quot;this&quot; will be the object that fired the event.
49  *                 alert(this.name + &quot; has quit!&quot;);
50  *             }
51  *         }
52  *     });
53  */
54 Ext.define('Ext.util.Observable', {
55
56     /* Begin Definitions */
57
58     requires: ['Ext.util.Event'],
59
60     statics: {
61 <span id='Ext-util-Observable-static-method-releaseCapture'>        /**
62 </span>         * Removes **all** added captures from the Observable.
63          *
64          * @param {Ext.util.Observable} o The Observable to release
65          * @static
66          */
67         releaseCapture: function(o) {
68             o.fireEvent = this.prototype.fireEvent;
69         },
70
71 <span id='Ext-util-Observable-static-method-capture'>        /**
72 </span>         * Starts capture on the specified Observable. All events will be passed to the supplied function with the event
73          * name + standard signature of the event **before** the event is fired. If the supplied function returns false,
74          * the event will not fire.
75          *
76          * @param {Ext.util.Observable} o The Observable to capture events from.
77          * @param {Function} fn The function to call when an event is fired.
78          * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed. Defaults to
79          * the Observable firing the event.
80          * @static
81          */
82         capture: function(o, fn, scope) {
83             o.fireEvent = Ext.Function.createInterceptor(o.fireEvent, fn, scope);
84         },
85
86 <span id='Ext-util-Observable-static-method-observe'>        /**
87 </span>         * Sets observability on the passed class constructor.
88          *
89          * This makes any event fired on any instance of the passed class also fire a single event through
90          * the **class** allowing for central handling of events on many instances at once.
91          *
92          * Usage:
93          *
94          *     Ext.util.Observable.observe(Ext.data.Connection);
95          *     Ext.data.Connection.on('beforerequest', function(con, options) {
96          *         console.log('Ajax request made to ' + options.url);
97          *     });
98          *
99          * @param {Function} c The class constructor to make observable.
100          * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
101          * @static
102          */
103         observe: function(cls, listeners) {
104             if (cls) {
105                 if (!cls.isObservable) {
106                     Ext.applyIf(cls, new this());
107                     this.capture(cls.prototype, cls.fireEvent, cls);
108                 }
109                 if (Ext.isObject(listeners)) {
110                     cls.on(listeners);
111                 }
112                 return cls;
113             }
114         }
115     },
116
117     /* End Definitions */
118
119 <span id='Ext-util-Observable-cfg-listeners'>    /**
120 </span>     * @cfg {Object} listeners
121      *
122      * A config object containing one or more event handlers to be added to this object during initialization. This
123      * should be a valid listeners config object as specified in the {@link #addListener} example for attaching multiple
124      * handlers at once.
125      *
126      * **DOM events from Ext JS {@link Ext.Component Components}**
127      *
128      * While _some_ Ext JS Component classes export selected DOM events (e.g. &quot;click&quot;, &quot;mouseover&quot; etc), this is usually
129      * only done when extra value can be added. For example the {@link Ext.view.View DataView}'s **`{@link
130      * Ext.view.View#itemclick itemclick}`** event passing the node clicked on. To access DOM events directly from a
131      * child element of a Component, we need to specify the `element` option to identify the Component property to add a
132      * DOM listener to:
133      *
134      *     new Ext.panel.Panel({
135      *         width: 400,
136      *         height: 200,
137      *         dockedItems: [{
138      *             xtype: 'toolbar'
139      *         }],
140      *         listeners: {
141      *             click: {
142      *                 element: 'el', //bind to the underlying el property on the panel
143      *                 fn: function(){ console.log('click el'); }
144      *             },
145      *             dblclick: {
146      *                 element: 'body', //bind to the underlying body property on the panel
147      *                 fn: function(){ console.log('dblclick body'); }
148      *             }
149      *         }
150      *     });
151      */
152     // @private
153     isObservable: true,
154
155     constructor: function(config) {
156         var me = this;
157
158         Ext.apply(me, config);
159         if (me.listeners) {
160             me.on(me.listeners);
161             delete me.listeners;
162         }
163         me.events = me.events || {};
164
165         if (me.bubbleEvents) {
166             me.enableBubble(me.bubbleEvents);
167         }
168     },
169
170     // @private
171     eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal|freezeEvent)$/,
172
173 <span id='Ext-util-Observable-method-addManagedListener'>    /**
174 </span>     * Adds listeners to any Observable object (or Ext.Element) which are automatically removed when this Component is
175      * destroyed.
176      *
177      * @param {Ext.util.Observable/Ext.Element} item The item to which to add a listener/listeners.
178      * @param {Object/String} ename The event name, or an object containing event name properties.
179      * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
180      * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
181      * in which the handler function is executed.
182      * @param {Object} opt (optional) If the `ename` parameter was an event name, this is the
183      * {@link Ext.util.Observable#addListener addListener} options.
184      */
185     addManagedListener : function(item, ename, fn, scope, options) {
186         var me = this,
187             managedListeners = me.managedListeners = me.managedListeners || [],
188             config;
189
190         if (typeof ename !== 'string') {
191             options = ename;
192             for (ename in options) {
193                 if (options.hasOwnProperty(ename)) {
194                     config = options[ename];
195                     if (!me.eventOptionsRe.test(ename)) {
196                         me.addManagedListener(item, ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
197                     }
198                 }
199             }
200         }
201         else {
202             managedListeners.push({
203                 item: item,
204                 ename: ename,
205                 fn: fn,
206                 scope: scope,
207                 options: options
208             });
209
210             item.on(ename, fn, scope, options);
211         }
212     },
213
214 <span id='Ext-util-Observable-method-removeManagedListener'>    /**
215 </span>     * Removes listeners that were added by the {@link #mon} method.
216      *
217      * @param {Ext.util.Observable/Ext.Element} item The item from which to remove a listener/listeners.
218      * @param {Object/String} ename The event name, or an object containing event name properties.
219      * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
220      * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
221      * in which the handler function is executed.
222      */
223     removeManagedListener : function(item, ename, fn, scope) {
224         var me = this,
225             options,
226             config,
227             managedListeners,
228             length,
229             i;
230
231         if (typeof ename !== 'string') {
232             options = ename;
233             for (ename in options) {
234                 if (options.hasOwnProperty(ename)) {
235                     config = options[ename];
236                     if (!me.eventOptionsRe.test(ename)) {
237                         me.removeManagedListener(item, ename, config.fn || config, config.scope || options.scope);
238                     }
239                 }
240             }
241         }
242
243         managedListeners = me.managedListeners ? me.managedListeners.slice() : [];
244
245         for (i = 0, length = managedListeners.length; i &lt; length; i++) {
246             me.removeManagedListenerItem(false, managedListeners[i], item, ename, fn, scope);
247         }
248     },
249
250 <span id='Ext-util-Observable-method-fireEvent'>    /**
251 </span>     * Fires the specified event with the passed parameters (minus the event name, plus the `options` object passed
252      * to {@link #addListener}).
253      *
254      * An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget}) by
255      * calling {@link #enableBubble}.
256      *
257      * @param {String} eventName The name of the event to fire.
258      * @param {Object...} args Variable number of parameters are passed to handlers.
259      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
260      */
261     fireEvent: function(eventName) {
262         var name = eventName.toLowerCase(),
263             events = this.events,
264             event = events &amp;&amp; events[name],
265             bubbles = event &amp;&amp; event.bubble;
266
267         return this.continueFireEvent(name, Ext.Array.slice(arguments, 1), bubbles);
268     },
269
270 <span id='Ext-util-Observable-method-continueFireEvent'>    /**
271 </span>     * Continue to fire event.
272      * @private
273      *
274      * @param {String} eventName
275      * @param {Array} args
276      * @param {Boolean} bubbles
277      */
278     continueFireEvent: function(eventName, args, bubbles) {
279         var target = this,
280             queue, event,
281             ret = true;
282
283         do {
284             if (target.eventsSuspended === true) {
285                 if ((queue = target.eventQueue)) {
286                     queue.push([eventName, args, bubbles]);
287                 }
288                 return ret;
289             } else {
290                 event = target.events[eventName];
291                 // Continue bubbling if event exists and it is `true` or the handler didn't returns false and it
292                 // configure to bubble.
293                 if (event &amp;&amp; event != true) {
294                     if ((ret = event.fire.apply(event, args)) === false) {
295                         break;
296                     }
297                 }
298             }
299         } while (bubbles &amp;&amp; (target = target.getBubbleParent()));
300         return ret;
301     },
302
303 <span id='Ext-util-Observable-method-getBubbleParent'>    /**
304 </span>     * Gets the bubbling parent for an Observable
305      * @private
306      * @return {Ext.util.Observable} The bubble parent. null is returned if no bubble target exists
307      */
308     getBubbleParent: function(){
309         var me = this, parent = me.getBubbleTarget &amp;&amp; me.getBubbleTarget();
310         if (parent &amp;&amp; parent.isObservable) {
311             return parent;
312         }
313         return null;
314     },
315
316 <span id='Ext-util-Observable-method-addListener'>    /**
317 </span>     * Appends an event handler to this object.
318      *
319      * @param {String} eventName The name of the event to listen for. May also be an object who's property names are
320      * event names.
321      * @param {Function} fn The method the event invokes.  Will be called with arguments given to
322      * {@link #fireEvent} plus the `options` parameter described below.
323      * @param {Object} [scope] The scope (`this` reference) in which the handler function is executed. **If
324      * omitted, defaults to the object which fired the event.**
325      * @param {Object} [options] An object containing handler configuration.
326      *
327      * **Note:** Unlike in ExtJS 3.x, the options object will also be passed as the last argument to every event handler.
328      *
329      * This object may contain any of the following properties:
330      *
331      * - **scope** : Object
332      *
333      *   The scope (`this` reference) in which the handler function is executed. **If omitted, defaults to the object
334      *   which fired the event.**
335      *
336      * - **delay** : Number
337      *
338      *   The number of milliseconds to delay the invocation of the handler after the event fires.
339      *
340      * - **single** : Boolean
341      *
342      *   True to add a handler to handle just the next firing of the event, and then remove itself.
343      *
344      * - **buffer** : Number
345      *
346      *   Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed by the specified number of
347      *   milliseconds. If the event fires again within that time, the original handler is _not_ invoked, but the new
348      *   handler is scheduled in its place.
349      *
350      * - **target** : Observable
351      *
352      *   Only call the handler if the event was fired on the target Observable, _not_ if the event was bubbled up from a
353      *   child Observable.
354      *
355      * - **element** : String
356      *
357      *   **This option is only valid for listeners bound to {@link Ext.Component Components}.** The name of a Component
358      *   property which references an element to add a listener to.
359      *
360      *   This option is useful during Component construction to add DOM event listeners to elements of
361      *   {@link Ext.Component Components} which will exist only after the Component is rendered.
362      *   For example, to add a click listener to a Panel's body:
363      *
364      *       new Ext.panel.Panel({
365      *           title: 'The title',
366      *           listeners: {
367      *               click: this.handlePanelClick,
368      *               element: 'body'
369      *           }
370      *       });
371      *
372      * **Combining Options**
373      *
374      * Using the options argument, it is possible to combine different types of listeners:
375      *
376      * A delayed, one-time listener.
377      *
378      *     myPanel.on('hide', this.handleClick, this, {
379      *         single: true,
380      *         delay: 100
381      *     });
382      *
383      * **Attaching multiple handlers in 1 call**
384      *
385      * The method also allows for a single argument to be passed which is a config object containing properties which
386      * specify multiple events. For example:
387      *
388      *     myGridPanel.on({
389      *         cellClick: this.onCellClick,
390      *         mouseover: this.onMouseOver,
391      *         mouseout: this.onMouseOut,
392      *         scope: this // Important. Ensure &quot;this&quot; is correct during handler execution
393      *     });
394      *
395      * One can also specify options for each event handler separately:
396      *
397      *     myGridPanel.on({
398      *         cellClick: {fn: this.onCellClick, scope: this, single: true},
399      *         mouseover: {fn: panel.onMouseOver, scope: panel}
400      *     });
401      *
402      */
403     addListener: function(ename, fn, scope, options) {
404         var me = this,
405             config,
406             event;
407
408         if (typeof ename !== 'string') {
409             options = ename;
410             for (ename in options) {
411                 if (options.hasOwnProperty(ename)) {
412                     config = options[ename];
413                     if (!me.eventOptionsRe.test(ename)) {
414                         me.addListener(ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
415                     }
416                 }
417             }
418         }
419         else {
420             ename = ename.toLowerCase();
421             me.events[ename] = me.events[ename] || true;
422             event = me.events[ename] || true;
423             if (Ext.isBoolean(event)) {
424                 me.events[ename] = event = new Ext.util.Event(me, ename);
425             }
426             event.addListener(fn, scope, Ext.isObject(options) ? options : {});
427         }
428     },
429
430 <span id='Ext-util-Observable-method-removeListener'>    /**
431 </span>     * Removes an event handler.
432      *
433      * @param {String} eventName The type of event the handler was associated with.
434      * @param {Function} fn The handler to remove. **This must be a reference to the function passed into the
435      * {@link #addListener} call.**
436      * @param {Object} scope (optional) The scope originally specified for the handler. It must be the same as the
437      * scope argument specified in the original call to {@link #addListener} or the listener will not be removed.
438      */
439     removeListener: function(ename, fn, scope) {
440         var me = this,
441             config,
442             event,
443             options;
444
445         if (typeof ename !== 'string') {
446             options = ename;
447             for (ename in options) {
448                 if (options.hasOwnProperty(ename)) {
449                     config = options[ename];
450                     if (!me.eventOptionsRe.test(ename)) {
451                         me.removeListener(ename, config.fn || config, config.scope || options.scope);
452                     }
453                 }
454             }
455         } else {
456             ename = ename.toLowerCase();
457             event = me.events[ename];
458             if (event &amp;&amp; event.isEvent) {
459                 event.removeListener(fn, scope);
460             }
461         }
462     },
463
464 <span id='Ext-util-Observable-method-clearListeners'>    /**
465 </span>     * Removes all listeners for this object including the managed listeners
466      */
467     clearListeners: function() {
468         var events = this.events,
469             event,
470             key;
471
472         for (key in events) {
473             if (events.hasOwnProperty(key)) {
474                 event = events[key];
475                 if (event.isEvent) {
476                     event.clearListeners();
477                 }
478             }
479         }
480
481         this.clearManagedListeners();
482     },
483
484     //&lt;debug&gt;
485     purgeListeners : function() {
486         if (Ext.global.console) {
487             Ext.global.console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
488         }
489         return this.clearListeners.apply(this, arguments);
490     },
491     //&lt;/debug&gt;
492
493 <span id='Ext-util-Observable-method-clearManagedListeners'>    /**
494 </span>     * Removes all managed listeners for this object.
495      */
496     clearManagedListeners : function() {
497         var managedListeners = this.managedListeners || [],
498             i = 0,
499             len = managedListeners.length;
500
501         for (; i &lt; len; i++) {
502             this.removeManagedListenerItem(true, managedListeners[i]);
503         }
504
505         this.managedListeners = [];
506     },
507
508 <span id='Ext-util-Observable-method-removeManagedListenerItem'>    /**
509 </span>     * Remove a single managed listener item
510      * @private
511      * @param {Boolean} isClear True if this is being called during a clear
512      * @param {Object} managedListener The managed listener item
513      * See removeManagedListener for other args
514      */
515     removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
516         if (isClear || (managedListener.item === item &amp;&amp; managedListener.ename === ename &amp;&amp; (!fn || managedListener.fn === fn) &amp;&amp; (!scope || managedListener.scope === scope))) {
517             managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
518             if (!isClear) {
519                 Ext.Array.remove(this.managedListeners, managedListener);
520             }
521         }
522     },
523
524     //&lt;debug&gt;
525     purgeManagedListeners : function() {
526         if (Ext.global.console) {
527             Ext.global.console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
528         }
529         return this.clearManagedListeners.apply(this, arguments);
530     },
531     //&lt;/debug&gt;
532
533 <span id='Ext-util-Observable-method-addEvents'>    /**
534 </span>     * Adds the specified events to the list of events which this Observable may fire.
535      *
536      * @param {Object/String} o Either an object with event names as properties with a value of `true` or the first
537      * event name string if multiple event names are being passed as separate parameters. Usage:
538      *
539      *     this.addEvents({
540      *         storeloaded: true,
541      *         storecleared: true
542      *     });
543      *
544      * @param {String...} more (optional) Additional event names if multiple event names are being passed as separate
545      * parameters. Usage:
546      *
547      *     this.addEvents('storeloaded', 'storecleared');
548      *
549      */
550     addEvents: function(o) {
551         var me = this,
552             args,
553             len,
554             i;
555
556             me.events = me.events || {};
557         if (Ext.isString(o)) {
558             args = arguments;
559             i = args.length;
560
561             while (i--) {
562                 me.events[args[i]] = me.events[args[i]] || true;
563             }
564         } else {
565             Ext.applyIf(me.events, o);
566         }
567     },
568
569 <span id='Ext-util-Observable-method-hasListener'>    /**
570 </span>     * Checks to see if this object has any listeners for a specified event
571      *
572      * @param {String} eventName The name of the event to check for
573      * @return {Boolean} True if the event is being listened for, else false
574      */
575     hasListener: function(ename) {
576         var event = this.events[ename.toLowerCase()];
577         return event &amp;&amp; event.isEvent === true &amp;&amp; event.listeners.length &gt; 0;
578     },
579
580 <span id='Ext-util-Observable-method-suspendEvents'>    /**
581 </span>     * Suspends the firing of all events. (see {@link #resumeEvents})
582      *
583      * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
584      * after the {@link #resumeEvents} call instead of discarding all suspended events.
585      */
586     suspendEvents: function(queueSuspended) {
587         this.eventsSuspended = true;
588         if (queueSuspended &amp;&amp; !this.eventQueue) {
589             this.eventQueue = [];
590         }
591     },
592
593 <span id='Ext-util-Observable-method-resumeEvents'>    /**
594 </span>     * Resumes firing events (see {@link #suspendEvents}).
595      *
596      * If events were suspended using the `queueSuspended` parameter, then all events fired
597      * during event suspension will be sent to any listeners now.
598      */
599     resumeEvents: function() {
600         var me = this,
601             queued = me.eventQueue;
602
603         me.eventsSuspended = false;
604         delete me.eventQueue;
605
606         if (queued) {
607             Ext.each(queued, function(e) {
608                 me.continueFireEvent.apply(me, e);
609             });
610         }
611     },
612
613 <span id='Ext-util-Observable-method-relayEvents'>    /**
614 </span>     * Relays selected events from the specified Observable as if the events were fired by `this`.
615      *
616      * @param {Object} origin The Observable whose events this object is to relay.
617      * @param {String[]} events Array of event names to relay.
618      * @param {String} prefix
619      */
620     relayEvents : function(origin, events, prefix) {
621         prefix = prefix || '';
622         var me = this,
623             len = events.length,
624             i = 0,
625             oldName,
626             newName;
627
628         for (; i &lt; len; i++) {
629             oldName = events[i].substr(prefix.length);
630             newName = prefix + oldName;
631             me.events[newName] = me.events[newName] || true;
632             origin.on(oldName, me.createRelayer(newName));
633         }
634     },
635
636 <span id='Ext-util-Observable-method-createRelayer'>    /**
637 </span>     * @private
638      * Creates an event handling function which refires the event from this object as the passed event name.
639      * @param newName
640      * @returns {Function}
641      */
642     createRelayer: function(newName){
643         var me = this;
644         return function(){
645             return me.fireEvent.apply(me, [newName].concat(Array.prototype.slice.call(arguments, 0, -1)));
646         };
647     },
648
649 <span id='Ext-util-Observable-method-enableBubble'>    /**
650 </span>     * Enables events fired by this Observable to bubble up an owner hierarchy by calling `this.getBubbleTarget()` if
651      * present. There is no implementation in the Observable base class.
652      *
653      * This is commonly used by Ext.Components to bubble events to owner Containers.
654      * See {@link Ext.Component#getBubbleTarget}. The default implementation in Ext.Component returns the
655      * Component's immediate owner. But if a known target is required, this can be overridden to access the
656      * required target more quickly.
657      *
658      * Example:
659      *
660      *     Ext.override(Ext.form.field.Base, {
661      *         //  Add functionality to Field's initComponent to enable the change event to bubble
662      *         initComponent : Ext.Function.createSequence(Ext.form.field.Base.prototype.initComponent, function() {
663      *             this.enableBubble('change');
664      *         }),
665      *
666      *         //  We know that we want Field's events to bubble directly to the FormPanel.
667      *         getBubbleTarget : function() {
668      *             if (!this.formPanel) {
669      *                 this.formPanel = this.findParentByType('form');
670      *             }
671      *             return this.formPanel;
672      *         }
673      *     });
674      *
675      *     var myForm = new Ext.formPanel({
676      *         title: 'User Details',
677      *         items: [{
678      *             ...
679      *         }],
680      *         listeners: {
681      *             change: function() {
682      *                 // Title goes red if form has been modified.
683      *                 myForm.header.setStyle('color', 'red');
684      *             }
685      *         }
686      *     });
687      *
688      * @param {String/String[]} events The event name to bubble, or an Array of event names.
689      */
690     enableBubble: function(events) {
691         var me = this;
692         if (!Ext.isEmpty(events)) {
693             events = Ext.isArray(events) ? events: Ext.Array.toArray(arguments);
694             Ext.each(events,
695             function(ename) {
696                 ename = ename.toLowerCase();
697                 var ce = me.events[ename] || true;
698                 if (Ext.isBoolean(ce)) {
699                     ce = new Ext.util.Event(me, ename);
700                     me.events[ename] = ce;
701                 }
702                 ce.bubble = true;
703             });
704         }
705     }
706 }, function() {
707
708     this.createAlias({
709 <span id='Ext-util-Observable-method-on'>        /**
710 </span>         * @method
711          * Shorthand for {@link #addListener}.
712          * @alias Ext.util.Observable#addListener
713          */
714         on: 'addListener',
715 <span id='Ext-util-Observable-method-un'>        /**
716 </span>         * @method
717          * Shorthand for {@link #removeListener}.
718          * @alias Ext.util.Observable#removeListener
719          */
720         un: 'removeListener',
721 <span id='Ext-util-Observable-method-mon'>        /**
722 </span>         * @method
723          * Shorthand for {@link #addManagedListener}.
724          * @alias Ext.util.Observable#addManagedListener
725          */
726         mon: 'addManagedListener',
727 <span id='Ext-util-Observable-method-mun'>        /**
728 </span>         * @method
729          * Shorthand for {@link #removeManagedListener}.
730          * @alias Ext.util.Observable#removeManagedListener
731          */
732         mun: 'removeManagedListener'
733     });
734
735     //deprecated, will be removed in 5.0
736     this.observeClass = this.observe;
737
738     Ext.apply(Ext.util.Observable.prototype, function(){
739         // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
740         // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
741         // private
742         function getMethodEvent(method){
743             var e = (this.methodEvents = this.methodEvents || {})[method],
744                 returnValue,
745                 v,
746                 cancel,
747                 obj = this;
748
749             if (!e) {
750                 this.methodEvents[method] = e = {};
751                 e.originalFn = this[method];
752                 e.methodName = method;
753                 e.before = [];
754                 e.after = [];
755
756                 var makeCall = function(fn, scope, args){
757                     if((v = fn.apply(scope || obj, args)) !== undefined){
758                         if (typeof v == 'object') {
759                             if(v.returnValue !== undefined){
760                                 returnValue = v.returnValue;
761                             }else{
762                                 returnValue = v;
763                             }
764                             cancel = !!v.cancel;
765                         }
766                         else
767                             if (v === false) {
768                                 cancel = true;
769                             }
770                             else {
771                                 returnValue = v;
772                             }
773                     }
774                 };
775
776                 this[method] = function(){
777                     var args = Array.prototype.slice.call(arguments, 0),
778                         b, i, len;
779                     returnValue = v = undefined;
780                     cancel = false;
781
782                     for(i = 0, len = e.before.length; i &lt; len; i++){
783                         b = e.before[i];
784                         makeCall(b.fn, b.scope, args);
785                         if (cancel) {
786                             return returnValue;
787                         }
788                     }
789
790                     if((v = e.originalFn.apply(obj, args)) !== undefined){
791                         returnValue = v;
792                     }
793
794                     for(i = 0, len = e.after.length; i &lt; len; i++){
795                         b = e.after[i];
796                         makeCall(b.fn, b.scope, args);
797                         if (cancel) {
798                             return returnValue;
799                         }
800                     }
801                     return returnValue;
802                 };
803             }
804             return e;
805         }
806
807         return {
808             // these are considered experimental
809             // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
810             // adds an 'interceptor' called before the original method
811             beforeMethod : function(method, fn, scope){
812                 getMethodEvent.call(this, method).before.push({
813                     fn: fn,
814                     scope: scope
815                 });
816             },
817
818             // adds a 'sequence' called after the original method
819             afterMethod : function(method, fn, scope){
820                 getMethodEvent.call(this, method).after.push({
821                     fn: fn,
822                     scope: scope
823                 });
824             },
825
826             removeMethodListener: function(method, fn, scope){
827                 var e = this.getMethodEvent(method),
828                     i, len;
829                 for(i = 0, len = e.before.length; i &lt; len; i++){
830                     if(e.before[i].fn == fn &amp;&amp; e.before[i].scope == scope){
831                         Ext.Array.erase(e.before, i, 1);
832                         return;
833                     }
834                 }
835                 for(i = 0, len = e.after.length; i &lt; len; i++){
836                     if(e.after[i].fn == fn &amp;&amp; e.after[i].scope == scope){
837                         Ext.Array.erase(e.after, i, 1);
838                         return;
839                     }
840                 }
841             },
842
843             toggleEventLogging: function(toggle) {
844                 Ext.util.Observable[toggle ? 'capture' : 'releaseCapture'](this, function(en) {
845                     if (Ext.isDefined(Ext.global.console)) {
846                         Ext.global.console.log(en, arguments);
847                     }
848                 });
849             }
850         };
851     }());
852 });
853 </pre>
854 </body>
855 </html>