4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-util-Observable'>/**
19 </span> * @class Ext.util.Observable
20 * Base class that provides a common interface for publishing events. Subclasses are expected to
21 * to have a property "events" with all the events defined, and, optionally, a property "listeners"
22 * with configured listeners defined.<br>
24 * <pre><code>
25 Ext.define('Employee', {
26 extend: 'Ext.util.Observable',
27 constructor: function(config){
28 this.name = config.name;
30 "fired" : true,
31 "quit" : true
34 // Copy configured listeners into *this* object so that the base class&#39;s
35 // constructor will add them.
36 this.listeners = config.listeners;
38 // Call our superclass constructor to complete construction process.
39 Employee.superclass.constructor.call(this, config)
42 </code></pre>
43 * This could then be used like this:<pre><code>
44 var newEmployee = new Employee({
48 // By default, "this" will be the object that fired the event.
49 alert(this.name + " has quit!");
53 </code></pre>
56 Ext.define('Ext.util.Observable', {
58 /* Begin Definitions */
60 requires: ['Ext.util.Event'],
63 <span id='Ext-util-Observable-method-releaseCapture'> /**
64 </span> * Removes <b>all</b> added captures from the Observable.
65 * @param {Observable} o The Observable to release
68 releaseCapture: function(o) {
69 o.fireEvent = this.prototype.fireEvent;
72 <span id='Ext-util-Observable-method-capture'> /**
73 </span> * Starts capture on the specified Observable. All events will be passed
74 * to the supplied function with the event name + standard signature of the event
75 * <b>before</b> the event is fired. If the supplied function returns false,
76 * the event will not fire.
77 * @param {Observable} o The Observable to capture events from.
78 * @param {Function} fn The function to call when an event is fired.
79 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Observable firing the event.
82 capture: function(o, fn, scope) {
83 o.fireEvent = Ext.Function.createInterceptor(o.fireEvent, fn, scope);
86 <span id='Ext-util-Observable-method-observe'> /**
87 </span>Sets observability on the passed class constructor.
89 This makes any event fired on any instance of the passed class also fire a single event through
90 the __class__ allowing for central handling of events on many instances at once.
94 Ext.util.Observable.observe(Ext.data.Connection);
95 Ext.data.Connection.on('beforerequest', function(con, options) {
96 console.log('Ajax request made to ' + options.url);
99 * @param {Function} c The class constructor to make observable.
100 * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
104 observe: function(cls, listeners) {
106 if (!cls.isObservable) {
107 Ext.applyIf(cls, new this());
108 this.capture(cls.prototype, cls.fireEvent, cls);
110 if (Ext.isObject(listeners)) {
118 /* End Definitions */
120 <span id='Ext-util-Observable-cfg-listeners'> /**
121 </span> * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
122 * object during initialization. This should be a valid listeners config object as specified in the
123 * {@link #addListener} example for attaching multiple handlers at once.</p>
124 * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
125 * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
126 * is usually only done when extra value can be added. For example the {@link Ext.view.View DataView}'s
127 * <b><code>{@link Ext.view.View#click click}</code></b> event passing the node clicked on. To access DOM
128 * events directly from a child element of a Component, we need to specify the <code>element</code> option to
129 * identify the Component property to add a DOM listener to:
130 * <pre><code>
131 new Ext.panel.Panel({
139 element: 'el', //bind to the underlying el property on the panel
140 fn: function(){ console.log('click el'); }
143 element: 'body', //bind to the underlying body property on the panel
144 fn: function(){ console.log('dblclick body'); }
148 </code></pre>
154 constructor: function(config) {
157 Ext.apply(me, config);
162 me.events = me.events || {};
164 if (me.bubbleEvents) {
165 me.enableBubble(me.bubbleEvents);
170 eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal)$/,
172 <span id='Ext-util-Observable-method-addManagedListener'> /**
173 </span> * <p>Adds listeners to any Observable object (or Element) which are automatically removed when this Component
175 * @param {Observable/Element} item The item to which to add a listener/listeners.
176 * @param {Object/String} ename The event name, or an object containing event name properties.
177 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
178 * is the handler function.
179 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
180 * is the scope (<code>this</code> reference) in which the handler function is executed.
181 * @param {Object} opt Optional. If the <code>ename</code> parameter was an event name, this
182 * is the {@link Ext.util.Observable#addListener addListener} options.
184 addManagedListener : function(item, ename, fn, scope, options) {
186 managedListeners = me.managedListeners = me.managedListeners || [],
189 if (Ext.isObject(ename)) {
191 for (ename in options) {
192 if (options.hasOwnProperty(ename)) {
193 config = options[ename];
194 if (!me.eventOptionsRe.test(ename)) {
195 me.addManagedListener(item, ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
201 managedListeners.push({
209 item.on(ename, fn, scope, options);
213 <span id='Ext-util-Observable-method-removeManagedListener'> /**
214 </span> * Removes listeners that were added by the {@link #mon} method.
215 * @param {Observable|Element} item The item from which to remove a listener/listeners.
216 * @param {Object|String} ename The event name, or an object containing event name properties.
217 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
218 * is the handler function.
219 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
220 * is the scope (<code>this</code> reference) in which the handler function is executed.
222 removeManagedListener : function(item, ename, fn, scope) {
230 if (Ext.isObject(ename)) {
232 for (ename in options) {
233 if (options.hasOwnProperty(ename)) {
234 config = options[ename];
235 if (!me.eventOptionsRe.test(ename)) {
236 me.removeManagedListener(item, ename, config.fn || config, config.scope || options.scope);
242 managedListeners = me.managedListeners ? me.managedListeners.slice() : [];
244 for (i = 0, length = managedListeners.length; i < length; i++) {
245 me.removeManagedListenerItem(false, managedListeners[i], item, ename, fn, scope);
249 <span id='Ext-util-Observable-method-fireEvent'> /**
250 </span> * <p>Fires the specified event with the passed parameters (minus the event name).</p>
251 * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
252 * by calling {@link #enableBubble}.</p>
253 * @param {String} eventName The name of the event to fire.
254 * @param {Object...} args Variable number of parameters are passed to handlers.
255 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
257 fireEvent: function() {
259 args = Ext.Array.toArray(arguments),
260 ename = args[0].toLowerCase(),
262 event = me.events[ename],
263 queue = me.eventQueue,
266 if (me.eventsSuspended === true) {
270 } else if (event && Ext.isObject(event) && event.bubble) {
271 if (event.fire.apply(event, args.slice(1)) === false) {
274 parent = me.getBubbleTarget && me.getBubbleTarget();
275 if (parent && parent.isObservable) {
276 if (!parent.events[ename] || !Ext.isObject(parent.events[ename]) || !parent.events[ename].bubble) {
277 parent.enableBubble(ename);
279 return parent.fireEvent.apply(parent, args);
281 } else if (event && Ext.isObject(event)) {
283 ret = event.fire.apply(event, args);
288 <span id='Ext-util-Observable-method-addListener'> /**
289 </span> * Appends an event handler to this object.
290 * @param {String} eventName The name of the event to listen for. May also be an object who's property names are event names. See
291 * @param {Function} handler The method the event invokes.
292 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
293 * <b>If omitted, defaults to the object which fired the event.</b>
294 * @param {Object} options (optional) An object containing handler configuration.
295 * properties. This may contain any of the following properties:<ul>
296 * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
297 * <b>If omitted, defaults to the object which fired the event.</b></div></li>
298 * <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>
299 * <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>
300 * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
301 * by the specified number of milliseconds. If the event fires again within that time, the original
302 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
303 * <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>
304 * if the event was bubbled up from a child Observable.</div></li>
305 * <li><b>element</b> : String<div class="sub-desc"><b>This option is only valid for listeners bound to {@link Ext.Component Components}.</b>
306 * The name of a Component property which references an element to add a listener to.
307 * <p>This option is useful during Component construction to add DOM event listeners to elements of {@link Ext.Component Components} which
308 * will exist only after the Component is rendered. For example, to add a click listener to a Panel's body:<pre><code>
309 new Ext.panel.Panel({
312 click: this.handlePanelClick,
316 </code></pre></p>
317 * <p>When added in this way, the options available are the options applicable to {@link Ext.core.Element#addListener}</p></div></li>
318 * </ul><br>
320 * <b>Combining Options</b><br>
321 * Using the options argument, it is possible to combine different types of listeners:<br>
323 * A delayed, one-time listener.
324 * <pre><code>
325 myPanel.on('hide', this.handleClick, this, {
328 });</code></pre>
330 * <b>Attaching multiple handlers in 1 call</b><br>
331 * The method also allows for a single argument to be passed which is a config object containing properties
332 * which specify multiple events. For example:<pre><code>
334 cellClick: this.onCellClick,
335 mouseover: this.onMouseOver,
336 mouseout: this.onMouseOut,
337 scope: this // Important. Ensure "this" is correct during handler execution
339 </code></pre>.
342 addListener: function(ename, fn, scope, options) {
347 if (Ext.isObject(ename)) {
349 for (ename in options) {
350 if (options.hasOwnProperty(ename)) {
351 config = options[ename];
352 if (!me.eventOptionsRe.test(ename)) {
353 me.addListener(ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
359 ename = ename.toLowerCase();
360 me.events[ename] = me.events[ename] || true;
361 event = me.events[ename] || true;
362 if (Ext.isBoolean(event)) {
363 me.events[ename] = event = new Ext.util.Event(me, ename);
365 event.addListener(fn, scope, Ext.isObject(options) ? options : {});
369 <span id='Ext-util-Observable-method-removeListener'> /**
370 </span> * Removes an event handler.
371 * @param {String} eventName The type of event the handler was associated with.
372 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
373 * @param {Object} scope (optional) The scope originally specified for the handler.
375 removeListener: function(ename, fn, scope) {
381 if (Ext.isObject(ename)) {
383 for (ename in options) {
384 if (options.hasOwnProperty(ename)) {
385 config = options[ename];
386 if (!me.eventOptionsRe.test(ename)) {
387 me.removeListener(ename, config.fn || config, config.scope || options.scope);
392 ename = ename.toLowerCase();
393 event = me.events[ename];
394 if (event && event.isEvent) {
395 event.removeListener(fn, scope);
400 <span id='Ext-util-Observable-method-clearListeners'> /**
401 </span> * Removes all listeners for this object including the managed listeners
403 clearListeners: function() {
404 var events = this.events,
408 for (key in events) {
409 if (events.hasOwnProperty(key)) {
412 event.clearListeners();
417 this.clearManagedListeners();
421 purgeListeners : function() {
422 if (Ext.global.console) {
423 Ext.global.console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
425 return this.clearListeners.apply(this, arguments);
429 <span id='Ext-util-Observable-method-clearManagedListeners'> /**
430 </span> * Removes all managed listeners for this object.
432 clearManagedListeners : function() {
433 var managedListeners = this.managedListeners || [],
435 len = managedListeners.length;
437 for (; i < len; i++) {
438 this.removeManagedListenerItem(true, managedListeners[i]);
441 this.managedListeners = [];
444 <span id='Ext-util-Observable-method-removeManagedListenerItem'> /**
445 </span> * Remove a single managed listener item
447 * @param {Boolean} isClear True if this is being called during a clear
448 * @param {Object} managedListener The managed listener item
449 * See removeManagedListener for other args
451 removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
452 if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
453 managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
455 Ext.Array.remove(this.managedListeners, managedListener);
461 purgeManagedListeners : function() {
462 if (Ext.global.console) {
463 Ext.global.console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
465 return this.clearManagedListeners.apply(this, arguments);
469 <span id='Ext-util-Observable-method-addEvents'> /**
470 </span> * Adds the specified events to the list of events which this Observable may fire.
471 * @param {Object/String} o Either an object with event names as properties with a value of <code>true</code>
472 * or the first event name string if multiple event names are being passed as separate parameters.
473 * @param {String} [additional] Optional additional event names if multiple event names are being passed as separate parameters.
474 * Usage:<pre><code>
475 this.addEvents('storeloaded', 'storecleared');
476 </code></pre>
478 addEvents: function(o) {
484 me.events = me.events || {};
485 if (Ext.isString(o)) {
490 me.events[args[i]] = me.events[args[i]] || true;
493 Ext.applyIf(me.events, o);
497 <span id='Ext-util-Observable-method-hasListener'> /**
498 </span> * Checks to see if this object has any listeners for a specified event
499 * @param {String} eventName The name of the event to check for
500 * @return {Boolean} True if the event is being listened for, else false
502 hasListener: function(ename) {
503 var event = this.events[ename.toLowerCase()];
504 return event && event.isEvent === true && event.listeners.length > 0;
507 <span id='Ext-util-Observable-method-suspendEvents'> /**
508 </span> * Suspend the firing of all events. (see {@link #resumeEvents})
509 * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
510 * after the {@link #resumeEvents} call instead of discarding all suspended events;
512 suspendEvents: function(queueSuspended) {
513 this.eventsSuspended = true;
514 if (queueSuspended && !this.eventQueue) {
515 this.eventQueue = [];
519 <span id='Ext-util-Observable-method-resumeEvents'> /**
520 </span> * Resume firing events. (see {@link #suspendEvents})
521 * If events were suspended using the <code><b>queueSuspended</b></code> parameter, then all
522 * events fired during event suspension will be sent to any listeners now.
524 resumeEvents: function() {
526 queued = me.eventQueue || [];
528 me.eventsSuspended = false;
529 delete me.eventQueue;
533 me.fireEvent.apply(me, e);
537 <span id='Ext-util-Observable-method-relayEvents'> /**
538 </span> * Relays selected events from the specified Observable as if the events were fired by <code><b>this</b></code>.
539 * @param {Object} origin The Observable whose events this object is to relay.
540 * @param {Array} events Array of event names to relay.
542 relayEvents : function(origin, events, prefix) {
543 prefix = prefix || '';
550 for (; i < len; i++) {
551 oldName = events[i].substr(prefix.length);
552 newName = prefix + oldName;
553 me.events[newName] = me.events[newName] || true;
554 origin.on(oldName, me.createRelayer(newName));
558 <span id='Ext-util-Observable-method-createRelayer'> /**
560 * Creates an event handling function which refires the event from this object as the passed event name.
562 * @returns {Function}
564 createRelayer: function(newName){
567 return me.fireEvent.apply(me, [newName].concat(Array.prototype.slice.call(arguments, 0, -1)));
571 <span id='Ext-util-Observable-method-enableBubble'> /**
572 </span> * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling
573 * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>
574 * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component#getBubbleTarget}. The default
575 * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to
576 * access the required target more quickly.</p>
577 * <p>Example:</p><pre><code>
578 Ext.override(Ext.form.field.Base, {
579 // Add functionality to Field&#39;s initComponent to enable the change event to bubble
580 initComponent : Ext.Function.createSequence(Ext.form.field.Base.prototype.initComponent, function() {
581 this.enableBubble('change');
584 // We know that we want Field&#39;s events to bubble directly to the FormPanel.
585 getBubbleTarget : function() {
586 if (!this.formPanel) {
587 this.formPanel = this.findParentByType('form');
589 return this.formPanel;
593 var myForm = new Ext.formPanel({
594 title: 'User Details',
600 // Title goes red if form has been modified.
601 myForm.header.setStyle('color', 'red');
605 </code></pre>
606 * @param {String/Array} events The event name to bubble, or an Array of event names.
608 enableBubble: function(events) {
610 if (!Ext.isEmpty(events)) {
611 events = Ext.isArray(events) ? events: Ext.Array.toArray(arguments);
614 ename = ename.toLowerCase();
615 var ce = me.events[ename] || true;
616 if (Ext.isBoolean(ce)) {
617 ce = new Ext.util.Event(me, ename);
618 me.events[ename] = ce;
625 <span id='Ext-util-Observable-method-un'> /**
626 </span> * Removes an event handler (shorthand for {@link #removeListener}.)
627 * @param {String} eventName The type of event the handler was associated with.
628 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
629 * @param {Object} scope (optional) The scope originally specified for the handler.
633 <span id='Ext-util-Observable-method-on'> /**
634 </span> * Appends an event handler to this object (shorthand for {@link #addListener}.)
635 * @param {String} eventName The type of event to listen for
636 * @param {Function} handler The method the event invokes
637 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
638 * <b>If omitted, defaults to the object which fired the event.</b>
639 * @param {Object} options (optional) An object containing handler configuration.
645 un: 'removeListener',
646 mon: 'addManagedListener',
647 mun: 'removeManagedListener'
650 //deprecated, will be removed in 5.0
651 this.observeClass = this.observe;
653 Ext.apply(Ext.util.Observable.prototype, function(){
654 // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
655 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
657 function getMethodEvent(method){
658 var e = (this.methodEvents = this.methodEvents || {})[method],
665 this.methodEvents[method] = e = {};
666 e.originalFn = this[method];
667 e.methodName = method;
671 var makeCall = function(fn, scope, args){
672 if((v = fn.apply(scope || obj, args)) !== undefined){
673 if (typeof v == 'object') {
674 if(v.returnValue !== undefined){
675 returnValue = v.returnValue;
691 this[method] = function(){
692 var args = Array.prototype.slice.call(arguments, 0),
694 returnValue = v = undefined;
697 for(i = 0, len = e.before.length; i < len; i++){
699 makeCall(b.fn, b.scope, args);
705 if((v = e.originalFn.apply(obj, args)) !== undefined){
709 for(i = 0, len = e.after.length; i < len; i++){
711 makeCall(b.fn, b.scope, args);
723 // these are considered experimental
724 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
725 // adds an 'interceptor' called before the original method
726 beforeMethod : function(method, fn, scope){
727 getMethodEvent.call(this, method).before.push({
733 // adds a 'sequence' called after the original method
734 afterMethod : function(method, fn, scope){
735 getMethodEvent.call(this, method).after.push({
741 removeMethodListener: function(method, fn, scope){
742 var e = this.getMethodEvent(method),
744 for(i = 0, len = e.before.length; i < len; i++){
745 if(e.before[i].fn == fn && e.before[i].scope == scope){
746 e.before.splice(i, 1);
750 for(i = 0, len = e.after.length; i < len; i++){
751 if(e.after[i].fn == fn && e.after[i].scope == scope){
752 e.after.splice(i, 1);
758 toggleEventLogging: function(toggle) {
759 Ext.util.Observable[toggle ? 'capture' : 'releaseCapture'](this, function(en) {
760 if (Ext.isDefined(Ext.global.console)) {
761 Ext.global.console.log(en, arguments);