3 <title>The source code</title>
\r
4 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
\r
5 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
\r
7 <body onload="prettyPrint();">
\r
8 <pre class="prettyprint lang-js">(function(){
10 var EXTUTIL = Ext.util,
11 TOARRAY = Ext.toArray,
13 ISOBJECT = Ext.isObject,
16 <div id="cls-Ext.util.Observable"></div>/**
17 * @class Ext.util.Observable
18 * Base class that provides a common interface for publishing events. Subclasses are expected to
19 * to have a property "events" with all the events defined, and, optionally, a property "listeners"
20 * with configured listeners defined.<br>
23 Employee = Ext.extend(Ext.util.Observable, {
24 constructor: function(config){
25 this.name = config.name;
31 // Copy configured listeners into *this* object so that the base class's
32 // constructor will add them.
33 this.listeners = config.listeners;
35 // Call our superclass constructor to complete construction process.
36 Employee.superclass.constructor.call(config)
40 * This could then be used like this:<pre><code>
41 var newEmployee = new Employee({
45 // By default, "this" will be the object that fired the event.
46 alert(this.name + " has quit!");
52 EXTUTIL.Observable = function(){
53 <div id="cfg-Ext.util.Observable-listeners"></div>/**
54 * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
55 * object during initialization. This should be a valid listeners config object as specified in the
56 * {@link #addListener} example for attaching multiple handlers at once.</p>
57 * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
58 * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
59 * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
60 * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
61 * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
62 * has been rendered. A plugin can simplify this step:<pre><code>
63 // Plugin is configured with a listeners config object.
64 // The Component is appended to the argument list of all handler functions.
65 Ext.DomObserver = Ext.extend(Object, {
66 constructor: function(config) {
67 this.listeners = config.listeners ? config.listeners : config;
70 // Component passes itself into plugin's init method
72 var p, l = this.listeners;
74 if (Ext.isFunction(l[p])) {
75 l[p] = this.createHandler(l[p], c);
77 l[p].fn = this.createHandler(l[p].fn, c);
81 // Add the listeners to the Element immediately following the render call
82 c.render = c.render.{@link Function#createSequence createSequence}(function() {
90 createHandler: function(fn, c) {
97 var combo = new Ext.form.ComboBox({
99 // Collapse combo when its element is clicked on
100 plugins: [ new Ext.DomObserver({
101 click: function(evt, comp) {
112 var me = this, e = me.events;
120 EXTUTIL.Observable.prototype = function(){
121 var filterOptRe = /^(?:scope|delay|buffer|single)$/, toLower = function(s){
122 return s.toLowerCase();
126 <div id="method-Ext.util.Observable-fireEvent"></div>/**
127 * <p>Fires the specified event with the passed parameters (minus the event name).</p>
128 * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
129 * by calling {@link #enableBubble}.</p>
130 * @param {String} eventName The name of the event to fire.
131 * @param {Object...} args Variable number of parameters are passed to handlers.
132 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
135 fireEvent : function(){
136 var a = TOARRAY(arguments),
137 ename = toLower(a[0]),
140 ce = me.events[ename],
143 if (me.eventsSuspended === TRUE) {
144 if (q = me.suspendedEventsQueue) {
148 else if(ISOBJECT(ce) && ce.bubble){
149 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
152 c = me.getBubbleTarget && me.getBubbleTarget();
153 if(c && c.enableBubble) {
154 c.enableBubble(ename);
155 return c.fireEvent.apply(c, a);
161 ret = ce.fire.apply(ce, a);
167 <div id="method-Ext.util.Observable-addListener"></div>/**
168 * Appends an event handler to this object.
169 * @param {String} eventName The name of the event to listen for.
170 * @param {Function} handler The method the event invokes.
171 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
172 * <b>If omitted, defaults to the object which fired the event.</b>
173 * @param {Object} options (optional) An object containing handler configuration.
174 * properties. This may contain any of the following properties:<ul>
175 * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
176 * <b>If omitted, defaults to the object which fired the event.</b></div></li>
177 * <li><b>delay</b> : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
178 * <li><b>single</b> : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
179 * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
180 * by the specified number of milliseconds. If the event fires again within that time, the original
181 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
182 * <li><b>target</b> : Observable<div class="sub-desc">Only call the handler if the event was fired on the target Observable, <i>not</i>
183 * if the event was bubbled up from a child Observable.</div></li>
186 * <b>Combining Options</b><br>
187 * Using the options argument, it is possible to combine different types of listeners:<br>
189 * A delayed, one-time listener.
191 myDataView.on('click', this.onClick, this, {
196 * <b>Attaching multiple handlers in 1 call</b><br>
197 * The method also allows for a single argument to be passed which is a config object containing properties
198 * which specify multiple handlers.
208 fn: this.onMouseOver,
217 * Or a shorthand syntax:<br>
220 'click' : this.onClick,
221 'mouseover' : this.onMouseOver,
222 'mouseout' : this.onMouseOut,
226 addListener : function(eventName, fn, scope, o){
232 if (ISOBJECT(eventName)) {
236 if (!filterOptRe.test(e)) {
237 me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
241 eventName = toLower(eventName);
242 ce = me.events[eventName] || TRUE;
243 if (typeof ce == "boolean") {
244 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
246 ce.addListener(fn, scope, ISOBJECT(o) ? o : {});
250 <div id="method-Ext.util.Observable-removeListener"></div>/**
251 * Removes an event handler.
252 * @param {String} eventName The type of event the handler was associated with.
253 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
254 * @param {Object} scope (optional) The scope originally specified for the handler.
256 removeListener : function(eventName, fn, scope){
257 var ce = this.events[toLower(eventName)];
259 ce.removeListener(fn, scope);
263 <div id="method-Ext.util.Observable-purgeListeners"></div>/**
264 * Removes all listeners for this object
266 purgeListeners : function(){
267 var events = this.events,
273 evt.clearListeners();
278 <div id="method-Ext.util.Observable-addEvents"></div>/**
279 * Used to define events on this Observable
280 * @param {Object} object The object with the events defined
282 addEvents : function(o){
284 me.events = me.events || {};
285 if (typeof o == 'string') {
286 EACH(arguments, function(a) {
287 me.events[a] = me.events[a] || TRUE;
290 Ext.applyIf(me.events, o);
294 <div id="method-Ext.util.Observable-hasListener"></div>/**
295 * Checks to see if this object has any listeners for a specified event
296 * @param {String} eventName The name of the event to check for
297 * @return {Boolean} True if the event is being listened for, else false
299 hasListener : function(eventName){
300 var e = this.events[eventName];
301 return ISOBJECT(e) && e.listeners.length > 0;
304 <div id="method-Ext.util.Observable-suspendEvents"></div>/**
305 * Suspend the firing of all events. (see {@link #resumeEvents})
306 * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
307 * after the {@link #resumeEvents} call instead of discarding all suspended events;
309 suspendEvents : function(queueSuspended){
310 this.eventsSuspended = TRUE;
312 this.suspendedEventsQueue = [];
316 <div id="method-Ext.util.Observable-resumeEvents"></div>/**
317 * Resume firing events. (see {@link #suspendEvents})
318 * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
319 * events fired during event suspension will be sent to any listeners now.
321 resumeEvents : function(){
323 me.eventsSuspended = !delete me.suspendedEventQueue;
324 EACH(me.suspendedEventsQueue, function(e) {
325 me.fireEvent.apply(me, e);
331 var OBSERVABLE = EXTUTIL.Observable.prototype;
332 <div id="method-Ext.util.Observable-on"></div>/**
333 * Appends an event handler to this object (shorthand for {@link #addListener}.)
334 * @param {String} eventName The type of event to listen for
335 * @param {Function} handler The method the event invokes
336 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
337 * <b>If omitted, defaults to the object which fired the event.</b>
338 * @param {Object} options (optional) An object containing handler configuration.
341 OBSERVABLE.on = OBSERVABLE.addListener;
342 <div id="method-Ext.util.Observable-un"></div>/**
343 * Removes an event handler (shorthand for {@link #removeListener}.)
344 * @param {String} eventName The type of event the handler was associated with.
345 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
346 * @param {Object} scope (optional) The scope originally specified for the handler.
349 OBSERVABLE.un = OBSERVABLE.removeListener;
351 <div id="method-Ext.util.Observable-Observable.releaseCapture"></div>/**
352 * Removes <b>all</b> added captures from the Observable.
353 * @param {Observable} o The Observable to release
356 EXTUTIL.Observable.releaseCapture = function(o){
357 o.fireEvent = OBSERVABLE.fireEvent;
360 function createTargeted(h, o, scope){
362 if(o.target == arguments[0]){
363 h.apply(scope, TOARRAY(arguments));
368 function createBuffered(h, o, scope){
369 var task = new EXTUTIL.DelayedTask();
371 task.delay(o.buffer, h, scope, TOARRAY(arguments));
375 function createSingle(h, e, fn, scope){
377 e.removeListener(fn, scope);
378 return h.apply(scope, arguments);
382 function createDelayed(h, o, scope){
384 var args = TOARRAY(arguments);
386 h.apply(scope, args);
387 }).defer(o.delay || 10);
391 EXTUTIL.Event = function(obj, name){
397 EXTUTIL.Event.prototype = {
398 addListener : function(fn, scope, options){
401 scope = scope || me.obj;
402 if(!me.isListening(fn, scope)){
403 l = me.createListener(fn, scope, options);
404 if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
405 me.listeners = me.listeners.slice(0);
407 me.listeners.push(l);
411 createListener: function(fn, scope, o){
412 o = o || {}, scope = scope || this.obj;
419 h = createTargeted(h, o, scope);
422 h = createDelayed(h, o, scope);
425 h = createSingle(h, this, fn, scope);
428 h = createBuffered(h, o, scope);
434 findListener : function(fn, scope){
436 EACH(this.listeners, function(l, i) {
438 if(l.fn == fn && (s == scope || s == this.obj)){
447 isListening : function(fn, scope){
448 return this.findListener(fn, scope) != -1;
451 removeListener : function(fn, scope){
455 if((index = me.findListener(fn, scope)) != -1){
457 me.listeners = me.listeners.slice(0);
459 me.listeners.splice(index, 1);
465 clearListeners : function(){
471 args = TOARRAY(arguments),
474 EACH(me.listeners, function(l) {
476 if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
477 return ret = me.firing = FALSE;