OpenLayers OpenLayers

Ticket #621: eventCacheID.patch

File eventCacheID.patch, 9.3 kB (added by euzuro, 2 years ago)

instead of using the element's 'id' field to index into the hashtable, assign each element a new, unique '_eventCacheID' property, which will be its key into the events cache hashtable. this way, it matters not if an element is observed has an id or not, nor if the user changes the id later. had to bubble out a new, private _stopObservingElementRow() function, but so be it. I even wrote a big test function with lots of tests to give us a gross sense that this is working. a real, thorough test would obviously be better, but this will do for now. tests pass in FF, IE6

  • tests/test_Events.html

    old new  
    202202        t.eq(a, 5, "if Events has no object set and an event is registered also with no object, triggerEvent() calls it without trying to set the context to null");         
    203203    } 
    204204 
    205     function test_05_Event_destroy (t) { 
     205    function test_05_Events_destroy (t) { 
    206206        t.plan(2); 
    207207 
    208208        var div   = OpenLayers.Util.getElement('test'); 
    209209        var obj   = {}; 
    210210        var events = new OpenLayers.Events(obj, div); 
     211 
    211212        // +1 because of blocking dragstart in attachToElement() 
    212         t.eq(OpenLayers.Event.observers["test"].length, 
     213        t.eq(OpenLayers.Event.observers[div._eventCacheID].length, 
    213214             OpenLayers.Events.prototype.BROWSER_EVENTS.length + 1, 
    214215             "construction creates new arrayin hash, registers appropriate events"); 
    215216              
     
    218219        t.eq(OpenLayers.Event.observers["test"], null, 
    219220             "destruction removes the event observer from hash"); 
    220221    } 
     222     
     223    function test_06_Event(t) { 
     224        t.plan(24); 
     225         
     226        var div   = OpenLayers.Util.getElement('test'); 
     227        var name = "mouseover"; 
     228        var func = function() {}; 
     229 
     230      //1st elem 1st listener         
     231        OpenLayers.Event.observe(div, name, func); 
     232 
     233        var cacheID = div._eventCacheID; 
     234        t.ok(cacheID, "element given new cache id"); 
     235         
     236        var elementObservers = OpenLayers.Event.observers[cacheID]; 
     237         
     238        t.ok(elementObservers, "new cache bucket made for event"); 
     239        t.eq(elementObservers.length, 1, "one listener registered");         
     240         
     241        var listener = elementObservers[0]; 
     242         
     243        t.ok(listener.element == div, "element registered"); 
     244        t.eq(listener.name, name, "name registered"); 
     245        t.ok(listener.observer == func, "function registered"); 
     246        t.eq(listener.useCapture, false, "useCapture defaults to false"); 
     247 
     248      //1st elem 2nd listener         
     249        name = "mouseout"; 
     250        var newFunc = function() {}; 
     251       
     252        OpenLayers.Event.observe(div, name, newFunc, true); 
     253        var newCacheID = div._eventCacheID; 
     254        t.eq(newCacheID, cacheID, "element's cache id not overridden"); 
     255         
     256        t.eq(elementObservers.length, 2, "listener added to existing bucket");         
     257         
     258        var listener = elementObservers[1]; 
     259         
     260        t.ok(listener.element == div, "element registered"); 
     261        t.eq(listener.name, name, "name registered"); 
     262        t.ok(listener.observer == newFunc, "function registered"); 
     263        t.eq(listener.useCapture, true, "useCapture correctly registered"); 
     264 
     265      //2st elem 1st listener         
     266        div = OpenLayers.Util.getElement('test2');  
     267        OpenLayers.Event.observe(div, name, func); 
     268 
     269        var cacheID = div._eventCacheID; 
     270        t.ok(cacheID, "new element given new cache id"); 
     271        t.ok(cacheID != newCacheID, "new cache id is unique"); 
     272         
     273        elementObservers = OpenLayers.Event.observers[cacheID]; 
     274         
     275        t.ok(elementObservers, "new cache bucket made for event"); 
     276        t.eq(elementObservers.length, 1, "one listener registered");         
     277         
     278        var listener = elementObservers[0]; 
     279         
     280        t.ok(listener.element == div, "element registered"); 
     281        t.eq(listener.name, name, "name registered"); 
     282        t.ok(listener.observer == func, "function registered"); 
     283        t.eq(listener.useCapture, false, "useCapture defaults to false"); 
     284 
     285      //stopObservingElement by element 
     286        OpenLayers.Event.stopObservingElement(div); 
     287        elementObservers = OpenLayers.Event.observers[cacheID]; 
     288        t.ok(elementObservers == null, "stopObservingElement by elem works"); 
     289 
     290      //stopObservingElement by id 
     291        OpenLayers.Event.stopObservingElement("test"); 
     292        elementObservers = OpenLayers.Event.observers[newCacheID]; 
     293        t.ok(elementObservers == null, "stopObservingElement by id works"); 
     294 
     295 
     296      //unloadCache by element 
     297        OpenLayers.Event.observe(div, name, func); 
     298         
     299        OpenLayers.Event.unloadCache(); 
     300 
     301        elementObservers = OpenLayers.Event.observers[cacheID]; 
     302        t.ok(elementObservers == null, "stopObservingElement by elem works"); 
     303 
     304         
     305    } 
     306 
     307 
    221308    
    222309  // --> 
    223310  </script> 
     
    225312<body> 
    226313    <div id="map" style="width: 1024px; height: 512px;"/> 
    227314    <div id="test"></div> 
     315    <div id="test2"></div> 
    228316</body> 
    229317</html> 
  • lib/OpenLayers/Events.js

    old new  
    1010 */ 
    1111OpenLayers.Event = { 
    1212 
    13     /** A hashtable cache of the event observers, keyed by element.id 
     13    /** A hashtable cache of the event observers. 
     14     *   Keyed by element._eventCacheID 
    1415     *  
    1516     * @type Object 
    1617     */ 
     
    136137            name = 'keydown'; 
    137138        } 
    138139 
     140        if (!element._eventCacheID) { 
     141            var idPrefix = "eventCacheID_"; 
     142            if (element.id) { 
     143                idPrefix = element.id + "_" + idPrefix; 
     144            } 
     145            element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix); 
     146        } 
     147 
    139148        this._observeAndCache(element, name, observer, useCapture); 
    140149    }, 
    141150 
     
    153162            this.observers = new Object(); 
    154163        } 
    155164         
     165        var cacheID = element._eventCacheID; 
     166 
    156167        //if there is not yet a hash entry for this element, add one 
    157         if (!this.observers[element.id]) { 
    158             this.observers[element.id] = new Array(); 
     168        if (!this.observers[cacheID]) { 
     169            this.observers[cacheID] = new Array(); 
    159170        } 
    160171        //add a new observer to this element's list 
    161         this.observers[element.id].push({ 
     172        this.observers[cacheID].push({ 
    162173            'element': element, 
    163174            'name': name, 
    164175            'observer': observer, 
     
    180191     * @param {DOMElement || String} elementParam 
    181192     */ 
    182193    stopObservingElement: function(elementParam) { 
     194        var element = OpenLayers.Util.getElement(elementParam); 
     195        var cacheID = element._eventCacheID; 
    183196 
    184         var elementId = (typeof elementParam == "string") ? elementParam  
    185                             : OpenLayers.Util.getElement(elementParam).id; 
     197        this._stopObservingElementRow(OpenLayers.Event.observers[cacheID]); 
     198    }, 
    186199 
    187         var elementObservers = OpenLayers.Event.observers[elementId]; 
     200    /** 
     201     * @private 
     202     *  
     203     * @param {Array(Object)} elementObservers Array of (element, name,  
     204     *                                         observer, usecapture) objects,  
     205     *                                         taken directly from hashtable 
     206     */ 
     207    _stopObservingElementRow: function(elementObservers) { 
    188208        if (elementObservers) { 
    189             var i=0; 
    190             while(i < elementObservers.length) { 
    191                 var entry = elementObservers[0]; 
     209            for(var i = elementObservers.length-1; i >= 0; i--) { 
     210                var entry = elementObservers[i]; 
    192211                var args = new Array(entry.element, 
    193212                                     entry.name, 
    194213                                     entry.observer, 
    195214                                     entry.useCapture); 
    196215                var removed = OpenLayers.Event.stopObserving.apply(this, args); 
    197                 if (!removed) { 
    198                     i++; 
    199                 } 
    200216            } 
    201217        } 
    202218    }, 
     
    214230        useCapture = useCapture || false; 
    215231     
    216232        var element = OpenLayers.Util.getElement(elementParam); 
    217         var elementId = (typeof elementParam == "string") ? elementParam 
    218                                                           : element.id; 
     233        var cacheID = element._eventCacheID; 
    219234 
    220235        if (name == 'keypress') { 
    221236            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||  
     
    226241 
    227242        // find element's entry in this.observers cache and remove it 
    228243        var foundEntry = false; 
    229         var elementObservers = OpenLayers.Event.observers[elementId]; 
     244        var elementObservers = OpenLayers.Event.observers[cacheID]; 
    230245        if (elementObservers) { 
    231246     
    232247            // find the specific event type in the element's list 
     
    240255     
    241256                    elementObservers.splice(i, 1); 
    242257                    if (elementObservers.length == 0) { 
    243                         delete OpenLayers.Event.observers[element.id]; 
     258                        delete OpenLayers.Event.observers[cacheID]; 
    244259                    } 
    245260                    foundEntry = true; 
    246261                    break;  
     
    263278     */ 
    264279    unloadCache: function() { 
    265280        if (OpenLayers.Event.observers) { 
    266             for (var elementId in OpenLayers.Event.observers) { 
    267                 OpenLayers.Event.stopObservingElement.apply(this, [elementId]); 
     281            for (var cacheID in OpenLayers.Event.observers) { 
     282                var elementObservers = OpenLayers.Event.observers[cacheID]; 
     283                OpenLayers.Event._stopObservingElementRow.apply(this,  
     284                                                           [elementObservers]); 
    268285            } 
    269286            OpenLayers.Event.observers = false; 
    270287        }