(function(){

var EXTUTIL = Ext.util, 
    TOARRAY = Ext.toArray, 
    EACH = Ext.each, 
    ISOBJECT = Ext.isObject
    TRUE = true,
    FALSE = false;
/** * @class Ext.util.Observable * Abstract base class that provides a common interface for publishing events. Subclasses are expected to * to have a property "events" with all the events defined.
* For example: *

 Employee = function(name){
    this.name = name;
    this.addEvents({
        "fired" : true,
        "quit" : true
    });
 }
 Ext.extend(Employee, Ext.util.Observable);
*/ EXTUTIL.Observable = function(){
/** * @cfg {Object} listeners (optional) A config object containing one or more event handlers to be added to this * object during initialization. This should be a valid listeners config object as specified in the * {@link #addListener} example for attaching multiple handlers at once. */ var me = this, e = me.events; if(me.listeners){ me.on(me.listeners); delete me.listeners; } me.events = e || {}; }; EXTUTIL.Observable.prototype = function(){ var filterOptRe = /^(?:scope|delay|buffer|single)$/, toLower = function(s){ return s.toLowerCase(); }; return {
/** *

Fires the specified event with the passed parameters (minus the event name).

*

An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget}) * by calling {@link #enableBubble}.

* @param {String} eventName The name of the event to fire. * @param {Object...} args Variable number of parameters are passed to handlers. * @return {Boolean} returns false if any of the handlers return false otherwise it returns true. */ fireEvent : function(){ var a = TOARRAY(arguments), ename = toLower(a[0]), me = this, ret = TRUE, ce = me.events[ename], q, c; if (me.eventsSuspended === TRUE) { if (q = me.suspendedEventsQueue) { q.push(a); } } else if(ISOBJECT(ce) && ce.bubble){ if(ce.fire.apply(ce, a.slice(1)) === FALSE) { return FALSE; } c = me.getBubbleTarget && me.getBubbleTarget(); if(c && c.enableBubble) { c.enableBubble(ename); return c.fireEvent.apply(c, a); } } else { if (ISOBJECT(ce)) { a.shift(); ret = ce.fire.apply(ce, a); } } return ret; },
/** * Appends an event handler to this component * @param {String} eventName The type of event to listen for * @param {Function} handler The method the event invokes * @param {Object} scope (optional) The scope in which to execute the handler * function. The handler function's "this" context. * @param {Object} options (optional) An object containing handler configuration * properties. This may contain any of the following properties:
*

* Combining Options
* Using the options argument, it is possible to combine different types of listeners:
*
* A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId) *


	el.on('click', this.onClick, this, {
	    single: true,
	    delay: 100,
	    forumId: 4
	});
*

* Attaching multiple handlers in 1 call
* The method also allows for a single argument to be passed which is a config object containing properties * which specify multiple handlers. *

*


	foo.on({
	    'click' : {
	        fn: this.onClick,
	        scope: this,
	        delay: 100
	    },
	    'mouseover' : {
	        fn: this.onMouseOver,
	        scope: this
	    },
	    'mouseout' : {
	        fn: this.onMouseOut,
	        scope: this
	    }
	});
*

* Or a shorthand syntax:
*


	foo.on({
	    'click' : this.onClick,
	    'mouseover' : this.onMouseOver,
	    'mouseout' : this.onMouseOut,
	     scope: this
	});
*/ addListener : function(eventName, fn, scope, o){ var me = this, e, oe, isF, ce; if (ISOBJECT(eventName)) { o = eventName; for (e in o){ oe = o[e]; if (!filterOptRe.test(e)) { me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o); } } } else { eventName = toLower(eventName); ce = me.events[eventName] || TRUE; if (typeof ce == "boolean") { me.events[eventName] = ce = new EXTUTIL.Event(me, eventName); } ce.addListener(fn, scope, ISOBJECT(o) ? o : {}); } },
/** * Removes a listener * @param {String} eventName The type of event to listen for * @param {Function} handler The handler to remove * @param {Object} scope (optional) The scope (this object) for the handler */ removeListener : function(eventName, fn, scope){ var ce = this.events[toLower(eventName)]; if (ISOBJECT(ce)) { ce.removeListener(fn, scope); } },
/** * Removes all listeners for this object */ purgeListeners : function(){ var events = this.events, evt, key; for(key in events){ evt = events[key]; if(ISOBJECT(evt)){ evt.clearListeners(); } } },
/** * Used to define events on this Observable * @param {Object} object The object with the events defined */ addEvents : function(o){ var me = this; me.events = me.events || {}; if (typeof o == 'string') { EACH(arguments, function(a) { me.events[a] = me.events[a] || TRUE; }); } else { Ext.applyIf(me.events, o); } },
/** * Checks to see if this object has any listeners for a specified event * @param {String} eventName The name of the event to check for * @return {Boolean} True if the event is being listened for, else false */ hasListener : function(eventName){ var e = this.events[eventName]; return ISOBJECT(e) && e.listeners.length > 0; },
/** * Suspend the firing of all events. (see {@link #resumeEvents}) * @param queueSuspended {Boolean} Pass as true to queue up suspended events to be fired * after the {@link #resumeEvents} call instead of discarding all suspended events; */ suspendEvents : function(queueSuspended){ this.eventsSuspended = TRUE; if (queueSuspended){ this.suspendedEventsQueue = []; } },
/** * Resume firing events. (see {@link #suspendEvents}) * If events were suspended using the queueSuspended parameter, then all * events fired during event suspension will be sent to any listeners now. */ resumeEvents : function(){ var me = this; me.eventsSuspended = !delete me.suspendedEventQueue; EACH(me.suspendedEventsQueue, function(e) { me.fireEvent.apply(me, e); }); } } }(); var OBSERVABLE = EXTUTIL.Observable.prototype;
/** * Appends an event handler to this element (shorthand for addListener) * @param {String} eventName The type of event to listen for * @param {Function} handler The method the event invokes * @param {Object} scope (optional) The scope in which to execute the handler * function. The handler function's "this" context. * @param {Object} options (optional) * @method */ OBSERVABLE.on = OBSERVABLE.addListener;
/** * Removes a listener (shorthand for removeListener) * @param {String} eventName The type of event to listen for * @param {Function} handler The handler to remove * @param {Object} scope (optional) The scope (this object) for the handler * @method */ OBSERVABLE.un = OBSERVABLE.removeListener;
/** * Removes all added captures from the Observable. * @param {Observable} o The Observable to release * @static */ EXTUTIL.Observable.releaseCapture = function(o){ o.fireEvent = OBSERVABLE.fireEvent; }; function createTargeted(h, o, scope){ return function(){ if(o.target == arguments[0]){ h.apply(scope, TOARRAY(arguments)); } }; }; function createBuffered(h, o, scope){ var task = new EXTUTIL.DelayedTask(); return function(){ task.delay(o.buffer, h, scope, TOARRAY(arguments)); }; } function createSingle(h, e, fn, scope){ return function(){ e.removeListener(fn, scope); return h.apply(scope, arguments); }; } function createDelayed(h, o, scope){ return function(){ var args = TOARRAY(arguments); (function(){ h.apply(scope, args); }).defer(o.delay || 10); }; }; EXTUTIL.Event = function(obj, name){ this.name = name; this.obj = obj; this.listeners = []; }; EXTUTIL.Event.prototype = { addListener : function(fn, scope, options){ var me = this, l; scope = scope || me.obj; if(!me.isListening(fn, scope)){ l = me.createListener(fn, scope, options); if(me.firing){ // if we are currently firing this event, don't disturb the listener loop me.listeners = me.listeners.slice(0); } me.listeners.push(l); } }, createListener: function(fn, scope, o){ o = o || {}, scope = scope || this.obj; var l = { fn: fn, scope: scope, options: o }, h = fn; if(o.target){ h = createTargeted(h, o, scope); } if(o.delay){ h = createDelayed(h, o, scope); } if(o.single){ h = createSingle(h, this, fn, scope); } if(o.buffer){ h = createBuffered(h, o, scope); } l.fireFn = h; return l; }, findListener : function(fn, scope){ var s, ret = -1 EACH(this.listeners, function(l, i) { s = l.scope; if(l.fn == fn && (s == scope || s == this.obj)){ ret = i; return FALSE; } }, this); return ret; }, isListening : function(fn, scope){ return this.findListener(fn, scope) != -1; }, removeListener : function(fn, scope){ var index, me = this, ret = FALSE; if((index = me.findListener(fn, scope)) != -1){ if (me.firing) { me.listeners = me.listeners.slice(0); } me.listeners.splice(index, 1); ret = TRUE; } return ret; }, clearListeners : function(){ this.listeners = []; }, fire : function(){ var me = this, args = TOARRAY(arguments), ret = TRUE; EACH(me.listeners, function(l) { me.firing = TRUE; if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) { return ret = me.firing = FALSE; } }); me.firing = FALSE; return ret; } }; })();