Upgrade to ExtJS 3.2.1 - Released 04/27/2010
[extjs.git] / docs / source / Observable.html
index b8119a9..b82a6e9 100644 (file)
@@ -1,16 +1,21 @@
-<html>\r
-<head>\r
-  <title>The source code</title>\r
-    <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
-    <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
-</head>\r
-<body  onload="prettyPrint();">\r
-    <pre class="prettyprint lang-js">(function(){
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
+  <title>The source code</title>
+    <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+    <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+</head>
+<body  onload="prettyPrint();">
+    <pre class="prettyprint lang-js">/*!
+ * Ext JS Library 3.2.1
+ * Copyright(c) 2006-2010 Ext JS, Inc.
+ * licensing@extjs.com
+ * http://www.extjs.com/license
+ */
+(function(){
 
 var EXTUTIL = Ext.util,
 
 var EXTUTIL = Ext.util,
-    TOARRAY = Ext.toArray,
     EACH = Ext.each,
     EACH = Ext.each,
-    ISOBJECT = Ext.isObject,
     TRUE = true,
     FALSE = false;
 <div id="cls-Ext.util.Observable"></div>/**
     TRUE = true,
     FALSE = false;
 <div id="cls-Ext.util.Observable"></div>/**
@@ -33,7 +38,7 @@ Employee = Ext.extend(Ext.util.Observable, {
         this.listeners = config.listeners;
 
         // Call our superclass constructor to complete construction process.
         this.listeners = config.listeners;
 
         // Call our superclass constructor to complete construction process.
-        Employee.superclass.constructor.call(config)
+        Employee.superclass.constructor.call(this, config)
     }
 });
 </code></pre>
     }
 });
 </code></pre>
@@ -117,216 +122,225 @@ var combo = new Ext.form.ComboBox({
     me.events = e || {};
 };
 
     me.events = e || {};
 };
 
-EXTUTIL.Observable.prototype = function(){
-    var filterOptRe = /^(?:scope|delay|buffer|single)$/, toLower = function(s){
-        return s.toLowerCase();
-    };
-
-    return {
-        <div id="method-Ext.util.Observable-fireEvent"></div>/**
-         * <p>Fires the specified event with the passed parameters (minus the event name).</p>
-         * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
-         * by calling {@link #enableBubble}.</p>
-         * @param {String} eventName The name of the event to fire.
-         * @param {Object...} args Variable number of parameters are passed to handlers.
-         * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
-         */
-
-        fireEvent : function(){
-            var a = TOARRAY(arguments),
-                ename = toLower(a[0]),
-                me = this,
-                ret = TRUE,
-                ce = me.events[ename],
-                q,
-                c;
-            if (me.eventsSuspended === TRUE) {
-                if (q = me.suspendedEventsQueue) {
-                    q.push(a);
-                }
+EXTUTIL.Observable.prototype = {
+    // private
+    filterOptRe : /^(?:scope|delay|buffer|single)$/,
+
+    <div id="method-Ext.util.Observable-fireEvent"></div>/**
+     * <p>Fires the specified event with the passed parameters (minus the event name).</p>
+     * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
+     * by calling {@link #enableBubble}.</p>
+     * @param {String} eventName The name of the event to fire.
+     * @param {Object...} args Variable number of parameters are passed to handlers.
+     * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
+     */
+    fireEvent : function(){
+        var a = Array.prototype.slice.call(arguments, 0),
+            ename = a[0].toLowerCase(),
+            me = this,
+            ret = TRUE,
+            ce = me.events[ename],
+            cc,
+            q,
+            c;
+        if (me.eventsSuspended === TRUE) {
+            if (q = me.eventQueue) {
+                q.push(a);
             }
             }
-            else if(ISOBJECT(ce) && ce.bubble){
+        }
+        else if(typeof ce == 'object') {
+            if (ce.bubble){
                 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
                     return FALSE;
                 }
                 c = me.getBubbleTarget && me.getBubbleTarget();
                 if(c && c.enableBubble) {
                 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
                     return FALSE;
                 }
                 c = me.getBubbleTarget && me.getBubbleTarget();
                 if(c && c.enableBubble) {
-                    c.enableBubble(ename);
+                    cc = c.events[ename];
+                    if(!cc || typeof cc != 'object' || !cc.bubble) {
+                        c.enableBubble(ename);
+                    }
                     return c.fireEvent.apply(c, a);
                 }
             }
             else {
                     return c.fireEvent.apply(c, a);
                 }
             }
             else {
-                if (ISOBJECT(ce)) {
-                    a.shift();
-                    ret = ce.fire.apply(ce, a);
-                }
+                a.shift();
+                ret = ce.fire.apply(ce, a);
             }
             }
-            return ret;
-        },
-
-        <div id="method-Ext.util.Observable-addListener"></div>/**
-         * Appends an event handler to this object.
-         * @param {String}   eventName The name of the event to listen for.
-         * @param {Function} handler The method the event invokes.
-         * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
-         * <b>If omitted, defaults to the object which fired the event.</b>
-         * @param {Object}   options (optional) An object containing handler configuration.
-         * properties. This may contain any of the following properties:<ul>
-         * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
-         * <b>If omitted, defaults to the object which fired the event.</b></div></li>
-         * <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>
-         * <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>
-         * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
-         * by the specified number of milliseconds. If the event fires again within that time, the original
-         * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
-         * <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>
-         * if the event was bubbled up from a child Observable.</div></li>
-         * </ul><br>
-         * <p>
-         * <b>Combining Options</b><br>
-         * Using the options argument, it is possible to combine different types of listeners:<br>
-         * <br>
-         * A delayed, one-time listener.
-         * <pre><code>
-myDataView.on('click', this.onClick, this, {
-    single: true,
-    delay: 100
-});</code></pre>
-         * <p>
-         * <b>Attaching multiple handlers in 1 call</b><br>
-         * The method also allows for a single argument to be passed which is a config object containing properties
-         * which specify multiple handlers.
-         * <p>
-         * <pre><code>
-myGridPanel.on({
-    'click' : {
-        fn: this.onClick,
-        scope: this,
-        delay: 100
-    },
-    'mouseover' : {
-        fn: this.onMouseOver,
-        scope: this
+        }
+        return ret;
     },
     },
-    'mouseout' : {
-        fn: this.onMouseOut,
-        scope: this
-    }
+
+    <div id="method-Ext.util.Observable-addListener"></div>/**
+     * Appends an event handler to this object.
+     * @param {String}   eventName The name of the event to listen for.
+     * @param {Function} handler The method the event invokes.
+     * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
+     * <b>If omitted, defaults to the object which fired the event.</b>
+     * @param {Object}   options (optional) An object containing handler configuration.
+     * properties. This may contain any of the following properties:<ul>
+     * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
+     * <b>If omitted, defaults to the object which fired the event.</b></div></li>
+     * <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>
+     * <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>
+     * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
+     * by the specified number of milliseconds. If the event fires again within that time, the original
+     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
+     * <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>
+     * if the event was bubbled up from a child Observable.</div></li>
+     * </ul><br>
+     * <p>
+     * <b>Combining Options</b><br>
+     * Using the options argument, it is possible to combine different types of listeners:<br>
+     * <br>
+     * A delayed, one-time listener.
+     * <pre><code>
+myDataView.on('click', this.onClick, this, {
+single: true,
+delay: 100
 });</code></pre>
      * <p>
 });</code></pre>
      * <p>
-     * Or a shorthand syntax:<br>
+     * <b>Attaching multiple handlers in 1 call</b><br>
+     * The method also allows for a single argument to be passed which is a config object containing properties
+     * which specify multiple handlers.
+     * <p>
      * <pre><code>
 myGridPanel.on({
      * <pre><code>
 myGridPanel.on({
-    'click' : this.onClick,
-    'mouseover' : this.onMouseOver,
-    'mouseout' : this.onMouseOut,
-     scope: this
+'click' : {
+    fn: this.onClick,
+    scope: this,
+    delay: 100
+},
+'mouseover' : {
+    fn: this.onMouseOver,
+    scope: this
+},
+'mouseout' : {
+    fn: this.onMouseOut,
+    scope: this
+}
 });</code></pre>
 });</code></pre>
-         */
-        addListener : function(eventName, fn, scope, o){
-            var me = this,
-                e,
-                oe,
-                isF,
-            ce;
-            if (ISOBJECT(eventName)) {
-                o = eventName;
-                for (e in o){
-                    oe = o[e];
-                    if (!filterOptRe.test(e)) {
-                        me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
-                    }
-                }
-            } else {
-                eventName = toLower(eventName);
-                ce = me.events[eventName] || TRUE;
-                if (typeof ce == "boolean") {
-                    me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
+ * <p>
+ * Or a shorthand syntax:<br>
+ * <pre><code>
+myGridPanel.on({
+'click' : this.onClick,
+'mouseover' : this.onMouseOver,
+'mouseout' : this.onMouseOut,
+ scope: this
+});</code></pre>
+     */
+    addListener : function(eventName, fn, scope, o){
+        var me = this,
+            e,
+            oe,
+            isF,
+        ce;
+        if (typeof eventName == 'object') {
+            o = eventName;
+            for (e in o){
+                oe = o[e];
+                if (!me.filterOptRe.test(e)) {
+                    me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
                 }
                 }
-                ce.addListener(fn, scope, ISOBJECT(o) ? o : {});
             }
             }
-        },
-
-        <div id="method-Ext.util.Observable-removeListener"></div>/**
-         * Removes an event handler.
-         * @param {String}   eventName The type of event the handler was associated with.
-         * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
-         * @param {Object}   scope     (optional) The scope originally specified for the handler.
-         */
-        removeListener : function(eventName, fn, scope){
-            var ce = this.events[toLower(eventName)];
-            if (ISOBJECT(ce)) {
-                ce.removeListener(fn, scope);
+        } else {
+            eventName = eventName.toLowerCase();
+            ce = me.events[eventName] || TRUE;
+            if (typeof ce == 'boolean') {
+                me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
             }
             }
-        },
-
-        <div id="method-Ext.util.Observable-purgeListeners"></div>/**
-         * Removes all listeners for this object
-         */
-        purgeListeners : function(){
-            var events = this.events,
-                evt,
-                key;
-            for(key in events){
-                evt = events[key];
-                if(ISOBJECT(evt)){
-                    evt.clearListeners();
-                }
-            }
-        },
-
-        <div id="method-Ext.util.Observable-addEvents"></div>/**
-         * Used to define events on this Observable
-         * @param {Object} object The object with the events defined
-         */
-        addEvents : function(o){
-            var me = this;
-            me.events = me.events || {};
-            if (typeof o == 'string') {
-                EACH(arguments, function(a) {
-                    me.events[a] = me.events[a] || TRUE;
-                });
-            } else {
-                Ext.applyIf(me.events, o);
+            ce.addListener(fn, scope, typeof o == 'object' ? o : {});
+        }
+    },
+
+    <div id="method-Ext.util.Observable-removeListener"></div>/**
+     * Removes an event handler.
+     * @param {String}   eventName The type of event the handler was associated with.
+     * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
+     * @param {Object}   scope     (optional) The scope originally specified for the handler.
+     */
+    removeListener : function(eventName, fn, scope){
+        var ce = this.events[eventName.toLowerCase()];
+        if (typeof ce == 'object') {
+            ce.removeListener(fn, scope);
+        }
+    },
+
+    <div id="method-Ext.util.Observable-purgeListeners"></div>/**
+     * Removes all listeners for this object
+     */
+    purgeListeners : function(){
+        var events = this.events,
+            evt,
+            key;
+        for(key in events){
+            evt = events[key];
+            if(typeof evt == 'object'){
+                evt.clearListeners();
             }
             }
-        },
-
-        <div id="method-Ext.util.Observable-hasListener"></div>/**
-         * Checks to see if this object has any listeners for a specified event
-         * @param {String} eventName The name of the event to check for
-         * @return {Boolean} True if the event is being listened for, else false
-         */
-        hasListener : function(eventName){
-            var e = this.events[eventName];
-            return ISOBJECT(e) && e.listeners.length > 0;
-        },
-
-        <div id="method-Ext.util.Observable-suspendEvents"></div>/**
-         * Suspend the firing of all events. (see {@link #resumeEvents})
-         * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
-         * after the {@link #resumeEvents} call instead of discarding all suspended events;
-         */
-        suspendEvents : function(queueSuspended){
-            this.eventsSuspended = TRUE;
-            if (queueSuspended){
-                this.suspendedEventsQueue = [];
+        }
+    },
+
+    <div id="method-Ext.util.Observable-addEvents"></div>/**
+     * Adds the specified events to the list of events which this Observable may fire.
+     * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
+     * or the first event name string if multiple event names are being passed as separate parameters.
+     * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
+     * Usage:<pre><code>
+this.addEvents('storeloaded', 'storecleared');
+</code></pre>
+     */
+    addEvents : function(o){
+        var me = this;
+        me.events = me.events || {};
+        if (typeof o == 'string') {
+            var a = arguments,
+                i = a.length;
+            while(i--) {
+                me.events[a[i]] = me.events[a[i]] || TRUE;
             }
             }
-        },
-
-        <div id="method-Ext.util.Observable-resumeEvents"></div>/**
-         * Resume firing events. (see {@link #suspendEvents})
-         * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
-         * events fired during event suspension will be sent to any listeners now.
-         */
-        resumeEvents : function(){
-            var me = this;
-            me.eventsSuspended = !delete me.suspendedEventQueue;
-            EACH(me.suspendedEventsQueue, function(e) {
-                me.fireEvent.apply(me, e);
-            });
+        } else {
+            Ext.applyIf(me.events, o);
         }
         }
+    },
+
+    <div id="method-Ext.util.Observable-hasListener"></div>/**
+     * Checks to see if this object has any listeners for a specified event
+     * @param {String} eventName The name of the event to check for
+     * @return {Boolean} True if the event is being listened for, else false
+     */
+    hasListener : function(eventName){
+        var e = this.events[eventName.toLowerCase()];
+        return typeof e == 'object' && e.listeners.length > 0;
+    },
+
+    <div id="method-Ext.util.Observable-suspendEvents"></div>/**
+     * Suspend the firing of all events. (see {@link #resumeEvents})
+     * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
+     * after the {@link #resumeEvents} call instead of discarding all suspended events;
+     */
+    suspendEvents : function(queueSuspended){
+        this.eventsSuspended = TRUE;
+        if(queueSuspended && !this.eventQueue){
+            this.eventQueue = [];
+        }
+    },
+
+    <div id="method-Ext.util.Observable-resumeEvents"></div>/**
+     * Resume firing events. (see {@link #suspendEvents})
+     * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
+     * events fired during event suspension will be sent to any listeners now.
+     */
+    resumeEvents : function(){
+        var me = this,
+            queued = me.eventQueue || [];
+        me.eventsSuspended = FALSE;
+        delete me.eventQueue;
+        EACH(queued, function(e) {
+            me.fireEvent.apply(me, e);
+        });
     }
     }
-}();
+};
 
 var OBSERVABLE = EXTUTIL.Observable.prototype;
 <div id="method-Ext.util.Observable-on"></div>/**
 
 var OBSERVABLE = EXTUTIL.Observable.prototype;
 <div id="method-Ext.util.Observable-on"></div>/**
@@ -360,31 +374,33 @@ EXTUTIL.Observable.releaseCapture = function(o){
 function createTargeted(h, o, scope){
     return function(){
         if(o.target == arguments[0]){
 function createTargeted(h, o, scope){
     return function(){
         if(o.target == arguments[0]){
-            h.apply(scope, TOARRAY(arguments));
+            h.apply(scope, Array.prototype.slice.call(arguments, 0));
         }
     };
 };
 
         }
     };
 };
 
-function createBuffered(h, o, scope){
-    var task = new EXTUTIL.DelayedTask();
+function createBuffered(h, o, l, scope){
+    l.task = new EXTUTIL.DelayedTask();
     return function(){
     return function(){
-        task.delay(o.buffer, h, scope, TOARRAY(arguments));
+        l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
     };
     };
-}
+};
 
 function createSingle(h, e, fn, scope){
     return function(){
         e.removeListener(fn, scope);
         return h.apply(scope, arguments);
     };
 
 function createSingle(h, e, fn, scope){
     return function(){
         e.removeListener(fn, scope);
         return h.apply(scope, arguments);
     };
-}
+};
 
 
-function createDelayed(h, o, scope){
+function createDelayed(h, o, l, scope){
     return function(){
     return function(){
-        var args = TOARRAY(arguments);
-        (function(){
-            h.apply(scope, args);
-        }).defer(o.delay || 10);
+        var task = new EXTUTIL.DelayedTask();
+        if(!l.tasks) {
+            l.tasks = [];
+        }
+        l.tasks.push(task);
+        task.delay(o.delay || 10, h, scope, Array.prototype.slice.call(arguments, 0));
     };
 };
 
     };
 };
 
@@ -419,29 +435,33 @@ EXTUTIL.Event.prototype = {
             h = createTargeted(h, o, scope);
         }
         if(o.delay){
             h = createTargeted(h, o, scope);
         }
         if(o.delay){
-            h = createDelayed(h, o, scope);
+            h = createDelayed(h, o, l, scope);
         }
         if(o.single){
             h = createSingle(h, this, fn, scope);
         }
         if(o.buffer){
         }
         if(o.single){
             h = createSingle(h, this, fn, scope);
         }
         if(o.buffer){
-            h = createBuffered(h, o, scope);
+            h = createBuffered(h, o, l, scope);
         }
         l.fireFn = h;
         return l;
     },
 
     findListener : function(fn, scope){
         }
         l.fireFn = h;
         return l;
     },
 
     findListener : function(fn, scope){
-        var s, ret = -1;
-        EACH(this.listeners, function(l, i) {
-            s = l.scope;
-            if(l.fn == fn && (s == scope || s == this.obj)){
-                ret = i;
-                return FALSE;
+        var list = this.listeners,
+            i = list.length,
+            l;
+
+        scope = scope || this.obj;
+        while(i--){
+            l = list[i];
+            if(l){
+                if(l.fn == fn && l.scope == scope){
+                    return i;
+                }
             }
             }
-        },
-        this);
-        return ret;
+        }
+        return -1;
     },
 
     isListening : function(fn, scope){
     },
 
     isListening : function(fn, scope){
@@ -450,37 +470,65 @@ EXTUTIL.Event.prototype = {
 
     removeListener : function(fn, scope){
         var index,
 
     removeListener : function(fn, scope){
         var index,
+            l,
+            k,
             me = this,
             ret = FALSE;
         if((index = me.findListener(fn, scope)) != -1){
             if (me.firing) {
                 me.listeners = me.listeners.slice(0);
             }
             me = this,
             ret = FALSE;
         if((index = me.findListener(fn, scope)) != -1){
             if (me.firing) {
                 me.listeners = me.listeners.slice(0);
             }
+            l = me.listeners[index];
+            if(l.task) {
+                l.task.cancel();
+                delete l.task;
+            }
+            k = l.tasks && l.tasks.length;
+            if(k) {
+                while(k--) {
+                    l.tasks[k].cancel();
+                }
+                delete l.tasks;
+            }
             me.listeners.splice(index, 1);
             ret = TRUE;
         }
         return ret;
     },
 
             me.listeners.splice(index, 1);
             ret = TRUE;
         }
         return ret;
     },
 
+    // Iterate to stop any buffered/delayed events
     clearListeners : function(){
     clearListeners : function(){
-        this.listeners = [];
+        var me = this,
+            l = me.listeners,
+            i = l.length;
+        while(i--) {
+            me.removeListener(l[i].fn, l[i].scope);
+        }
     },
 
     fire : function(){
         var me = this,
     },
 
     fire : function(){
         var me = this,
-            args = TOARRAY(arguments),
-            ret = TRUE;
+            listeners = me.listeners,
+            len = listeners.length,
+            i = 0,
+            l;
 
 
-        EACH(me.listeners, function(l) {
+        if(len > 0){
             me.firing = TRUE;
             me.firing = TRUE;
-            if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
-                return ret = me.firing = FALSE;
+            var args = Array.prototype.slice.call(arguments, 0);
+            for (; i < len; i++) {
+                l = listeners[i];
+                if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
+                    return (me.firing = FALSE);
+                }
             }
             }
-        });
+        }
         me.firing = FALSE;
         me.firing = FALSE;
-        return ret;
+        return TRUE;
     }
     }
+
 };
 };
-})();</pre>    \r
-</body>\r
+})();
+</pre>    
+</body>
 </html>
\ No newline at end of file
 </html>
\ No newline at end of file