[OpenLayers-Commits] r2966 - in sandbox/tschaub/gutter: build doc examples lib lib/OpenLayers lib/OpenLayers/Control lib/OpenLayers/Feature lib/OpenLayers/Format lib/OpenLayers/Geometry lib/OpenLayers/Handler lib/OpenLayers/Layer lib/OpenLayers/Layer/MapServer lib/OpenLayers/Renderer lib/OpenLayers/Tile tests tests/BaseTypes tests/Control tests/Format tests/Geometry tests/Layer tests/Tile

commits at openlayers.org commits at openlayers.org
Sun Apr 1 23:10:27 EDT 2007


Author: tschaub
Date: 2007-04-01 23:10:26 -0400 (Sun, 01 Apr 2007)
New Revision: 2966

Added:
   sandbox/tschaub/gutter/build/buildUncompressed.py
   sandbox/tschaub/gutter/examples/mapserver_untiled.html
   sandbox/tschaub/gutter/examples/wkt.html
   sandbox/tschaub/gutter/lib/OpenLayers/Format/WKT.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/MapServer/
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/MapServer/Untiled.js
   sandbox/tschaub/gutter/tests/Format/
   sandbox/tschaub/gutter/tests/Format/test_WKT.html
   sandbox/tschaub/gutter/tests/Layer/test_MapServer.html
   sandbox/tschaub/gutter/tests/Layer/test_MapServer_Untiled.html
   sandbox/tschaub/gutter/tests/test_Format.html
Modified:
   sandbox/tschaub/gutter/doc/authors.txt
   sandbox/tschaub/gutter/examples/editingtoolbar.html
   sandbox/tschaub/gutter/examples/freemap.html
   sandbox/tschaub/gutter/examples/gutter.html
   sandbox/tschaub/gutter/examples/openmnnd.html
   sandbox/tschaub/gutter/examples/overviewmap.html
   sandbox/tschaub/gutter/examples/wmst.html
   sandbox/tschaub/gutter/lib/OpenLayers.js
   sandbox/tschaub/gutter/lib/OpenLayers/BaseTypes.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/KeyboardDefaults.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/LayerSwitcher.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseDefaults.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseToolbar.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/Navigation.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/OverviewMap.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoom.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoomBar.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/Panel.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/Permalink.js
   sandbox/tschaub/gutter/lib/OpenLayers/Control/SelectFeature.js
   sandbox/tschaub/gutter/lib/OpenLayers/Events.js
   sandbox/tschaub/gutter/lib/OpenLayers/Feature.js
   sandbox/tschaub/gutter/lib/OpenLayers/Feature/Vector.js
   sandbox/tschaub/gutter/lib/OpenLayers/Format.js
   sandbox/tschaub/gutter/lib/OpenLayers/Format/GML.js
   sandbox/tschaub/gutter/lib/OpenLayers/Format/GeoRSS.js
   sandbox/tschaub/gutter/lib/OpenLayers/Format/KML.js
   sandbox/tschaub/gutter/lib/OpenLayers/Format/WFS.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Collection.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Curve.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LineString.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LinearRing.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiLineString.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPoint.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPolygon.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Point.js
   sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Polygon.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Box.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Drag.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Keyboard.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/MouseWheel.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Path.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Point.js
   sandbox/tschaub/gutter/lib/OpenLayers/Handler/Polygon.js
   sandbox/tschaub/gutter/lib/OpenLayers/Icon.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/GML.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/Google.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/Grid.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/Image.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/MapServer.js
   sandbox/tschaub/gutter/lib/OpenLayers/Layer/Vector.js
   sandbox/tschaub/gutter/lib/OpenLayers/Map.js
   sandbox/tschaub/gutter/lib/OpenLayers/Marker.js
   sandbox/tschaub/gutter/lib/OpenLayers/Popup.js
   sandbox/tschaub/gutter/lib/OpenLayers/Renderer/SVG.js
   sandbox/tschaub/gutter/lib/OpenLayers/Renderer/VML.js
   sandbox/tschaub/gutter/lib/OpenLayers/Tile/Image.js
   sandbox/tschaub/gutter/lib/OpenLayers/Util.js
   sandbox/tschaub/gutter/tests/BaseTypes/test_Bounds.html
   sandbox/tschaub/gutter/tests/Control/test_PanZoom.html
   sandbox/tschaub/gutter/tests/Control/test_PanZoomBar.html
   sandbox/tschaub/gutter/tests/Geometry/test_Collection.html
   sandbox/tschaub/gutter/tests/Geometry/test_Curve.html
   sandbox/tschaub/gutter/tests/Geometry/test_LineString.html
   sandbox/tschaub/gutter/tests/Geometry/test_LinearRing.html
   sandbox/tschaub/gutter/tests/Geometry/test_MultiPoint.html
   sandbox/tschaub/gutter/tests/Geometry/test_Point.html
   sandbox/tschaub/gutter/tests/Geometry/test_Polygon.html
   sandbox/tschaub/gutter/tests/Layer/test_Grid.html
   sandbox/tschaub/gutter/tests/Layer/test_Vector.html
   sandbox/tschaub/gutter/tests/Tile/test_Image.html
   sandbox/tschaub/gutter/tests/list-tests.html
   sandbox/tschaub/gutter/tests/test_Events.html
   sandbox/tschaub/gutter/tests/test_Map.html
   sandbox/tschaub/gutter/tests/test_Popup.html
Log:
merged version

Added: sandbox/tschaub/gutter/build/buildUncompressed.py
===================================================================
--- sandbox/tschaub/gutter/build/buildUncompressed.py	                        (rev 0)
+++ sandbox/tschaub/gutter/build/buildUncompressed.py	2007-04-02 03:10:26 UTC (rev 2966)
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+import sys
+sys.path.append("../tools")
+
+import jsmin, mergejs
+
+sourceDirectory = "../lib"
+configFilename = "library.cfg"
+outputFilename = "OpenLayers.js"
+
+if len(sys.argv) > 1:
+    configFilename = sys.argv[1] + ".cfg"
+if len(sys.argv) > 2:
+    outputFilename = sys.argv[2]
+
+print "Merging libraries."
+merged = mergejs.run(sourceDirectory, None, configFilename)
+print "Adding license file."
+merged = file("license.txt").read() + merged
+
+print "Writing to %s." % outputFilename
+file(outputFilename, "w").write(merged)
+
+print "Done."

Modified: sandbox/tschaub/gutter/doc/authors.txt
===================================================================
--- sandbox/tschaub/gutter/doc/authors.txt	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/doc/authors.txt	2007-04-02 03:10:26 UTC (rev 2966)
@@ -7,14 +7,17 @@
 John Frank
 Sean Gilles
 Pierre Giraud                                                                
+Andreas Hocevar
 Philip Lindsay
 Corey Puffault
 Tim Schaub
 Christopher Schmidt
 Cameron Shorter                                                              
 Paul Spencer                                                                 
+James Stembridge
 Erik Uzureau
 Bill Woodall
+Steve Woodbridge
 
 
 OpenLayers is graciously supported by MetaCarta, Inc.

Modified: sandbox/tschaub/gutter/examples/editingtoolbar.html
===================================================================
--- sandbox/tschaub/gutter/examples/editingtoolbar.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/editingtoolbar.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -1,3 +1,4 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <style type="text/css">
@@ -24,6 +25,7 @@
 
             vlayer = new OpenLayers.Layer.Vector( "Editable" );
             map.addLayer(vlayer);
+            map.addControl(new OpenLayers.Control.PanZoomBar());
             map.addControl(new OpenLayers.Control.EditingToolbar(vlayer));
             
             map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);

Modified: sandbox/tschaub/gutter/examples/freemap.html
===================================================================
--- sandbox/tschaub/gutter/examples/freemap.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/freemap.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -3,24 +3,24 @@
 
     <style type="text/css">
     body {
-	border: 0px;
-	margin: 0px;
-	padding: 0px;
+    border: 0px;
+    margin: 0px;
+    padding: 0px;
     }
     #map {
-	width: 100%;
-	height: 100%;
-	border: 0px;
-	padding: 0px;
+    width: 100%;
+    height: 100%;
+    border: 0px;
+    padding: 0px;
     }
     </style>
 
     <script src="../lib/OpenLayers.js"></script>
     <script type="text/javascript">
       <!--
-	var lat = 900863; 
-	var lon = 235829;
-	var zoom = 6;
+    var lat = 900863; 
+    var lon = 235829;
+    var zoom = 6;
     var map, layer;
 
         function init(){

Modified: sandbox/tschaub/gutter/examples/gutter.html
===================================================================
--- sandbox/tschaub/gutter/examples/gutter.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/gutter.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -1,49 +1,49 @@
-<html>
-  <head>
-    <style type="text/css">
-        #map {
-            width: 500px;
-            height: 300px;
-            border: 1px solid gray;
-        }
-        p.caption {
-            width: 500px;
-        }
-    </style>
-    <script src="../lib/OpenLayers.js"></script>
-    <script type="text/javascript">
-        <!--
-        OpenLayers.IMAGE_RELOAD_ATTEMPTS = 2;
-        var map;
-        window.onload = function() {
-            options = {maxExtent: new OpenLayers.Bounds(-73.5295, 41.2318,
-                                                        -69.9097, 42.8883),
-                       maxResolution: 0.0003}
-            map = new OpenLayers.Map('map', options);
-            var roads15 = new OpenLayers.Layer.WMS( "Roads (15px gutter)", 
-                "http://boston.freemap.in/cgi-bin/mapserv?map=/www/freemap.in/boston/map/gmaps.map&",
-                {layers: 'roads_200_40'},
-                {gutter: 15}); 
-            var roads = new OpenLayers.Layer.WMS( "Roads (no gutter)", 
-                "http://boston.freemap.in/cgi-bin/mapserv?map=/www/freemap.in/boston/map/gmaps.map&",
-                {layers: 'roads_200_40'}); 
-            map.addLayers([roads, roads15]);
-            map.addControl(new OpenLayers.Control.LayerSwitcher());
-            map.setCenter(new OpenLayers.LonLat(-71.848, 42.2), 0);
-        }
-        // -->
-    </script>
-  </head>
-  <body>
-    <h1>OpenLayers Gutter Example</h1>
-    <div id="map"></div>
-    <p class="caption">
-        When you render tiles with certain types of symbols, there are artifacts
-        at tile edges that make symbology not look continuous.  In the center of
-        the above map (when it first loads), the large orange road is split
-        vertically by a tile.  Open the layer switcher and change to the layer
-        with a 15 pixel gutter to see how the symbology looks nicer.
-    </p>
-        
-  </body>
-</html>
+<html> 
+  <head> 
+    <style type="text/css"> 
+        #map { 
+            width: 500px; 
+            height: 300px; 
+            border: 1px solid gray; 
+        } 
+        p.caption { 
+            width: 500px; 
+        } 
+    </style> 
+    <script src="../lib/OpenLayers.js"></script> 
+    <script type="text/javascript"> 
+        <!-- 
+        OpenLayers.IMAGE_RELOAD_ATTEMPTS = 2; 
+        var map; 
+        window.onload = function() { 
+            options = {maxExtent: new OpenLayers.Bounds(-73.5295, 41.2318, 
+                                                        -69.9097, 42.8883), 
+                       maxResolution: 0.0003} 
+            map = new OpenLayers.Map('map', options); 
+            var roads15 = new OpenLayers.Layer.WMS( "Roads (15px gutter)",  
+                "http://boston.freemap.in/cgi-bin/mapserv?map=/www/freemap.in/boston/map/gmaps.map&", 
+                {layers: 'roads_200_40'}, 
+                {gutter: 15});  
+            var roads = new OpenLayers.Layer.WMS( "Roads (no gutter)",  
+                "http://boston.freemap.in/cgi-bin/mapserv?map=/www/freemap.in/boston/map/gmaps.map&", 
+                {layers: 'roads_200_40'});  
+            map.addLayers([roads, roads15]); 
+            map.addControl(new OpenLayers.Control.LayerSwitcher()); 
+            map.setCenter(new OpenLayers.LonLat(-71.848, 42.2), 0); 
+        } 
+        // --> 
+    </script> 
+  </head> 
+  <body> 
+    <h1>OpenLayers Gutter Example</h1> 
+    <div id="map"></div> 
+    <p class="caption"> 
+        When you render tiles with certain types of symbols, there are artifacts 
+        at tile edges that make symbology not look continuous.  In the center of 
+        the above map (when it first loads), the large orange road is split 
+        vertically by a tile.  Open the layer switcher and change to the layer 
+        with a 15 pixel gutter to see how the symbology looks nicer. 
+    </p> 
+         
+  </body> 
+</html> 
\ No newline at end of file

Added: sandbox/tschaub/gutter/examples/mapserver_untiled.html
===================================================================
--- sandbox/tschaub/gutter/examples/mapserver_untiled.html	                        (rev 0)
+++ sandbox/tschaub/gutter/examples/mapserver_untiled.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <style type="text/css">
+        #map {
+            width: 800px;
+            height: 475px;
+            border: 1px solid black;
+        }
+    </style>
+    <script src="../lib/OpenLayers.js"></script>
+    <script src="../lib/OpenLayers/Layer/MapServer/Untiled.js"></script>
+    <script type="text/javascript">
+        window.onload = function(){
+            var map = new OpenLayers.Map( 'map', {maxResolution: 'auto'} );
+            var layer = new OpenLayers.Layer.MapServer.Untiled( "MapServer Untiled", 
+                    "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
+            map.addLayer(layer);
+            map.setCenter(new OpenLayers.LonLat(0, 0), 1);
+            map.addControl( new OpenLayers.Control.LayerSwitcher() );
+        }
+    </script>
+  </head>
+  <body>
+    <div id="map"></div>
+  </body>
+</html>

Modified: sandbox/tschaub/gutter/examples/openmnnd.html
===================================================================
--- sandbox/tschaub/gutter/examples/openmnnd.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/openmnnd.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -29,15 +29,42 @@
             map.addLayer(wms);
             
             wfs = new OpenLayers.Layer.WFS("Minnesota Streams (WFS)", wfs_url, {'typename':'streams'}, {ratio:1.25, minZoomLevel:4});
-            wfs.onFeatureInsert= function(feature) { feature.style.strokeWidth="3"; feature.style.strokeColor="blue"; feature.layer.renderer.drawGeometry(feature.geometry,feature.style); $('stream_features').innerHTML = feature.layer.features.length;}
+            
+            // preFeatureInsert can be used to set style before the feature is drawn 
+            wfs.preFeatureInsert= function(feature) { feature.style.strokeWidth="3"; feature.style.strokeColor="blue";  
+            }
+            wfs.onFeatureInsert = function() {
+              $('stream_features').innerHTML = feature.layer.features.length;
+            }  
             map.addLayer(wfs);
             
-            pwfs = new OpenLayers.Layer.WFS("Minnesota Plat (WFS)", wfs_url, {'typename':'plat'}, {ratio:1.25, minZoomLevel:8, extractAttributes: true});
-            pwfs.onFeatureInsert= function(feature) { feature.style.fillColor="green"; feature.layer.renderer.drawGeometry(feature.geometry,feature.style); $('plat_features').innerHTML = feature.layer.features.length;}
+            // Or a style can be set on the layer.
+            pwfsstyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
+            OpenLayers.Util.extend(pwfsstyle, {'fillColor': 'green'}); 
+            
+            pwfs = new OpenLayers.Layer.WFS("Minnesota Plat (WFS)", wfs_url, 
+              {'typename':'plat'}, 
+              {
+               ratio:1.25, 
+               minZoomLevel:8, 
+               extractAttributes: true, 
+               style: pwfsstyle
+              });
+            
+            pwfs.onFeatureInsert= function(feature) { 
+              $('plat_features').innerHTML = feature.layer.features.length;
+            }
             map.addLayer(pwfs); 
             
-            rwfs = new OpenLayers.Layer.WFS("Minnesota Roads (WFS)", wfs_url, {'typename':'roads'}, {ratio:1.25, minZoomLevel:7, extractAttributes: true});
-            rwfs.onFeatureInsert= function(feature) { feature.style.strokeColor="white"; feature.style.strokeWidth="4"; feature.layer.renderer.drawGeometry(feature.geometry,feature.style); $('road_features').innerHTML = feature.layer.features.length; }
+            rstyle = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
+            OpenLayers.Util.extend(rstyle, {'strokeColor': 'white', strokeWIdth: "4"}); 
+            rwfs = new OpenLayers.Layer.WFS("Minnesota Roads (WFS)", wfs_url, {'typename':'roads'}, 
+              {ratio:1.25, minZoomLevel:7, extractAttributes: true, style:rstyle});
+            
+            rwfs.onFeatureInsert= function(feature) {  
+              $('road_features').innerHTML = feature.layer.features.length; 
+            }
+            
             map.addLayer(rwfs); 
             
             map.events.register('moveend', null, function() { 

Modified: sandbox/tschaub/gutter/examples/overviewmap.html
===================================================================
--- sandbox/tschaub/gutter/examples/overviewmap.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/overviewmap.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -6,9 +6,9 @@
 <script src="../lib/OpenLayers.js" type="text/javascript"></script>
 <style>
 #map{
-	width:100%; 
-	height:500px;
-	border:1px solid;
+    width:100%; 
+    height:500px;
+    border:1px solid;
 }
 </style>
 </head>
@@ -16,32 +16,32 @@
   <div id="map"></div>
   <script defer="defer" type="text/javascript">
     var map = new OpenLayers.Map('map');
-	// my city
-	var constantina = new OpenLayers.LonLat(-5.6165,37.8623);
+    // my city
+    var constantina = new OpenLayers.LonLat(-5.6165,37.8623);
     var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
         "http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
     var nasa_wms = new OpenLayers.Layer.WMS( "NASA Global Mosaic", 
         "http://wms.jpl.nasa.gov/wms.cgi", {layers: "modis,global_mosaic"} );
 
-    map.addLayers([	
-		nasa_wms,
-		wms
-	]);
-	
-	map.addControl(new OpenLayers.Control.LayerSwitcher());
-	
-	var options = {
+    map.addLayers([    
+        nasa_wms,
+        wms
+    ]);
+    
+    map.addControl(new OpenLayers.Control.LayerSwitcher());
+    
+    var options = {
       layers: [wms.clone()],
       minRatio: 8,
       maxRatio: 128
     };
-	var overview = new OpenLayers.Control.OverviewMap(options);
-		
-	map.addControl(overview);
-	
-	map.setCenter(constantina, 4);
-	
-	overview.maximizeControl();	
+    var overview = new OpenLayers.Control.OverviewMap(options);
+        
+    map.addControl(overview);
+    
+    map.setCenter(constantina, 4);
+    
+    overview.maximizeControl();    
   </script>
 </body>
 </html>

Added: sandbox/tschaub/gutter/examples/wkt.html
===================================================================
--- sandbox/tschaub/gutter/examples/wkt.html	                        (rev 0)
+++ sandbox/tschaub/gutter/examples/wkt.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -0,0 +1,146 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>WKT</title>
+    <style type="text/css">
+        #info {
+            position: absolute;
+            top: 70px;
+            left: 550px;
+            width: 350px;
+        }
+        #map {
+            width: 512px;
+            height: 350px;
+            border: 1px solid gray;
+        }
+        #controls {
+            width: 512px;
+        }
+        #wktInput {
+            float: right;
+        }
+        #controlToggle {
+            padding-left: 1em;
+        }
+        #controlToggle li {
+            list-style: none;
+        }
+    </style>
+    <script src="../lib/OpenLayers.js"></script>
+    <script type="text/javascript">
+        <!--
+        var map, vectors, drawControls, wkt;
+        function init(){
+            map = new OpenLayers.Map('map');
+            var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
+                "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); 
+
+            vectors = new OpenLayers.Layer.Vector("Vector Layer");
+
+            map.addLayers([wms, vectors]);
+            map.addControl(new OpenLayers.Control.LayerSwitcher());
+            map.addControl(new OpenLayers.Control.MousePosition());
+            
+            var options = {
+                hover: true,
+                onSelect: displayWKT
+            };
+
+            drawControls = {
+                point: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Point),
+                line: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Path),
+                polygon: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Polygon),
+                hover: new OpenLayers.Control.SelectFeature(vectors, options)
+            };
+            
+            for(var key in drawControls) {
+                map.addControl(drawControls[key]);
+            }
+            
+            wkt = new OpenLayers.Format.WKT();
+            
+            map.setCenter(new OpenLayers.LonLat(0, 0), 3);
+            document.getElementById('noneToggle').checked = true;
+        }
+
+        function toggleControl(element) {
+            for(key in drawControls) {
+                var control = drawControls[key];
+                if(element.value == key && element.checked) {
+                    control.activate();
+                } else {
+                    control.deactivate();
+                }
+            }
+        }
+        
+        function displayWKT(geometry) {
+            var str = wkt.write(geometry);
+            // not a good idea in general, just for this demo
+            str = str.replace(/,/g, ', ');
+            document.getElementById('info').innerHTML = str;
+        }
+
+        function parseWKT() {
+            var element = document.getElementById('wkt');
+            var collection = wkt.read(element.value);
+            if(collection) {
+                if(collection.constructor != Array) {
+                    collection = [collection];
+                }
+                var features = [];
+                for(var i=0; i<collection.length; ++i) {
+                    features.push(new OpenLayers.Feature.Vector(collection[i]));
+                }
+                vectors.addFeatures(features);
+                var plural = (features.length > 1) ? 's' : '';
+                element.value = 'Feature' + plural + ' added'
+            } else {
+                element.value = 'Bad WKT';
+            }
+        }
+        // -->
+    </script>
+  </head>
+  <body onload="init()">
+    <h1>OpenLayers WKT Example</h1>
+    <div id="info"></div>
+    <div id="map"></div>
+    <div id="controls">
+        <p>See <a href="http://en.wikipedia.org/wiki/Well-known_text#Geometric_Objects">Wikipedia</a>
+        for a description and examples of WKT.</p>
+        <div id="wktInput">
+            <textarea id="wkt" rows="6" cols="30">paste WKT here...</textarea>
+            <br />
+            <input type="button" value="add feature" onclick="parseWKT();" />
+        </div>
+        <ul id="controlToggle">
+            <li>
+                <input type="radio" name="type" value="none" id="noneToggle"
+                       onclick="toggleControl(this);" checked="checked" />
+                <label for="noneToggle">navigate</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="point" id="pointToggle" onclick="toggleControl(this);" />
+                <label for="pointToggle">draw point</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="line" id="lineToggle" onclick="toggleControl(this);" />
+                <label for="lineToggle">draw line</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="polygon" id="polygonToggle" onclick="toggleControl(this);" />
+                <label for="polygonToggle">draw polygon</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="hover" id="hoverToggle"
+                       onclick="toggleControl(this);" />
+                <label for="hoverToggle">view WKT for feature</label>
+            </li>
+        </ul>
+    </div>
+  </body>
+</html>

Modified: sandbox/tschaub/gutter/examples/wmst.html
===================================================================
--- sandbox/tschaub/gutter/examples/wmst.html	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/examples/wmst.html	2007-04-02 03:10:26 UTC (rev 2966)
@@ -21,7 +21,7 @@
                 "http://wms.jpl.nasa.gov/wms.cgi", 
                 {layers: "modis,global_mosaic"});
 
-	        ia_wms = new OpenLayers.Layer.WMS("Nexrad","http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?",{layers:"nexrad-n0r-wmst",transparent:true,format:'image/png',time:OpenLayers.Util.getElement('time').value});
+            ia_wms = new OpenLayers.Layer.WMS("Nexrad","http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi?",{layers:"nexrad-n0r-wmst",transparent:true,format:'image/png',time:OpenLayers.Util.getElement('time').value});
 
             jpl_wms.setVisibility(false);
 

Modified: sandbox/tschaub/gutter/lib/OpenLayers/BaseTypes.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/BaseTypes.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/BaseTypes.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -32,7 +32,7 @@
             // 
             // to be revisited in 3.0
             // 
-            if (arguments[i].toString) {
+            if (arguments[i].hasOwnProperty('toString')) {
                 proto.toString = arguments[i].toString;
             }
         }
@@ -492,11 +492,14 @@
         var bounds = null;
         if (object) {
             switch(object.CLASS_NAME) {
-                case "OpenLayers.Geometry.Point":
                 case "OpenLayers.LonLat":    
                     bounds = new OpenLayers.Bounds(object.lon, object.lat,
                                                     object.lon, object.lat);
                     break;
+                case "OpenLayers.Geometry.Point":
+                    bounds = new OpenLayers.Bounds(object.x, object.y,
+                                                    object.x, object.y);
+                    break;
                     
                 case "OpenLayers.Bounds":    
                     bounds = object;

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/KeyboardDefaults.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/KeyboardDefaults.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/KeyboardDefaults.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -26,6 +26,18 @@
     /**
      * 
      */
+    destroy: function() {
+        if (this.handler) {
+            this.handler.destroy();
+        }        
+        this.handler = null;
+        
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * 
+     */
     draw: function() {
         this.handler = new OpenLayers.Handler.Keyboard( this, { 
                                 "keypress": this.defaultKeyPress });

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/LayerSwitcher.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/LayerSwitcher.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/LayerSwitcher.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -25,7 +25,7 @@
     baseLayersDiv: null,
 
     /** @type Array */
-    baseLayerInputs: null,
+    baseLayers: null,
     
     
     /** @type DOMElement */
@@ -35,7 +35,7 @@
     dataLayersDiv: null,
 
     /** @type Array */
-    dataLayerInputs: null,
+    dataLayers: null,
 
 
     /** @type DOMElement */
@@ -54,6 +54,28 @@
         OpenLayers.Control.prototype.initialize.apply(this, arguments);
     },
 
+    /**
+     * 
+     */    
+    destroy: function() {
+        
+        OpenLayers.Event.stopObservingElement(this.div);
+
+        OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+        OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+
+        //clear out layers info and unregister their events 
+        this.clearLayersArray("base");
+        this.clearLayersArray("data");
+        
+        this.map.events.unregister("addlayer", this, this.redraw);
+        this.map.events.unregister("changelayer", this, this.redraw);
+        this.map.events.unregister("removelayer", this, this.redraw);
+        this.map.events.unregister("changebaselayer", this, this.redraw);
+        
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
+
     /** 
      * @param {OpenLayers.Map} map
      */
@@ -85,6 +107,27 @@
         return this.div;
     },
 
+    /** user specifies either "base" or "data". we then clear all the 
+     *    corresponding listeners, the div, and reinitialize a new array.
+     * 
+     * @private
+     * 
+     * @param {String} layersType Ei
+     */
+    clearLayersArray: function(layersType) {
+        var layers = this[layersType + "Layers"];
+        if (layers) {
+            for(var i=0; i < layers.length; i++) {
+                var layer = layers[i];
+                OpenLayers.Event.stopObservingElement(layer.inputElem);
+                OpenLayers.Event.stopObservingElement(layer.labelSpan);
+            }
+        }
+        this[layersType + "LayersDiv"].innerHTML = "";
+        this[layersType + "Layers"] = new Array();
+    },
+
+
     /** Goes through and takes the current state of the Map and rebuilds the
      *   control to display that state. Groups base layers into a radio-button
      *   group and lists each data layer with a checkbox.
@@ -95,12 +138,9 @@
     redraw: function() {
 
         //clear out previous layers 
-        this.baseLayersDiv.innerHTML = "";
-        this.baseLayerInputs = new Array();
+        this.clearLayersArray("base");
+        this.clearLayersArray("data");
         
-        this.dataLayersDiv.innerHTML = "";
-        this.dataLayerInputs = new Array();
-        
         var containsOverlays = false;
         
         var layers = this.map.layers.slice();
@@ -128,14 +168,17 @@
                 inputElem.value = layer.name;
                 inputElem.checked = checked;
                 inputElem.defaultChecked = checked;
-                inputElem.layer = layer;
-                inputElem.control = this;
 
                 if (!baseLayer && !layer.inRange) {
                     inputElem.disabled = true;
                 }
+                var context = {
+                    'inputElem': inputElem,
+                    'layer': layer,
+                    'layerSwitcher': this
+                }
                 OpenLayers.Event.observe(inputElem, "mouseup", 
-                              this.onInputClick.bindAsEventListener(inputElem));
+                              this.onInputClick.bindAsEventListener(context));
                 
                 // create span
                 var labelSpan = document.createElement("span");
@@ -143,16 +186,21 @@
                     labelSpan.style.color = "gray";
                 }
                 labelSpan.innerHTML = layer.name;
-                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : "baseline";
+                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" 
+                                                            : "baseline";
                 OpenLayers.Event.observe(labelSpan, "click", 
-                              this.onInputClick.bindAsEventListener(inputElem));
+                              this.onInputClick.bindAsEventListener(context));
                 // create line break
                 var br = document.createElement("br");
     
                 
-                var groupArray = (baseLayer) ? this.baseLayerInputs
-                                             : this.dataLayerInputs;
-                groupArray.push(inputElem);
+                var groupArray = (baseLayer) ? this.baseLayers
+                                             : this.dataLayers;
+                groupArray.push({
+                    'layer': layer,
+                    'inputElem': inputElem,
+                    'labelSpan': labelSpan
+                });
                                                      
     
                 var groupDiv = (baseLayer) ? this.baseLayersDiv
@@ -173,18 +221,24 @@
      * 
      * @private
      * 
+     * @context 
+     *      {DOMElement} inputElem
+     *      {OpenLayers.Control.LayerSwitcher} layerSwitcher
+     *      {OpenLayers.Layer} layer
+     * 
      * @param {Event} e
      */
 
     onInputClick: function(e) {
-        if (!this.disabled) {
-            if (this.type == "radio") {
-                this.checked = true;
+
+        if (!this.inputElem.disabled) {
+            if (this.inputElem.type == "radio") {
+                this.inputElem.checked = true;
                 this.layer.map.setBaseLayer(this.layer, true);
                 this.layer.map.events.triggerEvent("changebaselayer");
             } else {
-                this.checked = !this.checked;
-                this.control.updateMap();
+                this.inputElem.checked = !this.inputElem.checked;
+                this.layerSwitcher.updateMap();
             }
         }
         OpenLayers.Event.stop(e);
@@ -211,17 +265,17 @@
     updateMap: function() {
 
         // set the newly selected base layer        
-        for(var i=0; i < this.baseLayerInputs.length; i++) {
-            var input = this.baseLayerInputs[i];   
-            if (input.checked) {
-                this.map.setBaseLayer(input.layer, false);
+        for(var i=0; i < this.baseLayers.length; i++) {
+            var layerEntry = this.baseLayers[i];
+            if (layerEntry.inputElem.checked) {
+                this.map.setBaseLayer(layerEntry.layer, false);
             }
         }
 
         // set the correct visibilities for the overlays
-        for(var i=0; i < this.dataLayerInputs.length; i++) {
-            var input = this.dataLayerInputs[i];   
-            input.layer.setVisibility(input.checked, true);
+        for(var i=0; i < this.dataLayers.length; i++) {
+            var layerEntry = this.dataLayers[i];   
+            layerEntry.layer.setVisibility(layerEntry.inputElem.checked, true);
         }
 
     },

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseDefaults.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseDefaults.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseDefaults.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -18,6 +18,9 @@
     /** @type Boolean */
     performedDrag: false,
 
+    /** @type function */
+    wheelObserver: null,
+
     /** 
      * @constructor
      */
@@ -28,6 +31,35 @@
     /**
      * 
      */    
+    destroy: function() {
+        
+        if (this.handler) {
+            this.handler.destroy();
+        }
+        this.handler = null;
+
+        this.map.events.unregister( "click", this, this.defaultClick );
+        this.map.events.unregister( "dblclick", this, this.defaultDblClick );
+        this.map.events.unregister( "mousedown", this, this.defaultMouseDown );
+        this.map.events.unregister( "mouseup", this, this.defaultMouseUp );
+        this.map.events.unregister( "mousemove", this, this.defaultMouseMove );
+        this.map.events.unregister( "mouseout", this, this.defaultMouseOut );
+
+        //unregister mousewheel events specifically on the window and document
+        OpenLayers.Event.stopObserving(window, "DOMMouseScroll", 
+                                        this.wheelObserver);
+        OpenLayers.Event.stopObserving(window, "mousewheel", 
+                                        this.wheelObserver);
+        OpenLayers.Event.stopObserving(document, "mousewheel", 
+                                        this.wheelObserver);
+        this.wheelObserver = null;
+                      
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);        
+    },
+
+    /**
+     * 
+     */
     draw: function() {
         this.map.events.register( "click", this, this.defaultClick );
         this.map.events.register( "dblclick", this, this.defaultDblClick );
@@ -44,15 +76,13 @@
      * 
      */
     registerWheelEvents: function() {
+
+        this.wheelObserver = this.onWheelEvent.bindAsEventListener(this);
         
         //register mousewheel events specifically on the window and document
-        OpenLayers.Event.observe(window, "DOMMouseScroll", 
-                      this.onWheelEvent.bindAsEventListener(this));
-        OpenLayers.Event.observe(window, "mousewheel", 
-                      this.onWheelEvent.bindAsEventListener(this));
-        OpenLayers.Event.observe(document, "mousewheel", 
-                      this.onWheelEvent.bindAsEventListener(this));
-
+        OpenLayers.Event.observe(window, "DOMMouseScroll", this.wheelObserver);
+        OpenLayers.Event.observe(window, "mousewheel", this.wheelObserver);
+        OpenLayers.Event.observe(document, "mousewheel", this.wheelObserver);
     },
 
     /**

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseToolbar.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseToolbar.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/MouseToolbar.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -41,6 +41,19 @@
         this.measureDivs = [];
     },
     
+    /**
+     * 
+     */
+    destroy: function() {
+        for( var btnId in this.buttons) {
+            var btn = this.buttons[btnId];
+            btn.map = null;
+            btn.events.destroy();
+        }
+        OpenLayers.Control.MouseDefaults.prototype.destroy.apply(this, 
+                                                                 arguments);
+    },
+    
     draw: function() {
         OpenLayers.Control.prototype.draw.apply(this, arguments); 
         OpenLayers.Control.MouseDefaults.prototype.draw.apply(this, arguments);
@@ -53,11 +66,9 @@
         centered = centered.add((this.direction == "vertical" ? 0 : sz.w), (this.direction == "vertical" ? sz.h : 0));
         this.switchModeTo("pan");
 
-        this.registerWheelEvents();
-
         return this.div;
     },
-    
+
     _addButton:function(id, img, activeImg, xy, sz, title) {
         var imgLocation = OpenLayers.Util.getImagesLocation() + img;
         var activeImgLocation = OpenLayers.Util.getImagesLocation() + activeImg;

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/Navigation.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/Navigation.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/Navigation.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -59,20 +59,33 @@
         return false;
     },
 
+    wheelChange: function(evt, deltaZ) {
+        var newZoom = this.map.getZoom() + deltaZ;
+        if (!this.map.isValidZoomLevel(newZoom)) return;
+
+        var size    = this.map.getSize();
+        var deltaX  = size.w/2 - evt.xy.x;
+        var deltaY  = evt.xy.y - size.h/2;
+        var newRes  = this.map.baseLayer.resolutions[newZoom];
+        var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
+        var newCenter = new OpenLayers.LonLat(
+                            zoomPoint.lon + deltaX * newRes,
+                            zoomPoint.lat + deltaY * newRes );
+        this.map.setCenter( newCenter, newZoom );
+    },
+
     /** User spun scroll wheel up
      * 
      */
     wheelUp: function(evt) {
-        this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
-                           this.map.getZoom() + 1);
+        this.wheelChange(evt, 1);
     },
 
     /** User spun scroll wheel down
      * 
      */
     wheelDown: function(evt) {
-        this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
-                           this.map.getZoom() - 1);
+        this.wheelChange(evt, -1);
     },
     
     /** @final @type String */

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/OverviewMap.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/OverviewMap.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/OverviewMap.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -77,7 +77,51 @@
     initialize: function(options) {
         OpenLayers.Control.prototype.initialize.apply(this, [options]);
     },
+    
+    /**
+     * 
+     */
+    destroy: function() {
+        if (!this.mapDiv) { // we've already been destroyed
+            return;
+        }
+        this.mapDiv.removeChild(this.extentRectangle);
+        this.extentRectangle = null;
+        this.rectEvents.destroy();
+        this.rectEvents = null;
 
+        this.ovmap.destroy();
+        this.ovmap = null;
+        
+        this.element.removeChild(this.mapDiv);
+        this.mapDiv = null;
+        this.mapDivEvents.destroy(); 
+        this.mapDivEvents = null;
+
+        this.div.removeChild(this.element);
+        this.element = null;
+        this.elementEvents.destroy();
+        this.elementEvents = null;
+
+        if (this.maximizeDiv) {
+            OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+            this.div.removeChild(this.maximizeDiv);
+            this.maximizeDiv = null;
+        }
+        
+        if (this.minimizeDiv) {
+            OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+            this.div.removeChild(this.minimizeDiv);
+            this.minimizeDiv = null;
+        }
+        
+        this.map.events.unregister('moveend', this, this.update);
+        this.map.events.unregister("changebaselayer", this, 
+                                    this.baseLayerDraw);
+
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);    
+    },
+
     /**
      * @type DOMElement
      */    
@@ -166,8 +210,8 @@
                           'click', 
                           this.maximizeControl.bindAsEventListener(this));
             OpenLayers.Event.observe(this.maximizeDiv,
-						  'dblclick',
-						  function(e) {
+                          'dblclick',
+                          function(e) {
                               OpenLayers.Event.stop(e);
                           });
             this.div.appendChild(this.maximizeDiv);
@@ -186,8 +230,8 @@
                           'click', 
                           this.minimizeControl.bindAsEventListener(this));
             OpenLayers.Event.observe(this.minimizeDiv,
-						  'dblclick',
-						  function(e) {
+                          'dblclick',
+                          function(e) {
                               OpenLayers.Event.stop(e);
                           });
             this.div.appendChild(this.minimizeDiv);

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoom.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoom.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoom.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -27,12 +27,26 @@
      * @constructor
      */
     initialize: function() {
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
         this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
                                              OpenLayers.Control.PanZoom.Y);
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
     },
 
     /**
+     * 
+     */
+    destroy: function() {
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+        while(this.buttons.length) {
+            var btn = this.buttons.shift();
+            btn.map = null;
+            OpenLayers.Event.stopObservingElement(btn);
+        }
+        this.buttons = null;
+        this.position = null;
+    },
+
+    /**
     * @param {OpenLayers.Pixel} px
     * 
     * @returns A reference to the container div for the PanZoom control
@@ -84,9 +98,12 @@
         //we want to add the outer div
         this.div.appendChild(btn);
 
-        btn.onmousedown = this.buttonDown.bindAsEventListener(btn);
-        btn.onmouseup = this.doubleClick.bindAsEventListener(btn);
-        btn.ondblclick  = this.doubleClick.bindAsEventListener(btn);
+        OpenLayers.Event.observe(btn, "mousedown", 
+                                 this.buttonDown.bindAsEventListener(btn));
+        OpenLayers.Event.observe(btn, "mouseup", 
+                                 this.doubleClick.bindAsEventListener(btn));
+        OpenLayers.Event.observe(btn, "dblclick", 
+                                 this.doubleClick.bindAsEventListener(btn));
         btn.action = id;
         btn.map = this.map;
         btn.slideFactor = this.slideFactor;
@@ -139,16 +156,6 @@
         OpenLayers.Event.stop(evt);
     },
 
-    /**
-     * 
-     */
-    destroy: function() {
-        OpenLayers.Control.prototype.destroy.apply(this, arguments);
-        for(i=0; i<this.buttons.length; i++) {
-            this.buttons[i].map = null;
-        }
-    },
-    
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Control.PanZoom"
 });

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoomBar.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoomBar.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/PanZoomBar.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -9,27 +9,55 @@
  * @requires OpenLayers/Control/PanZoom.js
  */
 OpenLayers.Control.PanZoomBar = OpenLayers.Class.create();
-OpenLayers.Control.PanZoomBar.X = 4;
-OpenLayers.Control.PanZoomBar.Y = 4;
 OpenLayers.Control.PanZoomBar.prototype = 
   OpenLayers.Class.inherit( OpenLayers.Control.PanZoom, {
 
-    /** @type Array(...) */
-    buttons: null,
-
     /** @type int */
     zoomStopWidth: 18,
 
     /** @type int */
     zoomStopHeight: 11,
 
+    /** @type DOMElement */
+    slider: null,
+
+    /** @type OpenLayers.Events */
+    sliderEvents: null,
+
+    /** @type DOMElement */
+    zoomBarDiv: null,
+
+    /** @type OpenLayers.Events */
+    divEvents: null,
+
     initialize: function() {
         OpenLayers.Control.PanZoom.prototype.initialize.apply(this, arguments);
-        this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoomBar.X,
-                                             OpenLayers.Control.PanZoomBar.Y);
     },
 
     /**
+     * 
+     */
+    destroy: function() {
+
+        this.div.removeChild(this.slider);
+        this.slider = null;
+
+        this.sliderEvents.destroy();
+        this.sliderEvents = null;
+        
+        this.div.removeChild(this.zoombarDiv);
+        this.zoomBarDiv = null;
+
+        this.divEvents.destroy();
+        this.divEvents = null;
+
+        this.map.events.unregister("zoomend", this, this.moveZoomBar);
+        this.map.events.unregister("changebaselayer", this, this.redraw)
+
+        OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
      * @param {OpenLayers.Map} map
      */
     setMap: function(map) {
@@ -167,6 +195,8 @@
         this.mouseDragStart = evt.xy.clone();
         this.zoomStart = evt.xy.clone();
         this.div.style.cursor = "move";
+        // reset the div offsets just in case the div moved
+        this.zoombarDiv.offsets = null; 
         OpenLayers.Event.stop(evt);
     },
     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/Panel.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/Panel.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/Panel.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -34,20 +34,28 @@
     },
 
     activate: function() {
-        OpenLayers.Control.prototype.activate.apply(this, arguments);
-        for(var i = 0; i < this.controls.length; i++) {
-            if (this.controls[i] == this.defaultControl) {
-                this.controls[i].activate();
-            }
-        }    
-        this.redraw();
+        if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
+            for(var i = 0; i < this.controls.length; i++) {
+                if (this.controls[i] == this.defaultControl) {
+                    this.controls[i].activate();
+                }
+            }    
+            this.redraw();
+            return true;
+        } else {
+            return false;
+        }
     },
     deactivate: function() {
-        OpenLayers.Control.prototype.deactivate.apply(this, arguments);
-        for(var i = 0; i < this.controls.length; i++) {
-            this.controls[i].deactivate();
-        }    
-        this.redraw();
+        if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
+            for(var i = 0; i < this.controls.length; i++) {
+                this.controls[i].deactivate();
+            }    
+            this.redraw();
+            return true;
+        } else {
+            return false;
+        }
     },
     
     /**
@@ -82,9 +90,12 @@
                     this.activateControl(ctrl);
                 };
                 var control = this.controls[i];
-                element.onclick = onClick.bind(this, control);
-                element.onmousedown = OpenLayers.Event.stop.bindAsEventListener();
-                element.onmouseup = OpenLayers.Event.stop.bindAsEventListener();
+                OpenLayers.Event.observe(element, "click", 
+                                         onClick.bind(this, control));
+                OpenLayers.Event.observe(element, "mousedown", 
+                                  OpenLayers.Event.stop.bindAsEventListener());
+                OpenLayers.Event.observe(element, "mouseup", 
+                                  OpenLayers.Event.stop.bindAsEventListener());
                 this.div.appendChild(element);
             }
         }
@@ -119,7 +130,7 @@
         this.controls = this.controls.concat(controls);
         if (this.map) { // map.addControl() has already been called on the panel
             for (var i = 0; i < controls.length; i++) {
-                map.addControl(controls[i]);
+                this.map.addControl(controls[i]);
                 controls[i].deactivate();
             }
             this.redraw();

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/Permalink.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/Permalink.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/Permalink.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -32,6 +32,20 @@
         }
     },
 
+    /**
+     * 
+     */
+    destroy: function()  {
+        if (this.element.parentNode == this.div) {
+            this.div.removeChild(this.element);
+        }
+        this.element = null;
+
+        this.map.events.unregister('moveend', this, this.updateLink);
+
+        OpenLayers.Control.prototype.destroy.apply(this, arguments); 
+    },
+
     /** Set the map property for the control. 
      * 
      * @param {OpenLayers.Map} map

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control/SelectFeature.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control/SelectFeature.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control/SelectFeature.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -26,6 +26,18 @@
     hover: false,
     
     /**
+     * @type {Function} Optional function to be called when a feature is selected.
+     *                  The function should expect to be called with a geometry.
+     */
+    onSelect: function() {},
+
+    /**
+     * @type {Function} Optional function to be called when a feature is unselected.
+     *                  The function should expect to be called with a geometry.
+     */
+    onUnselect: function() {},
+
+    /**
      * @type {OpenLayers.Layer.Vector}
      */
     layer: null,
@@ -73,40 +85,24 @@
         if(geometry.parent) {
             geometry = geometry.parent;
         }
-        // Store feature style for restoration later
-        if(geometry.feature.originalStyle == null) {
-            geometry.feature.originalStyle = geometry.feature.style;
-        }
-        
         if (this.multiple) {
             if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1) {
-                this.layer.renderer.drawGeometry(geometry,
-                                                 geometry.feature.originalStyle);
-                OpenLayers.Util.removeItem(this.layer.selectedFeatures,
-                                           geometry.feature);
+                this.unselect(geometry);
             } else {
-                this.layer.selectedFeatures.push(geometry.feature);
-                this.layer.renderer.drawGeometry(geometry, this.selectStyle);
+                this.select(geometry);
             }
         } else {
             if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1) {
-                this.layer.renderer.drawGeometry(geometry,
-                                                 geometry.feature.originalStyle);
-                OpenLayers.Util.removeItem(this.layer.selectedFeatures,
-                                           geometry.feature);
+                this.unselect(geometry);
             } else {
                 if (this.layer.selectedFeatures) {
                     for (var i = 0; i < this.layer.selectedFeatures.length; i++) {
-                        this.layer.renderer.drawGeometry(
-                            this.layer.selectedFeatures[i].geometry,
-                            this.layer.selectedFeatures[i].originalStyle);
+                        this.unselect(this.layer.selectedFeatures[i].geometry);
                     }
-                    OpenLayers.Util.clearArray(this.layer.selectedFeatures);
-                }    
-                this.layer.selectedFeatures.push(geometry.feature);
-                this.layer.renderer.drawGeometry(geometry, this.selectStyle);
+                }
+                this.select(geometry);
             }
-        }    
+        }
     },
 
     /**
@@ -121,14 +117,8 @@
         if(geometry.parent) {
             geometry = geometry.parent;
         }
-        // Store feature style for restoration later
-        if(geometry.feature.originalStyle == null) {
-            geometry.feature.originalStyle = geometry.feature.style;
-        }
-        
         if(!(OpenLayers.Util.indexOf(this.layer.selectedFeatures, geometry.feature) > -1)) {
-            this.layer.selectedFeatures.push(geometry.feature);
-            this.layer.renderer.drawGeometry(geometry, this.selectStyle);
+            this.select(geometry);
         }
     },
 
@@ -144,8 +134,37 @@
         if(geometry.parent) {
             geometry = geometry.parent;
         }
+        this.unselect(geometry);
+    },
+    
+    /**
+     * Add feature to the layer's selectedFeature array, render the feature as
+     * selected, and call the onSelect function.
+     * @param {OpenLayers.Geometry} geometry
+     */
+    select: function(geometry) {
+        // Store feature style for restoration later
+        if(geometry.feature.originalStyle == null) {
+            geometry.feature.originalStyle = geometry.feature.style;
+        }
+        this.layer.selectedFeatures.push(geometry.feature);
+        this.layer.renderer.drawGeometry(geometry, this.selectStyle);
+        this.onSelect(geometry);
+    },
+
+    /**
+     * Remove feature from the layer's selectedFeature array, render the feature as
+     * normal, and call the onUnselect function.
+     * @param {OpenLayers.Geometry} geometry
+     */
+    unselect: function(geometry) {
+        // Store feature style for restoration later
+        if(geometry.feature.originalStyle == null) {
+            geometry.feature.originalStyle = geometry.feature.style;
+        }
         this.layer.renderer.drawGeometry(geometry, geometry.feature.originalStyle);
         OpenLayers.Util.removeItem(this.layer.selectedFeatures, geometry.feature);
+        this.onUnselect(geometry);
     },
 
     /** Set the map property for the control. 

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Control.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Control.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Control.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -65,6 +65,9 @@
      */
     destroy: function () {
         // eliminate circular references
+        if (this.handler) {
+            this.handler.destroy();
+        }    
         this.map = null;
     },
 

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Events.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Events.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Events.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -55,27 +55,74 @@
     return element;
   },
 
+  /** A hashtable cach of the event observers, keyed by element.id
+   * 
+   * @type Object
+   */
   observers: false,
 
   _observeAndCache: function(element, name, observer, useCapture) {
-    if (!this.observers) this.observers = [];
+    if (!this.observers) this.observers = new Object();
+
+    //if there is not yet a hash entry for this element, add one
+    if (!this.observers[element.id]) {
+        this.observers[element.id] = new Array();
+    }
+    //add a new observer to this element's list
+    this.observers[element.id].push({
+        'element': element,
+        'name': name,
+        'observer': observer,
+        'useCapture': useCapture
+    });
+
+    //add the actual browser event listener
     if (element.addEventListener) {
-      this.observers.push([element, name, observer, useCapture]);
       element.addEventListener(name, observer, useCapture);
     } else if (element.attachEvent) {
-      this.observers.push([element, name, observer, useCapture]);
       element.attachEvent('on' + name, observer);
     }
   },
 
-  unloadCache: function() {
-    if (!OpenLayers.Event.observers) return;
-    for (var i = 0; i < OpenLayers.Event.observers.length; i++) {
-      OpenLayers.Event.stopObserving.apply(this, OpenLayers.Event.observers[i]);
-    }
-    OpenLayers.Event.observers = false;
-  },
+    /** Given the id of an element to stop observing, cycle through the 
+     *   element's cached observers, calling stopObserving on each one, 
+     *   skipping those entries which can no longer be removed.
+     * 
+     * @param {DOMElement || String} elementParam
+     */
+    stopObservingElement: function(elementParam) {
 
+        var elementId = (typeof elementParam == "string") ? elementParam 
+                            : OpenLayers.Util.getElement(elementParam).id;
+
+        var elementObservers = OpenLayers.Event.observers[elementId];
+        if (elementObservers) {
+            var i=0;
+            while(i < elementObservers.length) {
+                var entry = elementObservers[0];
+                var args = new Array(entry.element,
+                                     entry.name,
+                                     entry.observer,
+                                     entry.useCapture);
+                var removed = OpenLayers.Event.stopObserving.apply(this, args);
+                if (!removed) {
+                    i++;
+                }
+            }
+        }
+    },
+
+    /** Cycle through all the element entries in the events cache and call
+     *   stopObservingElement on each. 
+     */
+    unloadCache: function() {
+        if (!OpenLayers.Event.observers) return;
+        for (var elementId in OpenLayers.Event.observers) {
+            OpenLayers.Event.stopObservingElement.apply(this, [elementId]);
+        }
+        OpenLayers.Event.observers = false;
+    },
+
   observe: function(elementParam, name, observer, useCapture) {
     var element = OpenLayers.Util.getElement(elementParam);
     useCapture = useCapture || false;
@@ -88,44 +135,67 @@
     this._observeAndCache(element, name, observer, useCapture);
   },
 
-  stopObserving: function(elementParam, name, observer, useCapture) {
-    var element = OpenLayers.Util.getElement(elementParam);
-    useCapture = useCapture || false;
+    /**
+     * @param {DOMElement || String} elementParam
+     * @param {String} name
+     * @param {function} observer
+     * @param {Boolean} useCapture
+     * 
+     * @returns Whether or not the event observer was removed
+     * @type Boolean
+     */
+    stopObserving: function(elementParam, name, observer, useCapture) {
+        useCapture = useCapture || false;
+    
+        var element = OpenLayers.Util.getElement(elementParam);
+        var elementId = (typeof elementParam == "string") ? elementParam
+                                                          : element.id;
 
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.detachEvent))
-      name = 'keydown';
-
-    // find entry in this.observers cache array and remove it
-    var observers = OpenLayers.Event.observers;
-    var entry = [element, name, observer, useCapture];
-    for (var i = 0; i < observers.length; i++) {
-        var observer = observers[i];
-
-        //compare all 4 elements of entry with observer
-        var sameEntry = true;        
-        for (var j = 0; j < entry.length; j++) {
-            if (entry[j] != observer[j]) {
-                sameEntry = false;
-                break;
+        if (name == 'keypress') {
+            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || 
+                 element.detachEvent) {
+              name = 'keydown';
             }
         }
 
-        //if we've found it, remove it from the observers array
-        if (sameEntry) {
-            observers.splice(i--, 1);
-            break; 
+        // find element's entry in this.observers cache and remove it
+        var foundEntry = false;
+        var elementObservers = OpenLayers.Event.observers[elementId];
+        if (elementObservers) {
+    
+            // find the specific event type in the element's list
+            var i=0;
+            while(!foundEntry && i < elementObservers.length) {
+                var cacheEntry = elementObservers[i];
+    
+                if ((cacheEntry.name == name) &&
+                    (cacheEntry.observer == observer) &&
+                    (cacheEntry.useCapture == useCapture)) {
+    
+                    elementObservers.splice(i, 1);
+                    if (elementObservers.length == 0) {
+                        delete OpenLayers.Event.observers[element.id];
+                    }
+                    foundEntry = true;
+                    break; 
+                }
+                i++;           
+            }
         }
-    }
+    
+        //actually remove the event listener from browser
+        if (element.removeEventListener) {
+            element.removeEventListener(name, observer, useCapture);
+        } else if (element && element.detachEvent) {
+            element.detachEvent('on' + name, observer);
+        }
+        return foundEntry;
+    },
+    
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Event"
+};
 
-    if (element && element.removeEventListener) {
-      element.removeEventListener(name, observer, useCapture);
-    } else if (element && element.detachEvent) {
-      element.detachEvent('on' + name, observer);
-    }
-  }
-};
 /* prevent memory leaks in IE */
 OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
 
@@ -209,7 +279,7 @@
      */
     destroy: function () {
         if (this.element) {
-            this.detachFromElement();
+            OpenLayers.Event.stopObservingElement(this.element);
         }
         this.element = null;
 
@@ -238,23 +308,7 @@
         // disable dragstart in IE so that mousedown/move/up works normally
         OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
     },
-    
-    /**
-     * @private
-     */
-    detachFromElement: function () {
-        for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
-            var eventType = this.BROWSER_EVENTS[i];
 
-            OpenLayers.Event.stopObserving(
-                this.element, eventType, this.eventHandler);
-        }
-
-        // re-enable dragstart in IE
-        OpenLayers.Event.stopObserving(
-            this.element, "dragstart", OpenLayers.Event.stop);
-    },
-
     /**
      * @param {String} type Name of the event to register
      * @param {Object} obj The object to bind the context to for the callback#.

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Feature/Vector.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Feature/Vector.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Feature/Vector.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -51,7 +51,7 @@
         if (data) {
             OpenLayers.Util.extend(this.attributes, data);
         }    
-        this.style = style ? style : OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
+        this.style = style ? style : null; 
     },
     
         

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Feature.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Feature.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Feature.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -59,7 +59,11 @@
             }
         }
 
+        if (this.events) {
+            this.events.destroy();
+        }
         this.events = null;
+        
         this.layer = null;
         this.id = null;
         this.lonlat = null;

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Format/GML.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format/GML.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format/GML.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -180,24 +180,24 @@
      * @param DOMElement xmlNode
      */
     parseAttributes: function(xmlNode) {
-		var nodes = xmlNode.childNodes;
+        var nodes = xmlNode.childNodes;
         var attributes = {};
-		for(var i = 0; i < nodes.length; i++) {
+        for(var i = 0; i < nodes.length; i++) {
             var name = nodes[i].nodeName;
-			var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
+            var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
             // Ignore Geometry attributes
             // match ".//gml:pos|.//gml:posList|.//gml:coordinates"
-			if((name.search(":pos")!=-1)
-			  ||(name.search(":posList")!=-1)
-			  ||(name.search(":coordinates")!=-1)){
-			   continue;	
-			}
-			
-			// Check for a leaf node
-			if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
-			    || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
-				attributes[name] = value;
-			}
+            if((name.search(":pos")!=-1)
+              ||(name.search(":posList")!=-1)
+              ||(name.search(":coordinates")!=-1)){
+               continue;    
+            }
+            
+            // Check for a leaf node
+            if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
+                || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
+                attributes[name] = value;
+            }
             OpenLayers.Util.extend(attributes, this.parseAttributes(nodes[i]))
         }   
         return attributes;
@@ -429,5 +429,9 @@
         coordinatesNode.appendChild(txtNode);
         
         return coordinatesNode;
-    }
+    },
+    
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Format.GML" 
+
 });     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Format/GeoRSS.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format/GeoRSS.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format/GeoRSS.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -103,5 +103,9 @@
            path += geometry.lat + " " + geometry.lon + " ";
         }
         return document.createTextNode(path);
-    }    
+    },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Format.GeoRSS" 
+
 });     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Format/KML.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format/KML.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format/KML.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -93,24 +93,24 @@
      * @param DOMElement xmlNode
      */
     parseAttributes: function(xmlNode) {
-		var nodes = xmlNode.childNodes;
+        var nodes = xmlNode.childNodes;
         var attributes = {};
-		for(var i = 0; i < nodes.length; i++) {
+        for(var i = 0; i < nodes.length; i++) {
             var name = nodes[i].nodeName;
-			var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
+            var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
             // Ignore Geometry attributes
             // match ".//gml:pos|.//gml:posList|.//gml:coordinates"
-			if((name.search(":pos")!=-1)
-			  ||(name.search(":posList")!=-1)
-			  ||(name.search(":coordinates")!=-1)){
-			   continue;	
-			}
-			
-			// Check for a leaf node
-			if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
-			    || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
-				attributes[name] = value;
-			}
+            if((name.search(":pos")!=-1)
+              ||(name.search(":posList")!=-1)
+              ||(name.search(":coordinates")!=-1)){
+               continue;    
+            }
+            
+            // Check for a leaf node
+            if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
+                || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
+                attributes[name] = value;
+            }
             OpenLayers.Util.extend(attributes, this.parseAttributes(nodes[i]))
         }   
         return attributes;
@@ -164,6 +164,7 @@
         return p;
     },
 
+    /** @final @type String */
     CLASS_NAME: "OpenLayers.Format.KML" 
     
 });     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Format/WFS.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format/WFS.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format/WFS.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -25,7 +25,7 @@
      */
     
     initialize: function(options, layer) {
-        OpenLayers.Format.GML.prototype.initialize.apply(this, arguments);
+        OpenLayers.Format.GML.prototype.initialize.apply(this, [options]);
         this.layer = layer;
         if (this.layer.featureNS) {
             this.featureNS = this.layer.featureNS;
@@ -152,5 +152,9 @@
 
     destroy: function() {
         this.layer = null;
-    }
+    },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Format.WFS" 
+
 });    

Added: sandbox/tschaub/gutter/lib/OpenLayers/Format/WKT.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format/WKT.js	                        (rev 0)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format/WKT.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -0,0 +1,289 @@
+/* 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. */
+
+/**
+ * Read and write WKT. 
+ * @requires OpenLayers/Format/JSON.js
+ */
+OpenLayers.Format.WKT = OpenLayers.Class.create();
+OpenLayers.Format.WKT.prototype = 
+  OpenLayers.Class.inherit(OpenLayers.Format, {
+    
+    /**
+     *
+     */
+    initialize: function(options) {
+        this.regExes = {
+            'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
+            'spaces': /\s+/,
+            'parenComma': /\)\s*,\s*\(/,
+            'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,  // can't use {2} here
+            'trimParens': /^\s*\(?(.*?)\)?\s*$/
+        };
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * Deserialize a WKT string and return an OpenLayers.Geometry or an array
+     * of OpenLayers.Geometry.  Supports WKT for POINT, MULTIPOINT, LINESTRING,
+     * MULTILINESTRING, POLYGON, MULTIPOLYGON, and GEOMETRYCOLLECTION.
+     * @param {String} wkt A WKT string
+     * @returns {OpenLayers.Geometry|Array} A geometry or array of geometries
+     *                                      for GEOMETRYCOLLECTION WKT.
+     */
+    read: function(wkt) {
+        var geometry, type, str;
+        var matches = this.regExes.typeStr.exec(wkt);
+        if(matches) {
+            type = matches[1].toLowerCase();
+            str = matches[2];
+            if(this.parse[type]) {
+                geometry = this.parse[type].apply(this, [str]);
+            }
+        }
+        return geometry;
+    },
+
+    /**
+     * Serialize a geometry or array of geometries into a WKT string.
+     * @param {OpenLayers.Geometry|Array} geom A geometry or array of geometries
+     * @returns {String} The WKT string representation of the input geometries
+     */
+    write: function(geom) {
+        var collection, geometry, type, data, isCollection;
+        if(geom.constructor == Array) {
+            collection = geom;
+            isCollection = true;
+        } else {
+            collection = [geom];
+            isCollection = false;
+        }
+        var pieces = [];
+        if(isCollection) {
+            pieces.push('GEOMETRYCOLLECTION(');
+        }
+        for(var i=0; i<collection.length; ++i) {
+            if(isCollection && i>0) {
+                pieces.push(',');
+            }
+            geometry = collection[i];
+            type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
+            if(!this.extract[type]) {
+                return null;
+            }
+            data = this.extract[type].apply(this, [geometry]);
+            pieces.push(type.toUpperCase() + '(' + data + ')');
+        }
+        if(isCollection) {
+            pieces.push(')');
+        }
+        return pieces.join('');
+    },
+    
+    /**
+     * Object with properties corresponding to the geometry types.
+     * Property values are functions that do the actual data extraction.
+     */
+    extract: {
+        /**
+         * Return a space delimited string of point coordinates.
+         * @param {OpenLayers.Geometry.Point} point
+         * @returns {String} A string of coordinates representing the point
+         */
+        'point': function(point) {
+            return point.x + ' ' + point.y;
+        },
+
+        /**
+         * Return a comma delimited string of point coordinates from a multipoint.
+         * @param {OpenLayers.Geometry.MultiPoint} multipoint
+         * @returns {String} A string of point coordinate strings 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.join(',');
+        },
+        
+        /**
+         * Return a comma delimited string of point coordinates from a line.
+         * @param {OpenLayers.Geometry.LineString} linestring
+         * @returns {String} A string of point coordinate strings 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.join(',');
+        },
+
+        /**
+         * Return a comma delimited string of linestring strings from a multilinestring.
+         * @param {OpenLayers.Geometry.MultiLineString} multilinestring
+         * @returns {String} A string of of linestring strings 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.join(',');
+        },
+        
+        /**
+         * Return a comma delimited string of linear ring arrays from a polygon.
+         * @param {OpenLayers.Geometry.Polygon} polygon
+         * @returns {String} 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.join(',');
+        },
+
+        /**
+         * Return an array of polygon arrays from a multipolygon.
+         * @param {OpenLayers.Geometry.MultiPolygon} 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.join(',');
+        }
+
+    },
+
+    /**
+     * Object with properties corresponding to the geometry types.
+     * Property values are functions that do the actual parsing.
+     */
+    parse: {
+        /**
+         * Return point geometry given a point WKT fragment.
+         * @param {String} str A WKT fragment representing the point
+         * @returns {OpenLayers.Geometry.Point} A point geometry
+         */
+        'point': function(str) {
+            var coords = str.trim().split(this.regExes.spaces);
+            return new OpenLayers.Geometry.Point(coords[0], coords[1]);
+        },
+
+        /**
+         * Return a multipoint geometry given a multipoint WKT fragment.
+         * @param {String} A WKT fragment representing the multipoint
+         * @returns {OpenLayers.Geometry.MultiPoint} A multipoint geometry
+         */
+        'multipoint': function(str) {
+            var points = str.trim().split(',');
+            var components = [];
+            for(var i=0; i<points.length; ++i) {
+                components.push(this.parse.point.apply(this, [points[i]]));
+            }
+            return new OpenLayers.Geometry.MultiPoint(components);
+        },
+        
+        /**
+         * Return a linestring geometry given a linestring WKT fragment.
+         * @param {String} A WKT fragment representing the linestring
+         * @returns {OpenLayers.Geometry.LineString} A linestring geometry
+         */
+        'linestring': function(str) {
+            var points = str.trim().split(',');
+            var components = [];
+            for(var i=0; i<points.length; ++i) {
+                components.push(this.parse.point.apply(this, [points[i]]));
+            }
+            return new OpenLayers.Geometry.LineString(components);
+        },
+
+        /**
+         * Return a multilinestring geometry given a multilinestring WKT fragment.
+         * @param {String} A WKT fragment representing the multilinestring
+         * @returns {OpenLayers.Geometry.LineString} A multilinestring geometry
+         */
+        'multilinestring': function(str) {
+            var line;
+            var lines = str.trim().split(this.regExes.parenComma);
+            var components = [];
+            for(var i=0; i<lines.length; ++i) {
+                line = lines[i].replace(this.regExes.trimParens, '$1');
+                components.push(this.parse.linestring.apply(this, [line]));
+            }
+            return new OpenLayers.Geometry.MultiLineString(components);
+        },
+        
+        /**
+         * Return a polygon geometry given a polygon WKT fragment.
+         * @param {String} A WKT fragment representing the polygon
+         * @returns {OpenLayers.Geometry.Polygon} A polygon geometry
+         */
+        'polygon': function(str) {
+            var ring, linestring, linearring;
+            var rings = str.trim().split(this.regExes.parenComma);
+            var components = [];
+            for(var i=0; i<rings.length; ++i) {
+                ring = rings[i].replace(this.regExes.trimParens, '$1');
+                linestring = this.parse.linestring.apply(this, [ring]);
+                linearring  = new OpenLayers.Geometry.LinearRing(linestring.components);
+                components.push(linearring);
+            }
+            return new OpenLayers.Geometry.Polygon(components);
+        },
+
+        /**
+         * Return a multipolygon geometry given a multipolygon WKT fragment.
+         * @param {String} A WKT fragment representing the multipolygon
+         * @returns {OpenLayers.Geometry.MultiPolygon} A multipolygon geometry
+         */
+        'multipolygon': function(str) {
+            var polygon;
+            var polygons = str.trim().split(this.regExes.doubleParenComma);
+            var components = [];
+            for(var i=0; i<polygons.length; ++i) {
+                polygon = polygons[i].replace(this.regExes.trimParens, '$1');
+                components.push(this.parse.polygon.apply(this, [polygon]));
+            }
+            return new OpenLayers.Geometry.MultiPolygon(components);
+        },
+
+        /**
+         * Return an array of geometries given a geometrycollection WKT fragment.
+         * @param {String} A WKT fragment representing the geometrycollection
+         * @returns {Array} An array of OpenLayers.Geometry
+         */
+        'geometrycollection': function(str) {
+            // separate components of the collection with |
+            str = str.replace(/,\s*([A-Za-z])/g, '|$1');
+            var wktArray = str.trim().split('|');
+            var components = [];
+            for(var i=0; i<wktArray.length; ++i) {
+                components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
+            }
+            return components;
+        }
+
+    },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Format.WKT" 
+
+});     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Format.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Format.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Format.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -29,5 +29,9 @@
      */
      write: function(features) {
          alert("Write not implemented.");
-     }
+     },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Format"
+
 };     

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Collection.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Collection.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Collection.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -24,6 +24,14 @@
 
     /** @type Array(OpenLayers.Geometry) */
     components: null,
+    
+    /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: null,
 
     /**
      * @constructor
@@ -50,19 +58,16 @@
      * @returns An exact clone of this collection
      * @type OpenLayers.Geometry.Collection
      */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = eval("new " + this.CLASS_NAME + "()");
+    clone: function() {
+        var geometry = eval("new " + this.CLASS_NAME + "()");
+        for(var i=0; i<this.components.length; i++) {
+            geometry.addComponent(this.components[i].clone());
         }
         
-        for (var i = 0; i < this.components.length; i++) {
-            obj.addComponent(this.components[i].clone());
-        }
-        
         // catch any randomly tagged-on properties
-        OpenLayers.Util.applyDefaults(obj, this);
+        OpenLayers.Util.applyDefaults(geometry, this);
         
-        return obj;
+        return geometry;
     },
 
     /**
@@ -112,28 +117,39 @@
         }
     },
 
-    /** Add a new component (geometry) to the collection. 
+    /**
+     * Add a new component (geometry) to the collection.  If this.componentTypes
+     * is set, then the component class name must be in the componentTypes array.
      * 
      * The bounds cache is reset.
      * 
      * @param {OpenLayers.Geometry} component
      * @param {int} index Index into the array to insert the component
+     * @type Boolean
+     * @return Component was successfully added
     */    
     addComponent: function(component, index) {
-        if (component) {
+        var added = false;
+        if(component) {
+            if(this.componentTypes == null ||
+               (OpenLayers.Util.indexOf(this.componentTypes,
+                                        component.CLASS_NAME) > -1)) {
 
-            if (index) {
-                var components1 = this.components.slice(0, index);
-                var components2 = this.components.slice(index, 
-                                                       this.components.length);
-                components1.push(component);
-                this.components = components1.concat(components2);
-            } else {
-                this.components.push(component);
+                if(index != null && (index < this.components.length)) {
+                    var components1 = this.components.slice(0, index);
+                    var components2 = this.components.slice(index, 
+                                                           this.components.length);
+                    components1.push(component);
+                    this.components = components1.concat(components2);
+                } else {
+                    this.components.push(component);
+                }
+                component.parent = this;
+                this.clearBounds();
+                added = true;
             }
-            component.parent = this;
-            this.clearBounds();
         }
+        return added;
     },
     
     /**
@@ -196,6 +212,30 @@
         }
     },
 
+    /**
+     * Tests for equivalent geometries
+     * @param {OpenLayers.Geometry}
+     * @type Boolean
+     * @return The coordinates are equivalent
+     */
+    equals: function(geometry) {
+        var equivalent = true;
+        if(!geometry.CLASS_NAME || (this.CLASS_NAME != geometry.CLASS_NAME)) {
+            equivalent = false;
+        } else if(!(geometry.components instanceof Array) ||
+                  (geometry.components.length != this.components.length)) {
+            equivalent = false;
+        } else {
+            for(var i=0; i<this.components.length; ++i) {
+                if(!this.components[i].equals(geometry.components[i])) {
+                    equivalent = false;
+                    break;
+                }
+            }
+        }
+        return equivalent;
+    },
+
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Geometry.Collection"
 });

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Curve.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Curve.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Curve.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -16,6 +16,14 @@
   OpenLayers.Class.inherit(OpenLayers.Geometry.MultiPoint, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.Point"],
+
+    /**
      * @constructor
      *
      * @param {Array(OpenLayers.Geometry.Point)} points
@@ -26,20 +34,6 @@
     },
     
     /**
-     * @returns An exact clone of this OpenLayers.Feature
-     * @type OpenLayers.Feature
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Geometry.Curve();
-        }
-        
-        obj = OpenLayers.Geometry.Collection.prototype.clone.apply(this, 
-                                                                   [obj]);
-        return obj;
-    },
-    
-    /**
      * @returns The length of the curve
      * @type float
      */

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LineString.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LineString.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LineString.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -20,34 +20,9 @@
      * @param {Array(OpenLayers.Geometry.Point)} points
      */
     initialize: function(points) {
-    	OpenLayers.Geometry.Curve.prototype.initialize.apply(this, 
-    	                                                          arguments);        
+        OpenLayers.Geometry.Curve.prototype.initialize.apply(this, arguments);        
     },
 
-    /**
-     * @returns The coordinates components as a string
-     * @type String
-     */
-    toString: function() {
-        return this.components.toString();
-    },
-    
-    /**
-     * @returns An exact clone of this OpenLayers.Feature
-     * @type OpenLayers.Feature
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Geometry.LineString();
-        }
-        
-        for (var i = 0; i < this.components.length; i++) {
-            obj.addComponent(this.components[i].clone());
-        }
-        
-        return obj;
-    },
-
     /** Only allows removal of a point if there are three or more points in 
      *   the linestring. (otherwise the result would be just a single point)
      * 
@@ -55,7 +30,7 @@
      */
     removeComponent: function(point) {
         if ( this.components && (this.components.length > 2)) {
-            OpenLayers.Geometry.Curve.prototype.removeComponent.apply(this, 
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
                                                                   arguments);
         }
     },

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LinearRing.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LinearRing.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/LinearRing.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -19,50 +19,62 @@
     OpenLayers.Class.inherit(OpenLayers.Geometry.LineString, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.Point"],
+
+    /**
+     * Linear rings are constructed with an array of points.  This array
+     * can represent a closed or open ring.  If the ring is open (the last
+     * point does not equal the first point), the constructor will close
+     * the ring.  If the ring is already closed (the last point does equal
+     * the first point), it will be left closed.
+     * 
      * @constructor
-     *
      * @param {Array(OpenLayers.Geometry.Point)} points
      */
     initialize: function(points) {
         OpenLayers.Geometry.LineString.prototype.initialize.apply(this, 
                                                                   arguments);
     },
-    
+
     /**
-     * @returns An exact clone of this OpenLayers.Geometry.LinearRing
-     * @type OpenLayers.Geometry.LinearRing
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Geometry.LinearRing();
-        }
-        
-        for (var i = 0; i < this.components.length; i++) {
-            obj.addComponent(this.components[i].clone());
-        }
-        
-        return obj;
-    },
-    
-    /**
-     * Adds a point to geometry components
+     * Adds a point to geometry components.  If the point is to be added to
+     * the end of the components array and it is the same as the last point
+     * already in that array, the duplicate point is not added.  This has the
+     * effect of closing the ring if it is not already closed, and doing the
+     * right thing if it is already closed.  This behavior can be overridden
+     * by calling the method with a non-null index as the second argument.
      *
      * @param {OpenLayers.Geometry.Point} point
      * @param {int} index Index into the array to insert the component
-     */ 
+     * @type Boolean
+     * @return Point was successfully added
+     */
     addComponent: function(point, index) {
+        var added = false;
+
         //remove last point
         var lastPoint = this.components[this.components.length-1];
-        OpenLayers.Geometry.Curve.prototype.removeComponent.apply(this, 
-                                                                  [lastPoint]);
- 
-        //add our point
-        OpenLayers.Geometry.LineString.prototype.addComponent.apply(this, 
-                                                                    arguments);
+        OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
+                                                              [lastPoint]);
+
+        // given an index, add the point
+        // without an index only add non-duplicate points
+        if(index != null || !point.equals(lastPoint)) {
+            added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
+                                                                        arguments);
+        }
+
         //append copy of first point
         var firstPoint = this.components[0];
-        OpenLayers.Geometry.Curve.prototype.addComponent.apply(this, 
+        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
                                                          [firstPoint.clone()]);
+
+        return added;
     },
     
     /**
@@ -75,15 +87,15 @@
 
             //remove last point
             var lastPoint = this.components[this.components.length-1];
-            OpenLayers.Geometry.Curve.prototype.removeComponent.apply(this, 
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
                                                                  [lastPoint]);
             
             //remove our point
-            OpenLayers.Geometry.LineString.prototype.removeComponent.apply(this, 
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
                                                                     arguments);
             //append copy of first point
             var firstPoint = this.components[0];
-            OpenLayers.Geometry.Curve.prototype.addComponent.apply(this, 
+            OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
                                                          [firstPoint.clone()]);
         }
     },

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiLineString.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiLineString.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiLineString.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -14,29 +14,23 @@
     OpenLayers.Class.inherit(OpenLayers.Geometry.Collection, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.LineString"],
+
+    /**
      * @constructor
      *
      * @param {Array(OpenLayers.Geometry.LineString)} components
      */
     initialize: function(components) {
-    	OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
-    	                                                          arguments);        
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);        
     },
 
-    /**
-     * adds a component to the MultiPoint, checking type
-     *
-     * @param {OpenLayers.Geometry.LineString} component lineString to add
-     * @param {int} index Index into the array to insert the component
-     */
-    addComponent: function(component, index) {
-        if (!(component instanceof OpenLayers.Geometry.LineString)) {
-            throw "component should be an OpenLayers.Geometry.LineString";
-        }
-        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
-                                                                    arguments);        
-    },
-
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Geometry.MultiLineString"
 });

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPoint.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPoint.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPoint.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -14,30 +14,24 @@
     OpenLayers.Class.inherit(OpenLayers.Geometry.Collection, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.Point"],
+
+    /**
      * @constructor
      *
      * @param {Array(OpenLayers.Geometry.Point)} components
      */
     initialize: function(components) {
-    	OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
-    	                                                          arguments);
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);
     },
 
     /**
-     * adds component to the MultiPoint, checking type
-     *
-     * @param {OpenLayers.Geometry.Point} component point to add
-     * @param {int} index Index into the array to insert the component
-     */
-    addComponent: function(component, index) {
-        if (!(component instanceof OpenLayers.Geometry.Point)) {
-            throw "component should be an OpenLayers.Geometry.Point";
-        }
-        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
-                                                                    arguments);
-    },
-
-    /**
      * Wrapper for addComponent()
      * 
      * @param {OpenLayers.Geometry.Point} point

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPolygon.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPolygon.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/MultiPolygon.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -14,31 +14,22 @@
     OpenLayers.Class.inherit(OpenLayers.Geometry.Collection, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.Polygon"],
+
+    /**
     * @constructor
     *
     * @param {Array(OpenLayers.Geometry.Polygon)} components
     */
     initialize: function(components) {
-    	OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
-    	                                                          arguments);
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);
     },
-
-    /**
-     * adds component to the MultiPolygon, checking type
-     *
-     * @param {OpenLayers.Geometry.Polygon} component Polygon to add
-     * @param {int} index Index into the array to insert the component
-     */
-    addComponent: function(component, index) {
-        if (!(component instanceof OpenLayers.Geometry.Polygon)) {
-            var throwStr = "component should be an " +
-                           "OpenLayers.Geometry.Polygon but is an " + 
-                           component.CLASS_NAME;
-            throw throwStr;
-        }
-        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
-                                                                    arguments);
-    },
     
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Geometry.MultiPolygon"

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Point.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Point.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Point.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -4,21 +4,12 @@
 
 /**
  * @class
- *
- * The Point class is a subclass of Geometry and also a subclass of the
- * non-vector OpenLayers.LonLat class. The basic functionality that this adds
- * is the ability to switch between lon/lat and x/y at will, as well some 
- * convenience functions to create a Bounds from a point and measure the 
- * distance between two points. 
  * 
- * getX() and setX() should be used to access the x or lon variables.
- * 
- * @requires OpenLayers/BaseTypes.js
  * @requires OpenLayers/Geometry.js
  */
 OpenLayers.Geometry.Point = OpenLayers.Class.create();
 OpenLayers.Geometry.Point.prototype =
-    OpenLayers.Class.inherit(OpenLayers.Geometry, OpenLayers.LonLat, {
+    OpenLayers.Class.inherit(OpenLayers.Geometry, {
 
     /** @type float */
     x: null,
@@ -33,11 +24,10 @@
      * @param {float} y
      */
     initialize: function(x, y) {
-    	OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
-    	OpenLayers.LonLat.prototype.initialize.apply(this, arguments);
-    	
-    	this.x = this.lon;
-    	this.y = this.lat;
+        OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
+        
+        this.x = parseFloat(x);
+        this.y = parseFloat(y);
     },
 
     /**
@@ -55,46 +45,12 @@
         return obj;
     },
 
-    /**
-     * Sets the x coordinate
-     *
-     * @param {float} x
-     */
-    setX: function(x) {
-    	this.lon = x;
-    	this.x = x;
-    },
-
-    /**
-     * Sets the y coordinate
-     *
-     * @param {float} y
-     */
-    setY: function(y) {
-    	this.lat = y;
-    	this.y = y;
-    },
-
-    /**
-     * @type float
-     */
-    getX: function() {
-	   return this.lon;
-    },
-
-    /**
-     * @type float
-     */
-    getY: function() {
-	   return this.lat;
-    },
-
     /** Create a new Bounds based on the lon/lat
      * 
      */
     calculateBounds: function () {
-        this.bounds = new OpenLayers.Bounds(this.lon, this.lat,
-                                            this.lon, this.lat);
+        this.bounds = new OpenLayers.Bounds(this.x, this.y,
+                                            this.x, this.y);
     },
 
     /**
@@ -111,13 +67,31 @@
         }
         return distance;
     },
-
+    
+    /** 
+    * @param {OpenLayers.Geometry} xy
+    * @returns Boolean value indicating whether the passed-in 
+    *          OpenLayers.Geometryobject has the same  components as this
+    *          note that if ll passed in is null, returns false
+    *
+    * @type bool
+    */
+    equals:function(geom) {
+        var equals = false;
+        if (geom != null) {
+            equals = ((this.x == geom.x && this.y == geom.y) ||
+                      (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y)));
+        }
+        return equals;
+    },
+    
     /**
-     * @returns the coordinates as a string
+     * @return Shortened String representation of Point object. 
+     *         (ex. <i>"5, 42"</i>)
      * @type String
      */
-    toString: function() {
-	   return this.toShortString();
+    toShortString: function() {
+        return (this.x + ", " + this.y);
     },
     
     /**
@@ -126,8 +100,8 @@
      * @param {Float} y
      */
     move: function(x, y) {
-        this.setX(this.x + x);
-        this.setY(this.y + y);
+        this.x = this.x + x;
+        this.y = this.y + y;
     },
 
     /** @final @type String */

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Polygon.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Polygon.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry/Polygon.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -17,32 +17,22 @@
     OpenLayers.Class.inherit(OpenLayers.Geometry.Collection, {
 
     /**
+     * An array of class names representing the types of components that
+     * the collection can include.  A null value means the component types
+     * are not restricted.
+     * @type Array(String)
+     */
+    componentTypes: ["OpenLayers.Geometry.LinearRing"],
+
+    /**
      * @constructor
      *
      * @param {Array(OpenLayers.Geometry.LinearRing)}
      */
     initialize: function(components) {
-    	OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
-    	                                                          arguments);
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);
     },
-
-    /**
-     * adds a component to the Polygon, checking type
-     *
-     * @param {OpenLayers.Geometry.LinearRing} point to add
-     * @param {int} index Index into the array to insert the component
-     */
-    addComponent: function(component, index) {
-        if (!(component instanceof OpenLayers.Geometry.LinearRing)) {
-            var throwStr = "component should be an " +
-                           "OpenLayers.Geometry.LinearRing but is a " + 
-                           component.CLASS_NAME;
-            throw throwStr;
-                           
-        }
-        OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
-                                                                    arguments);
-    },
     
     /** Calculated by subtracting the areas of the internal holes from the 
      *   area of the outer hole.

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Geometry.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Geometry.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Geometry.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -4,6 +4,7 @@
  
 /**
  * @class
+ * @requires OpenLayers/Format/WKT.js
  */
 OpenLayers.Geometry = OpenLayers.Class.create();
 OpenLayers.Geometry.prototype = {
@@ -126,8 +127,8 @@
         var bounds = this.getBounds();
         if ((bounds != null) && (lonlat != null)) {
 
-    		var dX = (toleranceLon != null) ? toleranceLon : 0;
-    		var dY = (toleranceLat != null) ? toleranceLat : 0;
+            var dX = (toleranceLon != null) ? toleranceLon : 0;
+            var dY = (toleranceLat != null) ? toleranceLat : 0;
     
             var toleranceBounds = 
                 new OpenLayers.Bounds(this.bounds.left - dX,
@@ -160,6 +161,14 @@
         return 0.0;
     },
 
+    /**
+     * @returns the Well-Known Text representation of a geometry
+     * @type String
+     */
+    toString: function() {
+       return OpenLayers.Format.WKT.prototype.write(this);
+    },
+
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Geometry"
 };

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Handler/Box.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Handler/Box.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Handler/Box.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -113,13 +113,21 @@
     },
 
     activate: function () {
-        OpenLayers.Handler.prototype.activate.apply(this, arguments);
-        this.dragHandler.activate();
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragHandler.activate();
+            return true;
+        } else {
+            return false;
+        }
     },
 
     deactivate: function () {
-        OpenLayers.Handler.prototype.deactivate.apply(this, arguments);
-        this.dragHandler.deactivate();
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.dragHandler.deactivate();
+            return true;
+        } else {
+            return false;
+        }
     },
 
     CLASS_NAME: "OpenLayers.Handler.Box"

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Handler/Drag.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Handler/Drag.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Handler/Drag.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -16,17 +16,23 @@
      * When a mousedown event is received, we want to record it, but not set 
      * 'dragging' until the mouse moves after starting. 
      * 
-     * @type boolean 
+     * @type Boolean 
      **/
     started: false,
     
-    /** @type boolean **/
-    dragging: null,
+    /** @type Boolean **/
+    dragging: false,
 
     /** @type OpenLayers.Pixel **/
     start: null,
 
     /**
+     * @type Function
+     * @private
+     */
+    oldOnselectstart: null,
+
+    /**
      * @constructor
      *
      * @param {OpenLayers.Control} control
@@ -40,10 +46,16 @@
         OpenLayers.Handler.prototype.initialize.apply(this, arguments);
     },
     
+    /**
+     * Handle mousedown events
+     * @param {Event} evt
+     * @type Boolean
+     * @return Should the event propagate
+     */
     mousedown: function (evt) {
         if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
             this.started = true;
-            this.dragging = null;
+            this.dragging = false;
             this.start = evt.xy.clone();
             // TBD replace with CSS classes
             this.map.div.style.cursor = "move";
@@ -51,58 +63,113 @@
             OpenLayers.Event.stop(evt);
             return false;
         }
+        return true;
     },
 
+    /**
+     * Handle mousemove events
+     * @param {Event} evt
+     * @type Boolean
+     * @return Should the event propagate
+     */
     mousemove: function (evt) {
         if (this.started) {
             this.dragging = true;
             this.callback("move", [evt.xy]);
+            if(document.onselectstart) {
+                if(!this.oldOnselectstart) {
+                    this.oldOnselectstart = document.onselectstart;
+                    document.onselectstart = function() {return false;}
+                }
+            }
         }
+        return true;
     },
 
+    /**
+     * Handle mouseup events
+     * @param {Event} evt
+     * @type Boolean
+     * @return Should the event propagate
+     */
     mouseup: function (evt) {
         if (this.started) {
-            this.started = false; 
+            this.started = false;
+            this.dragging = false;
             // TBD replace with CSS classes
             this.map.div.style.cursor = "default";
             this.callback("up", [evt.xy]);
+            if(document.onselectstart) {
+                document.onselectstart = this.oldOnselectstart;
+            }
         }
+        return true;
     },
 
+    /**
+     * Handle mouseout events
+     * @param {Event} evt
+     * @type Boolean
+     * @return Should the event propagate
+     */
     mouseout: function (evt) {
         if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
             this.started = false; 
-            this.dragging = null;
+            this.dragging = false;
             // TBD replace with CSS classes
             this.map.div.style.cursor = "default";
             this.callback("out", []);
+            if(document.onselectstart) {
+                document.onselectstart = this.oldOnselectstart;
+            }
         }
+        return true;
     },
 
     /**
+     * The drag handler captures the click event.  If something else registers
+     * for clicks on the same element, its listener will not be called after a
+     * drag.
      * @param {Event} evt
-     * 
      * @type Boolean
+     * @return Should the event propagate
      */
     click: function (evt) {
         // throw away the first left click event that happens after a mouse up
-        if (OpenLayers.Event.isLeftClick(evt) && this.dragging != null) {
-            this.dragging = null;
+        if (OpenLayers.Event.isLeftClick(evt) && this.dragging) {
+            this.dragging = true;
             return false; 
         }
         this.started = false;
+        return true;
     },
 
-    activate: function (evt) {
-        OpenLayers.Handler.prototype.activate.apply(this, arguments);
-        document.onselectstart = function() { return false; };
-        this.dragging = null;
+    /**
+     * Activate the handler.
+     * @type Boolean
+     * @return Was activation successful.  Returns false if already active.
+     */
+    activate: function() {
+        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragging = false;
+            return true;
+        } else {
+            return false;
+        }
     },
 
-    deactivate: function (evt) {
-        OpenLayers.Handler.prototype.deactivate.apply(this, arguments);
-        document.onselectstart = null;
-        this.dragging = null;
+    /**
+     * Deactivate the handler.
+     * @type Boolean
+     * @return Was deactivation successful.  Returns false if not already active.
+     */
+    deactivate: function() {
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.dragging = false;
+            return true;
+        } else {
+            return false;
+        }
     },
 
     /** @final @type String */

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Handler/Keyboard.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Handler/Keyboard.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Handler/Keyboard.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -31,20 +31,37 @@
         // cache the bound event listener method so it can be unobserved later
         this.eventListener = this.handleKeyEvent.bindAsEventListener(this);
     },
+    
+    /**
+     * 
+     */
+    destroy: function() {
+        this.deactivate();
+        this.eventListener = null;
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
 
     activate: function() {
-        OpenLayers.Handler.prototype.activate.apply(this, arguments);
-        for (var i = 0; i < this.KEY_EVENTS.length; i++) {
-            OpenLayers.Event.observe(
-                window, this.KEY_EVENTS[i], this.eventListener);
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            for (var i = 0; i < this.KEY_EVENTS.length; i++) {
+                OpenLayers.Event.observe(
+                    window, this.KEY_EVENTS[i], this.eventListener);
+            }
+            return true;
+        } else {
+            return false;
         }
     },
 
     deactivate: function() {
-        OpenLayers.Handler.prototype.activate.apply(this, arguments);
-        for (var i = 0; i < this.KEY_EVENTS.length; i++) {
-            OpenLayers.Event.stopObserving(
-                document, this.KEY_EVENTS[i], this.eventListener);
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            for (var i = 0; i < this.KEY_EVENTS.length; i++) {
+                OpenLayers.Event.stopObserving(
+                    document, this.KEY_EVENTS[i], this.eventListener);
+            }
+            return true;
+        } else {
+            return false;
         }
     },
 

Modified: sandbox/tschaub/gutter/lib/OpenLayers/Handler/MouseWheel.js
===================================================================
--- sandbox/tschaub/gutter/lib/OpenLayers/Handler/MouseWheel.js	2007-04-02 01:03:25 UTC (rev 2965)
+++ sandbox/tschaub/gutter/lib/OpenLayers/Handler/MouseWheel.js	2007-04-02 03:10:26 UTC (rev 2966)
@@ -13,6 +13,14 @@
     /** @type function **/
     wheelListener: null,
 
+    /** @type OpenLayers.Pixel
+     *  @private
+     * 
+     *  mousePosition is necessary because evt.clientX/Y is buggy in Moz on
+     *  wheel events, so we cache and use the value from the last mousemove.
+     **/
+    mousePosition: null,
+
     /**
      * @constructor
      *
@@ -29,6 +37,15 @@
     },
 
     /**
+     * 
+     */    
+    destroy: function() {
+        this.deactivate();
+        this.wheelListener = null;
+        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
      *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
      */
 
@@ -68,8 +85,7 @@
                 // add the mouse position to the event because mozilla has a bug
                 // with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
                 // getLonLatFromViewPortPx(e) returns wrong values
-                // TODO FIXME FIXME this might not be the right way to port the 2.3 behavior
-                e.xy = this.map.events.getMousePosition(e);
+                e.xy = this.mousePosition;
                 if (delta < 0) {
                    this.callback("down", [e, delta]);
                 } else {
@@ -82,22 +98,34 @@
         }
     },
 
+    mousemove: function (evt) {
+        this.mousePosition = evt.xy;
+    },
+
     activate: function (evt) {
-        OpenLayers.Handler.prototype.activate.apply(this, arguments);
-        //register mousewheel events specifically on the window and document
-        var wheelListener = this.wheelListener;
-        OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
-        OpenLayers.Event.observe(window, "mousewheel", wheelListener);
-        OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            //register mousewheel events specifically on the window and document
+            var wheelListener = this.wheelListener;
+            OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
+            OpenLayers.Event.observe(window, "mousewheel", wheelListener);
+            OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+            return true;
+        } else {
+            return false;
+        }
     },
 
     deactivate: function (evt) {
-        OpenLayers.Handler.prototype.deactivate.apply(this, arguments);
-        // unregister mousewheel events specifically on the window and document
-        var wheelListener = this.wheelListener;
-