/*!
 * Ext JS Library 3.2.1
 * Copyright(c) 2006-2010 Ext JS, Inc.
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/**
 * @class Ext.util.Observable
 */
Ext.apply(Ext.util.Observable.prototype, function(){
    // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
    // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
    // private
    function getMethodEvent(method){
        var e = (this.methodEvents = this.methodEvents ||
        {})[method], returnValue, v, cancel, obj = this;

        if (!e) {
            this.methodEvents[method] = e = {};
            e.originalFn = this[method];
            e.methodName = method;
            e.before = [];
            e.after = [];

            var makeCall = function(fn, scope, args){
                if((v = fn.apply(scope || obj, args)) !== undefined){
                    if (typeof v == 'object') {
                        if(v.returnValue !== undefined){
                            returnValue = v.returnValue;
                        }else{
                            returnValue = v;
                        }
                        cancel = !!v.cancel;
                    }
                    else
                        if (v === false) {
                            cancel = true;
                        }
                        else {
                            returnValue = v;
                        }
                }
            };

            this[method] = function(){
                var args = Array.prototype.slice.call(arguments, 0),
                    b;
                returnValue = v = undefined;
                cancel = false;

                for(var i = 0, len = e.before.length; i < len; i++){
                    b = e.before[i];
                    makeCall(b.fn, b.scope, args);
                    if (cancel) {
                        return returnValue;
                    }
                }

                if((v = e.originalFn.apply(obj, args)) !== undefined){
                    returnValue = v;
                }

                for(var i = 0, len = e.after.length; i < len; i++){
                    b = e.after[i];
                    makeCall(b.fn, b.scope, args);
                    if (cancel) {
                        return returnValue;
                    }
                }
                return returnValue;
            };
        }
        return e;
    }

    return {
        // these are considered experimental
        // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
        // adds an 'interceptor' called before the original method
        beforeMethod : function(method, fn, scope){
            getMethodEvent.call(this, method).before.push({
                fn: fn,
                scope: scope
            });
        },

        // adds a 'sequence' called after the original method
        afterMethod : function(method, fn, scope){
            getMethodEvent.call(this, method).after.push({
                fn: fn,
                scope: scope
            });
        },

        removeMethodListener: function(method, fn, scope){
            var e = this.getMethodEvent(method);
            for(var i = 0, len = e.before.length; i < len; i++){
                if(e.before[i].fn == fn && e.before[i].scope == scope){
                    e.before.splice(i, 1);
                    return;
                }
            }
            for(var i = 0, len = e.after.length; i < len; i++){
                if(e.after[i].fn == fn && e.after[i].scope == scope){
                    e.after.splice(i, 1);
                    return;
                }
            }
        },

        
/** * Relays selected events from the specified Observable as if the events were fired by this. * @param {Object} o The Observable whose events this object is to relay. * @param {Array} events Array of event names to relay. */ relayEvents : function(o, events){ var me = this; function createHandler(ename){ return function(){ return me.fireEvent.apply(me, [ename].concat(Array.prototype.slice.call(arguments, 0))); }; } for(var i = 0, len = events.length; i < len; i++){ var ename = events[i]; me.events[ename] = me.events[ename] || true; o.on(ename, createHandler(ename), me); } },
/** *

Enables events fired by this Observable to bubble up an owner hierarchy by calling * this.getBubbleTarget() if present. There is no implementation in the Observable base class.

*

This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to * access the required target more quickly.

*

Example:


Ext.override(Ext.form.Field, {
    //  Add functionality to Field's initComponent to enable the change event to bubble
    initComponent : Ext.form.Field.prototype.initComponent.createSequence(function() {
        this.enableBubble('change');
    }),

    //  We know that we want Field's events to bubble directly to the FormPanel.
    getBubbleTarget : function() {
        if (!this.formPanel) {
            this.formPanel = this.findParentByType('form');
        }
        return this.formPanel;
    }
});

var myForm = new Ext.formPanel({
    title: 'User Details',
    items: [{
        ...
    }],
    listeners: {
        change: function() {
            // Title goes red if form has been modified.
            myForm.header.setStyle('color', 'red');
        }
    }
});
* @param {String/Array} events The event name to bubble, or an Array of event names. */ enableBubble : function(events){ var me = this; if(!Ext.isEmpty(events)){ events = Ext.isArray(events) ? events : Array.prototype.slice.call(arguments, 0); for(var i = 0, len = events.length; i < len; i++){ var ename = events[i]; ename = ename.toLowerCase(); var ce = me.events[ename] || true; if (typeof ce == 'boolean') { ce = new Ext.util.Event(me, ename); me.events[ename] = ce; } ce.bubble = true; } } } }; }());
/** * Starts capture on the specified Observable. All events will be passed * to the supplied function with the event name + standard signature of the event * before the event is fired. If the supplied function returns false, * the event will not fire. * @param {Observable} o The Observable to capture events from. * @param {Function} fn The function to call when an event is fired. * @param {Object} scope (optional) The scope (this reference) in which the function is executed. Defaults to the Observable firing the event. * @static */ Ext.util.Observable.capture = function(o, fn, scope){ o.fireEvent = o.fireEvent.createInterceptor(fn, scope); };
/** * Sets observability on the passed class constructor.

*

This makes any event fired on any instance of the passed class also fire a single event through * the class allowing for central handling of events on many instances at once.

*

Usage:


Ext.util.Observable.observeClass(Ext.data.Connection);
Ext.data.Connection.on('beforerequest', function(con, options) {
    console.log('Ajax request made to ' + options.url);
});
* @param {Function} c The class constructor to make observable. * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}. * @static */ Ext.util.Observable.observeClass = function(c, listeners){ if(c){ if(!c.fireEvent){ Ext.apply(c, new Ext.util.Observable()); Ext.util.Observable.capture(c.prototype, c.fireEvent, c); } if(typeof listeners == 'object'){ c.on(listeners); } return c; } };