4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
13 * @class Roo.util.Observable
14 * Base class that provides a common interface for publishing events. Subclasses are expected to
15 * to have a property "events" with all the events defined.<br>
18 Employee = function(name){
25 Roo.extend(Employee, Roo.util.Observable);
27 * @param {Object} config properties to use (incuding events / listeners)
30 Roo.util.Observable = function(cfg){
31 console.log("UTIL OBSERVABLE CONSTRUCTOR");
35 this.addEvents(cfg.events || {});
37 delete cfg.events; // make sure
43 this.on(this.listeners);
44 delete this.listeners;
47 Roo.util.Observable.prototype = {
49 * @cfg {Object} listeners list of events and functions to call for this object,
53 'click' : function(e) {
63 * Fires the specified event with the passed parameters (minus the event name).
64 * @param {String} eventName
65 * @param {Object...} args Variable number of parameters are passed to handlers
66 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
68 fireEvent : function(){
69 var ce = this.events[arguments[0].toLowerCase()];
70 if(typeof ce == "object"){
71 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
78 filterOptRe : /^(?:scope|delay|buffer|single)$/,
81 * Appends an event handler to this component
82 * @param {String} eventName The type of event to listen for
83 * @param {Function} handler The method the event invokes
84 * @param {Object} scope (optional) The scope in which to execute the handler
85 * function. The handler function's "this" context.
86 * @param {Object} options (optional) An object containing handler configuration
87 * properties. This may contain any of the following properties:<ul>
88 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
89 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
90 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
91 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
92 * by the specified number of milliseconds. If the event fires again within that time, the original
93 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
96 * <b>Combining Options</b><br>
97 * Using the options argument, it is possible to combine different types of listeners:<br>
99 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
101 el.on('click', this.onClick, this, {
108 * <b>Attaching multiple handlers in 1 call</b><br>
109 * The method also allows for a single argument to be passed which is a config object containing properties
110 * which specify multiple handlers.
119 fn: this.onMouseOver,
129 * Or a shorthand syntax which passes the same scope object to all handlers:
132 'click': this.onClick,
133 'mouseover': this.onMouseOver,
134 'mouseout': this.onMouseOut,
139 addListener : function(eventName, fn, scope, o){
140 if(typeof eventName == "object"){
143 if(this.filterOptRe.test(e)){
146 if(typeof o[e] == "function"){
148 this.addListener(e, o[e], o.scope, o);
150 // individual options
151 this.addListener(e, o[e].fn, o[e].scope, o[e]);
156 o = (!o || typeof o == "boolean") ? {} : o;
157 eventName = eventName.toLowerCase();
158 var ce = this.events[eventName] || true;
159 if(typeof ce == "boolean"){
160 ce = new Roo.util.Event(this, eventName);
161 this.events[eventName] = ce;
163 ce.addListener(fn, scope, o);
168 * @param {String} eventName The type of event to listen for
169 * @param {Function} handler The handler to remove
170 * @param {Object} scope (optional) The scope (this object) for the handler
172 removeListener : function(eventName, fn, scope){
173 var ce = this.events[eventName.toLowerCase()];
174 if(typeof ce == "object"){
175 ce.removeListener(fn, scope);
180 * Removes all listeners for this object
182 purgeListeners : function(){
183 for(var evt in this.events){
184 if(typeof this.events[evt] == "object"){
185 this.events[evt].clearListeners();
190 relayEvents : function(o, events){
191 var createHandler = function(ename){
194 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
197 for(var i = 0, len = events.length; i < len; i++){
198 var ename = events[i];
199 if(!this.events[ename]){
200 this.events[ename] = true;
202 o.on(ename, createHandler(ename), this);
207 * Used to define events on this Observable
208 * @param {Object} object The object with the events defined
210 addEvents : function(o){
214 Roo.applyIf(this.events, o);
218 * Checks to see if this object has any listeners for a specified event
219 * @param {String} eventName The name of the event to check for
220 * @return {Boolean} True if the event is being listened for, else false
222 hasListener : function(eventName){
223 var e = this.events[eventName];
224 return typeof e == "object" && e.listeners.length > 0;
228 * Appends an event handler to this element (shorthand for addListener)
229 * @param {String} eventName The type of event to listen for
230 * @param {Function} handler The method the event invokes
231 * @param {Object} scope (optional) The scope in which to execute the handler
232 * function. The handler function's "this" context.
233 * @param {Object} options (optional)
236 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
238 * Removes a listener (shorthand for removeListener)
239 * @param {String} eventName The type of event to listen for
240 * @param {Function} handler The handler to remove
241 * @param {Object} scope (optional) The scope (this object) for the handler
244 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
247 * Starts capture on the specified Observable. All events will be passed
248 * to the supplied function with the event name + standard signature of the event
249 * <b>before</b> the event is fired. If the supplied function returns false,
250 * the event will not fire.
251 * @param {Observable} o The Observable to capture
252 * @param {Function} fn The function to call
253 * @param {Object} scope (optional) The scope (this object) for the fn
256 Roo.util.Observable.capture = function(o, fn, scope){
257 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
261 * Removes <b>all</b> added captures from the Observable.
262 * @param {Observable} o The Observable to release
265 Roo.util.Observable.releaseCapture = function(o){
266 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
271 var createBuffered = function(h, o, scope){
272 var task = new Roo.util.DelayedTask();
274 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
278 var createSingle = function(h, e, fn, scope){
280 e.removeListener(fn, scope);
281 return h.apply(scope, arguments);
285 var createDelayed = function(h, o, scope){
287 var args = Array.prototype.slice.call(arguments, 0);
288 setTimeout(function(){
289 h.apply(scope, args);
294 Roo.util.Event = function(obj, name){
300 Roo.util.Event.prototype = {
301 addListener : function(fn, scope, options){
302 var o = options || {};
303 scope = scope || this.obj;
304 if(!this.isListening(fn, scope)){
305 var l = {fn: fn, scope: scope, options: o};
308 h = createDelayed(h, o, scope);
311 h = createSingle(h, this, fn, scope);
314 h = createBuffered(h, o, scope);
317 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
318 this.listeners.push(l);
320 this.listeners = this.listeners.slice(0);
321 this.listeners.push(l);
326 findListener : function(fn, scope){
327 scope = scope || this.obj;
328 var ls = this.listeners;
329 for(var i = 0, len = ls.length; i < len; i++){
331 if(l.fn == fn && l.scope == scope){
338 isListening : function(fn, scope){
339 return this.findListener(fn, scope) != -1;
342 removeListener : function(fn, scope){
344 if((index = this.findListener(fn, scope)) != -1){
346 this.listeners.splice(index, 1);
348 this.listeners = this.listeners.slice(0);
349 this.listeners.splice(index, 1);
356 clearListeners : function(){
361 var ls = this.listeners, scope, len = ls.length;
364 var args = Array.prototype.slice.call(arguments, 0);
365 for(var i = 0; i < len; i++){
367 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){