Changeset 8402

Show
Ignore:
Timestamp:
05/02/07 13:31:11 (19 months ago)
Author:
sjmiles
Message:

Another round of revisions to connect and event. Refs #2641.
*connect*: had to separate argument normalization from the main functions (hopefully this will aid the doc parser since there is only one "connect/disconnect" pair now, and overrides are done to private "_connect/_disconnect" functions.
*event*: eliminated confusing 'clean' methods and moved a key function out of the closure for leak prevention.
*disconnect*: changed disconnect so that it only takes one argument: the handle returned from connect, simplifying client code that needs to manage connections. Updated code in various modules to reflect this change.

Location:
dojo/trunk
Files:
8 modified

Legend:

Unmodified
Added
Removed
  • dojo/trunk/dnd/container.js

    r8059 r8402  
    5757        } 
    5858        // set up events 
    59         this.events = { 
    60                 onmouseover:    dojo.connect(this.node, "onmouseover", this, "onMouseOver"), 
    61                 onmouseout:             dojo.connect(this.node, "onmouseout",  this, "onMouseOut"), 
     59        this.events = [ 
     60                dojo.connect(this.node, "onmouseover", this, "onMouseOver"), 
     61                dojo.connect(this.node, "onmouseout",  this, "onMouseOut"), 
    6262                // cancel text selection and text dragging 
    63                 ondragstart:    dojo.connect(this.node, "ondragstart",   dojo, "stopEvent"), 
    64                 onselectstart:  dojo.connect(this.node, "onselectstart", dojo, "stopEvent") 
    65         }; 
     63                dojo.connect(this.node, "ondragstart",   dojo, "stopEvent"), 
     64                dojo.connect(this.node, "onselectstart", dojo, "stopEvent") 
     65        ]; 
    6666}, 
    6767{ 
     
    100100        destroy: function(){ 
    101101                // summary: prepares the object to be garbage-collected 
    102                 var t = {}; 
    103                 for(var i in this.events){ 
    104                         if(!(i in t)){ 
    105                                 dojo.disconnect(this.node, i, this.events[i]); 
    106                         } 
    107                 } 
     102                dojo.forEach(this.events, dojo.disconnect); 
    108103                this.node = this.parent = this.current = this.map = null; 
    109104        }, 
  • dojo/trunk/dnd/manager.js

    r8326 r8402  
    1212        this.target = null; 
    1313        this.canDropFlag = false; 
    14         this.events = {}; 
     14        this.events = []; 
    1515}; 
    1616 
     
    5151                dojo.body().appendChild(this.avatar.node); 
    5252                dojo.publish("dndStart", [source, nodes, copy]); 
    53                 this.events = { 
    54                         onmousemove:    dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"), 
    55                         onmouseup:              dojo.connect(dojo.doc, "onmouseup",   this, "onMouseUp"), 
    56                         onkeydown:              dojo.connect(dojo.doc, "onkeydown",   this, "onKeyDown"), 
    57                         onkeyup:                dojo.connect(dojo.doc, "onkeyup",     this, "onKeyUp") 
    58                 }; 
     53                this.events = [ 
     54                        dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"), 
     55                        dojo.connect(dojo.doc, "onmouseup",   this, "onMouseUp"), 
     56                        dojo.connect(dojo.doc, "onkeydown",   this, "onKeyDown"), 
     57                        dojo.connect(dojo.doc, "onkeyup",     this, "onKeyUp") 
     58                ]; 
    5959                //dojo.html.addClass(dojo.body(), "dojoDnd" + (copy ? "Copy" : "Move")); 
    6060                var c = "dojoDnd" + (copy ? "Copy" : "Move"); 
     
    7878                        replace(/(^|\s+)dojoDndCopy(\s+|$)/, "$1$2"). 
    7979                        replace(/(^|\s+)dojoDndMove(\s+|$)/, "$1$2"); 
    80                 var t = {}; 
    81                 for(var i in this.events){ 
    82                         if(!(i in t)){ 
    83                                 dojo.disconnect(dojo.doc, i, this.events[i]); 
    84                         } 
    85                 } 
    86                 this.events = {}; 
     80                dojo.forEach(this.events, dojo.disconnect); 
     81                this.events = []; 
    8782                this.avatar.destroy(); 
    8883                this.avatar = null; 
     
    128123                // summary: event processor for onkeydown, watching for CTRL for copy/move status 
    129124                // e: Event: keyboard event 
    130                 if(this.avatar && e.keyCode == dojo._keys.CTRL && !this.copy){ this._setCopyStatus(true); } 
     125                if(this.avatar && e.keyCode == dojo.keys.CTRL && !this.copy){ this._setCopyStatus(true); } 
    131126        }, 
    132127        onKeyUp: function(e){ 
    133128                // summary: event processor for onkeyup, watching for CTRL for copy/move status 
    134129                // e: Event: keyboard event 
    135                 if(this.avatar && e.keyCode == dojo._keys.CTRL && this.copy){ this._setCopyStatus(false); } 
     130                if(this.avatar && e.keyCode == dojo.keys.CTRL && this.copy){ this._setCopyStatus(false); } 
    136131        }, 
    137132        // utilities 
  • dojo/trunk/dnd/move.js

    r8059 r8402  
    1313        this.posY = np.y - dojo.dnd._getOffset(this.node, "Top")  - e.pageY; 
    1414        this.firstEvent = dojo.connect(dojo.doc, "onmousemove", this, "_makeAbsolute"); 
    15         this.events = { 
    16                 onmousemove:    dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"), 
    17                 onmouseup:              dojo.connect(dojo.doc, "onmouseup",   this, "destroy"), 
     15        this.events = [ 
     16                dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"), 
     17                dojo.connect(dojo.doc, "onmouseup",   this, "destroy"), 
    1818                // cancel text selection and text dragging 
    19                 ondragstart:    dojo.connect(dojo.doc, "ondragstart",   dojo, "stopEvent"), 
    20                 onselectstart:  dojo.connect(dojo.doc, "onselectstart", dojo, "stopEvent") 
    21         }; 
     19                dojo.connect(dojo.doc, "ondragstart",   dojo, "stopEvent"), 
     20                dojo.connect(dojo.doc, "onselectstart", dojo, "stopEvent") 
     21        ]; 
    2222}; 
    2323 
     
    3535                // summary: makes the node absolute; it is meant to be called only once 
    3636                this.node.style.position = "absolute";  // enforcing the absolute mode 
    37                 dojo.disconnect(dojo.doc, "onmousemove", this.firstEvent); 
     37                dojo.disconnect(this.firstEvent); 
    3838                delete this.firstEvent; 
    3939        }, 
    4040        destroy: function(){ 
    4141                // summary: stops the move, deletes all references, so the object can be garbage-collected 
    42                 var t = {}; 
    43                 for(var i in this.events){ 
    44                         if(!(i in t)){ 
    45                                 dojo.disconnect(dojo.doc, i, this.events[i]); 
    46                         } 
    47                 } 
     42                dojo.forEach(this.events, dojo.disconnect); 
    4843                if(this.firstEvent){ 
    49                         dojo.disconnect(dojo.doc, "onmousemove", this.firstEvent); 
     44                        dojo.disconnect(this.firstEvent); 
    5045                } 
    5146                this.node = null; 
     
    6257        this.handle = dojo.byId(handle); 
    6358        if(!this.handle){ this.handle = this.node; } 
    64         this.events = { 
    65                 onmousedown:    dojo.connect(this.handle, "onmousedown", this, "onMouseDown"), 
     59        this.events = [ 
     60                dojo.connect(this.handle, "onmousedown", this, "onMouseDown"), 
    6661                // cancel text selection and text dragging 
    67                 ondragstart:    dojo.connect(this.handle, "ondragstart",   dojo, "stopEvent"), 
    68                 onselectstart:  dojo.connect(this.handle, "onselectstart", dojo, "stopEvent") 
    69         }; 
     62                dojo.connect(this.handle, "ondragstart",   dojo, "stopEvent"), 
     63                dojo.connect(this.handle, "onselectstart", dojo, "stopEvent") 
     64        ]; 
    7065}; 
    7166 
     
    8176        destroy: function(){ 
    8277                // summary: stops watching for possible move, deletes all references, so the object can be garbage-collected 
    83                 var t = {}; 
    84                 for(var i in this.events){ 
    85                         if(!(i in t)){ 
    86                                 dojo.disconnect(this.handle, i, this.events[i]); 
    87                         } 
    88                 } 
     78                dojo.forEach(this.events, dojo.disconnect); 
    8979                this.node = this.handle = null; 
    9080        } 
  • dojo/trunk/dnd/selector.js

    r8059 r8402  
    2525        this.simpleSelection = false; 
    2626        // set up events 
    27         this.events.onmousedown = dojo.connect(this.node, "onmousedown", this, "onMouseDown"); 
    28         this.events.onmouseup   = dojo.connect(this.node, "onmouseup",   this, "onMouseUp"); 
     27        this.events.push( 
     28                dojo.connect(this.node, "onmousedown", this, "onMouseDown"), 
     29                dojo.connect(this.node, "onmouseup",   this, "onMouseUp")); 
    2930}, 
    3031{ 
     
    156157        onOverEvent: function(){ 
    157158                // summary: this function is called once, when mouse is over our container 
    158                 this.events.onmousemove = dojo.connect(this.node, "onmousemove", this, "onMouseMove"); 
     159                this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove"); 
    159160        }, 
    160161        onOutEvent: function(){ 
    161162                // summary: this function is called once, when mouse is out of our container 
    162                 dojo.disconnect(this.node, "onmousemove", this.events.onmousemove); 
    163                 delete this.events.onmousemove; 
     163                dojo.disconnect(this.onmousemoveEvent); 
     164                delete this.onmousemoveEvent; 
    164165        }, 
    165166        // methods 
  • dojo/trunk/tests/_base/connect.js

    r8301 r8402  
    3939        }  
    4040        for(var m=0; m<marked.length; m++){ 
    41                 dojo.disconnect('hub', marked[m]); 
     41                dojo.disconnect(marked[m]); 
    4242        } 
    4343        // test 
     
    119119                        // 
    120120                        dojo.connect(obj, "foo", obj, "baz"); 
    121                         dojo.disconnect(obj, "foo", foobar); 
     121                        dojo.disconnect(foobar); 
    122122                        // 
    123123                        out = ''; 
     
    151151                        var link = dojo.connect("gFoo", null, "gOk"); 
    152152                        gFoo(); 
    153                         dojo.disconnect("gFoo", link); 
     153                        dojo.disconnect(link); 
    154154                        t.is(true, ok); 
    155155                        // 3 arg shorthand for globals (b) 
    156156                        link = dojo.connect(null, "gFoo", "gOk"); 
    157157                        gFoo(); 
    158                         dojo.disconnect("gFoo", link); 
     158                        dojo.disconnect(link); 
    159159                        t.is(true, ok); 
    160160                        // verify disconnections  
     
    170170                        var link = dojo.connect("gFoo", "gOk"); 
    171171                        gFoo(); 
    172                         dojo.disconnect("gFoo", link); 
     172                        dojo.disconnect(link); 
    173173                        console.log('argsTest2a: ', (ok ? "ok" : "not ok")); 
    174174                        // 2 arg shorthand for globals, alternate scoping  
    175175                        link = dojo.connect("gFoo", gOk); 
    176176                        gFoo(); 
    177                         dojo.disconnect("gFoo", link); 
     177                        dojo.disconnect(link); 
    178178                        console.log('argsTest2b: ', (ok ? "ok" : "not ok")); 
    179179                }, 
  • dojo/trunk/_base/connect.js

    r8306 r8402  
    99dojo._listener = { 
    1010        // create a dispatcher function 
    11         dispatcher: function(){ 
     11        getDispatcher: function(){ 
    1212                // return a dispatcher function 
    1313                return function(){ 
     
    1515                        var ls = arguments.callee.listeners; 
    1616                        for(var i in ls){ 
    17                                 // properties that are really listeners will not be in "a" 
     17                                // indices that are really in the array will not be in Array.prototype 
     18                                // this 'sparse array' trick keeps us safe from libs that take 
     19                                // liberties with built-in objects 
    1820                                if(!(i in Array.prototype)){ 
    1921                                        // invoke the listener with our current scope 
     
    3739                // Ensure a dispatcher 
    3840                if(!f||!f.listeners){ 
    39                         var d = dojo._listener.dispatcher(); 
     41                        var d = dojo._listener.getDispatcher(); 
    4042                        // dispatcher holds a list of handlers 
    4143                        d.listeners = (f ? [f] : []); 
     
    112114        //              var link = dojo.connect(obj, "onchange", ui, "update"); 
    113115        //              ... 
    114         //              dojo.disconnect(obj, "onchange", link); 
     116        //              dojo.disconnect(link); 
    115117        // 
    116118        //              // when onglobalevent executes, watcher.handler is invoked 
     
    131133        //              dojo.connect("globalEvent", globalHandler); // same 
    132134 
    133         // support for omitting context argument depends on hitch 
    134         if(dojo.isString(obj)){ 
    135                 return dojo._listener.add(null, obj, dojo.hitch(event, context)); /*Handle*/ 
     135        // normalize arguments into args 
     136        var a=arguments, args=[], i=0; 
     137        if(dojo.isString(a[0])){ 
     138                args.push(null, a[i++]);  
    136139        }else{ 
    137                 return dojo._listener.add(obj, event, dojo.hitch(context, method)); /*Handle*/ 
     140                args.push(a[i++], a[i++]); 
    138141        } 
     142        if(dojo.isString(a[i+1])||(dojo.isFunction(a[i+1]))){ 
     143                args.push(a[i++], a[i++]); 
     144        }else{ 
     145                args.push(null, a[i++]); 
     146        } 
     147        for (; i<arguments.length; i++){ 
     148                args.push(arguments[i]); 
     149        } 
     150        return dojo._connect.apply(this, args); /*Handle*/ 
    139151} 
    140152 
    141 dojo.disconnect = function(/*Object|null*/ obj, /*String*/ event, /*Handle*/ handle){ 
     153dojo._connect = function(obj, event, context, method){ 
     154        var h = dojo._listener.add(obj, event, dojo.hitch(context, method));  
     155        return [obj, event, h]; /*Handle*/ 
     156} 
     157 
     158dojo.disconnect = function(/*Handle*/ handle){ 
    142159        // summary: 
    143160        //              Remove a link created by dojo.connect. 
    144161        // description: 
    145162        //              Removes the connection between event and the method referenced by handle. 
    146         // obj:  
    147         //              The source object for the event function.  
    148         //              Defaults to dojo.global if null. May be omitted. 
    149         // event: 
    150         //              String name of the event function in obj.  
    151         //              I.e. identifies a property obj[event]. 
    152163        // handle: 
    153164        //              the return value of the dojo.connect call that created the connection. 
    154         if(dojo.isString(obj)){ 
    155                 dojo._listener.remove(null, obj, event); 
    156         }else{ 
    157                 dojo._listener.remove(obj, event, handle); 
    158         } 
     165        dojo._disconnect.apply(this, handle); 
     166} 
     167 
     168dojo._disconnect = function(obj, event, handle){ 
     169        dojo._listener.remove(obj, event, handle); 
    159170} 
    160171 
  • dojo/trunk/_base/event.js

    r8366 r8402  
    55 
    66(function(){ 
    7  
    87        // DOM event machinery 
    98        var de = { 
     
    2221                        // node: 
    2322                        //              DOM node to attach the event to 
    24                         // fp: 
    25                         //              the function to register 
    26                         node.removeEventListener(de._normalizeEventName(event), handle, false); 
     23                        // handle: 
     24                        //              the handle returned from addListener 
     25                        (node)&&(node.removeEventListener(de._normalizeEventName(event), handle, false)); 
    2726                }, 
    2827                _normalizeEventName: function(/*String*/name){ 
    2928                        // Generally, name should be lower case, unless it is special 
    3029                        // somehow (e.g. a Mozilla event) 
    31  
    3230                        // Remove 'on' 
    3331                        return (name.slice(0,2)=="on" ? name.slice(2) : name); 
     
    5250                } 
    5351        }; 
    54         // FIXME: do we need this for debugging??? 
    55         // dojo.event = de; 
    5652 
    5753        // DOM events 
     54         
    5855        dojo.addListener = function(node, event, context, method){ 
    5956                return de.addListener(node, event, dojo.hitch(context, method)); // Handle 
     
    8380        } 
    8481 
    85         // ============================================= 
    86         // FIXME: I want to eliminate these and their 
    87         //        IE<7 bretheren below 
    88         dojo.cleanEvents = function(){ 
    89                 // self cleaning, except on IE 
    90                  
    91                 // FIXME: why public? 
    92         } 
    93         dojo.cleanNodeEvents = function(inNode){ 
    94                 // self cleaning, except on IE 
    95                  
    96                 // FIXME: why public? 
    97         } 
    98         // ============================================= 
    99  
    100         // cache raw implementations 
    101  
    102         var dc = dojo.connect; 
    103         var dd = dojo.disconnect; 
     82        // cache baseline implementations 
     83 
     84        var dc = dojo._connect; 
     85        var dd = dojo._disconnect; 
    10486 
    10587        // Unify connect/disconnect and add/removeListener 
    106  
    107         dojo.connect = function(        /*Object*/ obj,  
    108                                                                 /*String*/ event,  
    109                                                                 /*Object|null*/ context,  
    110                                                                 /*String|Function*/ method){ 
    111                 return (!obj||isNaN(obj.nodeType) ? dc: dojo.addListener).apply(de, arguments); 
     88         
     89        dojo._connect = function(obj, event, context, method, dontFix){ 
     90                dontFix = !obj || !(obj.nodeType||obj.attachEvent||obj.addEventListener) || dontFix; 
     91                var h = (dontFix ? dc.apply(this, arguments) : [obj, event, dojo.addListener.apply(this, arguments)]); 
     92                h.push(dontFix); 
     93                return h; 
    11294        }                                                                                        
    11395 
    114         dojo.disconnect = function(/*Object*/ obj, /*String*/ event, /*Handle*/ handle){ 
    115                 return (!obj||isNaN(obj.nodeType) ? dd: dojo.removeListener).apply(de, arguments); 
     96        dojo._disconnect = function(obj, event, handle, dontFix){ 
     97                (dontFix ? dd : dojo.removeListener).apply(this, arguments); 
    11698        }                                                                                        
    11799 
     
    181163                SCROLL_LOCK: 145 
    182164        }; 
    183  
     165         
    184166        // IE event normalization 
    185167        if(dojo.isIE){  
     168                var ap = Array.prototype; 
    186169                // by default, use the standard listener 
    187170                var iel = dojo._listener; 
     171                // dispatcher tracking property 
    188172                if((dojo.isIE<7)&&(!djConfig._allow_leaks)){ 
    189173                        // custom listener to handle leak protection for DOM events 
    190174                        iel = dojo._ie_listener = { 
    191                                 // support handler indirection 
     175                                // support handler indirection:  
     176                                // all event handler functions are actually referenced  
     177                                // here and event dispatchers reference only indices. 
    192178                                handlers: [], 
    193                                 // create a dispatcher function 
    194                                 dispatcher: function(f){ 
    195                                         // handy closeables 
    196                                         var a=[], hs=iel.handlers; 
    197                                         // Note that we close over h (i.e. d holds on to the 
    198                                         // current array of handlers).  Because dispatchers hold on 
    199                                         // to their array of handlers, we have to delete handlers 
    200                                         // entries individually.  handlers=[] won't cut it. 
    201                                         var d=function(){ 
    202                                                 var ls = arguments.callee.listeners; 
    203                                                 for(var i in ls){ 
    204                                                         if(!(i in a)){ 
    205                                                                 hs[ls[i]].apply(this, arguments); 
    206                                                         } 
    207                                                 } 
    208                                         } 
    209                                         d.listeners = (f ? [iel.handlers.push(f) - 1] : []); 
    210                                         console.log('created a dispatcher using indirect handlers'); 
    211                                         return d; 
    212                                 }, 
    213179                                // add a listener to an object 
    214180                                add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ 
    215181                                        source = source || dojo.global; 
    216                                         var d = source[method]; 
     182                                        var f = d = source[method]; 
    217183                                        if(!d||!d.listeners){ 
    218                                                 d = source[method] = iel.dispatcher(d); 
    219                                                 // ============================================= 
    220                                                 // FIXME: I want to eliminate this with the other 'clean' stuff 
    221                                                 // We're going to pollute your node with this property, sorry. 
    222                                                 // It provides support for stripping connections from this object. 
    223                                                 var p = "__djdisp__"; 
    224                                                 (source[p] || (source[p]=[])).push(d); 
    225                                                 // ============================================= 
     184                                                d = source[method] = dojo._getIeDispatcher(); 
     185                                                // initialize listeners with original event code (or just empty) 
     186                                                d.listeners = (f ? [ieh.push(f) - 1] : []); 
    226187                                        } 
    227                                         return d.listeners.push(iel.handlers.push(listener) - 1) ; /*Handle*/ 
     188                                        return d.listeners.push(ieh.push(listener) - 1) ; /*Handle*/ 
    228189                                }, 
    229190                                // remove a listener from an object 
    230191                                remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){ 
    231                                         var f = (source||dojo.global)[method]; 
    232                                         if(f && f.listeners && handle--){        
    233                                                 delete iel.handlers[f.listeners[handle]]; 
    234                                                 delete f.listeners[handle];  
     192                                        var f = (source||dojo.global)[method], l = f&&f.listeners; 
     193                                        if(f && l && handle--){  
     194                                                delete ieh[l[handle]]; 
     195                                                delete l[handle];  
    235196                                        } 
    236197                                } 
    237198                        }; 
    238                          
    239                         // ============================================= 
    240                         // FIXME: I want to eliminate these 
    241                         // otherwise, all client code has to call empty 'clean' events 
    242                         // just to be extra careful around IE < 7 
    243                         var a = []; 
    244                         dojo.cleanEvents = function(){ 
    245                                 // memory cleanup 
    246                                 var h = iel.handlers; 
    247                                 for(var i in h){ 
    248                                         if(!(i in a)){delete h[i];} 
    249                                 } 
    250                                 iel.handlers = []; 
    251                         } 
    252                         dojo.cleanNodeEvents = function(node){ 
    253                                 // cleanup node if it has bookkeeping info 
    254                                 var h = iel.handlers, p = "__djdisp__", s = inNode[p]; 
    255                                 if (!s || !s.length){return;} 
    256                                 // for each dispatcher 
    257                                 for(var di in s){ 
    258                                         if(di in a){continue;} 
    259                                         var d = s[di]; 
    260                                         // for each listener  
    261                                         for(var li in d){                                
    262                                     &nb