3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * @class Ext.util.Observable
10 Ext.apply(Ext.util.Observable.prototype, function(){
11 // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
12 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
14 function getMethodEvent(method){
15 var e = (this.methodEvents = this.methodEvents ||
16 {})[method], returnValue, v, cancel, obj = this;
19 this.methodEvents[method] = e = {};
20 e.originalFn = this[method];
21 e.methodName = method;
25 var makeCall = function(fn, scope, args){
26 if (!Ext.isEmpty(v = fn.apply(scope || obj, args))) {
27 if (Ext.isObject(v)) {
28 returnValue = !Ext.isEmpty(v.returnValue) ? v.returnValue : v;
41 this[method] = function(){
42 var args = Ext.toArray(arguments);
43 returnValue = v = undefined;
46 Ext.each(e.before, function(b){
47 makeCall(b.fn, b.scope, args);
53 if (!Ext.isEmpty(v = e.originalFn.apply(obj, args))) {
56 Ext.each(e.after, function(a){
57 makeCall(a.fn, a.scope, args);
69 // these are considered experimental
70 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
71 // adds an 'interceptor' called before the original method
72 beforeMethod : function(method, fn, scope){
73 getMethodEvent.call(this, method).before.push({
79 // adds a 'sequence' called after the original method
80 afterMethod : function(method, fn, scope){
81 getMethodEvent.call(this, method).after.push({
87 removeMethodListener: function(method, fn, scope){
88 var e = getMethodEvent.call(this, method), found = false;
89 Ext.each(e.before, function(b, i, arr){
90 if (b.fn == fn && b.scope == scope) {
97 Ext.each(e.after, function(a, i, arr){
98 if (a.fn == fn && a.scope == scope) {
107 * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.
108 * @param {Object} o The Observable whose events this object is to relay.
109 * @param {Array} events Array of event names to relay.
111 relayEvents : function(o, events){
113 function createHandler(ename){
115 return me.fireEvent.apply(me, [ename].concat(Ext.toArray(arguments)));
118 Ext.each(events, function(ename){
119 me.events[ename] = me.events[ename] || true;
120 o.on(ename, createHandler(ename), me);
125 * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling
126 * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>
127 * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default
128 * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to
129 * access the required target more quickly.</p>
130 * <p>Example:</p><pre><code>
131 Ext.override(Ext.form.Field, {
132 // Add functionality to Field's initComponent to enable the change event to bubble
133 initComponent : Ext.form.Field.prototype.initComponent.createSequence(function() {
134 this.enableBubble('change');
137 // We know that we want Field's events to bubble directly to the FormPanel.
138 getBubbleTarget : function() {
139 if (!this.formPanel) {
140 this.formPanel = this.findParentByType('form');
142 return this.formPanel;
146 var myForm = new Ext.formPanel({
147 title: 'User Details',
153 // Title goes red if form has been modified.
154 myForm.header.setStyle('color', 'red');
159 * @param {String/Array} events The event name to bubble, or an Array of event names.
161 enableBubble : function(events){
163 if(!Ext.isEmpty(events)){
164 events = Ext.isArray(events) ? events : Ext.toArray(arguments);
165 Ext.each(events, function(ename){
166 ename = ename.toLowerCase();
167 var ce = me.events[ename] || true;
168 if (Ext.isBoolean(ce)) {
169 ce = new Ext.util.Event(me, ename);
170 me.events[ename] = ce;
181 * Starts capture on the specified Observable. All events will be passed
182 * to the supplied function with the event name + standard signature of the event
183 * <b>before</b> the event is fired. If the supplied function returns false,
184 * the event will not fire.
185 * @param {Observable} o The Observable to capture events from.
186 * @param {Function} fn The function to call when an event is fired.
187 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Observable firing the event.
190 Ext.util.Observable.capture = function(o, fn, scope){
191 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
196 * Sets observability on the passed class constructor.<p>
197 * <p>This makes any event fired on any instance of the passed class also fire a single event through
198 * the <i>class</i> allowing for central handling of events on many instances at once.</p>
199 * <p>Usage:</p><pre><code>
200 Ext.util.Observable.observeClass(Ext.data.Connection);
201 Ext.data.Connection.on('beforerequest', function(con, options) {
202 console.log('Ajax request made to ' + options.url);
204 * @param {Function} c The class constructor to make observable.
205 * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
208 Ext.util.Observable.observeClass = function(c, listeners){
211 Ext.apply(c, new Ext.util.Observable());
212 Ext.util.Observable.capture(c.prototype, c.fireEvent, c);
214 if(Ext.isObject(listeners)){