Merge pull request #913 from ahocevar/modify-feature

Simplifying and unhacking the ModifyFeature control. r=@bartvde
This commit is contained in:
ahocevar
2013-03-20 02:23:42 -07:00
3 changed files with 144 additions and 217 deletions
+7 -1
View File
@@ -5,7 +5,13 @@ function init() {
styleMap: new OpenLayers.StyleMap({ styleMap: new OpenLayers.StyleMap({
temporary: OpenLayers.Util.applyDefaults({ temporary: OpenLayers.Util.applyDefaults({
pointRadius: 16 pointRadius: 16
}, OpenLayers.Feature.Vector.style.temporary) }, OpenLayers.Feature.Vector.style.temporary),
'default': OpenLayers.Util.applyDefaults({
pointRadius: 16
}, OpenLayers.Feature.Vector.style['default']),
select: OpenLayers.Util.applyDefaults({
pointRadius: 16
}, OpenLayers.Feature.Vector.style.select)
}) })
}); });
+96 -151
View File
@@ -4,8 +4,7 @@
* full text of the license. */ * full text of the license. */
/** /**
* @requires OpenLayers/Control/DragFeature.js * @requires OpenLayers/Handler/Drag.js
* @requires OpenLayers/Control/SelectFeature.js
* @requires OpenLayers/Handler/Keyboard.js * @requires OpenLayers/Handler/Keyboard.js
*/ */
@@ -50,7 +49,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* Default is true. * Default is true.
*/ */
toggle: true, toggle: true,
/** /**
* APIProperty: standalone * APIProperty: standalone
* {Boolean} Set to true to create a control without SelectFeature * {Boolean} Set to true to create a control without SelectFeature
@@ -67,20 +66,26 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* {<OpenLayers.Layer.Vector>} * {<OpenLayers.Layer.Vector>}
*/ */
layer: null, layer: null,
/** /**
* Property: feature * Property: feature
* {<OpenLayers.Feature.Vector>} Feature currently available for modification. * {<OpenLayers.Feature.Vector>} Feature currently available for modification.
*/ */
feature: null, feature: null,
/**
* Property: vertex
* {<OpenLayers.Feature.Vector>} Vertex currently being modified.
*/
vertex: null,
/** /**
* Property: vertices * Property: vertices
* {Array(<OpenLayers.Feature.Vector>)} Verticies currently available * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available
* for dragging. * for dragging.
*/ */
vertices: null, vertices: null,
/** /**
* Property: virtualVertices * Property: virtualVertices
* {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle
@@ -88,24 +93,12 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/ */
virtualVertices: null, virtualVertices: null,
/**
* Property: selectControl
* {<OpenLayers.Control.SelectFeature>}
*/
selectControl: null,
/**
* Property: dragControl
* {<OpenLayers.Control.DragFeature>}
*/
dragControl: null,
/** /**
* Property: handlers * Property: handlers
* {Object} * {Object}
*/ */
handlers: null, handlers: null,
/** /**
* APIProperty: deleteCodes * APIProperty: deleteCodes
* {Array(Integer)} Keycodes for deleting verticies. Set to null to disable * {Array(Integer)} Keycodes for deleting verticies. Set to null to disable
@@ -120,7 +113,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* {Object} A symbolizer to be used for virtual vertices. * {Object} A symbolizer to be used for virtual vertices.
*/ */
virtualStyle: null, virtualStyle: null,
/** /**
* APIProperty: vertexRenderIntent * APIProperty: vertexRenderIntent
* {String} The renderIntent to use for vertices. If no <virtualStyle> is * {String} The renderIntent to use for vertices. If no <virtualStyle> is
@@ -232,64 +225,50 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
if(!(OpenLayers.Util.isArray(this.deleteCodes))) { if(!(OpenLayers.Util.isArray(this.deleteCodes))) {
this.deleteCodes = [this.deleteCodes]; this.deleteCodes = [this.deleteCodes];
} }
var control = this;
// configure the drag handler
// configure the select control var dragCallbacks = {
var selectOptions = { down: function(pixel) {
geometryTypes: this.geometryTypes, this.vertex = null;
clickout: this.clickout, var feature = this.layer.getFeatureFromEvent(
toggle: this.toggle, this.handlers.drag.evt);
onBeforeSelect: this.beforeSelectFeature, if (feature) {
onSelect: this.selectFeature, this.dragStart(feature);
onUnselect: this.unselectFeature, } else if (this.feature && this.clickout) {
scope: this this.unselectFeature(this.feature);
}; }
if(this.standalone === false) {
this.selectControl = new OpenLayers.Control.SelectFeature(
layer, selectOptions
);
}
// configure the drag control
var dragOptions = {
documentDrag: this.documentDrag,
geometryTypes: ["OpenLayers.Geometry.Point"],
onStart: function(feature, pixel) {
control.dragStart.apply(control, [feature, pixel]);
}, },
onDrag: function(feature, pixel) { move: function(pixel) {
control.dragVertex.apply(control, [feature, pixel]); delete this._unselect;
if (this.vertex) {
this.dragVertex(this.vertex, pixel);
}
}, },
onComplete: function(feature) { up: function() {
control.dragComplete.apply(control, [feature]); this.handlers.drag.stopDown = false;
if (this._unselect) {
this.unselectFeature(this._unselect);
delete this._unselect;
}
}, },
featureCallbacks: { done: function(pixel) {
over: function(feature) { if (this.vertex) {
/** this.dragComplete(this.vertex);
* In normal mode, the feature handler is set up to allow
* dragging of all points. In standalone mode, we only
* want to allow dragging of sketch vertices and virtual
* vertices - or, in the case of a modifiable point, the
* point itself.
*/
if(control.standalone !== true || feature._sketch ||
control.feature === feature) {
control.dragControl.overFeature.apply(
control.dragControl, [feature]);
}
} }
} }
}; };
this.dragControl = new OpenLayers.Control.DragFeature( var dragOptions = {
layer, dragOptions documentDrag: this.documentDrag,
); stopDown: false
};
// configure the keyboard handler // configure the keyboard handler
var keyboardOptions = { var keyboardOptions = {
keydown: this.handleKeypress keydown: this.handleKeypress
}; };
this.handlers = { this.handlers = {
keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions) keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions),
drag: new OpenLayers.Handler.Drag(this, dragCallbacks, dragOptions)
}; };
}, },
@@ -299,8 +278,6 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/ */
destroy: function() { destroy: function() {
this.layer = null; this.layer = null;
this.standalone || this.selectControl.destroy();
this.dragControl.destroy();
OpenLayers.Control.prototype.destroy.apply(this, []); OpenLayers.Control.prototype.destroy.apply(this, []);
}, },
@@ -312,8 +289,8 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* {Boolean} Successfully activated the control. * {Boolean} Successfully activated the control.
*/ */
activate: function() { activate: function() {
return ((this.standalone || this.selectControl.activate()) && return (this.handlers.keyboard.activate() &&
this.handlers.keyboard.activate() && this.handlers.drag.activate() &&
OpenLayers.Control.prototype.activate.apply(this, arguments)); OpenLayers.Control.prototype.activate.apply(this, arguments));
}, },
@@ -331,26 +308,17 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
this.layer.removeFeatures(this.vertices, {silent: true}); this.layer.removeFeatures(this.vertices, {silent: true});
this.layer.removeFeatures(this.virtualVertices, {silent: true}); this.layer.removeFeatures(this.virtualVertices, {silent: true});
this.vertices = []; this.vertices = [];
this.dragControl.deactivate(); this.handlers.drag.deactivate();
var feature = this.feature;
var valid = feature && feature.geometry && feature.layer;
if(this.standalone === false) {
if(valid) {
this.selectControl.unselect.apply(this.selectControl,
[feature]);
}
this.selectControl.deactivate();
} else {
if(valid) {
this.unselectFeature(feature);
}
}
this.handlers.keyboard.deactivate(); this.handlers.keyboard.deactivate();
var feature = this.feature;
if (feature && feature.geometry && feature.layer) {
this.unselectFeature(feature);
}
deactivated = true; deactivated = true;
} }
return deactivated; return deactivated;
}, },
/** /**
* Method: beforeSelectFeature * Method: beforeSelectFeature
* Called before a feature is selected. * Called before a feature is selected.
@@ -375,11 +343,19 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* feature - {<OpenLayers.Feature.Vector>} the selected feature. * feature - {<OpenLayers.Feature.Vector>} the selected feature.
*/ */
selectFeature: function(feature) { selectFeature: function(feature) {
if (this.geometryTypes && OpenLayers.Util.indexOf(this.geometryTypes,
feature.geometry.CLASS_NAME) == -1) {
return;
}
if (!this.standalone || this.beforeSelectFeature(feature) !== false) { if (!this.standalone || this.beforeSelectFeature(feature) !== false) {
if (this.feature) {
this.unselectFeature(this.feature);
}
this.feature = feature; this.feature = feature;
this.layer.selectedFeatures.push(feature);
this.layer.drawFeature(feature, 'select');
this.modified = false; this.modified = false;
this.resetVertices(); this.resetVertices();
this.dragControl.activate();
this.onModificationStart(this.feature); this.onModificationStart(this.feature);
} }
// keep track of geometry modifications // keep track of geometry modifications
@@ -409,8 +385,9 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
this.layer.destroyFeatures([this.radiusHandle], {silent: true}); this.layer.destroyFeatures([this.radiusHandle], {silent: true});
delete this.radiusHandle; delete this.radiusHandle;
} }
this.layer.drawFeature(this.feature, 'default');
this.feature = null; this.feature = null;
this.dragControl.deactivate(); OpenLayers.Util.removeItem(this.layer.selectedFeatures, feature);
this.onModificationEnd(feature); this.onModificationEnd(feature);
this.layer.events.triggerEvent("afterfeaturemodified", { this.layer.events.triggerEvent("afterfeaturemodified", {
feature: feature, feature: feature,
@@ -418,64 +395,48 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
}); });
this.modified = false; this.modified = false;
}, },
/** /**
* Method: dragStart * Method: dragStart
* Called by the drag feature control with before a feature is dragged. * Called by the drag handler before a feature is dragged. This method is
* This method is used to differentiate between points and vertices * used to differentiate between points and vertices
* of higher order geometries. This respects the <geometryTypes> * of higher order geometries.
* property and forces a select of points when the drag control is
* already active (and stops events from propagating to the select
* control).
* *
* Parameters: * Parameters:
* feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be
* dragged. * dragged.
* pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
*/ */
dragStart: function(feature, pixel) { dragStart: function(feature) {
// only change behavior if the feature is not in the vertices array var isPoint = feature.geometry.CLASS_NAME ==
if(feature != this.feature && !feature.geometry.parent && 'OpenLayers.Geometry.Point';
feature != this.dragHandle && feature != this.radiusHandle) { if (!this.standalone &&
if(this.standalone === false && this.feature) { ((!feature._sketch && isPoint) || !feature._sketch)) {
// unselect the currently selected feature if (this.toggle && this.feature === feature) {
this.selectControl.clickFeature.apply(this.selectControl, // mark feature for unselection
[this.feature]); this._unselect = feature;
}
// check any constraints on the geometry type
if(this.geometryTypes == null ||
OpenLayers.Util.indexOf(this.geometryTypes,
feature.geometry.CLASS_NAME) != -1) {
// select the point
this.standalone || this.selectControl.clickFeature.apply(
this.selectControl, [feature]);
/**
* TBD: These lines improve workflow by letting the user
* immediately start dragging after the mouse down.
* However, it is very ugly to be messing with controls
* and their handlers in this way. I'd like a better
* solution if the workflow change is necessary.
*/
// prepare the point for dragging
this.dragControl.overFeature.apply(this.dragControl,
[feature]);
this.dragControl.lastPixel = pixel;
this.dragControl.handlers.drag.started = true;
this.dragControl.handlers.drag.start = pixel;
this.dragControl.handlers.drag.last = pixel;
} }
this.selectFeature(feature);
}
if (feature._sketch || isPoint) {
// feature is a drag or virtual handle or point
this.vertex = feature;
this.handlers.drag.stopDown = true;
} }
}, },
/** /**
* Method: dragVertex * Method: dragVertex
* Called by the drag feature control with each drag move of a vertex. * Called by the drag handler with each drag move of a vertex.
* *
* Parameters: * Parameters:
* vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
* pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event. * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
*/ */
dragVertex: function(vertex, pixel) { dragVertex: function(vertex, pixel) {
var pos = this.map.getLonLatFromViewPortPx(pixel);
var geom = vertex.geometry;
geom.move(pos.lon - geom.x, pos.lat - geom.y);
this.modified = true; this.modified = true;
/** /**
* Five cases: * Five cases:
@@ -487,9 +448,6 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/ */
if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
// dragging a simple point // dragging a simple point
if(this.feature != vertex) {
this.feature = vertex;
}
this.layer.events.triggerEvent("vertexmodified", { this.layer.events.triggerEvent("vertexmodified", {
vertex: vertex.geometry, vertex: vertex.geometry,
feature: this.feature, feature: this.feature,
@@ -526,7 +484,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
this.virtualVertices = []; this.virtualVertices = [];
} }
this.layer.drawFeature(this.feature, this.standalone ? undefined : this.layer.drawFeature(this.feature, this.standalone ? undefined :
this.selectControl.renderIntent); 'select');
} }
// keep the vertex on top so it gets the mouseout after dragging // keep the vertex on top so it gets the mouseout after dragging
// this should be removed in favor of an option to draw under or // this should be removed in favor of an option to draw under or
@@ -536,7 +494,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
/** /**
* Method: dragComplete * Method: dragComplete
* Called by the drag feature control when the feature dragging is complete. * Called by the drag handler when the feature dragging is complete.
* *
* Parameters: * Parameters:
* vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
@@ -572,16 +530,6 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* Method: resetVertices * Method: resetVertices
*/ */
resetVertices: function() { resetVertices: function() {
// if coming from a drag complete we're about to destroy the vertex
// that was just dragged. For that reason, the drag feature control
// will never detect a mouse-out on that vertex, meaning that the drag
// handler won't be deactivated. This can cause errors because the drag
// feature control still has a feature to drag but that feature is
// destroyed. To prevent this, we call outFeature on the drag feature
// control if the control actually has a feature to drag.
if(this.dragControl.feature) {
this.dragControl.outFeature(this.dragControl.feature);
}
if(this.vertices.length > 0) { if(this.vertices.length > 0) {
this.layer.removeFeatures(this.vertices, {silent: true}); this.layer.removeFeatures(this.vertices, {silent: true});
this.vertices = []; this.vertices = [];
@@ -632,11 +580,10 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
// check for delete key // check for delete key
if(this.feature && if(this.feature &&
OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) { OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) {
var vertex = this.dragControl.feature; var vertex = this.layer.getFeatureFromEvent(this.handlers.drag.evt);
if(vertex && if (vertex &&
OpenLayers.Util.indexOf(this.vertices, vertex) != -1 && OpenLayers.Util.indexOf(this.vertices, vertex) != -1 &&
!this.dragControl.handlers.drag.dragging && !this.handlers.drag.dragging && vertex.geometry.parent) {
vertex.geometry.parent) {
// remove the vertex // remove the vertex
vertex.geometry.parent.removeComponent(vertex.geometry); vertex.geometry.parent.removeComponent(vertex.geometry);
this.layer.events.triggerEvent("vertexremoved", { this.layer.events.triggerEvent("vertexremoved", {
@@ -645,8 +592,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
pixel: evt.xy pixel: evt.xy
}); });
this.layer.drawFeature(this.feature, this.standalone ? this.layer.drawFeature(this.feature, this.standalone ?
undefined : undefined : 'select');
this.selectControl.renderIntent);
this.modified = true; this.modified = true;
this.resetVertices(); this.resetVertices();
this.setFeatureState(); this.setFeatureState();
@@ -800,8 +746,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
* map - {<OpenLayers.Map>} The control's map. * map - {<OpenLayers.Map>} The control's map.
*/ */
setMap: function(map) { setMap: function(map) {
this.standalone || this.selectControl.setMap(map); this.handlers.drag.setMap(map);
this.dragControl.setMap(map);
OpenLayers.Control.prototype.setMap.apply(this, arguments); OpenLayers.Control.prototype.setMap.apply(this, arguments);
}, },
+41 -65
View File
@@ -13,34 +13,27 @@
} }
}; };
var options = { var options = {
geometryTypes: "bar" documentDrag: true
}; };
var control = new OpenLayers.Control.ModifyFeature(layer, options); var control = new OpenLayers.Control.ModifyFeature(layer, options);
t.ok(control.layer == layer, t.ok(control.layer == layer,
"constructor sets layer correctly"); "constructor sets layer correctly");
t.eq(control.selectControl.geometryTypes, "bar", t.eq(control.handlers.drag.documentDrag, true,
"constructor sets options correctly on feature handler"); "constructor sets options correctly on drag handler");
t.eq(control.mode, OpenLayers.Control.ModifyFeature.RESHAPE, t.eq(control.mode, OpenLayers.Control.ModifyFeature.RESHAPE,
"constructor initializes modification mode correctly"); "constructor initializes modification mode correctly");
control.destroy(); control.destroy();
} }
function test_destroy(t) { function test_destroy(t) {
t.plan(2); t.plan(1);
var map = new OpenLayers.Map("map"); var map = new OpenLayers.Map("map");
var layer = new OpenLayers.Layer.Vector(); var layer = new OpenLayers.Layer.Vector();
map.addLayer(layer); map.addLayer(layer);
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
control.selectControl.destroy = function() {
t.ok(true,
"control.destroy calls destroy on select control");
}
control.dragControl.destroy = function() {
t.ok(true,
"control.destroy calls destroy on feature handler");
}
control.destroy(); control.destroy();
t.eq(control.layer, null, "Layer reference removed on destroy.");
map.destroy(); map.destroy();
} }
@@ -51,11 +44,11 @@
map.addLayer(layer); map.addLayer(layer);
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
map.addControl(control); map.addControl(control);
t.ok(!control.selectControl.active, t.ok(!control.handlers.drag.active,
"select control is not active prior to activating control"); "drag handler is not active prior to activating control");
control.activate(); control.activate();
t.ok(control.selectControl.active, t.ok(control.handlers.drag.active,
"select control is active after activating control"); "drag handler is active after activating control");
map.destroy(); map.destroy();
} }
@@ -99,7 +92,8 @@
); );
// mock up vertex deletion // mock up vertex deletion
control.dragControl.feature = point; var origGetFeatureFromEvent = layer.getFeatureFromEvent;
layer.getFeatureFromEvent = function() { return point; };
control.feature = poly; control.feature = poly;
// we cannot use selectFeature since the control is not part of a map // we cannot use selectFeature since the control is not part of a map
control._originalGeometry = poly.geometry.clone(); control._originalGeometry = poly.geometry.clone();
@@ -139,17 +133,18 @@
t.eq(control.feature.state, OpenLayers.State.UPDATE, "feature state set to update"); t.eq(control.feature.state, OpenLayers.State.UPDATE, "feature state set to update");
// now make sure nothing happens if the vertex is mid-drag // now make sure nothing happens if the vertex is mid-drag
control.dragControl.handlers.drag.dragging = true; control.handlers.drag.dragging = true;
control.handleKeypress({keyCode:delKey}); control.handleKeypress({keyCode:delKey});
// clean up // clean up
layer.getFeatureFromEvent = origGetFeatureFromEvent;
control.destroy(); control.destroy();
layer.destroy(); layer.destroy();
} }
function test_onUnSelect(t) { function test_onUnSelect(t) {
t.plan(6); t.plan(5);
var layer = new OpenLayers.Layer.Vector(); var layer = new OpenLayers.Layer.Vector();
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
var fakeFeature = {'id':'myid'}; var fakeFeature = {'id':'myid'};
@@ -159,7 +154,6 @@
layer.events.on({"afterfeaturemodified": function(event) { layer.events.on({"afterfeaturemodified": function(event) {
t.eq(event.feature, fakeFeature, "afterfeaturemodified triggered"); t.eq(event.feature, fakeFeature, "afterfeaturemodified triggered");
}}); }});
control.dragControl.deactivate = function() { t.ok(true, "Deactivate called on drag control"); }
control.onModificationEnd = function (feature) { t.eq(feature.id, fakeFeature.id, "onModificationEnd got feature.") } control.onModificationEnd = function (feature) { t.eq(feature.id, fakeFeature.id, "onModificationEnd got feature.") }
layer.removeFeatures = function(verts) { layer.removeFeatures = function(verts) {
t.ok(verts == 'a', "Normal verts removed correctly"); t.ok(verts == 'a', "Normal verts removed correctly");
@@ -190,10 +184,6 @@
// If a feature is to be modified, control.selectFeature gets called. // If a feature is to be modified, control.selectFeature gets called.
// We want this test to fail if selectFeature gets called. // We want this test to fail if selectFeature gets called.
var modified = false; var modified = false;
var _ = OpenLayers.Control.ModifyFeature.prototype.selectFeature;
OpenLayers.Control.ModifyFeature.prototype.selectFeature = function() {
modified = true;
}
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
map.addControl(control); map.addControl(control);
@@ -202,21 +192,19 @@
// register a listener that will stop feature modification // register a listener that will stop feature modification
layer.events.on({"beforefeaturemodified": function() {return false}}); layer.events.on({"beforefeaturemodified": function() {return false}});
// we can initiate feature modification by selecting a feature with // we can initiate feature modification by programmatically selecting
// the control's select feature control // a feature
control.selectControl.select(feature); control.selectFeature(feature);
if(modified) { if(modified) {
t.fail("selectFeature called, prepping feature for modification"); t.fail("selectFeature called, prepping feature for modification");
} else { } else {
t.ok(true, "the beforefeaturemodified listener stopped feature modification"); t.ok(true, "the beforefeaturemodified listener stopped feature modification");
} }
OpenLayers.Control.ModifyFeature.prototype.selectFeature = _;
} }
function test_selectFeature(t) { function test_selectFeature(t) {
t.plan(12); t.plan(9);
var map = new OpenLayers.Map('map'); var map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.Vector("Vectors!", {isBaseLayer: true}); var layer = new OpenLayers.Layer.Vector("Vectors!", {isBaseLayer: true});
map.addLayer(layer); map.addLayer(layer);
@@ -228,7 +216,6 @@
t.ok(obj.feature == fakeFeature, "beforefeaturemodified triggered"); t.ok(obj.feature == fakeFeature, "beforefeaturemodified triggered");
}; };
layer.events.on({"beforefeaturemodified": callback}); layer.events.on({"beforefeaturemodified": callback});
control.dragControl.activate = function() { t.ok(true, "drag Control activated"); }
control.onModificationStart = function(feature) { t.eq(feature.id, fakeFeature.id, "On Modification Start called with correct feature."); } control.onModificationStart = function(feature) { t.eq(feature.id, fakeFeature.id, "On Modification Start called with correct feature."); }
// Start of testing // Start of testing
@@ -262,7 +249,7 @@
control.selectFeature(fakeFeature); control.selectFeature(fakeFeature);
control.vertices = ['a']; control.vertices = ['a'];
control.virtualVertices = ['b']; control.virtualVertices = [{destroy: function() {}}];
layer.addFeatures = function(features) {} layer.addFeatures = function(features) {}
@@ -283,7 +270,7 @@
} }
function test_resetVertices(t) { function test_resetVertices(t) {
t.plan(21); t.plan(20);
var layer = new OpenLayers.Layer.Vector(); var layer = new OpenLayers.Layer.Vector();
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
var point = new OpenLayers.Geometry.Point(5,6); var point = new OpenLayers.Geometry.Point(5,6);
@@ -340,18 +327,6 @@
t.eq(control.vertices.length, 0, "No vertices when both resizing and reshaping (RESIZE|RESHAPE)"); t.eq(control.vertices.length, 0, "No vertices when both resizing and reshaping (RESIZE|RESHAPE)");
t.eq(control.virtualVertices.length, 0, "No virtual vertices when both resizing and reshaping (RESIZE|RESHAPE)"); t.eq(control.virtualVertices.length, 0, "No virtual vertices when both resizing and reshaping (RESIZE|RESHAPE)");
control.dragControl.feature = new OpenLayers.Feature.Vector(polygon);
control.dragControl.map = {};
control.dragControl.map.div = {};
control.dragControl.map.div.style = {};
control.dragControl.map.viewPortDiv = "foo";
control.dragControl.handlers.drag.deactivate = function() {
this.active = false;
}
control.resetVertices();
t.ok(!control.dragControl.handlers.drag.active, "resetVertices deactivates drag handler");
control.dragControl.map = null;
control.destroy(); control.destroy();
layer.destroy(); layer.destroy();
} }
@@ -512,17 +487,19 @@
var control = new OpenLayers.Control.ModifyFeature(layer); var control = new OpenLayers.Control.ModifyFeature(layer);
map.addControl(control); map.addControl(control);
control.selectControl.deactivate = function() { control.handlers.keyboard.deactivate = function() {
t.ok(true, t.ok(true,
"control.deactivate calls deactivate on select control"); "control.deactivate calls deactivate on keyboard handler");
} }
control.dragControl.deactivate = function() { control.handlers.drag.deactivate = function() {
t.ok(true, t.ok(true,
"control.deactivate calls deactivate on drag control"); "control.deactivate calls deactivate on drag handler");
} }
control.active = true; control.active = true;
control.deactivate(); control.deactivate();
control.handlers.keyboard.deactivate = OpenLayers.Handler.Keyboard.prototype.deactivate;
control.handlers.drag.deactivate = OpenLayers.Handler.Drag.prototype.deactivate;
map.destroy(); map.destroy();
} }
@@ -609,14 +586,17 @@
layer.events.on({"featuremodified": function(event) { layer.events.on({"featuremodified": function(event) {
t.eq(event.feature.id, poly.id, "featuremodified triggered"); t.eq(event.feature.id, poly.id, "featuremodified triggered");
}}); }});
control.onModification = function(feature) { control.onModification = function(feature) {
t.eq(feature.id, poly.id, t.eq(feature.id, poly.id,
"onModification called with the right feature on vertex delete"); "onModification called with the right feature on vertex delete");
}; };
point.geometry.parent = poly.geometry; point.geometry.parent = poly.geometry;
control.dragControl.feature = point; origGetFeatureFromEvent = layer.getFeatureFromEvent;
layer.getFeatureFromEvent = function() { return point; };
control.handleKeypress({keyCode:46}); control.handleKeypress({keyCode:46});
layer.drawFeature = oldDraw; layer.drawFeature = oldDraw;
layer.getFeatureFromEvent = origGetFeatureFromEvent;
map.destroy(); map.destroy();
} }
@@ -694,7 +674,7 @@
function test_standalone(t) { function test_standalone(t) {
t.plan(18); t.plan(17);
var map = new OpenLayers.Map("map"); var map = new OpenLayers.Map("map");
var layer = new OpenLayers.Layer.Vector(); var layer = new OpenLayers.Layer.Vector();
@@ -733,7 +713,6 @@
// activate control // activate control
control.activate(); control.activate();
t.eq(control.active, true, "[activate] control activated"); t.eq(control.active, true, "[activate] control activated");
t.eq(control.selectControl, null, "[activate] no select control");
// manually select feature for editing // manually select feature for editing
control.selectFeature(f1); control.selectFeature(f1);
@@ -761,22 +740,19 @@
t.ok(log[0].feature === f2, "[deactivate] correct feature"); t.ok(log[0].feature === f2, "[deactivate] correct feature");
t.eq(log[0].modified, false, "[deactivate] feature not actually modified"); t.eq(log[0].modified, false, "[deactivate] feature not actually modified");
// reactivate control and select a point feature to see if we can drag
// another point feature;
control.activate();
control.selectFeature(f3);
control.dragControl.handlers.feature.triggerCallback("mousemove", "in", [f4]);
t.eq(control.dragControl.handlers.drag.active, false, "cannot drag unselected feature f4");
control.dragControl.handlers.feature.triggerCallback("mousemove", "in", [f3]);
t.eq(control.dragControl.handlers.drag.active, true, "can drag selected feature f3");
// select the polygon feature to make sure that we can drag vertices and // select the polygon feature to make sure that we can drag vertices and
// virtual vertices // virtual vertices
control.selectFeature(f2); control.selectFeature(f2);
control.dragControl.handlers.feature.triggerCallback("mousemove", "in", [control.vertices[0]]); var origGetFeatureFromEvent = layer.getFeatureFromEvent;
t.eq(control.dragControl.handlers.drag.active, true, "can drag vertex of feature f2"); layer.getFeatureFromEvent = function() { return control.vertices[0]; };
control.dragControl.handlers.feature.triggerCallback("mousemove", "in", [control.virtualVertices[0]]); control.handlers.drag.callbacks.down.call(control, new OpenLayers.Pixel(0,0));
t.eq(control.dragControl.handlers.drag.active, true, "can drag virtual vertex of feature f2"); t.ok(control.vertex === control.vertices[0], "can drag vertex of feature f2");
t.ok(control.feature === f2, "dragging a vertex does not change the selected feature");
layer.getFeatureFromEvent = function() { return control.virtualVertices[0]; };
control.handlers.drag.callbacks.down.call(control, new OpenLayers.Pixel(0,0));
t.ok(control.vertex === control.virtualVertices[0], "can drag virtual vertex of feature f2");
t.ok(control.feature === f2, "dragging a vertex does not change the selected feature");
layer.getFeatureFromEvent = origGetFeatureFromEvent;
control.deactivate(); control.deactivate();
map.destroy(); map.destroy();