[OpenLayers-Commits] r4214 - in sandbox/camptocamp/feature: build examples lib lib/OpenLayers lib/OpenLayers/BaseTypes lib/OpenLayers/Control lib/OpenLayers/Feature lib/OpenLayers/Format lib/OpenLayers/Geometry lib/OpenLayers/Handler lib/OpenLayers/Layer lib/OpenLayers/Marker lib/OpenLayers/Popup lib/OpenLayers/Renderer lib/OpenLayers/Tile tests tests/Control tests/Format tests/Geometry tests/Handler tests/Layer

commits at openlayers.org commits at openlayers.org
Tue Sep 11 09:11:42 EDT 2007


Author: pgiraud
Date: 2007-09-11 09:11:39 -0400 (Tue, 11 Sep 2007)
New Revision: 4214

Added:
   sandbox/camptocamp/feature/examples/mouse-position.html
   sandbox/camptocamp/feature/tests/Control/test_SelectFeature.html
   sandbox/camptocamp/feature/tests/Handler/test_Feature.html
   sandbox/camptocamp/feature/tests/Handler/test_Keyboard.html
Modified:
   sandbox/camptocamp/feature/build/build.py
   sandbox/camptocamp/feature/examples/regular-polygons.html
   sandbox/camptocamp/feature/examples/rotate-features.html
   sandbox/camptocamp/feature/examples/vector-features.html
   sandbox/camptocamp/feature/lib/OpenLayers.js
   sandbox/camptocamp/feature/lib/OpenLayers/Ajax.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Bounds.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Class.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Element.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/LonLat.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Pixel.js
   sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Size.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/DragFeature.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/ModifyFeature.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/MouseDefaults.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/OverviewMap.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/PanZoom.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/Panel.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/Permalink.js
   sandbox/camptocamp/feature/lib/OpenLayers/Control/Scale.js
   sandbox/camptocamp/feature/lib/OpenLayers/Events.js
   sandbox/camptocamp/feature/lib/OpenLayers/Feature.js
   sandbox/camptocamp/feature/lib/OpenLayers/Feature/Vector.js
   sandbox/camptocamp/feature/lib/OpenLayers/Feature/WFS.js
   sandbox/camptocamp/feature/lib/OpenLayers/Format.js
   sandbox/camptocamp/feature/lib/OpenLayers/Format/GeoJSON.js
   sandbox/camptocamp/feature/lib/OpenLayers/Format/WKT.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Collection.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Curve.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/LinearRing.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/MultiPoint.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Point.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Polygon.js
   sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Rectangle.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Drag.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Feature.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Keyboard.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/MouseWheel.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Path.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Point.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/Polygon.js
   sandbox/camptocamp/feature/lib/OpenLayers/Handler/RegularPolygon.js
   sandbox/camptocamp/feature/lib/OpenLayers/Icon.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/EventPane.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/FixedZoomLevels.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/Google.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/Grid.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/HTTPRequest.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/Image.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/KaMap.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/MapServer.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/MultiMap.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/TMS.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/TileCache.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/Vector.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/VirtualEarth.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/WFS.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/WMS.js
   sandbox/camptocamp/feature/lib/OpenLayers/Layer/Yahoo.js
   sandbox/camptocamp/feature/lib/OpenLayers/Map.js
   sandbox/camptocamp/feature/lib/OpenLayers/Marker.js
   sandbox/camptocamp/feature/lib/OpenLayers/Marker/Box.js
   sandbox/camptocamp/feature/lib/OpenLayers/Popup.js
   sandbox/camptocamp/feature/lib/OpenLayers/Popup/Anchored.js
   sandbox/camptocamp/feature/lib/OpenLayers/Popup/AnchoredBubble.js
   sandbox/camptocamp/feature/lib/OpenLayers/Renderer/Elements.js
   sandbox/camptocamp/feature/lib/OpenLayers/Renderer/SVG.js
   sandbox/camptocamp/feature/lib/OpenLayers/Renderer/VML.js
   sandbox/camptocamp/feature/lib/OpenLayers/Tile.js
   sandbox/camptocamp/feature/lib/OpenLayers/Tile/Image.js
   sandbox/camptocamp/feature/lib/OpenLayers/Util.js
   sandbox/camptocamp/feature/tests/Control/test_DragFeature.html
   sandbox/camptocamp/feature/tests/Control/test_ModifyFeature.html
   sandbox/camptocamp/feature/tests/Format/test_GML.html
   sandbox/camptocamp/feature/tests/Format/test_GeoJSON.html
   sandbox/camptocamp/feature/tests/Format/test_GeoRSS.html
   sandbox/camptocamp/feature/tests/Format/test_JSON.html
   sandbox/camptocamp/feature/tests/Format/test_WKT.html
   sandbox/camptocamp/feature/tests/Format/test_XML.html
   sandbox/camptocamp/feature/tests/Geometry/test_LinearRing.html
   sandbox/camptocamp/feature/tests/Geometry/test_Point.html
   sandbox/camptocamp/feature/tests/Handler/test_Drag.html
   sandbox/camptocamp/feature/tests/Handler/test_MouseWheel.html
   sandbox/camptocamp/feature/tests/Handler/test_RegularPolygon.html
   sandbox/camptocamp/feature/tests/Layer/test_Vector.html
   sandbox/camptocamp/feature/tests/list-tests.html
   sandbox/camptocamp/feature/tests/test_BaseTypes.html
   sandbox/camptocamp/feature/tests/test_Feature.html
   sandbox/camptocamp/feature/tests/test_Format.html
   sandbox/camptocamp/feature/tests/test_Map.html
   sandbox/camptocamp/feature/tests/test_Marker.html
   sandbox/camptocamp/feature/tests/test_Popup.html
   sandbox/camptocamp/feature/tests/test_Renderer.html
   sandbox/camptocamp/feature/tests/test_Tile.html
   sandbox/camptocamp/feature/tests/test_Util.html
Log:
merge r4103:HEAD from tschaub/feature sandbox
notably includes:
* new keyboard control in Control.ModifyFeature rejected for the moment
* proper spelling for vertices

Modified: sandbox/camptocamp/feature/build/build.py
===================================================================
--- sandbox/camptocamp/feature/build/build.py	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/build/build.py	2007-09-11 13:11:39 UTC (rev 4214)
@@ -10,7 +10,12 @@
 outputFilename = "OpenLayers.js"
 
 if len(sys.argv) > 1:
-    configFilename = sys.argv[1] + ".cfg"
+    configFilename = sys.argv[1]
+    extension = configFilename[-4:]
+
+    if extension  != ".cfg":
+        configFilename = sys.argv[1] + ".cfg"
+
 if len(sys.argv) > 2:
     outputFilename = sys.argv[2]
 

Copied: sandbox/camptocamp/feature/examples/mouse-position.html (from rev 4213, sandbox/tschaub/feature/examples/mouse-position.html)
===================================================================
--- sandbox/camptocamp/feature/examples/mouse-position.html	                        (rev 0)
+++ sandbox/camptocamp/feature/examples/mouse-position.html	2007-09-11 13:11:39 UTC (rev 4214)
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" debug="true">
+  <head>
+    <style type="text/css">
+        body {
+            margin: 0;
+            padding: 0;
+        }
+        #map {
+            width: 512px;
+            height: 256px;
+        }
+    </style>
+    <script src="../lib/OpenLayers.js"></script>
+    <script type="text/javascript">
+        <!--
+        function init(){
+            var map = new OpenLayers.Map('map');
+
+            map.addControl(new OpenLayers.Control.MousePosition());
+
+            var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
+                "http://labs.metacarta.com/wms/vmap0",
+                {layers: 'basic'} );
+
+            map.addLayers([ol_wms]);
+            if (!map.getCenter()) map.zoomToMaxExtent();
+            
+            map.events.register("mousemove", map, function(e) { 
+                var position = this.events.getMousePosition(e);
+                OpenLayers.Util.getElement("coords").innerHTML = position;
+            });
+        }
+        // -->
+    </script>
+  </head>
+  <body onload="init()">
+    <div id="map"></div>
+    <div id="coords"></div>
+    <p>Moving your mouse to the upper left corner of this map should return 'x=0,y=0' -- in the past, it didn't in IE. If it returns 2,2, consider it a bug, and report it.</p> 
+  </body>
+</html>

Modified: sandbox/camptocamp/feature/examples/regular-polygons.html
===================================================================
--- sandbox/camptocamp/feature/examples/regular-polygons.html	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/examples/regular-polygons.html	2007-09-11 13:11:39 UTC (rev 4214)
@@ -128,9 +128,9 @@
                         <select name="angle"
                                 onchange="setOptions({snapAngle: parseFloat(this.value)})">
                             <option value="" selected="selected">no snap</option>
-                            <option value="0.2617994">15&deg;</option>
-                            <option value="0.7853981">45&deg;</option>
-                            <option value="1.5707963">90&deg;</option>
+                            <option value="15">15&deg;</option>
+                            <option value="45">45&deg;</option>
+                            <option value="90">90&deg;</option>
                         </select>
                     </td>
                 </tr>

Modified: sandbox/camptocamp/feature/examples/rotate-features.html
===================================================================
--- sandbox/camptocamp/feature/examples/rotate-features.html	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/examples/rotate-features.html	2007-09-11 13:11:39 UTC (rev 4214)
@@ -82,11 +82,11 @@
             var center = new OpenLayers.Feature.Vector(origin, null, style);
             vectorLayer.addFeatures([center]);
             window.setInterval(rotateFeature, 100,
-                               pointFeature, Math.PI / 10, origin);
+                               pointFeature, 360 / 20, origin);
             window.setInterval(rotateFeature, 100,
-                               lineFeature, Math.PI / 20, origin);
+                               lineFeature, 360 / 40, origin);
             window.setInterval(rotateFeature, 100,
-                               polygonFeature, -1 * Math.PI / 10, origin);
+                               polygonFeature, -360 / 20, origin);
         }
 
         function rotateFeature(feature, angle, origin) {

Modified: sandbox/camptocamp/feature/examples/vector-features.html
===================================================================
--- sandbox/camptocamp/feature/examples/vector-features.html	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/examples/vector-features.html	2007-09-11 13:11:39 UTC (rev 4214)
@@ -17,12 +17,22 @@
             var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
                     "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
             map.addLayer(layer);
+
+            /*
+             * Layer style
+             */
+            // we want opaque external graphics and non-opaque internal graphics
+            var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
+            layer_style.fillOpacity = 0.2;
+            layer_style.graphicOpacity = 1;
             
-            var style_blue = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
+            /*
+             * Blue style
+             */
+            var style_blue = OpenLayers.Util.extend({}, layer_style);
             style_blue.strokeColor = "blue"; 
             style_blue.fillColor = "blue"; 
             style_blue.externalGraphic = "../img/marker.png";
-            
             // each of the three lines below means the same, if only one of
             // them is active: the image will have a size of 24px, and the
             // aspect ratio will be kept
@@ -30,7 +40,9 @@
             //style_blue.graphicWidth = 24;
             //style_blue.graphicHeight = 24;
             
-            style_blue.fillOpacity = 1;
+            /*
+             * Green style
+             */
             var style_green = {
                 strokeColor: "#00FF00",
                 strokeOpacity: 1,
@@ -38,16 +50,18 @@
                 pointRadius: 6,
                 pointerEvents: "visiblePainted"
             };
+
+            /*
+             * Mark style
+             */
             var style_mark = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
-            
             // if graphicWidth and graphicHeight are both set, the aspect ratio
             // of the image will be ignored
             style_mark.graphicWidth = 24;
             style_mark.graphicHeight = 20;
-            
             style_mark.externalGraphic = "../img/marker.png";
             
-            var vectorLayer = new OpenLayers.Layer.Vector("Simple Geometry");
+            var vectorLayer = new OpenLayers.Layer.Vector("Simple Geometry", {style: layer_style});
             
             // create a point feature
             var point = new OpenLayers.Geometry.Point(-111.04, 45.68);

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Ajax.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Ajax.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Ajax.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -80,7 +80,7 @@
  * Parameters:
  * text - {String} 
  * 
- * Return:
+ * Returns:
  * {?} Parsed AJAX Responsev
  */
 OpenLayers.parseXMLString = function(text) {
@@ -129,7 +129,7 @@
     /**
      * Method: getTransport
      * 
-     * Return: 
+     * Returns: 
      * {Object} Transport mechanism for whichever browser we're in, or false if
      *          none available.
      */
@@ -239,7 +239,7 @@
     /**
      * Function: responseIsSuccess
      * 
-     * Return:
+     * Returns:
      * {Boolean}
      */
     responseIsSuccess: function() {
@@ -251,7 +251,7 @@
     /**
      * Function: responseIsFailure
      * 
-     * Return:
+     * Returns:
      * {Boolean}
      */
     responseIsFailure: function() {
@@ -379,7 +379,7 @@
     /** 
      * Method: header
      * 
-     * Return:
+     * Returns:
      * {?}
      */
     header: function(name) {
@@ -391,7 +391,7 @@
     /** 
      * Method: evalJSON
      * 
-     * Return:
+     * Returns:
      * {?}
      */
     evalJSON: function() {
@@ -403,7 +403,7 @@
     /**
      * Method: evalResponse
      * 
-     * Return: 
+     * Returns: 
      * {?}
      */
     evalResponse: function() {
@@ -495,7 +495,7 @@
  * nsprefix - {?}
  * tagname - {?}
  * 
- * Return:
+ * Returns:
  * {?}
  */
 OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
@@ -519,7 +519,7 @@
  * Parameters: 
  * xmldom {XMLNode} xml dom to serialize
  * 
- * Return:
+ * Returns:
  * {?}
  */
 OpenLayers.Ajax.serializeXMLToString = function(xmldom) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Bounds.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Bounds.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Bounds.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -71,7 +71,7 @@
      * Method: clone
      * Create a cloned instance of this bounds.
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>} A fresh copy of the bounds
      */
     clone:function() {
@@ -86,7 +86,7 @@
      * Parameters:
      * bounds - {<OpenLayers.Bounds>}
      *
-     * Return:
+     * Returns:
      * {Boolean} The passed-in OpenLayers.Bounds object has the same left,
      *           right, top, bottom components as this.  Note that if bounds 
      *           passed in is null, returns false.
@@ -105,7 +105,7 @@
     /** 
      * APIMethod: toString
      * 
-     * Return:
+     * Returns:
      * {String} String representation of OpenLayers.Bounds object. 
      *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
      */
@@ -117,7 +117,7 @@
     /**
      * APIMethod: toArray
      *
-     * Return:
+     * Returns:
      * {Array} array of left, bottom, right, top
      */
     toArray: function() {
@@ -131,7 +131,7 @@
      * decimal - {Integer} How many significant digits in the bbox coords?
      *                     Default is 6
      * 
-     * Return:
+     * Returns:
      * {String} Simple String representation of OpenLayers.Bounds object.
      *          (ex. <i>"5,42,10,45"</i>)
      */
@@ -151,7 +151,7 @@
     /**
      * APIMethod: getWidth
      * 
-     * Return:
+     * Returns:
      * {Float} The width of the bounds
      */
     getWidth:function() {
@@ -161,7 +161,7 @@
     /**
      * APIMethod: getHeight
      * 
-     * Return:
+     * Returns:
      * {Float} The height of the bounds
      */
     getHeight:function() {
@@ -171,7 +171,7 @@
     /**
      * APIMethod: getSize
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Size>} An <OpenLayers.Size> which represents the size of the box
      */
     getSize:function() {
@@ -181,7 +181,7 @@
     /**
      * APIMethod: getCenterPixel
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which represents the center 
      *                      of the bounds
      */
@@ -193,7 +193,7 @@
     /**
      * APIMethod: getCenterLonLat
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.LonLat>} An <OpenLayers.LonLat> which represents the center 
      *                      of the bounds
      */
@@ -209,7 +209,7 @@
      * x - {Float}
      * y - {Float}
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>} A new <OpenLayers.Bounds> whose coordinates are 
      *                       the same as this, but shifted by the passed-in 
      *                       x and y values
@@ -276,7 +276,7 @@
      * inclusive - {Boolean} Whether or not to include the border. 
      *                       Default is true.
      *
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the passed-in lonlat is within this bounds.
      */
     containsLonLat:function(ll, inclusive) {
@@ -291,7 +291,7 @@
      * inclusive - {Boolean} Whether or not to include the border. 
      *                       Default is true.
      *
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the passed-in pixel is within this bounds.
      */
     containsPixel:function(px, inclusive) {
@@ -307,7 +307,7 @@
      * inclusive - {Boolean} Whether or not to include the border. 
      *                       Default is true.
      *
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the passed-in coordinates are within this
      *           bounds.
      */
@@ -337,7 +337,7 @@
      * inclusive - {<Boolean>} Whether or not to include the border. 
      *                         Default is true.
      *
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the passed-in OpenLayers.Bounds object 
      *           intersects this bounds. Simple math just check if either 
      *           contains the other, allowing for partial.
@@ -376,7 +376,7 @@
      * inclusive - {<Boolean>} Whether or not to include the border. 
      *                         Default is true.
      *
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the passed-in OpenLayers.Bounds object is 
      *           contained within this bounds. 
      */
@@ -417,7 +417,7 @@
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
      * 
-     * Return:
+     * Returns:
      * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which 
      *          the coordinate lies.
      */
@@ -447,7 +447,7 @@
      *                                             this bound.
      *                                             Default is 0.
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
      *                       "dateline" (as specified by the borders of 
      *                       maxExtent). Note that this function only returns 
@@ -494,7 +494,7 @@
  * Parameters: 
  * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
  * 
- * Return:
+ * Returns:
  * {<OpenLayers.Bounds>} New <OpenLayers.Bounds> object built from the 
  *                       passed-in String.
  */
@@ -511,7 +511,7 @@
  * Parameters:
  * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
  *
- * Return:
+ * Returns:
  * {<OpenLayers.Bounds>} New <OpenLayers.Bounds> object built from the 
  *                       passed-in Array.
  */
@@ -530,7 +530,7 @@
  * Parameters:
  * size - {<OpenLayers.Size>} 
  *
- * Return:
+ * Returns:
  * {<OpenLayers.Bounds>} New <OpenLayers.Bounds> object built from the 
  *                       passed-in size.
  */
@@ -548,7 +548,7 @@
  * Parameters:
  * quadrant - {String} two character quadrant shortstring
  *
- * Return:
+ * Returns:
  * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
  *          you pass in "bl" it returns "tr", if you pass in "br" it 
  *          returns "tl", etc.

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Class.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Class.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Class.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -59,7 +59,7 @@
  * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
  *     <OpenLayers.Class> constructor instead.
  *
- * Return:
+ * Returns:
  * An OpenLayers class
  */
 OpenLayers.Class.create = function() {
@@ -78,7 +78,7 @@
  * Parameters:
  * class - One or more classes can be provided as arguments
  *
- * Return:
+ * Returns:
  * An object prototype
  */
 OpenLayers.Class.inherit = function () {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Element.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Element.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Element.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -13,7 +13,7 @@
      * Parameters: 
      * element - {DOMElement}
      * 
-     * Return:
+     * Returns:
      * {Boolean} Is the element visible?
      */
     visible: function(element) {
@@ -83,7 +83,7 @@
      * Parameters:
      * element - {DOMElement}
      * 
-     * Return:
+     * Returns:
      * {Integer} The offset height of the element passed in
      */
     getHeight: function(element) {
@@ -97,7 +97,7 @@
      * Parameters:
      * element - {DOMElement}
      * 
-     * Return:
+     * Returns:
      * {Object} Object with 'width' and 'height' properties which are the 
      *          dimensions of the element passed in.
      */
@@ -130,7 +130,7 @@
      * element - {DOMElement}
      * style - {?}
      * 
-     * Return:
+     * Returns:
      * {?}
      */
     getStyle: function(element, style) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/LonLat.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/LonLat.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/LonLat.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -41,7 +41,7 @@
      * Method: toString
      * Return a readable string version of the lonlat
      *
-     * Return:
+     * Returns:
      * {String} String representation of OpenLayers.LonLat object. 
      *           (ex. <i>"lon=5,lat=42"</i>)
      */
@@ -52,7 +52,7 @@
     /** 
      * APIMethod: toShortString
      * 
-     * Return:
+     * Returns:
      * {String} Shortened String representation of OpenLayers.LonLat object. 
      *         (ex. <i>"5, 42"</i>)
      */
@@ -63,7 +63,7 @@
     /** 
      * APIMethod: clone
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
      *                       and lat values
      */
@@ -78,7 +78,7 @@
      * lon - {Float}
      * lat - {Float}
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
      *                       lat passed-in added to this's. 
      */
@@ -98,7 +98,7 @@
      * Parameters:
      * ll - {<OpenLayers.LonLat>}
      * 
-     * Return:
+     * Returns:
      * {Boolean} Boolean value indicating whether the passed-in 
      *           <OpenLayers.LonLat> object has the same lon and lat 
      *           components as this.
@@ -119,7 +119,7 @@
      * Parameters:
      * maxExtent - {<OpenLayers.Bounds>}
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
      *                       "dateline" (as specified by the borders of 
      *                       maxExtent)
@@ -155,7 +155,7 @@
  * str - {String} Comma-separated Lon,Lat coordinate string. 
  *                 (ex. <i>"5,40"</i>)
  * 
- * Return:
+ * Returns:
  * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
  *                       passed-in String.
  */

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Pixel.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Pixel.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Pixel.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -28,7 +28,7 @@
      * x - {Number} The x coordinate
      * y - {Number} The y coordinate
      *
-     * Return:
+     * Returns:
      * An instance of OpenLayers.Pixel
      */
     initialize: function(x, y) {
@@ -40,7 +40,7 @@
      * Method: toString
      * Cast this object into a string
      *
-     * Return:
+     * Returns:
      * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
      */
     toString:function() {
@@ -51,7 +51,7 @@
      * APIMethod: clone
      * Return a clone of this pixel object
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Pixel>} A clone pixel
      */
     clone:function() {
@@ -65,7 +65,7 @@
      * Parameters:
      * px - {<OpenLayers.Pixel>}
      *
-     * Return:
+     * Returns:
      * {Boolean} The point passed in as parameter is equal to this. Note that
      * if px passed in is null, returns false.
      */
@@ -85,7 +85,7 @@
      * x - {Integer}
      * y - {Integer}
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
      * values passed in.
      */
@@ -104,7 +104,7 @@
     * Parameters
     * px - {<OpenLayers.Pixel>}
     * 
-    * Return:
+    * Returns:
     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
     *                      x&y values of the pixel passed in.
     */

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Size.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Size.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes/Size.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -38,7 +38,7 @@
      * Method: toString
      * Return the string representation of a size object
      *
-     * Return:
+     * Returns:
      * {String} The string representation of OpenLayers.Size object. 
      * (ex. <i>"w=55,h=66"</i>)
      */
@@ -50,7 +50,7 @@
      * APIMethod: clone
      * Create a clone of this size object
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
      * values
      */
@@ -66,7 +66,7 @@
      * Parameters:
      * sz - {<OpenLayers.Size>}
      *
-     * Return: 
+     * Returns: 
      * {Boolean} The passed in size has the same h and w properties as this one.
      * Note that if sz passed in is null, returns false.
      *

Modified: sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/BaseTypes.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -21,7 +21,7 @@
  * Parameters:
  * sStart - {Sring} The string we're testing for.
  *  
- * Return:
+ * Returns:
  * {Boolean} Whether or not this string starts with the string passed in.
  */
 String.prototype.startsWith = function(sStart) {
@@ -35,7 +35,7 @@
  * Parameters:
  * str - {String} The string that we're testing for.
  * 
- * Return:
+ * Returns:
  * {Boolean} Whether or not this string contains with the string passed in.
  */
 String.prototype.contains = function(str) {
@@ -46,7 +46,7 @@
  * APIMethod: String.trim
  * Removes leading and trailing whitespace characters from a string.
  * 
- * Return:
+ * Returns:
  * {String} A trimmed version of the string - all leading and 
  *          trailing spaces removed
  */
@@ -72,7 +72,7 @@
  * Parameters:
  * object - {Object} Can be a string or a number
  * 
- * Return: 
+ * Returns: 
  * {Integer} The index of the encountered object, or -1 if not found.
  */
 String.indexOf = function(object) {
@@ -92,7 +92,7 @@
  *     Ex. "chicken-head" becomes "chickenHead", and
  *     "-chicken-head" becomes "ChickenHead".
  * 
- * Return:
+ * Returns:
  * {String} The string, camelized
  */
 String.prototype.camelize = function() {
@@ -120,7 +120,7 @@
  * Parameters:
  * sig - {Integer}
  * 
- * Return:
+ * Returns:
  * {Integer} The number, rounded to the specified number of significant digits.
  *           If null, 0, or negative value passed in, returns 0
  */
@@ -136,7 +136,7 @@
         numStr = Math.round( this / Math.pow(10, exp)) * Math.pow(10, exp);
     }
     return parseInt(numStr);
-}
+};
 
 
 /*********************
@@ -153,7 +153,7 @@
  * Parameters:
  * object - {Object} the this parameter
  * 
- * Return:
+ * Returns:
  * {Function} A closure with 'this' altered to the first
  *            argument.
  */
@@ -187,7 +187,7 @@
  * Parameters:
  * object - {Object} A reference to this.
  * 
- * Return:
+ * Returns:
  * {Function}
  */
 Function.prototype.bindAsEventListener = function(object) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/DragFeature.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/DragFeature.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/DragFeature.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -25,6 +25,19 @@
     geometryTypes: null,
     
     /**
+     * APIProperty: onStart
+     * {Function} Define this function if you want to know when a drag starts.
+     *     The function should expect to receive two arguments: the feature
+     *     that is about to be dragged and the pixel location of the mouse.
+     *
+     * Parameters:
+     * feature - {OpenLayers.Feature.Vector} The feature that is about to be
+     *     dragged.
+     * pixel - {OpenLayers.Pixel} The pixel location of the mouse.
+     */
+    onStart: function(feature, pixel) {},
+
+    /**
      * APIProperty: onDrag
      * {Function} Define this function if you want to know about each move of a
      *     feature. The function should expect to receive two arguments: the
@@ -156,6 +169,9 @@
         // the return from the handlers is unimportant in this case
         this.dragHandler.deactivate();
         this.featureHandler.deactivate();
+        this.feature = null;
+        this.dragging = false;
+        this.lastPixel = null;
         return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
     },
 
@@ -191,7 +207,7 @@
      * pixel - {OpenLayers.Pixel} Location of the mouse event.
      */
     downFeature: function(pixel) {
-        this.dragHandler.dragging = true;
+        this.onStart(this.feature, pixel);
     },
 
     /**
@@ -239,6 +255,7 @@
      */
     doneDragging: function(pixel) {
         this.onComplete(this.feature, pixel);
+        this.feature = null;
     },
 
     /**
@@ -254,6 +271,7 @@
             this.dragHandler.deactivate();
             // TBD replace with CSS classes
             this.map.div.style.cursor = "default";
+            this.feature = null;
         } else {
             if(this.feature.id == feature.id) {
                 this.over = false;

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/ModifyFeature.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/ModifyFeature.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/ModifyFeature.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -5,10 +5,13 @@
 
 /**
  * @requires OpenLayers/Control/DragFeature.js
+ * @requires OpenLayers/Control/SelectFeature.js
  * 
  * Class: OpenLayers.Control.ModifyFeature
- * Control to modify features.  When activated, a click renders the verticies
- *     of a feature - these verticies can then be dragged.  Create a new
+ * Control to modify features.  When activated, a click renders the vertices
+ *     of a feature - these vertices can then be dragged. 
+ *     New features are
+ *     added by dragging "virtual vertices" between vertices.  Create a new
  *     control with the <OpenLayers.Control.ModifyFeature> constructor.
  *
  * Inherits From:
@@ -32,23 +35,23 @@
     
     /**
      * Property: feature
-     * {OpenLayers.Feature.Vector} Feature currently available for modification.
+     * {<OpenLayers.Feature.Vector>} Feature currently available for modification.
      */
     feature: null,
     
     /**
-     * Property: verticies
+     * Property: vertices
      * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available
      *     for dragging.
      */
-    verticies: null,
+    vertices: null,
     
     /**
-     * Property: virtualVerticies
-     * {Array(<OpenLayers.Feature.Vector>)} Virtual verticies in the middle
-     *                  of each edge
+     * Property: virtualVertices
+     * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle
+     *     of each edge.
      */
-    virtualVerticies: null,
+    virtualVertices: null,
 
     /**
      * Property: selectControl
@@ -61,9 +64,9 @@
      * {<OpenLayers.Control.DragFeature>}
      */
     dragControl: null,
-    
+
     /**
-     * Property: virtualStyle
+     * APIProperty: virtualStyle
      * {<OpenLayers.Feature.Vector.Style>}
      */
     virtualStyle: null,
@@ -71,26 +74,24 @@
     /**
      * APIProperty: onModificationStart 
      * {Function} Optional function to be called when a feature is selected
-     *              to be modified.
-     *            The function should expect to be called with a feature.
-     *            This could be used for example to allow to lock the feature
-     *            on server-side
+     *     to be modified. The function should expect to be called with a
+     *     feature.  This could be used for example to allow to lock the
+     *     feature on server-side.
      */
     onModificationStart: function() {},
 
     /**
      * APIProperty: onModification
-     * {Function} Optional function to be called when a feature has been 
-     *             modified.
-     *                  The function should expect to be called with a feature.
+     * {Function} Optional function to be called when a feature has been
+     *     modified.  The function should expect to be called with a feature.
      */
     onModification: function() {},
 
     /**
      * APIProperty: onModificationEnd
      * {Function} Optional function to be called when a feature is finished 
-     *            to be modified.
-     *                  The function should expect to be called with a feature.
+     *     being modified.  The function should expect to be called with a
+     *     feature.
      */
     onModificationEnd: function() {},
     
@@ -105,33 +106,46 @@
      *     control.
      */
     initialize: function(layer, options) {
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
         this.layer = layer;
-        this.verticies = [];
-        this.virtualVerticies = [];
-        var control = this;
-        this.selectControl = new OpenLayers.Control.SelectFeature(layer,
-                                    {geometryTypes: this.geometryTypes,
-                                     onSelect: function(feature) {
-                                        control.onSelect.apply(control, [feature]);
-                                     },
-                                     onUnselect: function(feature) {
-                                        control.onUnselect.apply(control, [feature]);
-                                     }});
-        this.dragControl = new OpenLayers.Control.DragFeature(layer,
-                                {geometryTypes: ["OpenLayers.Geometry.Point"],
-                                 snappingOptions: options.snappingOptions,
-                                 onDrag: function(feature) {
-                                    control.onDrag.apply(control, [feature]);
-                                 },
-                                 onComplete: function(feature) {
-                                    control.onComplete.apply(control, [feature]);
-                                 }});
-                                 
-        // virtual verticies are rendered
+        this.vertices = [];
+        this.virtualVertices = [];
         this.styleVirtual = OpenLayers.Util.extend({}, this.layer.style);
         this.styleVirtual.fillOpacity = 0.3;
         this.styleVirtual.strokeOpacity = 0.3;
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        var control = this;
+
+        // configure the select control
+        var selectOptions = {
+            geometryTypes: this.geometryTypes,
+            onSelect: function(feature) {
+                control.selectFeature.apply(control, [feature]);
+            },
+            onUnselect: function(feature) {
+                control.unselectFeature.apply(control, [feature]);
+            }
+        };
+        this.selectControl = new OpenLayers.Control.SelectFeature(
+            layer, selectOptions
+        );
+
+        // configure the drag control
+        var dragOptions = {
+            geometryTypes: ["OpenLayers.Geometry.Point"],
+            snappingOptions: this.snappingOptions,
+            onStart: function(feature, pixel) {
+                control.dragStart.apply(control, [feature, pixel]);
+            },
+            onDrag: function(feature) {
+                control.dragVertex.apply(control, [feature]);
+            },
+            onComplete: function(feature) {
+                control.dragComplete.apply(control, [feature]);
+            }
+        };
+        this.dragControl = new OpenLayers.Control.DragFeature(
+            layer, dragOptions
+        );
     },
 
     /**
@@ -165,83 +179,126 @@
      * {Boolean} Successfully deactivated the control.
      */
     deactivate: function() {
+        var deactivated = false;
         // the return from the controls is unimportant in this case
         if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
-            this.layer.removeFeatures(this.verticies);
-            this.layer.removeFeatures(this.virtualVerticies);
-            this.verticies = [];
+            this.layer.removeFeatures(this.vertices);
+            this.layer.removeFeatures(this.virtualVertices);
+            this.vertices = [];
             this.dragControl.deactivate();
+            if(this.feature) {
+                this.selectControl.unselect.apply(this.selectControl,
+                                                  [this.feature]);
+            }
             this.selectControl.deactivate();
-            return true;
-        } else {
-            return false;
-        }   
+            deactivated = true;
+        }
+        return deactivated;
     },
 
     /**
-     * Method: onSelect
+     * Method: selectFeature
      * Called when the select feature control selects a feature.
      *
      * Parameters:
-     * feature - {OpenLayers.Feature.Vector} The selected feature.
+     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
      */
-    onSelect: function(feature) {
+    selectFeature: function(feature) {
         this.feature = feature;
-        if(this.verticies.length > 0) {
-            this.layer.removeFeatures(this.verticies);
-            this.verticies = [];
-        }
-        if(this.virtualVerticies.length > 0) {
-            this.layer.removeFeatures(this.virtualVerticies);
-            this.virtualVerticies = [];
-        }
-        if(this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
-            this.collectVerticies(feature.geometry);
-            this.layer.addFeatures(this.verticies);
-            this.layer.addFeatures(this.virtualVerticies);
-        }
+        this.resetVertices();
         this.dragControl.activate();
         this.onModificationStart(this.feature);
     },
 
     /**
-     * Method: onUnselect
+     * Method: unselectFeature
      * Called when the select feature control unselects a feature.
      *
      * Parameters:
-     * feature - {OpenLayers.Feature.Vector} The unselected feature.
+     * feature - {<OpenLayers.Feature.Vector>} The unselected feature.
      */
-    onUnselect: function(feature) {
-        this.layer.removeFeatures(this.verticies);
-        this.layer.removeFeatures(this.virtualVerticies);
-        this.verticies = [];
-        this.virtualVerticies = [];
+    unselectFeature: function(feature) {
+        this.layer.removeFeatures(this.vertices);
+        this.layer.removeFeatures(this.virtualVertices);
+        this.vertices = [];
+        this.virtualVertices = [];
         this.feature = null;
         this.dragControl.deactivate();
         this.onModificationEnd(feature);
     },
+
+    /**
+     * Method: dragStart
+     * Called by the drag feature control with before a feature is dragged.
+     *     This method is used to differentiate between points and vertices
+     *     of higher order geometries.  This respects the <geometryTypes>
+     *     property and forces a select of points when the drag control is
+     *     already active (and stops events from propagating to the select
+     *     control).
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be
+     *     dragged.
+     * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
+     */
+    dragStart: function(feature, pixel) {
+        // only change behavior if the feature is not in the vertices array
+        if(feature != this.feature &&
+           OpenLayers.Util.indexOf(this.vertices, feature) == -1 &&
+           OpenLayers.Util.indexOf(this.virtualVertices, feature) == -1) {
+            if(this.feature) {
+                // unselect the currently selected feature
+                this.selectControl.clickFeature.apply(this.selectControl,
+                                                      [this.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.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.dragHandler.started = true;
+                this.dragControl.dragHandler.start = pixel;
+                this.dragControl.dragHandler.last = pixel;
+            }
+        }
+    },
     
     /**
-     * Method: onDrag
+     * Method: dragVertex
      * Called by the drag feature control with each drag move of a vertex.
      *
      * Parameters:
-     * vertex - {OpenLayers.Feature.Vector} The vertex being dragged.
+     * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
      */
-    onDrag: function(vertex) {
+    dragVertex: function(vertex) {
         if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
             if(this.feature != vertex) {
                 this.feature = vertex;
             }
+        } else {
+            if(OpenLayers.Util.indexOf(this.virtualVertices, vertex) != -1) {
+                vertex.geometry.parent.addComponent(vertex.geometry,
+                                                    vertex._index);
+                delete vertex._index;
+                OpenLayers.Util.removeItem(this.virtualVertices, vertex);
+                this.layer.removeFeatures(vertex);
+            }
         }
-        if (OpenLayers.Util.indexOf(this.virtualVerticies, vertex) != -1) {
-            vertex.data.parent.addComponent(vertex.geometry, vertex.data.index);
-            OpenLayers.Util.removeItem(this.virtualVerticies, vertex);
-            this.layer.removeFeatures(vertex);
-        }
-        
         this.layer.drawFeature(this.feature, this.selectControl.selectStyle);
-        this.layer.removeFeatures(this.virtualVerticies);
+        this.layer.removeFeatures(this.virtualVertices);
         // 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
         // maintain node z-index
@@ -249,72 +306,84 @@
     },
     
     /**
-     * Method: onDrag
+     * Method: dragComplete
      * Called by the drag feature control when the feature dragging is complete.
      *
      * Parameters:
-     * vertex - {OpenLayers.Feature.Vector} The vertex being dragged.
+     * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
      */
-    onComplete: function(vertex) {
-        // TBD check if this is needed
-        // if dragHandler properties are not reset
-        // the vertex is dragged once more
-        this.dragControl.dragHandler.feature = null;
-        this.dragControl.dragHandler.dragging = false;
-        
-        this.layer.removeFeatures(this.verticies);
-        this.layer.removeFeatures(this.virtualVerticies);
-        this.verticies = [];
-        this.virtualVerticies = [];
-        
-        this.collectVerticies(this.feature.geometry);
-        this.layer.addFeatures(this.verticies);
-        this.layer.addFeatures(this.virtualVerticies);
+    dragComplete: function(vertex) {
+        this.resetVertices();
         this.onModification(this.feature);
     },
     
     /**
-     * Method: collectVerticies
-     * Collect the verticies from the input geometry and push them on to the
-     *     control's vertices array
-     *
-     * Parameters:
-     * geometry - {OpenLayers.Geometry} The target geometry.
+     * Method: resetVertices
      */
-    collectVerticies: function(geometry) {
-        var i, vertex, component;
-        
-        if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
-            vertex = new  OpenLayers.Feature.Vector(geometry);
-            this.verticies.push(vertex);
-        } else {
-            for(i=0; i<geometry.components.length; ++i) {
-                component = geometry.components[i];
-                if(component.CLASS_NAME == "OpenLayers.Geometry.Point") {
-                    vertex = new OpenLayers.Feature.Vector(component);
-                    this.verticies.push(vertex);
-                } else {
-                    this.collectVerticies(component);
+    resetVertices: function() {
+        if(this.vertices.length > 0) {
+            this.layer.removeFeatures(this.vertices);
+            this.vertices = [];
+        }
+        if(this.virtualVertices.length > 0) {
+            this.layer.removeFeatures(this.virtualVertices);
+            this.virtualVertices = [];
+        }
+        if(this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
+            this.collectVertices(this.feature.geometry);
+            this.layer.addFeatures(this.vertices);
+            this.layer.addFeatures(this.virtualVertices);
+        }
+    },
+
+    /**
+     * Method: collectVertices
+     * Collect the vertices from the modifiable feature's geometry and push
+     *     them on to the control's vertices array.
+     */
+    collectVertices: function() {
+        this.vertices = [];
+        this.virtualVirtices = [];        
+        var control = this;
+        function collectComponentVertices(geometry) {
+            var i, vertex, component;
+            if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                vertex = new OpenLayers.Feature.Vector(geometry);
+                control.vertices.push(vertex);
+            } else {
+                for(i=0; i<geometry.components.length; ++i) {
+                    component = geometry.components[i];
+                    if(component.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                        vertex = new OpenLayers.Feature.Vector(component);
+                        control.vertices.push(vertex);
+                    } else {
+                        collectComponentVertices(component);
+                    }
                 }
-            }
-            
-            // add virtual verticies in the middle of each edge
-            for (i = 0; i < geometry.components.length - 1; i++) {
-                var prevVertex = geometry.components[i];
-                var nextVertex = geometry.components[i + 1];
-                if (prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" &&
-                    nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") {
-                    var x = (prevVertex.x + nextVertex.x) / 2;
-                    var y = (prevVertex.y + nextVertex.y) / 2;
-                    var point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x, y), null, this.styleVirtual);
-                    point.data = {
-                        parent: geometry,
-                        index: i + 1
+                
+                // add virtual vertices in the middle of each edge
+                if(geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
+                    for(i=0; i<geometry.components.length-1; ++i) {
+                        var prevVertex = geometry.components[i];
+                        var nextVertex = geometry.components[i + 1];
+                        if(prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" &&
+                           nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                            var x = (prevVertex.x + nextVertex.x) / 2;
+                            var y = (prevVertex.y + nextVertex.y) / 2;
+                            var point = new OpenLayers.Feature.Vector(
+                                new OpenLayers.Geometry.Point(x, y),
+                                null, control.styleVirtual
+                            );
+                            // set the virtual parent and intended index
+                            point.geometry.parent = geometry;
+                            point._index = i + 1;
+                            control.virtualVertices.push(point);
+                        }
                     }
-                    this.virtualVerticies.push(point);
                 }
             }
-        }
+        }       
+        collectComponentVertices(this.feature.geometry);
     },
 
     /**

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/MouseDefaults.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/MouseDefaults.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/MouseDefaults.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -109,11 +109,11 @@
     },
 
     /**
-    * Method: defaultDblClick
-    * 
-    * Parameters:
-    * evt - {Event} 
-    */
+     * Method: defaultDblClick
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
     defaultDblClick: function (evt) {
         var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
         this.map.setCenter(newCenter, this.map.zoom + 1);
@@ -122,11 +122,11 @@
     },
 
     /**
-    * Method: defaultMouseDown
-    * 
-    * Parameters:
-    * evt - {Event} 
-    */
+     * Method: defaultMouseDown
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
     defaultMouseDown: function (evt) {
         if (!OpenLayers.Event.isLeftClick(evt)) return;
         this.mouseDragStart = evt.xy.clone();
@@ -151,11 +151,11 @@
     },
 
     /**
-    * Method: defaultMouseMove
-    *
-    * Parameters:
-    * evt - {Event} 
-    */
+     * Method: defaultMouseMove
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
     defaultMouseMove: function (evt) {
         // record the mouse position, used in onWheelEvent
         this.mousePosition = evt.xy.clone();
@@ -188,11 +188,11 @@
     },
 
     /**
-    * Method: defaultMouseUp
-    * 
-    * Parameters:
-    * evt - {<OpenLayers.Event>} 
-    */
+     * Method: defaultMouseUp
+     * 
+     * Parameters:
+     * evt - {<OpenLayers.Event>} 
+     */
     defaultMouseUp: function (evt) {
         if (!OpenLayers.Event.isLeftClick(evt)) return;
         if (this.zoomBox) {
@@ -208,11 +208,11 @@
     },
 
     /**
-    * Method: defaultMouseOut
-    * 
-    * Parameters:
-    * evt - {Event} 
-    */
+     * Method: defaultMouseOut
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
     defaultMouseOut: function (evt) {
         if (this.mouseDragStart != null && 
             OpenLayers.Util.mouseLeft(evt, this.map.div)) {
@@ -343,4 +343,3 @@
 
     CLASS_NAME: "OpenLayers.Control.MouseDefaults"
 });
-

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/OverviewMap.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/OverviewMap.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/OverviewMap.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -555,7 +555,7 @@
      * Method: getRectPxBounds
      * Get extent rectangle pixel bounds
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>} A bounds which is the extent rectangle's pixel
      * bounds (relative to the parent element)
      */
@@ -594,7 +594,7 @@
      * Parameters:
      * lonLatBounds - {<OpenLayers.Bounds>}
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
      * translated into pixel bounds for the overview map
      */
@@ -620,7 +620,7 @@
      * Parameters:
      * pxBounds - {<OpenLayers.Bounds>}
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
      * translated into lon/lat bounds for the overview map
      */
@@ -642,7 +642,7 @@
      * Parameters:
      * overviewMapPx - {<OpenLayers.Pixel>}
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.LonLat>} Location which is the passed-in overview map
      * OpenLayers.Pixel, translated into lon/lat by the overview map
      */
@@ -665,7 +665,7 @@
      * Parameters:
      * lonlat - {<OpenLayers.LonLat>}
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
      * translated into overview map pixels
      */

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/PanZoom.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/PanZoom.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/PanZoom.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -55,14 +55,14 @@
     },
 
     /**
-    * Method: draw
-    *
-    * Parameters:
-    * px - {<OpenLayers.Pixel>} 
-    * 
-    * Returns:
-    * {DOMElement} A reference to the container div for the PanZoom control
-    */
+     * Method: draw
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     * 
+     * Returns:
+     * {DOMElement} A reference to the container div for the PanZoom control
+     */
     draw: function(px) {
         // initialize our internal div
         OpenLayers.Control.prototype.draw.apply(this, arguments);
@@ -132,7 +132,8 @@
      * Parameters:
      * evt - {Event} 
      *
-     * Returns: {Boolean}
+     * Returns:
+     * {Boolean}
      */
     doubleClick: function (evt) {
         OpenLayers.Event.stop(evt);

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/Panel.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/Panel.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/Panel.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -82,7 +82,8 @@
     /**
      * Method: draw
      *
-     * Returns: {DOMElement}
+     * Returns:
+     * {DOMElement}
      */    
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/Permalink.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/Permalink.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/Permalink.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -78,7 +78,8 @@
     /**
      * Method: draw
      *
-     * Returns: {DOMElement}
+     * Returns:
+     * {DOMElement}
      */    
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control/Scale.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control/Scale.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control/Scale.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -34,7 +34,8 @@
     /**
      * Method: draw
      * 
-     * Returns: {DOMElemen}t
+     * Returns:
+     * {DOMElemen}
      */    
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments);

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Control.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Control.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Control.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -161,7 +161,7 @@
      * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
      *      or null.
      *
-     * Return:
+     * Returns:
      * {DOMElement} A reference to the DIV DOMElement containing the control
      */
     draw: function (px) {
@@ -198,7 +198,7 @@
      * handler if one has been set.  Controls can be
      * deactivated by calling the deactivate() method.
      * 
-     * Return:
+     * Returns:
      * {Boolean}  True if the control was successfully activated or
      *            false if the control was already active.
      */
@@ -218,7 +218,7 @@
      * Deactivates a control and it's associated handler if any.  The exact
      * effect of this depends on the control itself.
      * 
-     * Return:
+     * Returns:
      * {Boolean} True if the control was effectively deactivated or false
      *           if the control was already inactive.
      */

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Events.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Events.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Events.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -138,7 +138,7 @@
      * event - {Event} 
      * tagName - {String} 
      * 
-     * Return:
+     * Returns:
      * {DOMElement} The first node with the given tagName, starting from the
      * node the event was triggered on and traversing the DOM upwards
      */
@@ -252,7 +252,7 @@
      * observer - {function} 
      * useCapture - {Boolean} 
      *  
-     * Return:
+     * Returns:
      * {Boolean} Whether or not the event observer was removed
      */
     stopObserving: function(elementParam, name, observer, useCapture) {
@@ -656,9 +656,11 @@
         }
         return new OpenLayers.Pixel(
             (evt.clientX + (document.documentElement.scrollLeft
-                         || document.body.scrollLeft)) - this.element.offsets[0], 
+                         || document.body.scrollLeft)) - this.element.offsets[0]
+                         - (document.documentElement.clientLeft || 0), 
             (evt.clientY + (document.documentElement.scrollTop
-                         || document.body.scrollTop)) - this.element.offsets[1] 
+                         || document.body.scrollTop)) - this.element.offsets[1]
+                         - (document.documentElement.clientTop || 0)
         ); 
     },
 

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Feature/Vector.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Feature/Vector.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Feature/Vector.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -96,14 +96,14 @@
         OpenLayers.Feature.prototype.destroy.apply(this, arguments);
     },
     
-   /**
-    * Method: clone
-    * Create a clone of this vector feature.  Does not set any non-standard
-    *     properties.
-    *
-    * Returns:
-    * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
-    */
+    /**
+     * Method: clone
+     * Create a clone of this vector feature.  Does not set any non-standard
+     *     properties.
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
+     */
     clone: function () {
         return new OpenLayers.Feature.Vector(this.geometry.clone(),
                                              this.attributes,
@@ -114,7 +114,7 @@
      * Method: onScreen
      * HACK - we need to rewrite this for non-point geometry
      * 
-     * Return:
+     * Returns:
      * {Boolean} For now just returns null
      */
     onScreen:function() {
@@ -126,7 +126,7 @@
      * HACK - we need to decide if all vector features should be able to
      *     create markers
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Marker>} For now just returns null
      */
     createMarker: function() {
@@ -150,7 +150,7 @@
      * HACK - we need to decide if all vector features should be able to
      *     create popups
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Popup>} For now just returns null
      */
     createPopup: function() {
@@ -264,11 +264,10 @@
 });
 
 
-/*
+/**
  * Constant: OpenLayers.Feature.Vector.style
- * OpenLayers features can have a number of 
- * style attributes. The 'default' style will
- * typically be used if no other style is specified.
+ * OpenLayers features can have a number of style attributes. The 'default' 
+ *     style will typically be used if no other style is specified.
  *
  * Default style properties:
  *
@@ -287,8 +286,14 @@
  *  - hoverPointRadius: 1,
  *  - hoverPointUnit: "%",
  *  - pointerEvents: "visiblePainted"
+ *
+ * Other style properties that have no default values:
+ *
+ *  - externalGraphic,
+ *  - graphicWidth,
+ *  - graphicHeight,
+ *  - graphicOpacity
  */ 
-
 OpenLayers.Feature.Vector.style = {
     'default': {
         fillColor: "#ee9900",

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Feature/WFS.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Feature/WFS.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Feature/WFS.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -54,7 +54,7 @@
      * Parameters:
      * xmlNode - {XMLNode} 
      * 
-     * Return:
+     * Returns:
      * {Object} Data Object with 'id', 'lonlat', and private properties set
      */
     processXMLNode: function(xmlNode) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Feature.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Feature.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Feature.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -6,6 +6,7 @@
 /**
  * @requires OpenLayers/Util.js
  * @requires OpenLayers/Marker.js
+ * @requires OpenLayers/Popup/AnchoredBubble.js
  *
  * Class: OpenLayers.Feature
  * Features are combinations of geography and attributes. The OpenLayers.Feature
@@ -43,6 +44,13 @@
      */
     marker: null,
 
+    /**
+     * APIProperty: popupClass
+     * {<OpenLayers.Class>} The class which will be used to instantiate
+     *     a new Popup. Default is <OpenLayers.Popup.AnchoredBubble>.
+     */
+    popupClass: OpenLayers.Popup.AnchoredBubble,
+
     /** 
      * Property: popup 
      * {<OpenLayers.Popup>} 
@@ -58,7 +66,7 @@
      * lonlat - {<OpenLayers.LonLat>} 
      * data - {Object} 
      * 
-     * Return:
+     * Returns:
      * {<OpenLayers.Feature>}
      */
     initialize: function(layer, lonlat, data) {
@@ -117,7 +125,7 @@
      * Method: createMarker
      * Based on the data associated with the Feature, create and return a marker object.
      *
-     * Return: 
+     * Returns: 
      * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
      *          set in this.data. If no 'lonlat' is set, returns null. If no
      *          'icon' is set, OpenLayers.Marker() will load the default image.
@@ -145,9 +153,9 @@
 
     /**
      * Method: createPopup
-     *  Creates a popup object created from the 'lonlat', 'popupSize',
-     *  and 'popupContentHTML' properties set in this.data. It uses
-     *  this.marker.icon as default anchor. 
+     * Creates a popup object created from the 'lonlat', 'popupSize',
+     *     and 'popupContentHTML' properties set in this.data. It uses
+     *     this.marker.icon as default anchor. 
      *  
      *  If no 'lonlat' is set, returns null. 
      *  If no this.marker has been created, no anchor is sent.
@@ -158,7 +166,10 @@
      * closeBox - {Boolean} create popup with closebox or not
      * 
      * Returns:
-     * {<OpenLayers.Popup.AnchoredBubble>} 
+     * {<OpenLayers.Popup>} Returns the created popup, which is also set
+     *     as 'popup' property of this feature. Will be of whatever type
+     *     specified by this feature's 'popupClass' property, but must be
+     *     of type <OpenLayers.Popup>.
      * 
      */
     createPopup: function(closeBox) {
@@ -168,11 +179,13 @@
             var id = this.id + "_popup";
             var anchor = (this.marker) ? this.marker.icon : null;
 
-            this.popup = new OpenLayers.Popup.AnchoredBubble(id, 
-                                                    this.lonlat,
-                                                    this.data.popupSize,
-                                                    this.data.popupContentHTML,
-                                                    anchor, closeBox); 
+            this.popup = new this.popupClass(id, 
+                                             this.lonlat,
+                                             this.data.popupSize,
+                                             this.data.popupContentHTML,
+                                             anchor, 
+                                             closeBox); 
+            this.popup.feature = this;
         }        
         return this.popup;
     },
@@ -186,6 +199,7 @@
      *   should also be able to override the destruction
      */
     destroyPopup: function() {
+        this.popup.feature = null;
         this.popup.destroy() 
     },
 

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Format/GeoJSON.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Format/GeoJSON.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Format/GeoJSON.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -1,644 +1,641 @@
-/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Format/JSON.js
- *
- * Class: OpenLayers.Format.GeoJSON
- * Read and write GeoJSON. Create a new parser with the
- *     <OpenLayers.Format.GeoJSON> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Format.JSON>
- */
-OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, {
-
-    /**
-     * Constructor: OpenLayers.Format.GeoJSON
-     * Create a new parser for GeoJSON.
-     *
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *     this instance.
-     */
-    initialize: function(options) {
-        OpenLayers.Format.JSON.prototype.initialize.apply(this, [options]);
-    },
-
-    /**
-     * APIMethod: read
-     * Deserialize a GeoJSON string.
-     *
-     * Parameters:
-     * json - {String} A GeoJSON string
-     * type - {String} Optional string that determines the structure of
-     *     the output.  Supported values are "Geometry", "Feature",
-     *     "GeometryCollection", and "FeatureCollection".  If absent or null,
-     *     a default of "FeatureCollection" is assumed.
-     * filter - {Function} A function which will be called for every key and
-     *     value at every level of the final result. Each value will be
-     *     replaced by the result of the filter function. This can be used to
-     *     reform generic objects into instances of classes, or to transform
-     *     date strings into Date objects.
-     *
-     * Returns: 
-     * {Object} The return depends on the value of the type argument. If type
-     *     is "FeatureCollection" (the default), the return will be an array
-     *     of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
-     *     must represent a single geometry, and the return will be an
-     *     <OpenLayers.Geometry>.  If type is "Feature", the input json must
-     *     represent a single feature, and the return will be an
-     *     <OpenLayers.Feature.Vector>.  If type is "GeometryCollection", the
-     *     input json must represent a geometry collection, and the return will
-     *     be an array of <OpenLayers.Geometry>.
-     */
-    read: function(json, type, filter) {
-        type = (type) ? type : "FeatureCollection";
-        var results = null;
-        var obj = null;
-        if (typeof json == "string") {
-            obj = OpenLayers.Format.JSON.prototype.read.apply(this,
-                                                              [json, filter]);
-        } else { 
-            obj = json;
-        }    
-        if(!obj) {
-            OpenLayers.Console.error("Bad JSON: " + json);
-        } else if(typeof(obj.type) != "string") {
-            OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
-        } else if(this.isValidType(obj, type)) {
-            switch(type) {
-                case "Geometry":
-                    try {
-                        results = this.parseGeometry(obj);
-                    } catch(err) {
-                        OpenLayers.Console.error(err);
-                    }
-                    break;
-                case "Feature":
-                    try {
-                        results = this.parseFeature(obj);
-                        results.type = "Feature";
-                    } catch(err) {
-                        OpenLayers.Console.error(err);
-                    }
-                    break;
-                case "GeometryCollection":
-                    results = [];
-                    for(var i=0; i<obj.members.length; ++i) {
-                        try {
-                            results.push(this.parseGeometry(obj.members[i]));
-                        } catch(err) {
-                            results = null;
-                            OpenLayers.Console.error(err);
-                        }
-                    }
-                    break;
-                case "FeatureCollection":
-                    // for type FeatureCollection, we allow input to be any type
-                    results = [];
-                    switch(obj.type) {
-                        case "Feature":
-                            try {
-                                results.push(this.parseFeature(obj));
-                            } catch(err) {
-                                results = null;
-                                OpenLayers.Console.error(err);
-                            }
-                            break;
-                        case "FeatureCollection":
-                            for(var i=0; i<obj.members.length; ++i) {
-                                try {
-                                    results.push(this.parseFeature(obj.members[i]));
-                                } catch(err) {
-                                    results = null;
-                                    OpenLayers.Console.error(err);
-                                }
-                            }
-                            break;
-                        case "GeometryCollection":
-                            for(var i=0; i<obj.members.length; ++i) {
-                                try {
-                                    var geom = this.parseGeometry(obj.members[i]);
-                                    results.push(new OpenLayers.Feature.Vector(geom));
-                                } catch(err) {
-                                    results = null;
-                                    OpenLayers.Console.error(err);
-                                }
-                            }
-                            break;
-                        default:
-                            try {
-                                var geom = this.parseGeometry(obj);
-                                results.push(new OpenLayers.Feature.Vector(geom));
-                            } catch(err) {
-                                results = null;
-                                OpenLayers.Console.error(err);
-                            }
-                    }
-                break;
-            }
-        }
-        return results;
-    },
-    
-    /**
-     * Method: isValidType
-     * Check if a GeoJSON object is a valid representative of the given type.
-     *
-     * Returns:
-     * {Boolean} The object is valid GeoJSON object of the given type.
-     */
-    isValidType: function(obj, type) {
-        var valid = false;
-        switch(type) {
-            case "Geometry":
-                if(OpenLayers.Util.indexOf(["Point", "MultiPoint", "LineString",
-                                            "MultiLineString", "Polygon",
-                                            "MultiPolygon", "Box"], obj.type) == -1) {
-                    // unsupported geometry type
-                    OpenLayers.Console.error("Unsupported geometry type: " +
-                                              obj.type);
-                } else {
-                    valid = true;
-                }
-                break;
-            case "FeatureCollection":
-                // allow for any type to be converted to a feature collection
-                valid = true;
-                break
-            default:
-                // for GeometryCollection and Feature, types must match
-                if(obj.type == type) {
-                    valid = true;
-                } else {
-                    OpenLayers.Console.error("Cannot convert types from " +
-                                              obj.type + " to " + type);
-                }
-        }
-        return valid;
-    },
-    
-    /**
-     * Method: parseFeature
-     * Convert a feature object from GeoJSON into an
-     *     <OpenLayers.Feature.Vector>.
-     *
-     * Parameters:
-     * obj - {Object} An object created from a GeoJSON object
-     *
-     * Returns:
-     * {<OpenLayers.Feature.Vector>} A feature.
-     */
-    parseFeature: function(obj) {
-        var feature, geometry, attributes;
-        attributes = (obj.properties) ? obj.properties : {};
-        try {
-            geometry = this.parseGeometry(obj.geometry);            
-        } catch(err) {
-            // deal with bad geometries
-            throw err;
-        }
-        feature = new OpenLayers.Feature.Vector(geometry, attributes);
-        if(obj.id) {
-            feature.fid = obj.id;
-        }
-        return feature;
-    },
-    
-    /**
-     * Method: parseGeometry
-     * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>.
-     *
-     * Parameters:
-     * obj - {Object} An object created from a GeoJSON object
-     *
-     * Returns: 
-     * {<OpenLayers.Geometry>} A geometry.
-     */
-    parseGeometry: function(obj) {
-        var geometry;
-        if(!(obj.coordinates instanceof Array)) {
-            throw "Geometry must have coordinates array: " + obj;
-        }
-        if(!this.parseCoords[obj.type.toLowerCase()]) {
-            throw "Unsupported geometry type: " + obj.type;
-        }
-        try {
-            geometry = this.parseCoords[obj.type.toLowerCase()].apply(this, [obj.coordinates]);
-        } catch(err) {
-            // deal with bad coordinates
-            throw err;
-        }
-        return geometry;
-    },
-    
-    /**
-     * Property: parseCoords
-     * Object with properties corresponding to the GeoJSON geometry types.
-     *     Property values are functions that do the actual parsing.
-     */
-    parseCoords: {
-        /**
-         * Method: parseCoords.point
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "point": function(array) {
-            if(array.length != 2) {
-                throw "Only 2D points are supported: " + array;
-            }
-            return new OpenLayers.Geometry.Point(array[0], array[1]);
-        },
-        
-        /**
-         * Method: parseCoords.multipoint
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "multipoint": function(array) {
-            var points = [];
-            var p = null;
-            for(var i=0; i<array.length; ++i) {
-                try {
-                    p = this.parseCoords["point"].apply(this, [array[i]]);
-                } catch(err) {
-                    throw err;
-                }
-                points.push(p);
-            }
-            return new OpenLayers.Geometry.MultiPoint(points);
-        },
-
-        /**
-         * Method: parseCoords.linestring
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "linestring": function(array) {
-            var points = [];
-            var p = null;
-            for(var i=0; i<array.length; ++i) {
-                try {
-                    p = this.parseCoords["point"].apply(this, [array[i]]);
-                } catch(err) {
-                    throw err;
-                }
-                points.push(p);
-            }
-            return new OpenLayers.Geometry.LineString(points);
-        },
-        
-        /**
-         * Method: parseCoords.multilinestring
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "multilinestring": function(array) {
-            var lines = [];
-            var l = null;
-            for(var i=0; i<array.length; ++i) {
-                try {
-                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
-                } catch(err) {
-                    throw err;
-                }
-                lines.push(l);
-            }
-            return new OpenLayers.Geometry.MultiLineString(lines);
-        },
-        
-        /**
-         * Method: parseCoords.polygon
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Returns:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "polygon": function(array) {
-            var rings = [];
-            var r, l;
-            for(var i=0; i<array.length; ++i) {
-                try {
-                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
-                } catch(err) {
-                    throw err;
-                }
-                r = new OpenLayers.Geometry.LinearRing(l.components);
-                rings.push(r);
-            }
-            return new OpenLayers.Geometry.Polygon(rings);
-        },
-
-        /**
-         * Method: parseCoords.multipolygon
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "multipolygon": function(array) {
-            var polys = [];
-            var p = null;
-            for(var i=0; i<array.length; ++i) {
-                try {
-                    p = this.parseCoords["polygon"].apply(this, [array[i]]);
-                } catch(err) {
-                    throw err;
-                }
-                polys.push(p);
-            }
-            return new OpenLayers.Geometry.MultiPolygon(polys);
-        },
-
-        /**
-         * Method: parseCoords.box
-         * Convert a coordinate array from GeoJSON into an
-         *     <OpenLayers.Geometry>.
-         *
-         * Parameters:
-         * array - {Object} The coordinates array from the GeoJSON fragment.
-         *
-         * Returns:
-         * {<OpenLayers.Geometry>} A geometry.
-         */
-        "box": function(array) {
-            if(array.length != 2) {
-                throw "GeoJSON box coordinates must have 2 elements";
-            }
-            return new OpenLayers.Geometry.Polygon([
-                new OpenLayers.Geometry.LinearRing([
-                    new OpenLayers.Geometry.Point(array[0][0], array[0][1]),
-                    new OpenLayers.Geometry.Point(array[1][0], array[0][1]),
-                    new OpenLayers.Geometry.Point(array[1][0], array[1][1]),
-                    new OpenLayers.Geometry.Point(array[0][0], array[1][1]),
-                    new OpenLayers.Geometry.Point(array[0][0], array[0][1])
-                ])
-            ]);
-        }
-
-    },
-
-    /**
-     * APIMethod: write
-     * Serialize a feature, geometry, array of features, or array of geometries
-     *     into a GeoJSON string.
-     *
-     * Parameters:
-     * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>,
-     *     or an array of either features or geometries.
-     * pretty - {Boolean} Structure the output with newlines and indentation.
-     *     Default is false.
-     *
-     * Returns:
-     * {String} The GeoJSON string representation of the input geometry,
-     *     features, array of geometries, or array of features.
-     */
-    write: function(obj, pretty) {
-        var geojson = {
-            "type": null
-        };
-        if(obj instanceof Array) {
-            geojson.members = [];
-            for(var i=0; i<obj.length; ++i) {
-                var element = obj[i];
-                if(element instanceof OpenLayers.Feature.Vector) {
-                    if(geojson.type == null) {
-                        geojson.type = "FeatureCollection";
-                        if(element.layer && element.layer.projection) {
-                            var proj = element.layer.projection;
-                            if(proj.match(/epsg:/i)) {
-                                geojson.crs = {
-                                    "type": "EPSG",
-                                    "properties": {
-                                        "code": parseInt(proj.substring(proj.indexOf(":") + 1))
-                                    }
-                                };
-                            }
-                        }
-                    } else if(geojson.type != "FeatureCollection") {
-                        OpenLayers.Console.error("FeatureCollection only supports collections of features: " + element);
-                        break;
-                    }
-                    geojson.members.push(this.extract.feature.apply(this, [element]));
-                } else if (element.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
-                    if(geojson.type == null) {
-                        geojson.type = "GeometryCollection";
-                    } else if(geojson.type != "GeometryCollection") {
-                        OpenLayers.Console.error("GeometryCollection only supports collections of geometries: " + element);
-                        break;
-                    }
-                    geojson.members.push(this.extract.geometry.apply(this, [element]));
-                }
-            }
-        } else if (obj.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
-            geojson = this.extract.geometry.apply(this, [obj]);
-        } else if (obj instanceof OpenLayers.Feature.Vector) {
-            geojson = this.extract.feature.apply(this, [obj]);
-            if(obj.layer && obj.layer.projection) {
-                var proj = obj.layer.projection;
-                if(proj.match(/epsg:/i)) {
-                    geojson.crs = {
-                        "type": "EPSG",
-                        "properties": {
-                            "code": parseInt(proj.substring(proj.indexOf(":") + 1))
-                        }
-                    };
-                }
-            }
-        }
-        return OpenLayers.Format.JSON.prototype.write.apply(this,
-                                                            [geojson, pretty]);
-    },
-    
-    /**
-     * Property: extract
-     * Object with properties corresponding to the GeoJSON types.
-     *     Property values are functions that do the actual value extraction.
-     */
-    extract: {
-        /**
-         * Method: extract.feature
-         * Return a partial GeoJSON object representing a single feature.
-         *
-         * Parameters:
-         * feature - {<OpenLayers.Feature.Vector>}
-         *
-         * Returns:
-         * {Object} An object representing the point.
-         */
-        'feature': function(feature) {
-            var geom = this.extract.geometry.apply(this, [feature.geometry]);
-            return {
-                "type": "Feature",
-                "id": feature.fid == null ? feature.id : feature.fid,
-                "properties": feature.attributes,
-                "geometry": geom
-            }
-        },
-        
-        /**
-         * Method: extract.geometry
-         * Return a GeoJSON object representing a single geometry.
-         *
-         * Parameters:
-         * geometry - {<OpenLayers.Geometry>}
-         *
-         * Returns:
-         * {Object} An object representing the geometry.
-         */
-        'geometry': function(geometry) {
-            var geometryType = geometry.CLASS_NAME.split('.')[2];
-            var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
-            return {
-                "type": geometryType,
-                "coordinates": data
-            }
-        },
-
-        /**
-         * Method: extract.poin
-         * Return an array of coordinates from a point.
-         *
-         * Parameters:
-         * point - {<OpenLayers.Geometry.Point>}
-         *
-         * Returns: 
-         * {Array} An array of coordinates representing the point.
-         */
-        'point': function(point) {
-            return [point.x, point.y];
-        },
-
-        /**
-         * Method: extract.multipoint
-         * Return an array of point coordinates from a multipoint.
-         *
-         * Parameters:
-         * multipoint - {<OpenLayers.Geometry.MultiPoint>}
-         *
-         * Returns:
-         * {Array} An array of point coordinate arrays representing
-         *     the multipoint.
-         */
-        'multipoint': function(multipoint) {
-            var array = [];
-            for(var i=0; i<multipoint.components.length; ++i) {
-                array.push(this.extract.point.apply(this, [multipoint.components[i]]));
-            }
-            return array;
-        },
-        
-        /**
-         * Method: extract.linestring
-         * Return an array of coordinate arrays from a linestring.
-         *
-         * Parameters:
-         * linestring - {<OpenLayers.Geometry.LineString>}
-         *
-         * Returns:
-         * {Array} An array of coordinate arrays representing
-         *     the linestring.
-         */
-        'linestring': function(linestring) {
-            var array = [];
-            for(var i=0; i<linestring.components.length; ++i) {
-                array.push(this.extract.point.apply(this, [linestring.components[i]]));
-            }
-            return array;
-        },
-
-        /**
-         * Method: extract.multilinestring
-         * Return an array of linestring arrays from a linestring.
-         * 
-         * Parameters:
-         * linestring - {<OpenLayers.Geometry.MultiLineString>}
-         * 
-         * Returns:
-         * {Array} An array of linestring arrays representing
-         *     the multilinestring.
-         */
-        'multilinestring': function(multilinestring) {
-            var array = [];
-            for(var i=0; i<multilinestring.components.length; ++i) {
-                array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
-            }
-            return array;
-        },
-        
-        /**
-         * Method: extract.polygon
-         * Return an array of linear ring arrays from a polygon.
-         *
-         * Parameters:
-         * polygon - {<OpenLayers.Geometry.Polygon>}
-         * 
-         * Returns:
-         * {Array} An array of linear ring arrays representing the polygon.
-         */
-        'polygon': function(polygon) {
-            var array = [];
-            for(var i=0; i<polygon.components.length; ++i) {
-                array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
-            }
-            return array;
-        },
-
-        /**
-         * Method: extract.multipolygon
-         * Return an array of polygon arrays from a multipolygon.
-         * 
-         * Parameters:
-         * multipolygon - {<OpenLayers.Geometry.MultiPolygon>}
-         * 
-         * Returns:
-         * {Array} An array of polygon arrays representing
-         *     the multipolygon
-         */
-        'multipolygon': function(multipolygon) {
-            var array = [];
-            for(var i=0; i<multipolygon.components.length; ++i) {
-                array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
-            }
-            return array;
-        }
-
-    },
-
-    CLASS_NAME: "OpenLayers.Format.GeoJSON" 
-
-});     
+/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/JSON.js
+ *
+ * Class: OpenLayers.Format.GeoJSON
+ * Read and write GeoJSON. Create a new parser with the
+ *     <OpenLayers.Format.GeoJSON> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.JSON>
+ */
+OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, {
+
+    /**
+     * Constructor: OpenLayers.Format.GeoJSON
+     * Create a new parser for GeoJSON.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.JSON.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: read
+     * Deserialize a GeoJSON string.
+     *
+     * Parameters:
+     * json - {String} A GeoJSON string
+     * type - {String} Optional string that determines the structure of
+     *     the output.  Supported values are "Geometry", "Feature",
+     *     "GeometryCollection", and "FeatureCollection".  If absent or null,
+     *     a default of "FeatureCollection" is assumed.
+     * filter - {Function} A function which will be called for every key and
+     *     value at every level of the final result. Each value will be
+     *     replaced by the result of the filter function. This can be used to
+     *     reform generic objects into instances of classes, or to transform
+     *     date strings into Date objects.
+     *
+     * Returns: 
+     * {Object} The return depends on the value of the type argument. If type
+     *     is "FeatureCollection" (the default), the return will be an array
+     *     of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
+     *     must represent a single geometry, and the return will be an
+     *     <OpenLayers.Geometry>.  If type is "Feature", the input json must
+     *     represent a single feature, and the return will be an
+     *     <OpenLayers.Feature.Vector>.  If type is "GeometryCollection", the
+     *     input json must represent a geometry collection, and the return will
+     *     be an array of <OpenLayers.Geometry>.
+     */
+    read: function(json, type, filter) {
+        type = (type) ? type : "FeatureCollection";
+        var results = null;
+        var obj = null;
+        if (typeof json == "string") {
+            obj = OpenLayers.Format.JSON.prototype.read.apply(this,
+                                                              [json, filter]);
+        } else { 
+            obj = json;
+        }    
+        if(!obj) {
+            OpenLayers.Console.error("Bad JSON: " + json);
+        } else if(typeof(obj.type) != "string") {
+            OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
+        } else if(this.isValidType(obj, type)) {
+            switch(type) {
+                case "Geometry":
+                    try {
+                        results = this.parseGeometry(obj);
+                    } catch(err) {
+                        OpenLayers.Console.error(err);
+                    }
+                    break;
+                case "Feature":
+                    try {
+                        results = this.parseFeature(obj);
+                        results.type = "Feature";
+                    } catch(err) {
+                        OpenLayers.Console.error(err);
+                    }
+                    break;
+                case "GeometryCollection":
+                    results = [];
+                    for(var i=0; i<obj.members.length; ++i) {
+                        try {
+                            results.push(this.parseGeometry(obj.members[i]));
+                        } catch(err) {
+                            results = null;
+                            OpenLayers.Console.error(err);
+                        }
+                    }
+                    break;
+                case "FeatureCollection":
+                    // for type FeatureCollection, we allow input to be any type
+                    results = [];
+                    switch(obj.type) {
+                        case "Feature":
+                            try {
+                                results.push(this.parseFeature(obj));
+                            } catch(err) {
+                                results = null;
+                                OpenLayers.Console.error(err);
+                            }
+                            break;
+                        case "FeatureCollection":
+                            for(var i=0; i<obj.members.length; ++i) {
+                                try {
+                                    results.push(this.parseFeature(obj.members[i]));
+                                } catch(err) {
+                                    results = null;
+                                    OpenLayers.Console.error(err);
+                                }
+                            }
+                            break;
+                        case "GeometryCollection":
+                            for(var i=0; i<obj.members.length; ++i) {
+                                try {
+                                    var geom = this.parseGeometry(obj.members[i]);
+                                    results.push(new OpenLayers.Feature.Vector(geom));
+                                } catch(err) {
+                                    results = null;
+                                    OpenLayers.Console.error(err);
+                                }
+                            }
+                            break;
+                        default:
+                            try {
+                                var geom = this.parseGeometry(obj);
+                                results.push(new OpenLayers.Feature.Vector(geom));
+                            } catch(err) {
+                                results = null;
+                                OpenLayers.Console.error(err);
+                            }
+                    }
+                break;
+            }
+        }
+        return results;
+    },
+    
+    /**
+     * Method: isValidType
+     * Check if a GeoJSON object is a valid representative of the given type.
+     *
+     * Returns:
+     * {Boolean} The object is valid GeoJSON object of the given type.
+     */
+    isValidType: function(obj, type) {
+        var valid = false;
+        switch(type) {
+            case "Geometry":
+                if(OpenLayers.Util.indexOf(["Point", "MultiPoint", "LineString",
+                                            "MultiLineString", "Polygon",
+                                            "MultiPolygon", "Box"], obj.type) == -1) {
+                    // unsupported geometry type
+                    OpenLayers.Console.error("Unsupported geometry type: " +
+                                              obj.type);
+                } else {
+                    valid = true;
+                }
+                break;
+            case "FeatureCollection":
+                // allow for any type to be converted to a feature collection
+                valid = true;
+                break
+            default:
+                // for GeometryCollection and Feature, types must match
+                if(obj.type == type) {
+                    valid = true;
+                } else {
+                    OpenLayers.Console.error("Cannot convert types from " +
+                                              obj.type + " to " + type);
+                }
+        }
+        return valid;
+    },
+    
+    /**
+     * Method: parseFeature
+     * Convert a feature object from GeoJSON into an
+     *     <OpenLayers.Feature.Vector>.
+     *
+     * Parameters:
+     * obj - {Object} An object created from a GeoJSON object
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature.
+     */
+    parseFeature: function(obj) {
+        var feature, geometry, attributes;
+        attributes = (obj.properties) ? obj.properties : {};
+        try {
+            geometry = this.parseGeometry(obj.geometry);            
+        } catch(err) {
+            // deal with bad geometries
+            throw err;
+        }
+        feature = new OpenLayers.Feature.Vector(geometry, attributes);
+        if(obj.id) {
+            feature.fid = obj.id;
+        }
+        return feature;
+    },
+    
+    /**
+     * Method: parseGeometry
+     * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>.
+     *
+     * Parameters:
+     * obj - {Object} An object created from a GeoJSON object
+     *
+     * Returns: 
+     * {<OpenLayers.Geometry>} A geometry.
+     */
+    parseGeometry: function(obj) {
+        var geometry;
+        if(!(obj.coordinates instanceof Array)) {
+            throw "Geometry must have coordinates array: " + obj;
+        }
+        if(!this.parseCoords[obj.type.toLowerCase()]) {
+            throw "Unsupported geometry type: " + obj.type;
+        }
+        try {
+            geometry = this.parseCoords[obj.type.toLowerCase()].apply(this, [obj.coordinates]);
+        } catch(err) {
+            // deal with bad coordinates
+            throw err;
+        }
+        return geometry;
+    },
+    
+    /**
+     * Property: parseCoords
+     * Object with properties corresponding to the GeoJSON geometry types.
+     *     Property values are functions that do the actual parsing.
+     */
+    parseCoords: {
+        /**
+         * Method: parseCoords.point
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array - {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "point": function(array) {
+            if(array.length != 2) {
+                throw "Only 2D points are supported: " + array;
+            }
+            return new OpenLayers.Geometry.Point(array[0], array[1]);
+        },
+        
+        /**
+         * Method: parseCoords.multipoint
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "multipoint": function(array) {
+            var points = [];
+            var p = null;
+            for(var i=0; i<array.length; ++i) {
+                try {
+                    p = this.parseCoords["point"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
+                points.push(p);
+            }
+            return new OpenLayers.Geometry.MultiPoint(points);
+        },
+
+        /**
+         * Method: parseCoords.linestring
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array - {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "linestring": function(array) {
+            var points = [];
+            var p = null;
+            for(var i=0; i<array.length; ++i) {
+                try {
+                    p = this.parseCoords["point"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
+                points.push(p);
+            }
+            return new OpenLayers.Geometry.LineString(points);
+        },
+        
+        /**
+         * Method: parseCoords.multilinestring
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array - {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "multilinestring": function(array) {
+            var lines = [];
+            var l = null;
+            for(var i=0; i<array.length; ++i) {
+                try {
+                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
+                lines.push(l);
+            }
+            return new OpenLayers.Geometry.MultiLineString(lines);
+        },
+        
+        /**
+         * Method: parseCoords.polygon
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "polygon": function(array) {
+            var rings = [];
+            var r, l;
+            for(var i=0; i<array.length; ++i) {
+                try {
+                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
+                r = new OpenLayers.Geometry.LinearRing(l.components);
+                rings.push(r);
+            }
+            return new OpenLayers.Geometry.Polygon(rings);
+        },
+
+        /**
+         * Method: parseCoords.multipolygon
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array - {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "multipolygon": function(array) {
+            var polys = [];
+            var p = null;
+            for(var i=0; i<array.length; ++i) {
+                try {
+                    p = this.parseCoords["polygon"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
+                polys.push(p);
+            }
+            return new OpenLayers.Geometry.MultiPolygon(polys);
+        },
+
+        /**
+         * Method: parseCoords.box
+         * Convert a coordinate array from GeoJSON into an
+         *     <OpenLayers.Geometry>.
+         *
+         * Parameters:
+         * array - {Object} The coordinates array from the GeoJSON fragment.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry>} A geometry.
+         */
+        "box": function(array) {
+            if(array.length != 2) {
+                throw "GeoJSON box coordinates must have 2 elements";
+            }
+            return new OpenLayers.Geometry.Polygon([
+                new OpenLayers.Geometry.LinearRing([
+                    new OpenLayers.Geometry.Point(array[0][0], array[0][1]),
+                    new OpenLayers.Geometry.Point(array[1][0], array[0][1]),
+                    new OpenLayers.Geometry.Point(array[1][0], array[1][1]),
+                    new OpenLayers.Geometry.Point(array[0][0], array[1][1]),
+                    new OpenLayers.Geometry.Point(array[0][0], array[0][1])
+                ])
+            ]);
+        }
+
+    },
+
+    /**
+     * APIMethod: write
+     * Serialize a feature, geometry, array of features, or array of geometries
+     *     into a GeoJSON string.
+     *
+     * Parameters:
+     * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>,
+     *     or an array of either features or geometries.
+     * pretty - {Boolean} Structure the output with newlines and indentation.
+     *     Default is false.
+     *
+     * Returns:
+     * {String} The GeoJSON string representation of the input geometry,
+     *     features, array of geometries, or array of features.
+     */
+    write: function(obj, pretty) {
+        var geojson = {
+            "type": null
+        };
+        if(obj instanceof Array) {
+            geojson.members = [];
+            for(var i=0; i<obj.length; ++i) {
+                var element = obj[i];
+                if(element instanceof OpenLayers.Feature.Vector) {
+                    if(geojson.type == null) {
+                        geojson.type = "FeatureCollection";
+                        if(element.layer && element.layer.projection) {
+                            var proj = element.layer.projection;
+                            if(proj.match(/epsg:/i)) {
+                                geojson.crs = {
+                                    "type": "EPSG",
+                                    "properties": {
+                                        "code": parseInt(proj.substring(proj.indexOf(":") + 1))
+                                    }
+                                };
+                            }
+                        }
+                    } else if(geojson.type != "FeatureCollection") {
+                        OpenLayers.Console.error("FeatureCollection only supports collections of features: " + element);
+                        break;
+                    }
+                    geojson.members.push(this.extract.feature.apply(this, [element]));
+                } else if (element.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
+                    if(geojson.type == null) {
+                        geojson.type = "GeometryCollection";
+                    } else if(geojson.type != "GeometryCollection") {
+                        OpenLayers.Console.error("GeometryCollection only supports collections of geometries: " + element);
+                        break;
+                    }
+                    geojson.members.push(this.extract.geometry.apply(this, [element]));
+                }
+            }
+        } else if (obj.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
+            geojson = this.extract.geometry.apply(this, [obj]);
+        } else if (obj instanceof OpenLayers.Feature.Vector) {
+            geojson = this.extract.feature.apply(this, [obj]);
+            if(obj.layer && obj.layer.projection) {
+                var proj = obj.layer.projection;
+                if(proj.match(/epsg:/i)) {
+                    geojson.crs = {
+                        "type": "EPSG",
+                        "properties": {
+                            "code": parseInt(proj.substring(proj.indexOf(":") + 1))
+                        }
+                    };
+                }
+            }
+        }
+        return OpenLayers.Format.JSON.prototype.write.apply(this,
+                                                            [geojson, pretty]);
+    },
+    
+    /**
+     * Property: extract
+     * Object with properties corresponding to the GeoJSON types.
+     *     Property values are functions that do the actual value extraction.
+     */
+    extract: {
+        /**
+         * Method: extract.feature
+         * Return a partial GeoJSON object representing a single feature.
+         *
+         * Parameters:
+         * feature - {<OpenLayers.Feature.Vector>}
+         *
+         * Returns:
+         * {Object} An object representing the point.
+         */
+        'feature': function(feature) {
+            var geom = this.extract.geometry.apply(this, [feature.geometry]);
+            return {
+                "type": "Feature",
+                "id": feature.fid == null ? feature.id : feature.fid,
+                "properties": feature.attributes,
+                "geometry": geom
+            }
+        },
+        
+        /**
+         * Method: extract.geometry
+         * Return a GeoJSON object representing a single geometry.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry>}
+         *
+         * Returns:
+         * {Object} An object representing the geometry.
+         */
+        'geometry': function(geometry) {
+            var geometryType = geometry.CLASS_NAME.split('.')[2];
+            var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
+            return {
+                "type": geometryType,
+                "coordinates": data
+            }
+        },
+
+        /**
+         * Method: extract.poin
+         * Return an array of coordinates from a point.
+         *
+         * Parameters:
+         * point - {<OpenLayers.Geometry.Point>}
+         *
+         * Returns: 
+         * {Array} An array of coordinates representing the point.
+         */
+        'point': function(point) {
+            return [point.x, point.y];
+        },
+
+        /**
+         * Method: extract.multipoint
+         * Return an array of point coordinates from a multipoint.
+         *
+         * Parameters:
+         * multipoint - {<OpenLayers.Geometry.MultiPoint>}
+         *
+         * Returns:
+         * {Array} An array of point coordinate arrays representing
+         *     the multipoint.
+         */
+        'multipoint': function(multipoint) {
+            var array = [];
+            for(var i=0; i<multipoint.components.length; ++i) {
+                array.push(this.extract.point.apply(this, [multipoint.components[i]]));
+            }
+            return array;
+        },
+        
+        /**
+         * Method: extract.linestring
+         * Return an array of coordinate arrays from a linestring.
+         *
+         * Parameters:
+         * linestring - {<OpenLayers.Geometry.LineString>}
+         *
+         * Returns:
+         * {Array} An array of coordinate arrays representing
+         *     the linestring.
+         */
+        'linestring': function(linestring) {
+            var array = [];
+            for(var i=0; i<linestring.components.length; ++i) {
+                array.push(this.extract.point.apply(this, [linestring.components[i]]));
+            }
+            return array;
+        },
+
+        /**
+         * Method: extract.multilinestring
+         * Return an array of linestring arrays from a linestring.
+         * 
+         * Parameters:
+         * linestring - {<OpenLayers.Geometry.MultiLineString>}
+         * 
+         * Returns:
+         * {Array} An array of linestring arrays representing
+         *     the multilinestring.
+         */
+        'multilinestring': function(multilinestring) {
+            var array = [];
+            for(var i=0; i<multilinestring.components.length; ++i) {
+                array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
+            }
+            return array;
+        },
+        
+        /**
+         * Method: extract.polygon
+         * Return an array of linear ring arrays from a polygon.
+         *
+         * Parameters:
+         * polygon - {<OpenLayers.Geometry.Polygon>}
+         * 
+         * Returns:
+         * {Array} An array of linear ring arrays representing the polygon.
+         */
+        'polygon': function(polygon) {
+            var array = [];
+            for(var i=0; i<polygon.components.length; ++i) {
+                array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
+            }
+            return array;
+        },
+
+        /**
+         * Method: extract.multipolygon
+         * Return an array of polygon arrays from a multipolygon.
+         * 
+         * Parameters:
+         * multipolygon - {<OpenLayers.Geometry.MultiPolygon>}
+         * 
+         * Returns:
+         * {Array} An array of polygon arrays representing
+         *     the multipolygon
+         */
+        'multipolygon': function(multipolygon) {
+            var array = [];
+            for(var i=0; i<multipolygon.components.length; ++i) {
+                array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
+            }
+            return array;
+        }
+
+    },
+
+    CLASS_NAME: "OpenLayers.Format.GeoJSON" 
+
+});     

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Format/WKT.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Format/WKT.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Format/WKT.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -22,7 +22,7 @@
      * options - {Object} An optional object whose properties will be set on
      *           this instance
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Format.WKT>} A new WKT parser.
      */
     initialize: function(options) {
@@ -46,7 +46,7 @@
      * Parameters:
      * wkt - {String} A WKT string
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
      * GEOMETRYCOLLECTION WKT.
      */
@@ -71,7 +71,7 @@
      * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
      *            features
      *
-     * Return:
+     * Returns:
      * {String} The WKT string representation of the input geometries
      */
     write: function(features) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Format.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Format.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Format.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -19,7 +19,7 @@
      * options - {Object} An optional object with properties to set on the
      *           format
      *
-     * Return:
+     * Returns:
      * An instance of OpenLayers.Format
      */
     initialize: function(options) {
@@ -34,7 +34,7 @@
      * Parameters:
      * data - {string} Data to read/parse.
      *
-     * Return:
+     * Returns:
      * Depends on the subclass
      */
     read: function(data) {
@@ -48,7 +48,7 @@
      * Parameters:
      * object - {Object} Object to be serialized
      *
-     * Return:
+     * Returns:
      * {String} A string representation of the object.
      */
     write: function(object) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Collection.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Collection.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Collection.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -67,7 +67,7 @@
      * APIMethod: clone
      * Clone this geometry.
      *
-     * Return:
+     * Returns:
      * {<OpenLayers.Geometry.Collection>} An exact clone of this collection
      */
     clone: function() {
@@ -86,7 +86,7 @@
      * Method: getComponentsString
      * Get a string representing the components for this collection
      * 
-     * Return:
+     * Returns:
      * {String} A string representation of the components of this geometry
      */
     getComponentsString: function(){
@@ -155,7 +155,7 @@
      * component - {<OpenLayers.Geometry>} A geometry to add
      * index - {int} Optional index into the array to insert the component
      *
-     * Return:
+     * Returns:
      * {Boolean} The component geometry was successfully added
      */    
     addComponent: function(component, index) {
@@ -218,7 +218,7 @@
      * APIMethod: getLength
      * Calculate the length of this geometry
      *
-     * Return:
+     * Returns:
      * {Float} The length of the geometry
      */
     getLength: function() {
@@ -234,7 +234,7 @@
      * Calculate the area of this geometry. Note how this function is overridden
      * in <OpenLayers.Geometry.Polygon>.
      *
-     * Return:
+     * Returns:
      * {Float} The area of the collection by summing its parts
      */
     getArea: function() {
@@ -264,7 +264,7 @@
      * Rotate a geometry around some origin
      *
      * Parameters:
-     * angle - {Float} Rotation angle in radians (measured counterclockwise
+     * angle - {Float} Rotation angle in degrees (measured counterclockwise
      *                 from the positive x-axis)
      * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
      */
@@ -299,7 +299,7 @@
      * Parameters:
      * geometry - {<OpenLayers.Geometry>}
      *
-     * Return:
+     * Returns:
      * {Boolean} The coordinates are equivalent
      */
     equals: function(geometry) {

Modified: sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Curve.js
===================================================================
--- sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Curve.js	2007-09-11 11:16:51 UTC (rev 4213)
+++ sandbox/camptocamp/feature/lib/OpenLayers/Geometry/Curve.js	2007-09-11 13:11:39 UTC (rev 4214)
@@ -37,7 +37,7 @@
     /**
      * APIMethod: getLength
      * 
-     * Return:
+     * Returns:
      * {Float} The length of the curve
      */
     getLength: function() {

M