3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4 <title>The source code</title>
5 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8 <body onload="prettyPrint();">
9 <pre class="prettyprint lang-js">/*!
10 * Ext JS Library 3.3.0
11 * Copyright(c) 2006-2010 Ext JS, Inc.
13 * http://www.extjs.com/license
17 var EXTUTIL = Ext.util,
21 <div id="cls-Ext.util.Observable"></div>/**
22 * @class Ext.util.Observable
23 * Base class that provides a common interface for publishing events. Subclasses are expected to
24 * to have a property "events" with all the events defined, and, optionally, a property "listeners"
25 * with configured listeners defined.<br>
28 Employee = Ext.extend(Ext.util.Observable, {
29 constructor: function(config){
30 this.name = config.name;
36 // Copy configured listeners into *this* object so that the base class's
37 // constructor will add them.
38 this.listeners = config.listeners;
40 // Call our superclass constructor to complete construction process.
41 Employee.superclass.constructor.call(this, config)
45 * This could then be used like this:<pre><code>
46 var newEmployee = new Employee({
50 // By default, "this" will be the object that fired the event.
51 alert(this.name + " has quit!");
57 EXTUTIL.Observable = function(){
58 <div id="cfg-Ext.util.Observable-listeners"></div>/**
59 * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
60 * object during initialization. This should be a valid listeners config object as specified in the
61 * {@link #addListener} example for attaching multiple handlers at once.</p>
62 * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
63 * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
64 * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
65 * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
66 * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
67 * has been rendered. A plugin can simplify this step:<pre><code>
68 // Plugin is configured with a listeners config object.
69 // The Component is appended to the argument list of all handler functions.
70 Ext.DomObserver = Ext.extend(Object, {
71 constructor: function(config) {
72 this.listeners = config.listeners ? config.listeners : config;
75 // Component passes itself into plugin's init method
77 var p, l = this.listeners;
79 if (Ext.isFunction(l[p])) {
80 l[p] = this.createHandler(l[p], c);
82 l[p].fn = this.createHandler(l[p].fn, c);
86 // Add the listeners to the Element immediately following the render call
87 c.render = c.render.{@link Function#createSequence createSequence}(function() {
95 createHandler: function(fn, c) {
102 var combo = new Ext.form.ComboBox({
104 // Collapse combo when its element is clicked on
105 plugins: [ new Ext.DomObserver({
106 click: function(evt, comp) {
117 var me = this, e = me.events;
125 EXTUTIL.Observable.prototype = {
127 filterOptRe : /^(?:scope|delay|buffer|single)$/,
129 <div id="method-Ext.util.Observable-fireEvent"></div>/**
130 * <p>Fires the specified event with the passed parameters (minus the event name).</p>
131 * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
132 * by calling {@link #enableBubble}.</p>
133 * @param {String} eventName The name of the event to fire.
134 * @param {Object...} args Variable number of parameters are passed to handlers.
135 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
137 fireEvent : function(){
138 var a = Array.prototype.slice.call(arguments, 0),
139 ename = a[0].toLowerCase(),
142 ce = me.events[ename],
146 if (me.eventsSuspended === TRUE) {
147 if (q = me.eventQueue) {
151 else if(typeof ce == 'object') {
153 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
156 c = me.getBubbleTarget && me.getBubbleTarget();
157 if(c && c.enableBubble) {
158 cc = c.events[ename];
159 if(!cc || typeof cc != 'object' || !cc.bubble) {
160 c.enableBubble(ename);
162 return c.fireEvent.apply(c, a);
167 ret = ce.fire.apply(ce, a);
173 <div id="method-Ext.util.Observable-addListener"></div>/**
174 * Appends an event handler to this object.
175 * @param {String} eventName The name of the event to listen for.
176 * @param {Function} handler The method the event invokes.
177 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
178 * <b>If omitted, defaults to the object which fired the event.</b>
179 * @param {Object} options (optional) An object containing handler configuration.
180 * properties. This may contain any of the following properties:<ul>
181 * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
182 * <b>If omitted, defaults to the object which fired the event.</b></div></li>
183 * <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>
184 * <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>
185 * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
186 * by the specified number of milliseconds. If the event fires again within that time, the original
187 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
188 * <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>
189 * if the event was bubbled up from a child Observable.</div></li>
192 * <b>Combining Options</b><br>
193 * Using the options argument, it is possible to combine different types of listeners:<br>
195 * A delayed, one-time listener.
197 myDataView.on('click', this.onClick, this, {
202 * <b>Attaching multiple handlers in 1 call</b><br>
203 * The method also allows for a single argument to be passed which is a config object containing properties
204 * which specify multiple handlers.
214 fn: this.onMouseOver,
223 * Or a shorthand syntax:<br>
226 'click' : this.onClick,
227 'mouseover' : this.onMouseOver,
228 'mouseout' : this.onMouseOut,
232 addListener : function(eventName, fn, scope, o){
238 if (typeof eventName == 'object') {
242 if (!me.filterOptRe.test(e)) {
243 me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
247 eventName = eventName.toLowerCase();
248 ce = me.events[eventName] || TRUE;
249 if (typeof ce == 'boolean') {
250 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
252 ce.addListener(fn, scope, typeof o == 'object' ? o : {});
256 <div id="method-Ext.util.Observable-removeListener"></div>/**
257 * Removes an event handler.
258 * @param {String} eventName The type of event the handler was associated with.
259 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
260 * @param {Object} scope (optional) The scope originally specified for the handler.
262 removeListener : function(eventName, fn, scope){
263 var ce = this.events[eventName.toLowerCase()];
264 if (typeof ce == 'object') {
265 ce.removeListener(fn, scope);
269 <div id="method-Ext.util.Observable-purgeListeners"></div>/**
270 * Removes all listeners for this object
272 purgeListeners : function(){
273 var events = this.events,
278 if(typeof evt == 'object'){
279 evt.clearListeners();
284 <div id="method-Ext.util.Observable-addEvents"></div>/**
285 * Adds the specified events to the list of events which this Observable may fire.
286 * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
287 * or the first event name string if multiple event names are being passed as separate parameters.
288 * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
290 this.addEvents('storeloaded', 'storecleared');
293 addEvents : function(o){
295 me.events = me.events || {};
296 if (typeof o == 'string') {
300 me.events[a[i]] = me.events[a[i]] || TRUE;
303 Ext.applyIf(me.events, o);
307 <div id="method-Ext.util.Observable-hasListener"></div>/**
308 * Checks to see if this object has any listeners for a specified event
309 * @param {String} eventName The name of the event to check for
310 * @return {Boolean} True if the event is being listened for, else false
312 hasListener : function(eventName){
313 var e = this.events[eventName.toLowerCase()];
314 return typeof e == 'object' && e.listeners.length > 0;
317 <div id="method-Ext.util.Observable-suspendEvents"></div>/**
318 * Suspend the firing of all events. (see {@link #resumeEvents})
319 * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
320 * after the {@link #resumeEvents} call instead of discarding all suspended events;
322 suspendEvents : function(queueSuspended){
323 this.eventsSuspended = TRUE;
324 if(queueSuspended && !this.eventQueue){
325 this.eventQueue = [];
329 <div id="method-Ext.util.Observable-resumeEvents"></div>/**
330 * Resume firing events. (see {@link #suspendEvents})
331 * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
332 * events fired during event suspension will be sent to any listeners now.
334 resumeEvents : function(){
336 queued = me.eventQueue || [];
337 me.eventsSuspended = FALSE;
338 delete me.eventQueue;
339 EACH(queued, function(e) {
340 me.fireEvent.apply(me, e);
345 var OBSERVABLE = EXTUTIL.Observable.prototype;
346 <div id="method-Ext.util.Observable-on"></div>/**
347 * Appends an event handler to this object (shorthand for {@link #addListener}.)
348 * @param {String} eventName The type of event to listen for
349 * @param {Function} handler The method the event invokes
350 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
351 * <b>If omitted, defaults to the object which fired the event.</b>
352 * @param {Object} options (optional) An object containing handler configuration.
355 OBSERVABLE.on = OBSERVABLE.addListener;
356 <div id="method-Ext.util.Observable-un"></div>/**
357 * Removes an event handler (shorthand for {@link #removeListener}.)
358 * @param {String} eventName The type of event the handler was associated with.
359 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
360 * @param {Object} scope (optional) The scope originally specified for the handler.
363 OBSERVABLE.un = OBSERVABLE.removeListener;
365 <div id="method-Ext.util.Observable-Observable.releaseCapture"></div>/**
366 * Removes <b>all</b> added captures from the Observable.
367 * @param {Observable} o The Observable to release
370 EXTUTIL.Observable.releaseCapture = function(o){
371 o.fireEvent = OBSERVABLE.fireEvent;
374 function createTargeted(h, o, scope){
376 if(o.target == arguments[0]){
377 h.apply(scope, Array.prototype.slice.call(arguments, 0));
382 function createBuffered(h, o, l, scope){
383 l.task = new EXTUTIL.DelayedTask();
385 l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
389 function createSingle(h, e, fn, scope){
391 e.removeListener(fn, scope);
392 return h.apply(scope, arguments);
396 function createDelayed(h, o, l, scope){
398 var task = new EXTUTIL.DelayedTask(),
399 args = Array.prototype.slice.call(arguments, 0);
404 task.delay(o.delay || 10, function(){
405 l.tasks.remove(task);
406 h.apply(scope, args);
411 EXTUTIL.Event = function(obj, name){
417 EXTUTIL.Event.prototype = {
418 addListener : function(fn, scope, options){
421 scope = scope || me.obj;
422 if(!me.isListening(fn, scope)){
423 l = me.createListener(fn, scope, options);
424 if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
425 me.listeners = me.listeners.slice(0);
427 me.listeners.push(l);
431 createListener: function(fn, scope, o){
433 scope = scope || this.obj;
440 h = createTargeted(h, o, scope);
443 h = createDelayed(h, o, l, scope);
446 h = createSingle(h, this, fn, scope);
449 h = createBuffered(h, o, l, scope);
455 findListener : function(fn, scope){
456 var list = this.listeners,
460 scope = scope || this.obj;
464 if(l.fn == fn && l.scope == scope){
472 isListening : function(fn, scope){
473 return this.findListener(fn, scope) != -1;
476 removeListener : function(fn, scope){
482 if((index = me.findListener(fn, scope)) != -1){
484 me.listeners = me.listeners.slice(0);
486 l = me.listeners[index];
491 k = l.tasks && l.tasks.length;
498 me.listeners.splice(index, 1);
504 // Iterate to stop any buffered/delayed events
505 clearListeners : function(){
510 me.removeListener(l[i].fn, l[i].scope);
516 listeners = me.listeners,
517 len = listeners.length,
523 var args = Array.prototype.slice.call(arguments, 0);
524 for (; i < len; i++) {
526 if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
527 return (me.firing = FALSE);