OpenLayers OpenLayers

Changeset 8581

Show
Ignore:
Timestamp:
01/04/09 22:46:34 (6 months ago)
Author:
tschaub
Message:

Take care not to handle features without a layer. These are typically destroyed features - but could be some other sort of miscreants. Thanks for the report igrcic. r=crschmidt (closes #1806).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/lib/OpenLayers/Handler/Feature.js

    r8284 r8581  
    219219     */ 
    220220    handle: function(evt) { 
     221        if(this.feature && !this.feature.layer) { 
     222            // feature has been destroyed 
     223            this.feature = null; 
     224        } 
    221225        var type = evt.type; 
    222226        var handled = false; 
     
    224228        var click = (type == "click" || type == "dblclick"); 
    225229        this.feature = this.layer.getFeatureFromEvent(evt); 
    226         if(this.feature && this.feature.layer) { 
     230        if(this.feature && !this.feature.layer) { 
     231            // feature has been destroyed 
     232            this.feature = null; 
     233        } 
     234        if(this.lastFeature && !this.lastFeature.layer) { 
     235            // last feature has been destroyed 
     236            this.lastFeature = null; 
     237        } 
     238        if(this.feature) { 
    227239            var inNew = (this.feature != this.lastFeature); 
    228240            if(this.geometryTypeMatches(this.feature)) { 
     
    230242                if(previouslyIn && inNew) { 
    231243                    // out of last feature and in to another 
    232                     this.triggerCallback(type, 'out', [this.lastFeature]); 
     244                    if(this.lastFeature) { 
     245                        this.triggerCallback(type, 'out', [this.lastFeature]); 
     246                    } 
    233247                    this.triggerCallback(type, 'in', [this.feature]); 
    234248                } else if(!previouslyIn || click) { 
     
    240254            } else { 
    241255                // not in to a feature 
    242                 if(previouslyIn && inNew || (click && this.lastFeature)) { 
     256                if(this.lastFeature && (previouslyIn && inNew || click)) { 
    243257                    // out of last feature for the first time 
    244258                    this.triggerCallback(type, 'out', [this.lastFeature]); 
     
    252266            } 
    253267        } else { 
    254             if(this.lastFeature && this.lastFeature.layer && 
    255                (previouslyIn || click)) { 
     268            if(this.lastFeature && (previouslyIn || click)) { 
    256269                this.triggerCallback(type, 'out', [this.lastFeature]); 
    257270            } 
  • trunk/openlayers/tests/Handler/Feature.html

    r8284 r8581  
    293293 
    294294    function test_destroyed_feature(t) { 
    295         t.plan(2); 
     295        t.plan(18); 
     296         
     297        // setup 
    296298        var map = new OpenLayers.Map('map'); 
    297299        var control = new OpenLayers.Control(); 
     
    299301        var layer = new OpenLayers.Layer(); 
    300302        layer.removeFeatures = function() {}; 
    301         var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
    302         feature.layer = layer; 
     303        map.addLayer(layer); 
     304        var handler = new OpenLayers.Handler.Feature(control, layer); 
     305        var feature, count, lastType, lastHandled; 
     306        handler.callback = function(type, features) { 
     307            ++count; 
     308            lastType = type; 
     309            lastHandled = features; 
     310        } 
     311 
     312        /** 
     313         * Test that a destroyed feature doesn't get sent to the "click" callback 
     314         */ 
     315        count = 0; 
     316        handler.activate(); 
     317        feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
     318        feature.layer = layer; 
     319        // mock click on a feature 
    303320        layer.getFeatureFromEvent = function(evt) {return feature}; 
    304         map.addLayer(layer); 
    305         var handler = new OpenLayers.Handler.Feature(control, layer); 
    306         handler.activate(); 
    307         var count = 0; 
    308         handler.callback = function(type, featurelist) { 
    309             ++count; 
    310             t.eq(featurelist[0].id, feature.id, type + ": correct feature sent to callback"); 
    311         } 
    312321        handler.handle({type: "click"}); 
     322        // confirm that feature was handled 
     323        t.eq(count, 1, "[click] callback called once"); 
     324        t.eq(lastType, "click", "[click] correct callback type"); 
     325        t.eq(lastHandled[0].id, feature.id, "[click] correct feature sent to callback"); 
    313326         
    314327        // now destroy the feature and confirm that the callback is not called again 
    315328        feature.destroy(); 
    316329        handler.handle({type: "click"}); 
    317         t.eq(count, 1, "callback not called after destroy"); 
     330        if(count === 1) { 
     331            t.ok(true, "[click] callback not called after destroy"); 
     332        } else { 
     333            t.fail("[click] callback called after destroy: " + lastType); 
     334        } 
     335         
     336        /** 
     337         * Test that a destroyed feature doesn't get sent to the "clickout" callback 
     338         */ 
     339        count = 0; 
     340        handler.deactivate(); 
     341        handler.activate(); 
     342        feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
     343        feature.layer = layer; 
     344 
     345        // mock a click on a feature 
     346        layer.getFeatureFromEvent = function(evt) {return feature}; 
     347        handler.handle({type: "click"}); 
     348        // confirm that callback got feature 
     349        t.eq(count, 1, "[clickout] callback called once on in"); 
     350        t.eq(lastType, "click", "[clickout] click callback called on in"); 
     351        t.eq(lastHandled.length, 1, "[clickout] callback called with one feature"); 
     352        t.eq(lastHandled[0].id, feature.id, "[clickout] callback called with correct feature"); 
     353 
     354        // now mock a click off a destroyed feature 
     355        feature.destroy(); 
     356        layer.getFeatureFromEvent = function(evt) {return null}; 
     357        handler.handle({type: "click"}); 
     358        // confirm that callback does not get called 
     359        if(count === 1) { 
     360            t.ok(true, "[clickout] callback not called when clicking out of a destroyed feature"); 
     361        } else { 
     362            t.fail("[clickout] callback called when clicking out of a destroyed feature: " + lastType); 
     363        } 
     364         
     365        /** 
     366         * Test that a destroyed feature doesn't get sent to the "over" callback 
     367         */ 
     368        count = 0; 
     369        handler.deactivate(); 
     370        handler.activate(); 
     371        feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
     372        feature.layer = layer; 
     373        // mock mousemove over a feature 
     374        layer.getFeatureFromEvent = function(evt) {return feature}; 
     375        handler.handle({type: "mousemove"}); 
     376        // confirm that feature was handled 
     377        t.eq(count, 1, "[over] callback called once"); 
     378        t.eq(lastType, "over", "[over] correct callback type"); 
     379        t.eq(lastHandled[0].id, feature.id, "[over] correct feature sent to callback"); 
     380         
     381        // now destroy the feature and confirm that the callback is not called again 
     382        feature.destroy(); 
     383        handler.handle({type: "mousemove"}); 
     384        if(count === 1) { 
     385            t.ok(true, "[over] callback not called after destroy"); 
     386        } else { 
     387            t.fail("[over] callback called after destroy: " + lastType); 
     388        } 
     389 
     390        /** 
     391         * Test that a destroyed feature doesn't get sent to the "out" callback 
     392         */ 
     393        count = 0; 
     394        handler.deactivate(); 
     395        handler.activate(); 
     396        feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0)); 
     397        feature.layer = layer; 
     398 
     399        // mock a mousemove over a feature 
     400        layer.getFeatureFromEvent = function(evt) {return feature}; 
     401        handler.handle({type: "mousemove"}); 
     402        // confirm that callback got feature 
     403        t.eq(count, 1, "[out] callback called once on over"); 
     404        t.eq(lastType, "over", "[out] click callback called on over"); 
     405        t.eq(lastHandled.length, 1, "[out] callback called with one feature"); 
     406        t.eq(lastHandled[0].id, feature.id, "[out] callback called with correct feature"); 
     407 
     408        // now mock a click off a destroyed feature 
     409        feature.destroy(); 
     410        layer.getFeatureFromEvent = function(evt) {return null}; 
     411        handler.handle({type: "mousemove"}); 
     412        // confirm that callback does not get called 
     413        if(count === 1) { 
     414            t.ok(true, "[out] callback not called when moving out of a destroyed feature"); 
     415        } else { 
     416            t.fail("[out] callback called when moving out of a destroyed feature: " + lastType); 
     417        } 
     418         
     419        handler.destroy(); 
     420         
     421 
    318422    } 
    319423