3
* Copyright(c) 2006-2008, Ext JS, LLC.
6
* http://extjs.com/license
10
* @class Ext.util.Observable
11
* Abstract base class that provides a common interface for publishing events. Subclasses are expected to
12
* to have a property "events" with all the events defined.<br>
15
Employee = function(name){
22
Ext.extend(Employee, Ext.util.Observable);
25
Ext.util.Observable = function(){
27
* @cfg {Object} listeners A config object containing one or more event handlers to be added to this
28
* object during initialization. This should be a valid listeners config object as specified in the
29
* {@link #addListener} example for attaching multiple handlers at once.
32
this.on(this.listeners);
33
delete this.listeners;
36
Ext.util.Observable.prototype = {
38
* Fires the specified event with the passed parameters (minus the event name).
39
* @param {String} eventName
40
* @param {Object...} args Variable number of parameters are passed to handlers
41
* @return {Boolean} returns false if any of the handlers return false otherwise it returns true
43
fireEvent : function(){
44
if(this.eventsSuspended !== true){
45
var ce = this.events[arguments[0].toLowerCase()];
46
if(typeof ce == "object"){
47
return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
54
filterOptRe : /^(?:scope|delay|buffer|single)$/,
57
* Appends an event handler to this component
58
* @param {String} eventName The type of event to listen for
59
* @param {Function} handler The method the event invokes
60
* @param {Object} scope (optional) The scope in which to execute the handler
61
* function. The handler function's "this" context.
62
* @param {Object} options (optional) An object containing handler configuration
63
* properties. This may contain any of the following properties:<ul>
64
* <li><b>scope</b> : Object<p class="sub-desc">The scope in which to execute the handler function. The handler function's "this" context.</p></li>
65
* <li><b>delay</b> : Number<p class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</p></li>
66
* <li><b>single</b> : Boolean<p class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</p></li>
67
* <li><b>buffer</b> : Number<p class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
68
* by the specified number of milliseconds. If the event fires again within that time, the original
69
* handler is <em>not</em> invoked, but the new handler is scheduled in its place.</p></li>
72
* <b>Combining Options</b><br>
73
* Using the options argument, it is possible to combine different types of listeners:<br>
75
* A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
77
el.on('click', this.onClick, this, {
83
* <b>Attaching multiple handlers in 1 call</b><br>
84
* The method also allows for a single argument to be passed which is a config object containing properties
85
* which specify multiple handlers.
104
* Or a shorthand syntax:<br>
107
'click' : this.onClick,
108
'mouseover' : this.onMouseOver,
109
'mouseout' : this.onMouseOut,
113
addListener : function(eventName, fn, scope, o){
114
if(typeof eventName == "object"){
117
if(this.filterOptRe.test(e)){
120
if(typeof o[e] == "function"){
122
this.addListener(e, o[e], o.scope, o);
124
// individual options
125
this.addListener(e, o[e].fn, o[e].scope, o[e]);
130
o = (!o || typeof o == "boolean") ? {} : o;
131
eventName = eventName.toLowerCase();
132
var ce = this.events[eventName] || true;
133
if(typeof ce == "boolean"){
134
ce = new Ext.util.Event(this, eventName);
135
this.events[eventName] = ce;
137
ce.addListener(fn, scope, o);
142
* @param {String} eventName The type of event to listen for
143
* @param {Function} handler The handler to remove
144
* @param {Object} scope (optional) The scope (this object) for the handler
146
removeListener : function(eventName, fn, scope){
147
var ce = this.events[eventName.toLowerCase()];
148
if(typeof ce == "object"){
149
ce.removeListener(fn, scope);
154
* Removes all listeners for this object
156
purgeListeners : function(){
157
for(var evt in this.events){
158
if(typeof this.events[evt] == "object"){
159
this.events[evt].clearListeners();
165
* Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.
166
* @param {Object} o The Observable whose events this object is to relay.
167
* @param {Array} events Array of event names to relay.
169
relayEvents : function(o, events){
170
var createHandler = function(ename){
172
return this.fireEvent.apply(this, Ext.combine(ename, Array.prototype.slice.call(arguments, 0)));
175
for(var i = 0, len = events.length; i < len; i++){
176
var ename = events[i];
177
if(!this.events[ename]){ this.events[ename] = true; };
178
o.on(ename, createHandler(ename), this);
183
* Used to define events on this Observable
184
* @param {Object} object The object with the events defined
186
addEvents : function(o){
190
if(typeof o == 'string'){
191
for(var i = 0, a = arguments, v; v = a[i]; i++){
192
if(!this.events[a[i]]){
193
this.events[a[i]] = true;
197
Ext.applyIf(this.events, o);
202
* Checks to see if this object has any listeners for a specified event
203
* @param {String} eventName The name of the event to check for
204
* @return {Boolean} True if the event is being listened for, else false
206
hasListener : function(eventName){
207
var e = this.events[eventName];
208
return typeof e == "object" && e.listeners.length > 0;
212
* Suspend the firing of all events. (see {@link #resumeEvents})
214
suspendEvents : function(){
215
this.eventsSuspended = true;
219
* Resume firing events. (see {@link #suspendEvents})
221
resumeEvents : function(){
222
this.eventsSuspended = false;
225
// these are considered experimental
226
// allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
228
getMethodEvent : function(method){
229
if(!this.methodEvents){
230
this.methodEvents = {};
232
var e = this.methodEvents[method];
235
this.methodEvents[method] = e;
237
e.originalFn = this[method];
238
e.methodName = method;
243
var returnValue, v, cancel;
246
var makeCall = function(fn, scope, args){
247
if((v = fn.apply(scope || obj, args)) !== undefined){
248
if(typeof v === 'object'){
249
if(v.returnValue !== undefined){
250
returnValue = v.returnValue;
254
if(v.cancel === true){
257
}else if(v === false){
265
this[method] = function(){
266
returnValue = v = undefined; cancel = false;
267
var args = Array.prototype.slice.call(arguments, 0);
268
for(var i = 0, len = e.before.length; i < len; i++){
269
makeCall(e.before[i].fn, e.before[i].scope, args);
275
if((v = e.originalFn.apply(obj, args)) !== undefined){
279
for(var i = 0, len = e.after.length; i < len; i++){
280
makeCall(e.after[i].fn, e.after[i].scope, args);
291
// adds an "interceptor" called before the original method
292
beforeMethod : function(method, fn, scope){
293
var e = this.getMethodEvent(method);
294
e.before.push({fn: fn, scope: scope});
297
// adds a "sequence" called after the original method
298
afterMethod : function(method, fn, scope){
299
var e = this.getMethodEvent(method);
300
e.after.push({fn: fn, scope: scope});
303
removeMethodListener : function(method, fn, scope){
304
var e = this.getMethodEvent(method);
305
for(var i = 0, len = e.before.length; i < len; i++){
306
if(e.before[i].fn == fn && e.before[i].scope == scope){
307
e.before.splice(i, 1);
311
for(var i = 0, len = e.after.length; i < len; i++){
312
if(e.after[i].fn == fn && e.after[i].scope == scope){
313
e.after.splice(i, 1);
320
* Appends an event handler to this element (shorthand for addListener)
321
* @param {String} eventName The type of event to listen for
322
* @param {Function} handler The method the event invokes
323
* @param {Object} scope (optional) The scope in which to execute the handler
324
* function. The handler function's "this" context.
325
* @param {Object} options (optional)
328
Ext.util.Observable.prototype.on = Ext.util.Observable.prototype.addListener;
330
* Removes a listener (shorthand for removeListener)
331
* @param {String} eventName The type of event to listen for
332
* @param {Function} handler The handler to remove
333
* @param {Object} scope (optional) The scope (this object) for the handler
336
Ext.util.Observable.prototype.un = Ext.util.Observable.prototype.removeListener;
339
* Starts capture on the specified Observable. All events will be passed
340
* to the supplied function with the event name + standard signature of the event
341
* <b>before</b> the event is fired. If the supplied function returns false,
342
* the event will not fire.
343
* @param {Observable} o The Observable to capture
344
* @param {Function} fn The function to call
345
* @param {Object} scope (optional) The scope (this object) for the fn
348
Ext.util.Observable.capture = function(o, fn, scope){
349
o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
353
* Removes <b>all</b> added captures from the Observable.
354
* @param {Observable} o The Observable to release
357
Ext.util.Observable.releaseCapture = function(o){
358
o.fireEvent = Ext.util.Observable.prototype.fireEvent;
363
var createBuffered = function(h, o, scope){
364
var task = new Ext.util.DelayedTask();
366
task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
370
var createSingle = function(h, e, fn, scope){
372
e.removeListener(fn, scope);
373
return h.apply(scope, arguments);
377
var createDelayed = function(h, o, scope){
379
var args = Array.prototype.slice.call(arguments, 0);
380
setTimeout(function(){
381
h.apply(scope, args);
386
Ext.util.Event = function(obj, name){
392
Ext.util.Event.prototype = {
393
addListener : function(fn, scope, options){
394
scope = scope || this.obj;
395
if(!this.isListening(fn, scope)){
396
var l = this.createListener(fn, scope, options);
398
this.listeners.push(l);
399
}else{ // if we are currently firing this event, don't disturb the listener loop
400
this.listeners = this.listeners.slice(0);
401
this.listeners.push(l);
406
createListener : function(fn, scope, o){
408
scope = scope || this.obj;
409
var l = {fn: fn, scope: scope, options: o};
412
h = createDelayed(h, o, scope);
415
h = createSingle(h, this, fn, scope);
418
h = createBuffered(h, o, scope);
424
findListener : function(fn, scope){
425
scope = scope || this.obj;
426
var ls = this.listeners;
427
for(var i = 0, len = ls.length; i < len; i++){
429
if(l.fn == fn && l.scope == scope){
436
isListening : function(fn, scope){
437
return this.findListener(fn, scope) != -1;
440
removeListener : function(fn, scope){
442
if((index = this.findListener(fn, scope)) != -1){
444
this.listeners.splice(index, 1);
446
this.listeners = this.listeners.slice(0);
447
this.listeners.splice(index, 1);
454
clearListeners : function(){
459
var ls = this.listeners, scope, len = ls.length;
462
var args = Array.prototype.slice.call(arguments, 0);
463
for(var i = 0; i < len; i++){
465
if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
b'\\ No newline at end of file'