[Mapbender-commits] r4593 - in trunk/mapbender/http/extensions/OpenLayers-2.8: lib/OpenLayers lib/OpenLayers/BaseTypes lib/OpenLayers/Control lib/OpenLayers/Feature lib/OpenLayers/Filter lib/OpenLayers/Format lib/OpenLayers/Format/ArcXML lib/OpenLayers/Format/Filter lib/OpenLayers/Format/GML lib/OpenLayers/Format/SLD lib/OpenLayers/Format/WFSCapabilities lib/OpenLayers/Format/WFST lib/OpenLayers/Format/WMC lib/OpenLayers/Format/WMSCapabilities lib/OpenLayers/Geometry lib/OpenLayers/Handler lib/OpenLayers/Lang lib/OpenLayers/Layer lib/OpenLayers/Layer/WMS lib/OpenLayers/Popup lib/OpenLayers/Protocol lib/OpenLayers/Protocol/SQL lib/OpenLayers/Protocol/WFS lib/OpenLayers/Renderer lib/OpenLayers/Request lib/OpenLayers/Strategy lib/OpenLayers/Tile lib/Rico theme/default theme/default/img

svn_mapbender at osgeo.org svn_mapbender at osgeo.org
Thu Sep 3 10:07:47 EDT 2009


Author: christoph
Date: 2009-09-03 10:07:47 -0400 (Thu, 03 Sep 2009)
New Revision: 4593

Added:
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Ajax.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Bounds.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Class.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Element.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/LonLat.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Pixel.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Size.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Console.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ArgParser.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/DragPan.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/KeyboardDefaults.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/LayerSwitcher.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Measure.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ModifyFeature.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseDefaults.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseToolbar.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavToolbar.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavigationHistory.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/OverviewMap.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Pan.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/PanPanel.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Panel.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Permalink.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Scale.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ScaleLine.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Snapping.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Split.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomBox.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomIn.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomOut.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomPanel.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature/WFS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Comparison.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/FeatureId.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Logical.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Spatial.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML/Features.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/Base.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v2.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v3.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GPX.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GeoJSON.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GeoRSS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/JSON.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/KML.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/OSM.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/SLD/v1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Text.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WKT.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_0_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSDescribeLayer.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/XML.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/LinearRing.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiLineString.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiPolygon.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Point.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Rectangle.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Surface.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Box.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Click.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Drag.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Feature.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Keyboard.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/MouseWheel.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Path.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Polygon.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Icon.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/ca.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/cs-CZ.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/en.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/pt-BR.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/sv-SE.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-CN.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-TW.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcGIS93Rest.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcIMS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/FixedZoomLevels.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/GeoRSS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Google.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Grid.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/HTTPRequest.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Image.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/KaMapCache.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapGuide.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapServer.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Markers.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MultiMap.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/PointTrack.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/SphericalMercator.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TMS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TileCache.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Vector.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WFS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS/Untiled.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WorldWind.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Map.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/Framed.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/FramedCloud.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Projection.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/HTTP.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL/Gears.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1_1_0.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/Elements.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/SVG.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/VML.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request/XMLHttpRequest.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/SingleFile.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/BBOX.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Cluster.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Fixed.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Paging.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Save.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/StyleMap.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/Image.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/WFS.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tween.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/lib/Rico/Corner.js
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/google.css
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/ie6-style.css
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/close.gif
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/drag-rectangle-off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_polygon_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/editing_tool_bar.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/overview_replacement.gif
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan-panel-NOALPHA.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/ruler.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_off.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_on.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel-NOALPHA.png
   trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel.png
Log:


Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Ajax.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Ajax.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Ajax.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,677 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ * @requires OpenLayers/Console.js
+ */
+
+OpenLayers.ProxyHost = "";
+//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
+
+/**
+ * Ajax reader for OpenLayers
+ *
+ *  @uri url to do remote XML http get
+ *  @param {String} 'get' format params (x=y&a=b...)
+ *  @who object to handle callbacks for this request
+ *  @complete  the function to be called on success 
+ *  @failure  the function to be called on failure
+ *  
+ *   example usage from a caller:
+ *  
+ *     caps: function(request) {
+ *      -blah-  
+ *     },
+ *  
+ *     OpenLayers.loadURL(url,params,this,caps);
+ *
+ * Notice the above example does not provide an error handler; a default empty
+ * handler is provided which merely logs the error if a failure handler is not 
+ * supplied
+ *
+ */
+
+
+/**
+ * Function: OpenLayers.nullHandler
+ * @param {} request
+ */
+OpenLayers.nullHandler = function(request) {
+    OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
+};
+
+/** 
+ * APIFunction: loadURL
+ * Background load a document.  For more flexibility in using XMLHttpRequest,
+ *     see the <OpenLayers.Request> methods.
+ *
+ * Parameters:
+ * uri - {String} URI of source doc
+ * params - {String} or {Object} GET params. Either a string in the form
+ *     "?hello=world&foo=bar" (do not forget the leading question mark)
+ *     or an object in the form {'hello': 'world', 'foo': 'bar}
+ * caller - {Object} object which gets callbacks
+ * onComplete - {Function} Optional callback for success.  The callback
+ *     will be called with this set to caller and will receive the request
+ *     object as an argument.  Note that if you do not specify an onComplete
+ *     function, <OpenLayers.nullHandler> will be called (which pops up a 
+ *     user friendly error message dialog).
+ * onFailure - {Function} Optional callback for failure.  In the event of
+ *     a failure, the callback will be called with this set to caller and will
+ *     receive the request object as an argument.  Note that if you do not
+ *     specify an onComplete function, <OpenLayers.nullHandler> will be called
+ *     (which pops up a user friendly error message dialog).
+ *
+ * Returns:
+ * {<OpenLayers.Request.XMLHttpRequest>}  The request object. To abort loading,
+ *     call request.abort().
+ */
+OpenLayers.loadURL = function(uri, params, caller,
+                                  onComplete, onFailure) {
+    
+    if(typeof params == 'string') {
+        params = OpenLayers.Util.getParameters(params);
+    }
+    var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
+    var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
+    
+    return OpenLayers.Request.GET({
+        url: uri, params: params,
+        success: success, failure: failure, scope: caller
+    });
+};
+
+/** 
+ * Function: parseXMLString
+ * Parse XML into a doc structure
+ * 
+ * Parameters:
+ * text - {String} 
+ * 
+ * Returns:
+ * {?} Parsed AJAX Responsev
+ */
+OpenLayers.parseXMLString = function(text) {
+
+    //MS sucks, if the server is bad it dies
+    var index = text.indexOf('<');
+    if (index > 0) {
+        text = text.substring(index);
+    }
+
+    var ajaxResponse = OpenLayers.Util.Try(
+        function() {
+            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
+            xmldom.loadXML(text);
+            return xmldom;
+        },
+        function() {
+            return new DOMParser().parseFromString(text, 'text/xml');
+        },
+        function() {
+            var req = new XMLHttpRequest();
+            req.open("GET", "data:" + "text/xml" +
+                     ";charset=utf-8," + encodeURIComponent(text), false);
+            if (req.overrideMimeType) {
+                req.overrideMimeType("text/xml");
+            }
+            req.send(null);
+            return req.responseXML;
+        }
+    );
+
+    return ajaxResponse;
+};
+
+
+/**
+ * Namespace: OpenLayers.Ajax
+ */
+OpenLayers.Ajax = {
+
+    /**
+     * Method: emptyFunction
+     */
+    emptyFunction: function () {},
+
+    /**
+     * Method: getTransport
+     * 
+     * Returns: 
+     * {Object} Transport mechanism for whichever browser we're in, or false if
+     *          none available.
+     */
+    getTransport: function() {
+        return OpenLayers.Util.Try(
+            function() {return new XMLHttpRequest();},
+            function() {return new ActiveXObject('Msxml2.XMLHTTP');},
+            function() {return new ActiveXObject('Microsoft.XMLHTTP');}
+        ) || false;
+    },
+
+    /**
+     * Property: activeRequestCount
+     * {Integer}
+     */
+    activeRequestCount: 0
+};
+
+/**
+ * Namespace: OpenLayers.Ajax.Responders
+ * {Object}
+ */
+OpenLayers.Ajax.Responders = {
+  
+    /**
+     * Property: responders
+     * {Array}
+     */
+    responders: [],
+
+    /**
+     * Method: register
+     *  
+     * Parameters:
+     * responderToAdd - {?}
+     */
+    register: function(responderToAdd) {
+        for (var i = 0; i < this.responders.length; i++){
+            if (responderToAdd == this.responders[i]){
+                return;
+            }
+        }
+        this.responders.push(responderToAdd);
+    },
+
+    /**
+     * Method: unregister
+     *  
+     * Parameters:
+     * responderToRemove - {?}
+     */
+    unregister: function(responderToRemove) {
+        OpenLayers.Util.removeItem(this.reponders, responderToRemove);
+    },
+
+    /**
+     * Method: dispatch
+     * 
+     * Parameters:
+     * callback - {?}
+     * request - {?}
+     * transport - {?}
+     */
+    dispatch: function(callback, request, transport) {
+        var responder;
+        for (var i = 0; i < this.responders.length; i++) {
+            responder = this.responders[i];
+     
+            if (responder[callback] && 
+                typeof responder[callback] == 'function') {
+                try {
+                    responder[callback].apply(responder, 
+                                              [request, transport]);
+                } catch (e) {}
+            }
+        }
+    }
+};
+
+OpenLayers.Ajax.Responders.register({
+    /** 
+     * Function: onCreate
+     */
+    onCreate: function() {
+        OpenLayers.Ajax.activeRequestCount++;
+    },
+
+    /**
+     * Function: onComplete
+     */
+     onComplete: function() {
+         OpenLayers.Ajax.activeRequestCount--;
+     }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Base
+ */
+OpenLayers.Ajax.Base = OpenLayers.Class({
+      
+    /**
+     * Constructor: OpenLayers.Ajax.Base
+     * 
+     * Parameters: 
+     * options - {Object}
+     */
+    initialize: function(options) {
+        this.options = {
+            method:       'post',
+            asynchronous: true,
+            contentType:  'application/xml',
+            parameters:   ''
+        };
+        OpenLayers.Util.extend(this.options, options || {});
+        
+        this.options.method = this.options.method.toLowerCase();
+        
+        if (typeof this.options.parameters == 'string') {
+            this.options.parameters = 
+                OpenLayers.Util.getParameters(this.options.parameters);
+        }
+    }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Request
+ * *Deprecated*.  Use <OpenLayers.Request> method instead.
+ *
+ * Inherit:
+ *  - <OpenLayers.Ajax.Base>
+ */
+OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
+
+    /**
+     * Property: _complete
+     *
+     * {Boolean}
+     */
+    _complete: false,
+      
+    /**
+     * Constructor: OpenLayers.Ajax.Request
+     * 
+     * Parameters: 
+     * url - {String}
+     * options - {Object}
+     */
+    initialize: function(url, options) {
+        OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
+        
+        if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
+            url = OpenLayers.ProxyHost + encodeURIComponent(url);
+        }
+        
+        this.transport = OpenLayers.Ajax.getTransport();
+        this.request(url);
+    },
+
+    /**
+     * Method: request
+     * 
+     * Parameters:
+     * url - {String}
+     */
+    request: function(url) {
+        this.url = url;
+        this.method = this.options.method;
+        var params = OpenLayers.Util.extend({}, this.options.parameters);
+        
+        if (this.method != 'get' && this.method != 'post') {
+            // simulate other verbs over post
+            params['_method'] = this.method;
+            this.method = 'post';
+        }
+
+        this.parameters = params;        
+        
+        if (params = OpenLayers.Util.getParameterString(params)) {
+            // when GET, append parameters to URL
+            if (this.method == 'get') {
+                this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
+            } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+                params += '&_=';
+            }
+        }
+        try {
+            var response = new OpenLayers.Ajax.Response(this);
+            if (this.options.onCreate) {
+                this.options.onCreate(response);
+            }
+            
+            OpenLayers.Ajax.Responders.dispatch('onCreate', 
+                                                this, 
+                                                response);
+    
+            this.transport.open(this.method.toUpperCase(), 
+                                this.url,
+                                this.options.asynchronous);
+    
+            if (this.options.asynchronous) {
+                window.setTimeout(
+                    OpenLayers.Function.bind(this.respondToReadyState, this, 1),
+                    10);
+            }
+            
+            this.transport.onreadystatechange = 
+                OpenLayers.Function.bind(this.onStateChange, this);    
+            this.setRequestHeaders();
+    
+            this.body =  this.method == 'post' ?
+                (this.options.postBody || params) : null;
+            this.transport.send(this.body);
+    
+            // Force Firefox to handle ready state 4 for synchronous requests
+            if (!this.options.asynchronous && 
+                this.transport.overrideMimeType) {
+                this.onStateChange();
+            }
+        } catch (e) {
+            this.dispatchException(e);
+        }
+    },
+
+    /**
+     * Method: onStateChange
+     */
+    onStateChange: function() {
+        var readyState = this.transport.readyState;
+        if (readyState > 1 && !((readyState == 4) && this._complete)) {
+            this.respondToReadyState(this.transport.readyState);
+        }
+    },
+     
+    /**
+     * Method: setRequestHeaders
+     */
+    setRequestHeaders: function() {
+        var headers = {
+            'X-Requested-With': 'XMLHttpRequest',
+            'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
+            'OpenLayers': true
+        };
+
+        if (this.method == 'post') {
+            headers['Content-type'] = this.options.contentType +
+                (this.options.encoding ? '; charset=' + this.options.encoding : '');
+    
+            /* Force "Connection: close" for older Mozilla browsers to work
+             * around a bug where XMLHttpRequest sends an incorrect
+             * Content-length header. See Mozilla Bugzilla #246651.
+             */
+            if (this.transport.overrideMimeType &&
+                (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
+                headers['Connection'] = 'close';
+            }
+        }
+        // user-defined headers
+        if (typeof this.options.requestHeaders == 'object') {    
+            var extras = this.options.requestHeaders;
+            
+            if (typeof extras.push == 'function') {
+                for (var i = 0, length = extras.length; i < length; i += 2) {
+                    headers[extras[i]] = extras[i+1];
+                }
+            } else {
+                for (var i in extras) {
+                    headers[i] = extras[i];
+                }
+            }
+        }
+        
+        for (var name in headers) {
+            this.transport.setRequestHeader(name, headers[name]);
+        }
+    },
+    
+    /**
+     * Method: success
+     *
+     * Returns:
+     * {Boolean} - 
+     */
+    success: function() {
+        var status = this.getStatus();
+        return !status || (status >=200 && status < 300);
+    },
+    
+    /**
+     * Method: getStatus
+     *
+     * Returns:
+     * {Integer} - Status
+     */
+    getStatus: function() {
+        try {
+            return this.transport.status || 0;
+        } catch (e) {
+            return 0;
+        }
+    },
+
+    /**
+     * Method: respondToReadyState
+     *
+     * Parameters:
+     * readyState - {?}
+     */
+    respondToReadyState: function(readyState) {
+        var state = OpenLayers.Ajax.Request.Events[readyState];
+        var response = new OpenLayers.Ajax.Response(this);
+    
+        if (state == 'Complete') {
+            try {
+                this._complete = true;
+                (this.options['on' + response.status] ||
+                    this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
+                    OpenLayers.Ajax.emptyFunction)(response);
+            } catch (e) {
+                this.dispatchException(e);
+            }
+    
+            var contentType = response.getHeader('Content-type');
+        }
+    
+        try {
+            (this.options['on' + state] || 
+             OpenLayers.Ajax.emptyFunction)(response);
+             OpenLayers.Ajax.Responders.dispatch('on' + state, 
+                                                 this, 
+                                                 response);
+        } catch (e) {
+            this.dispatchException(e);
+        }
+    
+        if (state == 'Complete') {
+            // avoid memory leak in MSIE: clean up
+            this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
+        }
+    },
+    
+    /**
+     * Method: getHeader
+     * 
+     * Parameters:
+     * name - {String} Header name
+     *
+     * Returns:
+     * {?} - response header for the given name
+     */
+    getHeader: function(name) {
+        try {
+            return this.transport.getResponseHeader(name);
+        } catch (e) {
+            return null;
+        }
+    },
+
+    /**
+     * Method: dispatchException
+     * If the optional onException function is set, execute it
+     * and then dispatch the call to any other listener registered
+     * for onException.
+     * 
+     * If no optional onException function is set, we suspect that
+     * the user may have also not used
+     * OpenLayers.Ajax.Responders.register to register a listener
+     * for the onException call.  To make sure that something
+     * gets done with this exception, only dispatch the call if there
+     * are listeners.
+     *
+     * If you explicitly want to swallow exceptions, set
+     * request.options.onException to an empty function (function(){})
+     * or register an empty function with <OpenLayers.Ajax.Responders>
+     * for onException.
+     * 
+     * Parameters:
+     * exception - {?}
+     */
+    dispatchException: function(exception) {
+        var handler = this.options.onException;
+        if(handler) {
+            // call options.onException and alert any other listeners
+            handler(this, exception);
+            OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+        } else {
+            // check if there are any other listeners
+            var listener = false;
+            var responders = OpenLayers.Ajax.Responders.responders;
+            for (var i = 0; i < responders.length; i++) {
+                if(responders[i].onException) {
+                    listener = true;
+                    break;
+                }
+            }
+            if(listener) {
+                // call all listeners
+                OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+            } else {
+                // let the exception through
+                throw exception;
+            }
+        }
+    }
+});
+
+/** 
+ * Property: Events
+ * {Array(String)}
+ */
+OpenLayers.Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+/**
+ * Class: OpenLayers.Ajax.Response
+ */
+OpenLayers.Ajax.Response = OpenLayers.Class({
+
+    /**
+     * Property: status
+     *
+     * {Integer}
+     */
+    status: 0,
+    
+
+    /**
+     * Property: statusText
+     *
+     * {String}
+     */
+    statusText: '',
+      
+    /**
+     * Constructor: OpenLayers.Ajax.Response
+     * 
+     * Parameters: 
+     * request - {Object}
+     */
+    initialize: function(request) {
+        this.request = request;
+        var transport = this.transport = request.transport,
+            readyState = this.readyState = transport.readyState;
+        
+        if ((readyState > 2 &&
+            !(!!(window.attachEvent && !window.opera))) ||
+            readyState == 4) {
+            this.status       = this.getStatus();
+            this.statusText   = this.getStatusText();
+            this.responseText = transport.responseText == null ?
+                '' : String(transport.responseText);
+        }
+        
+        if(readyState == 4) {
+            var xml = transport.responseXML;
+            this.responseXML  = xml === undefined ? null : xml;
+        }
+    },
+    
+    /**
+     * Method: getStatus
+     */
+    getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
+    
+    /**
+     * Method: getStatustext
+     *
+     * Returns:
+     * {String} - statusText
+     */
+    getStatusText: function() {
+        try {
+            return this.transport.statusText || '';
+        } catch (e) {
+            return '';
+        }
+    },
+    
+    /**
+     * Method: getHeader
+     */
+    getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
+    
+    /** 
+     * Method: getResponseHeader
+     *
+     * Returns:
+     * {?} - response header for given name
+     */
+    getResponseHeader: function(name) {
+        return this.transport.getResponseHeader(name);
+    }
+});
+
+
+/**
+ * Function: getElementsByTagNameNS
+ * 
+ * Parameters:
+ * parentnode - {?}
+ * nsuri - {?}
+ * nsprefix - {?}
+ * tagname - {?}
+ * 
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
+                                                   nsprefix, tagname) {
+    var elem = null;
+    if (parentnode.getElementsByTagNameNS) {
+        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
+    } else {
+        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
+    }
+    return elem;
+};
+
+
+/**
+ * Function: serializeXMLToString
+ * Wrapper function around XMLSerializer, which doesn't exist/work in
+ *     IE/Safari. We need to come up with a way to serialize in those browser:
+ *     for now, these browsers will just fail. #535, #536
+ *
+ * Parameters: 
+ * xmldom {XMLNode} xml dom to serialize
+ * 
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
+    var serializer = new XMLSerializer();
+    var data = serializer.serializeToString(xmldom);
+    return data;
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Bounds.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Bounds.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Bounds.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,671 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Bounds
+ * Instances of this class represent bounding boxes.  Data stored as left,
+ * bottom, right, top floats. All values are initialized to null, however,
+ * you should make sure you set them before using the bounds for anything.
+ * 
+ * Possible use case:
+ * > bounds = new OpenLayers.Bounds();
+ * > bounds.extend(new OpenLayers.LonLat(4,5));
+ * > bounds.extend(new OpenLayers.LonLat(5,6));
+ * > bounds.toBBOX(); // returns 4,5,5,6
+ */
+OpenLayers.Bounds = OpenLayers.Class({
+
+    /**
+     * Property: left
+     * {Number} Minimum horizontal coordinate.
+     */
+    left: null,
+
+    /**
+     * Property: bottom
+     * {Number} Minimum vertical coordinate.
+     */
+    bottom: null,
+
+    /**
+     * Property: right
+     * {Number} Maximum horizontal coordinate.
+     */
+    right: null,
+
+    /**
+     * Property: top
+     * {Number} Maximum vertical coordinate.
+     */
+    top: null,
+    
+    /**
+     * Property: centerLonLat
+     * {<OpenLayers.LonLat>} A cached center location.  This should not be
+     *     accessed directly.  Use <getCenterLonLat> instead.
+     */
+    centerLonLat: null,
+
+    /**
+     * Constructor: OpenLayers.Bounds
+     * Construct a new bounds object.
+     *
+     * Parameters:
+     * left - {Number} The left bounds of the box.  Note that for width
+     *        calculations, this is assumed to be less than the right value.
+     * bottom - {Number} The bottom bounds of the box.  Note that for height
+     *          calculations, this is assumed to be more than the top value.
+     * right - {Number} The right bounds.
+     * top - {Number} The top bounds.
+     */
+    initialize: function(left, bottom, right, top) {
+        if (left != null) {
+            this.left = OpenLayers.Util.toFloat(left);
+        }
+        if (bottom != null) {
+            this.bottom = OpenLayers.Util.toFloat(bottom);
+        }
+        if (right != null) {
+            this.right = OpenLayers.Util.toFloat(right);
+        }
+        if (top != null) {
+            this.top = OpenLayers.Util.toFloat(top);
+        }
+    },
+
+    /**
+     * Method: clone
+     * Create a cloned instance of this bounds.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} A fresh copy of the bounds
+     */
+    clone:function() {
+        return new OpenLayers.Bounds(this.left, this.bottom, 
+                                     this.right, this.top);
+    },
+
+    /**
+     * Method: equals
+     * Test a two bounds for equivalence.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {Boolean} The passed-in bounds object has the same left,
+     *           right, top, bottom components as this.  Note that if bounds 
+     *           passed in is null, returns false.
+     */
+    equals:function(bounds) {
+        var equals = false;
+        if (bounds != null) {
+            equals = ((this.left == bounds.left) && 
+                      (this.right == bounds.right) &&
+                      (this.top == bounds.top) && 
+                      (this.bottom == bounds.bottom));
+        }
+        return equals;
+    },
+
+    /** 
+     * APIMethod: toString
+     * 
+     * Returns:
+     * {String} String representation of bounds object. 
+     *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
+     */
+    toString:function() {
+        return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+                 + " right-top=(" + this.right + "," + this.top + ")" );
+    },
+
+    /**
+     * APIMethod: toArray
+     *
+     * Returns:
+     * {Array} array of left, bottom, right, top
+     */
+    toArray: function() {
+        return [this.left, this.bottom, this.right, this.top];
+    },    
+
+    /** 
+     * APIMethod: toBBOX
+     * 
+     * Parameters:
+     * decimal - {Integer} How many significant digits in the bbox coords?
+     *                     Default is 6
+     * 
+     * Returns:
+     * {String} Simple String representation of bounds object.
+     *          (ex. <i>"5,42,10,45"</i>)
+     */
+    toBBOX:function(decimal) {
+        if (decimal== null) {
+            decimal = 6; 
+        }
+        var mult = Math.pow(10, decimal);
+        var bbox = Math.round(this.left * mult) / mult + "," + 
+                   Math.round(this.bottom * mult) / mult + "," + 
+                   Math.round(this.right * mult) / mult + "," + 
+                   Math.round(this.top * mult) / mult;
+
+        return bbox;
+    },
+ 
+    /**
+     * APIMethod: toGeometry
+     * Create a new polygon geometry based on this bounds.
+     *
+     * Returns:
+     * {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
+     *     of this bounds.
+     */
+    toGeometry: function() {
+        return new OpenLayers.Geometry.Polygon([
+            new OpenLayers.Geometry.LinearRing([
+                new OpenLayers.Geometry.Point(this.left, this.bottom),
+                new OpenLayers.Geometry.Point(this.right, this.bottom),
+                new OpenLayers.Geometry.Point(this.right, this.top),
+                new OpenLayers.Geometry.Point(this.left, this.top)
+            ])
+        ]);
+    },
+    
+    /**
+     * APIMethod: getWidth
+     * 
+     * Returns:
+     * {Float} The width of the bounds
+     */
+    getWidth:function() {
+        return (this.right - this.left);
+    },
+
+    /**
+     * APIMethod: getHeight
+     * 
+     * Returns:
+     * {Float} The height of the bounds (top minus bottom).
+     */
+    getHeight:function() {
+        return (this.top - this.bottom);
+    },
+
+    /**
+     * APIMethod: getSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} The size of the box.
+     */
+    getSize:function() {
+        return new OpenLayers.Size(this.getWidth(), this.getHeight());
+    },
+
+    /**
+     * APIMethod: getCenterPixel
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
+     */
+    getCenterPixel:function() {
+        return new OpenLayers.Pixel( (this.left + this.right) / 2,
+                                     (this.bottom + this.top) / 2);
+    },
+
+    /**
+     * APIMethod: getCenterLonLat
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} The center of the bounds in map space.
+     */
+    getCenterLonLat:function() {
+        if(!this.centerLonLat) {
+            this.centerLonLat = new OpenLayers.LonLat(
+                (this.left + this.right) / 2, (this.bottom + this.top) / 2
+            );
+        }
+        return this.centerLonLat;
+    },
+
+    /**
+     * Method: scale
+     * Scales the bounds around a pixel or lonlat. Note that the new 
+     *     bounds may return non-integer properties, even if a pixel
+     *     is passed. 
+     * 
+     * Parameters:
+     * ratio - {Float} 
+     * origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
+     *          Default is center.
+     *
+     * Returns:
+     * {<OpenLayers.Bound>} A new bounds that is scaled by ratio
+     *                      from origin.
+     */
+
+    scale: function(ratio, origin){
+        if(origin == null){
+            origin = this.getCenterLonLat();
+        }
+
+        var bounds = [];
+        
+        var origx,origy;
+
+        // get origin coordinates
+        if(origin.CLASS_NAME == "OpenLayers.LonLat"){
+            origx = origin.lon;
+            origy = origin.lat;
+        } else {
+            origx = origin.x;
+            origy = origin.y;
+        }
+
+        var left = (this.left - origx) * ratio + origx;
+        var bottom = (this.bottom - origy) * ratio + origy;
+        var right = (this.right - origx) * ratio + origx;
+        var top = (this.top - origy) * ratio + origy;
+        
+        return new OpenLayers.Bounds(left, bottom, right, top);
+    },
+
+    /**
+     * APIMethod: add
+     * 
+     * Parameters:
+     * x - {Float}
+     * y - {Float}
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
+     *     this, but shifted by the passed-in x and y values.
+     */
+    add:function(x, y) {
+        if ( (x == null) || (y == null) ) {
+            var msg = OpenLayers.i18n("boundsAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.Bounds(this.left + x, this.bottom + y,
+                                     this.right + x, this.top + y);
+    },
+    
+    /**
+     * APIMethod: extend
+     * Extend the bounds to include the point, lonlat, or bounds specified.
+     *     Note, this function assumes that left < right and bottom < top.
+     * 
+     * Parameters: 
+     * object - {Object} Can be LonLat, Point, or Bounds
+     */
+    extend:function(object) {
+        var bounds = null;
+        if (object) {
+            // clear cached center location
+            switch(object.CLASS_NAME) {
+                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;
+                    break;
+            }
+    
+            if (bounds) {
+                this.centerLonLat = null;
+                if ( (this.left == null) || (bounds.left < this.left)) {
+                    this.left = bounds.left;
+                }
+                if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
+                    this.bottom = bounds.bottom;
+                } 
+                if ( (this.right == null) || (bounds.right > this.right) ) {
+                    this.right = bounds.right;
+                }
+                if ( (this.top == null) || (bounds.top > this.top) ) { 
+                    this.top = bounds.top;
+                }
+            }
+        }
+    },
+
+    /**
+     * APIMethod: containsLonLat
+     * 
+     * Parameters:
+     * ll - {<OpenLayers.LonLat>}
+     * inclusive - {Boolean} Whether or not to include the border.
+     *     Default is true.
+     *
+     * Returns:
+     * {Boolean} The passed-in lonlat is within this bounds.
+     */
+    containsLonLat:function(ll, inclusive) {
+        return this.contains(ll.lon, ll.lat, inclusive);
+    },
+
+    /**
+     * APIMethod: containsPixel
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     * inclusive - {Boolean} Whether or not to include the border. Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} The passed-in pixel is within this bounds.
+     */
+    containsPixel:function(px, inclusive) {
+        return this.contains(px.x, px.y, inclusive);
+    },
+    
+    /**
+     * APIMethod: contains
+     * 
+     * Parameters:
+     * x - {Float}
+     * y - {Float}
+     * inclusive - {Boolean} Whether or not to include the border. Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} Whether or not the passed-in coordinates are within this
+     *     bounds.
+     */
+    contains:function(x, y, inclusive) {
+        //set default
+        if (inclusive == null) {
+            inclusive = true;
+        }
+
+        if (x == null || y == null) {
+            return false;
+        }
+
+        x = OpenLayers.Util.toFloat(x);
+        y = OpenLayers.Util.toFloat(y);
+
+        var contains = false;
+        if (inclusive) {
+            contains = ((x >= this.left) && (x <= this.right) && 
+                        (y >= this.bottom) && (y <= this.top));
+        } else {
+            contains = ((x > this.left) && (x < this.right) && 
+                        (y > this.bottom) && (y < this.top));
+        }              
+        return contains;
+    },
+
+    /**
+     * APIMethod: intersectsBounds
+     * Determine whether the target bounds intersects this bounds.  Bounds are
+     *     considered intersecting if any of their edges intersect or if one
+     *     bounds contains the other.
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} The target bounds.
+     * inclusive - {Boolean} Treat coincident borders as intersecting.  Default
+     *     is true.  If false, bounds that do not overlap but only touch at the
+     *     border will not be considered as intersecting.
+     *
+     * Returns:
+     * {Boolean} The passed-in bounds object intersects this bounds.
+     */
+    intersectsBounds:function(bounds, inclusive) {
+        if (inclusive == null) {
+            inclusive = true;
+        }
+        var intersects = false;
+        var mightTouch = (
+            this.left == bounds.right ||
+            this.right == bounds.left ||
+            this.top == bounds.bottom ||
+            this.bottom == bounds.top
+        );
+        
+        // if the two bounds only touch at an edge, and inclusive is false,
+        // then the bounds don't *really* intersect.
+        if (inclusive || !mightTouch) {
+            // otherwise, if one of the boundaries even partially contains another,
+            // inclusive of the edges, then they do intersect.
+            var inBottom = (
+                ((bounds.bottom >= this.bottom) && (bounds.bottom <= this.top)) ||
+                ((this.bottom >= bounds.bottom) && (this.bottom <= bounds.top))
+            );
+            var inTop = (
+                ((bounds.top >= this.bottom) && (bounds.top <= this.top)) ||
+                ((this.top > bounds.bottom) && (this.top < bounds.top))
+            );
+            var inLeft = (
+                ((bounds.left >= this.left) && (bounds.left <= this.right)) ||
+                ((this.left >= bounds.left) && (this.left <= bounds.right))
+            );
+            var inRight = (
+                ((bounds.right >= this.left) && (bounds.right <= this.right)) ||
+                ((this.right >= bounds.left) && (this.right <= bounds.right))
+            );
+            intersects = ((inBottom || inTop) && (inLeft || inRight));
+        }
+        return intersects;
+    },
+    
+    /**
+     * APIMethod: containsBounds
+     * Determine whether the target bounds is contained within this bounds.
+     * 
+     * bounds - {<OpenLayers.Bounds>} The target bounds.
+     * partial - {Boolean} If any of the target corners is within this bounds
+     *     consider the bounds contained.  Default is false.  If true, the
+     *     entire target bounds must be contained within this bounds.
+     * inclusive - {Boolean} Treat shared edges as contained.  Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} The passed-in bounds object is contained within this bounds. 
+     */
+    containsBounds:function(bounds, partial, inclusive) {
+        if (partial == null) {
+            partial = false;
+        }
+        if (inclusive == null) {
+            inclusive = true;
+        }
+        var bottomLeft  = this.contains(bounds.left, bounds.bottom, inclusive);
+        var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
+        var topLeft  = this.contains(bounds.left, bounds.top, inclusive);
+        var topRight = this.contains(bounds.right, bounds.top, inclusive);
+        
+        return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
+                         : (bottomLeft && bottomRight && topLeft && topRight);
+    },
+
+    /** 
+     * APIMethod: determineQuadrant
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
+     *     coordinate lies.
+     */
+    determineQuadrant: function(lonlat) {
+    
+        var quadrant = "";
+        var center = this.getCenterLonLat();
+        
+        quadrant += (lonlat.lat < center.lat) ? "b" : "t";
+        quadrant += (lonlat.lon < center.lon) ? "l" : "r";
+    
+        return quadrant; 
+    },
+    
+    /**
+     * APIMethod: transform
+     * Transform the Bounds object from source to dest. 
+     *
+     * Parameters: 
+     * source - {<OpenLayers.Projection>} Source projection. 
+     * dest   - {<OpenLayers.Projection>} Destination projection. 
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
+     */
+    transform: function(source, dest) {
+        // clear cached center location
+        this.centerLonLat = null;
+        var ll = OpenLayers.Projection.transform(
+            {'x': this.left, 'y': this.bottom}, source, dest);
+        var lr = OpenLayers.Projection.transform(
+            {'x': this.right, 'y': this.bottom}, source, dest);
+        var ul = OpenLayers.Projection.transform(
+            {'x': this.left, 'y': this.top}, source, dest);
+        var ur = OpenLayers.Projection.transform(
+            {'x': this.right, 'y': this.top}, source, dest);
+        this.left   = Math.min(ll.x, ul.x);
+        this.bottom = Math.min(ll.y, lr.y);
+        this.right  = Math.max(lr.x, ur.x);
+        this.top    = Math.max(ul.y, ur.y);
+        return this;
+    },
+
+    /**
+     * APIMethod: wrapDateLine
+     *  
+     * Parameters:
+     * maxExtent - {<OpenLayers.Bounds>}
+     * options - {Object} Some possible options are:
+     *                    leftTolerance - {float} Allow for a margin of error 
+     *                                            with the 'left' value of this 
+     *                                            bound.
+     *                                            Default is 0.
+     *                    rightTolerance - {float} Allow for a margin of error 
+     *                                             with the 'right' value of 
+     *                                             this bound.
+     *                                             Default is 0.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
+     *                       maxExtent). Note that this function only returns 
+     *                       a different bounds value if this bounds is 
+     *                       *entirely* outside of the maxExtent. If this 
+     *                       bounds straddles the dateline (is part in/part 
+     *                       out of maxExtent), the returned bounds will be 
+     *                       merely a copy of this one.
+     */
+    wrapDateLine: function(maxExtent, options) {    
+        options = options || {};
+        
+        var leftTolerance = options.leftTolerance || 0;
+        var rightTolerance = options.rightTolerance || 0;
+
+        var newBounds = this.clone();
+    
+        if (maxExtent) {
+
+           //shift right?
+           while ( newBounds.left < maxExtent.left && 
+                   (newBounds.right - rightTolerance) <= maxExtent.left ) { 
+                newBounds = newBounds.add(maxExtent.getWidth(), 0);
+           }
+
+           //shift left?
+           while ( (newBounds.left + leftTolerance) >= maxExtent.right && 
+                   newBounds.right > maxExtent.right ) { 
+                newBounds = newBounds.add(-maxExtent.getWidth(), 0);
+           }
+        }
+                
+        return newBounds;
+    },
+
+    CLASS_NAME: "OpenLayers.Bounds"
+});
+
+/** 
+ * APIFunction: fromString
+ * Alternative constructor that builds a new OpenLayers.Bounds from a 
+ *     parameter string
+ * 
+ * Parameters: 
+ * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ * 
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the 
+ *                       passed-in String.
+ */
+OpenLayers.Bounds.fromString = function(str) {
+    var bounds = str.split(",");
+    return OpenLayers.Bounds.fromArray(bounds);
+};
+
+/** 
+ * APIFunction: fromArray
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ *     from an array
+ * 
+ * Parameters:
+ * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
+ */
+OpenLayers.Bounds.fromArray = function(bbox) {
+    return new OpenLayers.Bounds(parseFloat(bbox[0]),
+                                 parseFloat(bbox[1]),
+                                 parseFloat(bbox[2]),
+                                 parseFloat(bbox[3]));
+};
+
+/** 
+ * APIFunction: fromSize
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ *     from a size
+ * 
+ * Parameters:
+ * size - {<OpenLayers.Size>} 
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
+ */
+OpenLayers.Bounds.fromSize = function(size) {
+    return new OpenLayers.Bounds(0,
+                                 size.h,
+                                 size.w,
+                                 0);
+};
+
+/**
+ * Function: oppositeQuadrant
+ * Get the opposite quadrant for a given quadrant string.
+ *
+ * Parameters:
+ * quadrant - {String} two character quadrant shortstring
+ *
+ * Returns:
+ * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
+ *          you pass in "bl" it returns "tr", if you pass in "br" it 
+ *          returns "tl", etc.
+ */
+OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
+    var opp = "";
+    
+    opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
+    opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
+    
+    return opp;
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Class.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Class.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Class.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,114 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Constructor: OpenLayers.Class
+ * Base class used to construct all other classes. Includes support for 
+ *     multiple inheritance. 
+ *     
+ * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
+ *     syntax for creating classes and dealing with inheritance 
+ *     will be removed.
+ * 
+ * To create a new OpenLayers-style class, use the following syntax:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ *     following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ * Note that instanceof reflection will only reveil Class1 as superclass.
+ * Class2 ff are mixins.
+ *
+ */
+OpenLayers.Class = function() {
+    var Class = function() {
+        /**
+         * This following condition can be removed at 3.0 - this is only for
+         * backwards compatibility while the Class.inherit method is still
+         * in use.  So at 3.0, the following three lines would be replaced with
+         * simply:
+         * this.initialize.apply(this, arguments);
+         */
+        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+            this.initialize.apply(this, arguments);
+        }
+    };
+    var extended = {};
+    var parent, initialize;
+    for(var i=0, len=arguments.length; i<len; ++i) {
+        if(typeof arguments[i] == "function") {
+            // make the class passed as the first argument the superclass
+            if(i == 0 && len > 1) {
+                initialize = arguments[i].prototype.initialize;
+                // replace the initialize method with an empty function,
+                // because we do not want to create a real instance here
+                arguments[i].prototype.initialize = function() {};
+                // the line below makes sure that the new class has a
+                // superclass
+                extended = new arguments[i];
+                // restore the original initialize method
+                if(initialize === undefined) {
+                    delete arguments[i].prototype.initialize;
+                } else {
+                    arguments[i].prototype.initialize = initialize;
+                }
+            }
+            // get the prototype of the superclass
+            parent = arguments[i].prototype;
+        } else {
+            // in this case we're extending with the prototype
+            parent = arguments[i];
+        }
+        OpenLayers.Util.extend(extended, parent);
+    }
+    Class.prototype = extended;
+    return Class;
+};
+
+/**
+ * Property: isPrototype
+ * *Deprecated*.  This is no longer needed and will be removed at 3.0.
+ */
+OpenLayers.Class.isPrototype = function () {};
+
+/**
+ * APIFunction: OpenLayers.create
+ * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
+ *     <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
+ */
+OpenLayers.Class.create = function() {
+    return function() {
+        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+            this.initialize.apply(this, arguments);
+        }
+    };
+};
+
+
+/**
+ * APIFunction: inherit
+ * *Deprecated*.  Old method to inherit from one or more OpenLayers style
+ *     classes.  Use the <OpenLayers.Class> constructor instead.
+ *
+ * Parameters:
+ * class - One or more classes can be provided as arguments
+ *
+ * Returns:
+ * An object prototype
+ */
+OpenLayers.Class.inherit = function () {
+    var superClass = arguments[0];
+    var proto = new superClass(OpenLayers.Class.isPrototype);
+    for (var i=1, len=arguments.length; i<len; i++) {
+        if (typeof arguments[i] == "function") {
+            var mixin = arguments[i];
+            arguments[i] = new mixin(OpenLayers.Class.isPrototype);
+        }
+        OpenLayers.Util.extend(proto, arguments[i]);
+    }
+    return proto;
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Element.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Element.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Element.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,244 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Element
+ */
+OpenLayers.Element = {
+
+    /**
+     * APIFunction: visible
+     * 
+     * Parameters: 
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Boolean} Is the element visible?
+     */
+    visible: function(element) {
+        return OpenLayers.Util.getElement(element).style.display != 'none';
+    },
+
+    /**
+     * APIFunction: toggle
+     * Toggle the visibility of element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    toggle: function() {
+        for (var i=0, len=arguments.length; i<len; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            var display = OpenLayers.Element.visible(element) ? 'hide' 
+                                                              : 'show';
+            OpenLayers.Element[display](element);
+        }
+    },
+
+
+    /**
+     * APIFunction: hide
+     * Hide element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    hide: function() {
+        for (var i=0, len=arguments.length; i<len; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            element.style.display = 'none';
+        }
+    },
+
+    /**
+     * APIFunction: show
+     * Show element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    show: function() {
+        for (var i=0, len=arguments.length; i<len; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            element.style.display = '';
+        }
+    },
+
+    /**
+     * APIFunction: remove
+     * Remove the specified element from the DOM.
+     * 
+     * Parameters:
+     * element - {DOMElement}
+     */
+    remove: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        element.parentNode.removeChild(element);
+    },
+
+    /**
+     * APIFunction: getHeight
+     *  
+     * Parameters:
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Integer} The offset height of the element passed in
+     */
+    getHeight: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        return element.offsetHeight;
+    },
+
+    /**
+     * APIFunction: getDimensions
+     *  
+     * Parameters:
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Object} Object with 'width' and 'height' properties which are the 
+     *          dimensions of the element passed in.
+     */
+    getDimensions: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
+            return {width: element.offsetWidth, height: element.offsetHeight};
+        }
+    
+        // All *Width and *Height properties give 0 on elements with display none,
+        // so enable the element temporarily
+        var els = element.style;
+        var originalVisibility = els.visibility;
+        var originalPosition = els.position;
+        els.visibility = 'hidden';
+        els.position = 'absolute';
+        els.display = '';
+        var originalWidth = element.clientWidth;
+        var originalHeight = element.clientHeight;
+        els.display = 'none';
+        els.position = originalPosition;
+        els.visibility = originalVisibility;
+        return {width: originalWidth, height: originalHeight};
+    },
+
+    /**
+     * Function: hasClass
+     * Tests if an element has the given CSS class name.
+     *
+     * Parameters:
+     * element - {DOMElement} A DOM element node.
+     * name - {String} The CSS class name to search for.
+     *
+     * Returns:
+     * {Boolean} The element has the given class name.
+     */
+    hasClass: function(element, name) {
+        var names = element.className;
+        return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names));
+    },
+    
+    /**
+     * Function: addClass
+     * Add a CSS class name to an element.  Safe where element already has
+     *     the class name.
+     *
+     * Parameters:
+     * element - {DOMElement} A DOM element node.
+     * name - {String} The CSS class name to add.
+     *
+     * Returns:
+     * {DOMElement} The element.
+     */
+    addClass: function(element, name) {
+        if(!OpenLayers.Element.hasClass(element, name)) {
+            element.className += (element.className ? " " : "") + name;
+        }
+        return element;
+    },
+
+    /**
+     * Function: removeClass
+     * Remove a CSS class name from an element.  Safe where element does not
+     *     have the class name.
+     *
+     * Parameters:
+     * element - {DOMElement} A DOM element node.
+     * name - {String} The CSS class name to remove.
+     *
+     * Returns:
+     * {DOMElement} The element.
+     */
+    removeClass: function(element, name) {
+        var names = element.className;
+        if(names) {
+            element.className = OpenLayers.String.trim(
+                names.replace(
+                    new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " "
+                )
+            );
+        }
+        return element;
+    },
+
+    /**
+     * Function: toggleClass
+     * Remove a CSS class name from an element if it exists.  Add the class name
+     *     if it doesn't exist.
+     *
+     * Parameters:
+     * element - {DOMElement} A DOM element node.
+     * name - {String} The CSS class name to toggle.
+     *
+     * Returns:
+     * {DOMElement} The element.
+     */
+    toggleClass: function(element, name) {
+        if(OpenLayers.Element.hasClass(element, name)) {
+            OpenLayers.Element.removeClass(element, name);
+        } else {
+            OpenLayers.Element.addClass(element, name);
+        }
+        return element;
+    },
+
+    /**
+     * APIFunction: getStyle
+     * 
+     * Parameters:
+     * element - {DOMElement}
+     * style - {?}
+     * 
+     * Returns:
+     * {?}
+     */
+    getStyle: function(element, style) {
+        element = OpenLayers.Util.getElement(element);
+
+        var value = null;
+        if (element && element.style) {
+            value = element.style[OpenLayers.String.camelize(style)];
+            if (!value) {
+                if (document.defaultView && 
+                    document.defaultView.getComputedStyle) {
+                    
+                    var css = document.defaultView.getComputedStyle(element, null);
+                    value = css ? css.getPropertyValue(style) : null;
+                } else if (element.currentStyle) {
+                    value = element.currentStyle[OpenLayers.String.camelize(style)];
+                }
+            }
+        
+            var positions = ['left', 'top', 'right', 'bottom'];
+            if (window.opera &&
+                (OpenLayers.Util.indexOf(positions,style) != -1) &&
+                (OpenLayers.Element.getStyle(element, 'position') == 'static')) { 
+                value = 'auto';
+            }
+        }
+    
+        return value == 'auto' ? null : value;
+    }
+
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/LonLat.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/LonLat.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/LonLat.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,189 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.LonLat
+ * This class represents a longitude and latitude pair
+ */
+OpenLayers.LonLat = OpenLayers.Class({
+
+    /** 
+     * APIProperty: lon
+     * {Float} The x-axis coodinate in map units
+     */
+    lon: 0.0,
+    
+    /** 
+     * APIProperty: lat
+     * {Float} The y-axis coordinate in map units
+     */
+    lat: 0.0,
+
+    /**
+     * Constructor: OpenLayers.LonLat
+     * Create a new map location.
+     *
+     * Parameters:
+     * lon - {Number} The x-axis coordinate in map units.  If your map is in
+     *     a geographic projection, this will be the Longitude.  Otherwise,
+     *     it will be the x coordinate of the map location in your map units.
+     * lat - {Number} The y-axis coordinate in map units.  If your map is in
+     *     a geographic projection, this will be the Latitude.  Otherwise,
+     *     it will be the y coordinate of the map location in your map units.
+     */
+    initialize: function(lon, lat) {
+        this.lon = OpenLayers.Util.toFloat(lon);
+        this.lat = OpenLayers.Util.toFloat(lat);
+    },
+    
+    /**
+     * Method: toString
+     * Return a readable string version of the lonlat
+     *
+     * Returns:
+     * {String} String representation of OpenLayers.LonLat object. 
+     *           (ex. <i>"lon=5,lat=42"</i>)
+     */
+    toString:function() {
+        return ("lon=" + this.lon + ",lat=" + this.lat);
+    },
+
+    /** 
+     * APIMethod: toShortString
+     * 
+     * Returns:
+     * {String} Shortened String representation of OpenLayers.LonLat object. 
+     *         (ex. <i>"5, 42"</i>)
+     */
+    toShortString:function() {
+        return (this.lon + ", " + this.lat);
+    },
+
+    /** 
+     * APIMethod: clone
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
+     *                       and lat values
+     */
+    clone:function() {
+        return new OpenLayers.LonLat(this.lon, this.lat);
+    },
+
+    /** 
+     * APIMethod: add
+     * 
+     * Parameters:
+     * lon - {Float}
+     * lat - {Float}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
+     *                       lat passed-in added to this's. 
+     */
+    add:function(lon, lat) {
+        if ( (lon == null) || (lat == null) ) {
+            var msg = OpenLayers.i18n("lonlatAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
+    },
+
+    /** 
+     * APIMethod: equals
+     * 
+     * Parameters:
+     * ll - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {Boolean} Boolean value indicating whether the passed-in 
+     *           <OpenLayers.LonLat> object has the same lon and lat 
+     *           components as this.
+     *           Note: if ll passed in is null, returns false
+     */
+    equals:function(ll) {
+        var equals = false;
+        if (ll != null) {
+            equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
+                      (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
+        }
+        return equals;
+    },
+
+    /**
+     * APIMethod: transform
+     * Transform the LonLat object from source to dest. This transformation is
+     *    *in place*: if you want a *new* lonlat, use .clone() first.
+     *
+     * Parameters: 
+     * source - {<OpenLayers.Projection>} Source projection. 
+     * dest   - {<OpenLayers.Projection>} Destination projection. 
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} Itself, for use in chaining operations.
+     */
+    transform: function(source, dest) {
+        var point = OpenLayers.Projection.transform(
+            {'x': this.lon, 'y': this.lat}, source, dest);
+        this.lon = point.x;
+        this.lat = point.y;
+        return this;
+    },
+    
+    /**
+     * APIMethod: wrapDateLine
+     * 
+     * Parameters:
+     * maxExtent - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
+     *                       maxExtent)
+     */
+    wrapDateLine: function(maxExtent) {    
+
+        var newLonLat = this.clone();
+    
+        if (maxExtent) {
+            //shift right?
+            while (newLonLat.lon < maxExtent.left) {
+                newLonLat.lon +=  maxExtent.getWidth();
+            }    
+           
+            //shift left?
+            while (newLonLat.lon > maxExtent.right) {
+                newLonLat.lon -= maxExtent.getWidth();
+            }    
+        }
+                
+        return newLonLat;
+    },
+
+    CLASS_NAME: "OpenLayers.LonLat"
+});
+
+/** 
+ * Function: fromString
+ * Alternative constructor that builds a new <OpenLayers.LonLat> from a 
+ *     parameter string
+ * 
+ * Parameters:
+ * str - {String} Comma-separated Lon,Lat coordinate string. 
+ *                 (ex. <i>"5,40"</i>)
+ * 
+ * Returns:
+ * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
+ *                       passed-in String.
+ */
+OpenLayers.LonLat.fromString = function(str) {
+    var pair = str.split(",");
+    return new OpenLayers.LonLat(parseFloat(pair[0]), 
+                                 parseFloat(pair[1]));
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Pixel.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Pixel.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Pixel.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,124 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Pixel
+ * This class represents a screen coordinate, in x and y coordinates
+ */
+OpenLayers.Pixel = OpenLayers.Class({
+    
+    /**
+     * APIProperty: x
+     * {Number} The x coordinate
+     */
+    x: 0.0,
+
+    /**
+     * APIProperty: y
+     * {Number} The y coordinate
+     */
+    y: 0.0,
+    
+    /**
+     * Constructor: OpenLayers.Pixel
+     * Create a new OpenLayers.Pixel instance
+     *
+     * Parameters:
+     * x - {Number} The x coordinate
+     * y - {Number} The y coordinate
+     *
+     * Returns:
+     * An instance of OpenLayers.Pixel
+     */
+    initialize: function(x, y) {
+        this.x = parseFloat(x);
+        this.y = parseFloat(y);
+    },
+    
+    /**
+     * Method: toString
+     * Cast this object into a string
+     *
+     * Returns:
+     * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
+     */
+    toString:function() {
+        return ("x=" + this.x + ",y=" + this.y);
+    },
+
+    /**
+     * APIMethod: clone
+     * Return a clone of this pixel object
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} A clone pixel
+     */
+    clone:function() {
+        return new OpenLayers.Pixel(this.x, this.y); 
+    },
+    
+    /**
+     * APIMethod: equals
+     * Determine whether one pixel is equivalent to another
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {Boolean} The point passed in as parameter is equal to this. Note that
+     * if px passed in is null, returns false.
+     */
+    equals:function(px) {
+        var equals = false;
+        if (px != null) {
+            equals = ((this.x == px.x && this.y == px.y) ||
+                      (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
+        }
+        return equals;
+    },
+
+    /**
+     * APIMethod: add
+     *
+     * Parameters:
+     * x - {Integer}
+     * y - {Integer}
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
+     * values passed in.
+     */
+    add:function(x, y) {
+        if ( (x == null) || (y == null) ) {
+            var msg = OpenLayers.i18n("pixelAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.Pixel(this.x + x, this.y + y);
+    },
+
+    /**
+    * APIMethod: offset
+    * 
+    * Parameters
+    * px - {<OpenLayers.Pixel>}
+    * 
+    * Returns:
+    * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
+    *                      x&y values of the pixel passed in.
+    */
+    offset:function(px) {
+        var newPx = this.clone();
+        if (px) {
+            newPx = this.add(px.x, px.y);
+        }
+        return newPx;
+    },
+
+    CLASS_NAME: "OpenLayers.Pixel"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Size.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Size.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes/Size.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,84 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
+ */
+OpenLayers.Size = OpenLayers.Class({
+
+    /**
+     * APIProperty: w
+     * {Number} width
+     */
+    w: 0.0,
+    
+    /**
+     * APIProperty: h
+     * {Number} height
+     */
+    h: 0.0,
+
+
+    /**
+     * Constructor: OpenLayers.Size
+     * Create an instance of OpenLayers.Size
+     *
+     * Parameters:
+     * w - {Number} width
+     * h - {Number} height
+     */
+    initialize: function(w, h) {
+        this.w = parseFloat(w);
+        this.h = parseFloat(h);
+    },
+
+    /**
+     * Method: toString
+     * Return the string representation of a size object
+     *
+     * Returns:
+     * {String} The string representation of OpenLayers.Size object. 
+     * (ex. <i>"w=55,h=66"</i>)
+     */
+    toString:function() {
+        return ("w=" + this.w + ",h=" + this.h);
+    },
+
+    /**
+     * APIMethod: clone
+     * Create a clone of this size object
+     *
+     * Returns:
+     * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+     * values
+     */
+    clone:function() {
+        return new OpenLayers.Size(this.w, this.h);
+    },
+
+    /**
+     *
+     * APIMethod: equals
+     * Determine where this size is equal to another
+     *
+     * Parameters:
+     * sz - {<OpenLayers.Size>}
+     *
+     * Returns: 
+     * {Boolean} The passed in size has the same h and w properties as this one.
+     * Note that if sz passed in is null, returns false.
+     *
+     */
+    equals:function(sz) {
+        var equals = false;
+        if (sz != null) {
+            equals = ((this.w == sz.w && this.h == sz.h) ||
+                      (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
+        }
+        return equals;
+    },
+
+    CLASS_NAME: "OpenLayers.Size"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/BaseTypes.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,529 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/BaseTypes/LonLat.js
+ * @requires OpenLayers/BaseTypes/Size.js
+ * @requires OpenLayers/BaseTypes/Pixel.js
+ * @requires OpenLayers/BaseTypes/Bounds.js
+ * @requires OpenLayers/BaseTypes/Element.js
+ * @requires OpenLayers/Lang/en.js
+ * @requires OpenLayers/Console.js
+ */
+ 
+/** 
+ * Header: OpenLayers Base Types
+ * OpenLayers custom string, number and function functions are described here.
+ */
+
+/**
+ * Namespace: OpenLayers.String
+ * Contains convenience functions for string manipulation.
+ */
+OpenLayers.String = {
+
+    /**
+     * APIFunction: startsWith
+     * Test whether a string starts with another string. 
+     * 
+     * Parameters:
+     * str - {String} The string to test.
+     * sub - {Sring} The substring to look for.
+     *  
+     * Returns:
+     * {Boolean} The first string starts with the second.
+     */
+    startsWith: function(str, sub) {
+        return (str.indexOf(sub) == 0);
+    },
+
+    /**
+     * APIFunction: contains
+     * Test whether a string contains another string.
+     * 
+     * Parameters:
+     * str - {String} The string to test.
+     * sub - {String} The substring to look for.
+     * 
+     * Returns:
+     * {Boolean} The first string contains the second.
+     */
+    contains: function(str, sub) {
+        return (str.indexOf(sub) != -1);
+    },
+    
+    /**
+     * APIFunction: trim
+     * Removes leading and trailing whitespace characters from a string.
+     * 
+     * Parameters:
+     * str - {String} The (potentially) space padded string.  This string is not
+     *     modified.
+     * 
+     * Returns:
+     * {String} A trimmed version of the string with all leading and 
+     *     trailing spaces removed.
+     */
+    trim: function(str) {
+        return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+    },
+    
+    /**
+     * APIFunction: camelize
+     * Camel-case a hyphenated string. 
+     *     Ex. "chicken-head" becomes "chickenHead", and
+     *     "-chicken-head" becomes "ChickenHead".
+     *
+     * Parameters:
+     * str - {String} The string to be camelized.  The original is not modified.
+     * 
+     * Returns:
+     * {String} The string, camelized
+     */
+    camelize: function(str) {
+        var oStringList = str.split('-');
+        var camelizedString = oStringList[0];
+        for (var i=1, len=oStringList.length; i<len; i++) {
+            var s = oStringList[i];
+            camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+        }
+        return camelizedString;
+    },
+    
+    /**
+     * APIFunction: format
+     * Given a string with tokens in the form ${token}, return a string
+     *     with tokens replaced with properties from the given context
+     *     object.  Represent a literal "${" by doubling it, e.g. "${${".
+     *
+     * Parameters:
+     * template - {String} A string with tokens to be replaced.  A template
+     *     has the form "literal ${token}" where the token will be replaced
+     *     by the value of context["token"].
+     * context - {Object} An optional object with properties corresponding
+     *     to the tokens in the format string.  If no context is sent, the
+     *     window object will be used.
+     * args - {Array} Optional arguments to pass to any functions found in
+     *     the context.  If a context property is a function, the token
+     *     will be replaced by the return from the function called with
+     *     these arguments.
+     *
+     * Returns:
+     * {String} A string with tokens replaced from the context object.
+     */
+    format: function(template, context, args) {
+        if(!context) {
+            context = window;
+        }
+
+        // Example matching: 
+        // str   = ${foo.bar}
+        // match = foo.bar
+        var replacer = function(str, match) {
+            var replacement;
+
+            // Loop through all subs. Example: ${a.b.c}
+            // 0 -> replacement = context[a];
+            // 1 -> replacement = context[a][b];
+            // 2 -> replacement = context[a][b][c];
+            var subs = match.split(/\.+/);
+            for (var i=0; i< subs.length; i++) {
+                if (i == 0) {
+                    replacement = context;
+                }
+
+                replacement = replacement[subs[i]];
+            }
+
+            if(typeof replacement == "function") {
+                replacement = args ?
+                    replacement.apply(null, args) :
+                    replacement();
+            }
+
+            // If replacement is undefined, return the string 'undefined'.
+            // This is a workaround for a bugs in browsers not properly 
+            // dealing with non-participating groups in regular expressions:
+            // http://blog.stevenlevithan.com/archives/npcg-javascript
+            if (typeof replacement == 'undefined') {
+                return 'undefined';
+            } else {
+                return replacement; 
+            }
+        };
+
+        return template.replace(OpenLayers.String.tokenRegEx, replacer);
+    },
+
+    /**
+     * Property: OpenLayers.String.tokenRegEx
+     * Used to find tokens in a string.
+     * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
+     */
+    tokenRegEx:  /\$\{([\w.]+?)\}/g,
+    
+    /**
+     * Property: OpenLayers.String.numberRegEx
+     * Used to test strings as numbers.
+     */
+    numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
+    
+    /**
+     * APIFunction: OpenLayers.String.isNumeric
+     * Determine whether a string contains only a numeric value.
+     *
+     * Examples:
+     * (code)
+     * OpenLayers.String.isNumeric("6.02e23") // true
+     * OpenLayers.String.isNumeric("12 dozen") // false
+     * OpenLayers.String.isNumeric("4") // true
+     * OpenLayers.String.isNumeric(" 4 ") // false
+     * (end)
+     *
+     * Returns:
+     * {Boolean} String contains only a number.
+     */
+    isNumeric: function(value) {
+        return OpenLayers.String.numberRegEx.test(value);
+    },
+    
+    /**
+     * APIFunction: numericIf
+     * Converts a string that appears to be a numeric value into a number.
+     * 
+     * Returns
+     * {Number|String} a Number if the passed value is a number, a String
+     *     otherwise. 
+     */
+    numericIf: function(value) {
+        return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value;
+    }
+
+};
+
+if (!String.prototype.startsWith) {
+    /**
+     * APIMethod: String.startsWith
+     * *Deprecated*. Whether or not a string starts with another string. 
+     * 
+     * Parameters:
+     * sStart - {Sring} The string we're testing for.
+     *  
+     * Returns:
+     * {Boolean} Whether or not this string starts with the string passed in.
+     */
+    String.prototype.startsWith = function(sStart) {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                                {'newMethod':'OpenLayers.String.startsWith'}));
+        return OpenLayers.String.startsWith(this, sStart);
+    };
+}
+
+if (!String.prototype.contains) {
+    /**
+     * APIMethod: String.contains
+     * *Deprecated*. Whether or not a string contains another string.
+     * 
+     * Parameters:
+     * str - {String} The string that we're testing for.
+     * 
+     * Returns:
+     * {Boolean} Whether or not this string contains with the string passed in.
+     */
+    String.prototype.contains = function(str) {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                                  {'newMethod':'OpenLayers.String.contains'}));
+        return OpenLayers.String.contains(this, str);
+    };
+}
+
+if (!String.prototype.trim) {
+    /**
+     * APIMethod: String.trim
+     * *Deprecated*. Removes leading and trailing whitespace characters from a string.
+     * 
+     * Returns:
+     * {String} A trimmed version of the string - all leading and 
+     *          trailing spaces removed
+     */
+    String.prototype.trim = function() {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                                      {'newMethod':'OpenLayers.String.trim'}));
+        return OpenLayers.String.trim(this);
+    };
+}
+
+if (!String.prototype.camelize) {
+    /**
+     * APIMethod: String.camelize
+     * *Deprecated*. Camel-case a hyphenated string. 
+     *     Ex. "chicken-head" becomes "chickenHead", and
+     *     "-chicken-head" becomes "ChickenHead".
+     * 
+     * Returns:
+     * {String} The string, camelized
+     */
+    String.prototype.camelize = function() {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                                  {'newMethod':'OpenLayers.String.camelize'}));
+        return OpenLayers.String.camelize(this);
+    };
+}
+
+/**
+ * Namespace: OpenLayers.Number
+ * Contains convenience functions for manipulating numbers.
+ */
+OpenLayers.Number = {
+
+    /**
+     * Property: decimalSeparator
+     * Decimal separator to use when formatting numbers.
+     */
+    decimalSeparator: ".",
+    
+    /**
+     * Property: thousandsSeparator
+     * Thousands separator to use when formatting numbers.
+     */
+    thousandsSeparator: ",",
+    
+    /**
+     * APIFunction: limitSigDigs
+     * Limit the number of significant digits on a float.
+     * 
+     * Parameters:
+     * num - {Float}
+     * sig - {Integer}
+     * 
+     * Returns:
+     * {Float} The number, rounded to the specified number of significant
+     *     digits.
+     */
+    limitSigDigs: function(num, sig) {
+        var fig = 0;
+        if (sig > 0) {
+            fig = parseFloat(num.toPrecision(sig));
+        }
+        return fig;
+    },
+    
+    /**
+     * APIFunction: format
+     * Formats a number for output.
+     * 
+     * Parameters:
+     * num  - {Float}
+     * dec  - {Integer} Number of decimal places to round to.
+     *        Defaults to 0. Set to null to leave decimal places unchanged.
+     * tsep - {String} Thousands separator.
+     *        Default is ",".
+     * dsep - {String} Decimal separator.
+     *        Default is ".".
+     *
+     * Returns:
+     * {String} A string representing the formatted number.
+     */
+    format: function(num, dec, tsep, dsep) {
+        dec = (typeof dec != "undefined") ? dec : 0; 
+        tsep = (typeof tsep != "undefined") ? tsep :
+            OpenLayers.Number.thousandsSeparator; 
+        dsep = (typeof dsep != "undefined") ? dsep :
+            OpenLayers.Number.decimalSeparator;
+
+        if (dec != null) {
+            num = parseFloat(num.toFixed(dec));
+        }
+
+        var parts = num.toString().split(".");
+        if (parts.length == 1 && dec == null) {
+            // integer where we do not want to touch the decimals
+            dec = 0;
+        }
+        
+        var integer = parts[0];
+        if (tsep) {
+            var thousands = /(-?[0-9]+)([0-9]{3})/; 
+            while(thousands.test(integer)) { 
+                integer = integer.replace(thousands, "$1" + tsep + "$2"); 
+            }
+        }
+        
+        var str;
+        if (dec == 0) {
+            str = integer;
+        } else {
+            var rem = parts.length > 1 ? parts[1] : "0";
+            if (dec != null) {
+                rem = rem + new Array(dec - rem.length + 1).join("0");
+            }
+            str = integer + dsep + rem;
+        }
+        return str;
+    }
+};
+
+if (!Number.prototype.limitSigDigs) {
+    /**
+     * APIMethod: Number.limitSigDigs
+     * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
+     *     work with floats!
+     * 
+     * Parameters:
+     * sig - {Integer}
+     * 
+     * Returns:
+     * {Integer} The number, rounded to the specified number of significant digits.
+     *           If null, 0, or negative value passed in, returns 0
+     */
+    Number.prototype.limitSigDigs = function(sig) {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                              {'newMethod':'OpenLayers.Number.limitSigDigs'}));
+        return OpenLayers.Number.limitSigDigs(this, sig);
+    };
+}
+
+/**
+ * Namespace: OpenLayers.Function
+ * Contains convenience functions for function manipulation.
+ */
+OpenLayers.Function = {
+    /**
+     * APIFunction: bind
+     * Bind a function to an object.  Method to easily create closures with
+     *     'this' altered.
+     * 
+     * Parameters:
+     * func - {Function} Input function.
+     * object - {Object} The object to bind to the input function (as this).
+     * 
+     * Returns:
+     * {Function} A closure with 'this' set to the passed in object.
+     */
+    bind: function(func, object) {
+        // create a reference to all arguments past the second one
+        var args = Array.prototype.slice.apply(arguments, [2]);
+        return function() {
+            // Push on any additional arguments from the actual function call.
+            // These will come after those sent to the bind call.
+            var newArgs = args.concat(
+                Array.prototype.slice.apply(arguments, [0])
+            );
+            return func.apply(object, newArgs);
+        };
+    },
+    
+    /**
+     * APIFunction: bindAsEventListener
+     * Bind a function to an object, and configure it to receive the event
+     *     object as first parameter when called. 
+     * 
+     * Parameters:
+     * func - {Function} Input function to serve as an event listener.
+     * object - {Object} A reference to this.
+     * 
+     * Returns:
+     * {Function}
+     */
+    bindAsEventListener: function(func, object) {
+        return function(event) {
+            return func.call(object, event || window.event);
+        };
+    }
+};
+
+if (!Function.prototype.bind) {
+    /**
+     * APIMethod: Function.bind
+     * *Deprecated*. Bind a function to an object. 
+     * Method to easily create closures with 'this' altered.
+     * 
+     * Parameters:
+     * object - {Object} the this parameter
+     * 
+     * Returns:
+     * {Function} A closure with 'this' altered to the first
+     *            argument.
+     */
+    Function.prototype.bind = function() {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                                {'newMethod':'OpenLayers.Function.bind'}));
+        // new function takes the same arguments with this function up front
+        Array.prototype.unshift.apply(arguments, [this]);
+        return OpenLayers.Function.bind.apply(null, arguments);
+    };
+}
+
+if (!Function.prototype.bindAsEventListener) {
+    /**
+     * APIMethod: Function.bindAsEventListener
+     * *Deprecated*. Bind a function to an object, and configure it to receive the
+     *     event object as first parameter when called. 
+     * 
+     * Parameters:
+     * object - {Object} A reference to this.
+     * 
+     * Returns:
+     * {Function}
+     */
+    Function.prototype.bindAsEventListener = function(object) {
+        OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+                        {'newMethod':'OpenLayers.Function.bindAsEventListener'}));
+        return OpenLayers.Function.bindAsEventListener(this, object);
+    };
+}
+
+/**
+ * Namespace: OpenLayers.Array
+ * Contains convenience functions for array manipulation.
+ */
+OpenLayers.Array = {
+
+    /**
+     * APIMethod: filter
+     * Filter an array.  Provides the functionality of the
+     *     Array.prototype.filter extension to the ECMA-262 standard.  Where
+     *     available, Array.prototype.filter will be used.
+     *
+     * Based on well known example from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter
+     *
+     * Parameters:
+     * array - {Array} The array to be filtered.  This array is not mutated.
+     *     Elements added to this array by the callback will not be visited.
+     * callback - {Function} A function that is called for each element in
+     *     the array.  If this function returns true, the element will be
+     *     included in the return.  The function will be called with three
+     *     arguments: the element in the array, the index of that element, and
+     *     the array itself.  If the optional caller parameter is specified
+     *     the callback will be called with this set to caller.
+     * caller - {Object} Optional object to be set as this when the callback
+     *     is called.
+     *
+     * Returns:
+     * {Array} An array of elements from the passed in array for which the
+     *     callback returns true.
+     */
+    filter: function(array, callback, caller) {
+        var selected = [];
+        if (Array.prototype.filter) {
+            selected = array.filter(callback, caller);
+        } else {
+            var len = array.length;
+            if (typeof callback != "function") {
+                throw new TypeError();
+            }
+            for(var i=0; i<len; i++) {
+                if (i in array) {
+                    var val = array[i];
+                    if (callback.call(caller, val, i, array)) {
+                        selected.push(val);
+                    }
+                }
+            }        
+        }
+        return selected;
+    }
+    
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Console.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Console.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Console.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,245 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Console
+ * The OpenLayers.Console namespace is used for debugging and error logging.
+ * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
+ * calls to OpenLayers.Console methods will get redirected to window.console.
+ * This makes use of the Firebug extension where available and allows for
+ * cross-browser debugging Firebug style.
+ *
+ * Note:
+ * Note that behavior will differ with the Firebug extention and Firebug Lite.
+ * Most notably, the Firebug Lite console does not currently allow for
+ * hyperlinks to code or for clicking on object to explore their properties.
+ * 
+ */
+OpenLayers.Console = {
+    /**
+     * Create empty functions for all console methods.  The real value of these
+     * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
+     * included.  We explicitly require the Firebug Lite script to trigger
+     * functionality of the OpenLayers.Console methods.
+     */
+    
+    /**
+     * APIFunction: log
+     * Log an object in the console.  The Firebug Lite console logs string
+     * representation of objects.  Given multiple arguments, they will
+     * be cast to strings and logged with a space delimiter.  If the first
+     * argument is a string with printf-like formatting, subsequent arguments
+     * will be used in string substitution.  Any additional arguments (beyond
+     * the number substituted in a format string) will be appended in a space-
+     * delimited line.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    log: function() {},
+
+    /**
+     * APIFunction: debug
+     * Writes a message to the console, including a hyperlink to the line
+     * where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    debug: function() {},
+
+    /**
+     * APIFunction: info
+     * Writes a message to the console with the visual "info" icon and color
+     * coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    info: function() {},
+
+    /**
+     * APIFunction: warn
+     * Writes a message to the console with the visual "warning" icon and
+     * color coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    warn: function() {},
+
+    /**
+     * APIFunction: error
+     * Writes a message to the console with the visual "error" icon and color
+     * coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    error: function() {},
+    
+    /**
+     * APIFunction: userError
+     * A single interface for showing error messages to the user. The default
+     * behavior is a Javascript alert, though this can be overridden by
+     * reassigning OpenLayers.Console.userError to a different function.
+     *
+     * Expects a single error message
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    userError: function(error) {
+        alert(error);
+    },
+
+    /**
+     * APIFunction: assert
+     * Tests that an expression is true. If not, it will write a message to
+     * the console and throw an exception.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    assert: function() {},
+
+    /**
+     * APIFunction: dir
+     * Prints an interactive listing of all properties of the object. This
+     * looks identical to the view that you would see in the DOM tab.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    dir: function() {},
+
+    /**
+     * APIFunction: dirxml
+     * Prints the XML source tree of an HTML or XML element. This looks
+     * identical to the view that you would see in the HTML tab. You can click
+     * on any node to inspect it in the HTML tab.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    dirxml: function() {},
+
+    /**
+     * APIFunction: trace
+     * Prints an interactive stack trace of JavaScript execution at the point
+     * where it is called.  The stack trace details the functions on the stack,
+     * as well as the values that were passed as arguments to each function.
+     * You can click each function to take you to its source in the Script tab,
+     * and click each argument value to inspect it in the DOM or HTML tabs.
+     * 
+     */
+    trace: function() {},
+
+    /**
+     * APIFunction: group
+     * Writes a message to the console and opens a nested block to indent all
+     * future messages sent to the console. Call OpenLayers.Console.groupEnd()
+     * to close the block.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    group: function() {},
+
+    /**
+     * APIFunction: groupEnd
+     * Closes the most recently opened block created by a call to
+     * OpenLayers.Console.group
+     */
+    groupEnd: function() {},
+    
+    /**
+     * APIFunction: time
+     * Creates a new timer under the given name. Call
+     * OpenLayers.Console.timeEnd(name)
+     * with the same name to stop the timer and print the time elapsed.
+     *
+     * Parameters:
+     * name - {String}
+     */
+    time: function() {},
+
+    /**
+     * APIFunction: timeEnd
+     * Stops a timer created by a call to OpenLayers.Console.time(name) and
+     * writes the time elapsed.
+     *
+     * Parameters:
+     * name - {String}
+     */
+    timeEnd: function() {},
+
+    /**
+     * APIFunction: profile
+     * Turns on the JavaScript profiler. The optional argument title would
+     * contain the text to be printed in the header of the profile report.
+     *
+     * This function is not currently implemented in Firebug Lite.
+     * 
+     * Parameters:
+     * title - {String} Optional title for the profiler
+     */
+    profile: function() {},
+
+    /**
+     * APIFunction: profileEnd
+     * Turns off the JavaScript profiler and prints its report.
+     * 
+     * This function is not currently implemented in Firebug Lite.
+     */
+    profileEnd: function() {},
+
+    /**
+     * APIFunction: count
+     * Writes the number of times that the line of code where count was called
+     * was executed. The optional argument title will print a message in
+     * addition to the number of the count.
+     *
+     * This function is not currently implemented in Firebug Lite.
+     *
+     * Parameters:
+     * title - {String} Optional title to be printed with count
+     */
+    count: function() {},
+
+    CLASS_NAME: "OpenLayers.Console"
+};
+
+/**
+ * Execute an anonymous function to extend the OpenLayers.Console namespace
+ * if the firebug.js script is included.  This closure is used so that the
+ * "scripts" and "i" variables don't pollute the global namespace.
+ */
+(function() {
+    /**
+     * If Firebug Lite is included (before this script), re-route all
+     * OpenLayers.Console calls to the console object.
+     */
+    var scripts = document.getElementsByTagName("script");
+    for(var i=0, len=scripts.length; i<len; ++i) {
+        if(scripts[i].src.indexOf("firebug.js") != -1) {
+            if(console) {
+                OpenLayers.Util.extend(OpenLayers.Console, console);
+                break;
+            }
+        }
+    }
+})();

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ArgParser.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ArgParser.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ArgParser.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,165 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ArgParser
+ * The ArgParser control adds location bar querystring parsing functionality 
+ * to an OpenLayers Map.
+ * When added to a Map control, on a page load/refresh, the Map will 
+ * automatically take the href string and parse it for lon, lat, zoom, and 
+ * layers information. 
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Parameter: center
+     * {<OpenLayers.LonLat>}
+     */
+    center: null,
+    
+    /**
+     * Parameter: zoom
+     * {int}
+     */
+    zoom: null,
+
+    /**
+     * Parameter: layers 
+     * {Array(<OpenLayers.Layer>)}
+     */
+    layers: null,
+    
+    /** 
+     * APIProperty: displayProjection
+     * {<OpenLayers.Projection>} Requires proj4js support. 
+     *     Projection used when reading the coordinates from the URL. This will
+     *
+     *     reproject the map coordinates from the URL into the map's
+     *     projection.
+     *
+     *     If you are using this functionality, be aware that any permalink
+     *     which is added to the map will determine the coordinate type which
+     *     is read from the URL, which means you should not add permalinks with
+     *     different displayProjections to the same map. 
+     */
+    displayProjection: null, 
+
+    /**
+     * Constructor: OpenLayers.Control.ArgParser
+     *
+     * Parameters:
+     * options - {Object}
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+        //make sure we dont already have an arg parser attached
+        for(var i=0, len=this.map.controls.length; i<len; i++) {
+            var control = this.map.controls[i];
+            if ( (control != this) &&
+                 (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
+                
+                // If a second argparser is added to the map, then we 
+                // override the displayProjection to be the one added to the
+                // map. 
+                if (control.displayProjection != this.displayProjection) {
+                    this.displayProjection = control.displayProjection;
+                }    
+                
+                break;
+            }
+        }
+        if (i == this.map.controls.length) {
+
+            var args = OpenLayers.Util.getParameters();
+            // Be careful to set layer first, to not trigger unnecessary layer loads
+            if (args.layers) {
+                this.layers = args.layers;
+    
+                // when we add a new layer, set its visibility 
+                this.map.events.register('addlayer', this, 
+                                         this.configureLayers);
+                this.configureLayers();
+            }
+            if (args.lat && args.lon) {
+                this.center = new OpenLayers.LonLat(parseFloat(args.lon),
+                                                    parseFloat(args.lat));
+                if (args.zoom) {
+                    this.zoom = parseInt(args.zoom);
+                }
+    
+                // when we add a new baselayer to see when we can set the center
+                this.map.events.register('changebaselayer', this, 
+                                         this.setCenter);
+                this.setCenter();
+            }
+        }
+    },
+   
+    /** 
+     * Method: setCenter
+     * As soon as a baseLayer has been loaded, we center and zoom
+     *   ...and remove the handler.
+     */
+    setCenter: function() {
+        
+        if (this.map.baseLayer) {
+            //dont need to listen for this one anymore
+            this.map.events.unregister('changebaselayer', this, 
+                                       this.setCenter);
+            
+            if (this.displayProjection) {
+                this.center.transform(this.displayProjection, 
+                                      this.map.getProjectionObject()); 
+            }      
+
+            this.map.setCenter(this.center, this.zoom);
+        }
+    },
+
+    /** 
+     * Method: configureLayers
+     * As soon as all the layers are loaded, cycle through them and 
+     *   hide or show them. 
+     */
+    configureLayers: function() {
+
+        if (this.layers.length == this.map.layers.length) { 
+            this.map.events.unregister('addlayer', this, this.configureLayers);
+
+            for(var i=0, len=this.layers.length; i<len; i++) {
+                
+                var layer = this.map.layers[i];
+                var c = this.layers.charAt(i);
+                
+                if (c == "B") {
+                    this.map.setBaseLayer(layer);
+                } else if ( (c == "T") || (c == "F") ) {
+                    layer.setVisibility(c == "T");
+                }
+            }
+        }
+    },     
+
+    CLASS_NAME: "OpenLayers.Control.ArgParser"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/DragPan.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/DragPan.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/DragPan.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,85 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Control.DragPan
+ * The DragPan control pans the map with a drag of the mouse.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
+
+    /** 
+     * Property: type
+     * {OpenLayers.Control.TYPES}
+     */
+    type: OpenLayers.Control.TYPE_TOOL,
+    
+    /**
+     * Property: panned
+     * {Boolean} The map moved.
+     */
+    panned: false,
+    
+    /**
+     * Property: interval
+     * {Integer} The number of milliseconds that should ellapse before
+     *     panning the map again. Set this to increase dragging performance.
+     *     Defaults to 25 milliseconds.
+     */
+    interval: 25, 
+    
+    /**
+     * Method: draw
+     * Creates a Drag handler, using <panMap> and
+     * <panMapDone> as callbacks.
+     */    
+    draw: function() {
+        this.handler = new OpenLayers.Handler.Drag(this, {
+                "move": this.panMap,
+                "done": this.panMapDone
+            }, {
+                interval: this.interval
+            }
+        );
+    },
+
+    /**
+    * Method: panMap
+    *
+    * Parameters:
+    * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+    */
+    panMap: function(xy) {
+        this.panned = true;
+        this.map.pan(
+            this.handler.last.x - xy.x,
+            this.handler.last.y - xy.y,
+            {dragging: this.handler.dragging, animate: false}
+        );
+    },
+    
+    /**
+     * Method: panMapDone
+     * Finish the panning operation.  Only call setCenter (through <panMap>)
+     *     if the map has actually been moved.
+     *
+     * Parameters:
+     * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+     */
+    panMapDone: function(xy) {
+        if(this.panned) {
+            this.panMap(xy);
+            this.panned = false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.DragPan"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/KeyboardDefaults.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/KeyboardDefaults.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/KeyboardDefaults.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,121 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Keyboard.js
+ */
+
+/**
+ * Class: OpenLayers.Control.KeyboardDefaults
+ * The KeyboardDefaults control adds panning and zooming functions, controlled
+ * with the keyboard. By default arrow keys pan, +/- keys zoom & Page Up/Page
+ * Down/Home/End scroll by three quarters of a page.
+ * 
+ * This control has no visible appearance.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * APIProperty: slideFactor
+     * Pixels to slide by.
+     */
+    slideFactor: 75,
+
+    /**
+     * Constructor: OpenLayers.Control.KeyboardDefaults
+     */
+    initialize: function() {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        if (this.handler) {
+            this.handler.destroy();
+        }        
+        this.handler = null;
+        
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * Method: draw
+     * Create handler.
+     */
+    draw: function() {
+        this.handler = new OpenLayers.Handler.Keyboard( this, { 
+                                "keydown": this.defaultKeyPress });
+        this.activate();
+    },
+    
+    /**
+     * Method: defaultKeyPress
+     * When handling the key event, we only use evt.keyCode. This holds 
+     * some drawbacks, though we get around them below. When interpretting
+     * the keycodes below (including the comments associated with them),
+     * consult the URL below. For instance, the Safari browser returns
+     * "IE keycodes", and so is supported by any keycode labeled "IE".
+     * 
+     * Very informative URL:
+     *    http://unixpapa.com/js/key.html
+     *
+     * Parameters:
+     * code - {Integer} 
+     */
+    defaultKeyPress: function (evt) {
+        switch(evt.keyCode) {
+            case OpenLayers.Event.KEY_LEFT:
+                this.map.pan(-this.slideFactor, 0);
+                break;
+            case OpenLayers.Event.KEY_RIGHT: 
+                this.map.pan(this.slideFactor, 0);
+                break;
+            case OpenLayers.Event.KEY_UP:
+                this.map.pan(0, -this.slideFactor);
+                break;
+            case OpenLayers.Event.KEY_DOWN:
+                this.map.pan(0, this.slideFactor);
+                break;
+            
+            case 33: // Page Up. Same in all browsers.
+                var size = this.map.getSize();
+                this.map.pan(0, -0.75*size.h);
+                break;
+            case 34: // Page Down. Same in all browsers.
+                var size = this.map.getSize();
+                this.map.pan(0, 0.75*size.h);
+                break; 
+            case 35: // End. Same in all browsers.
+                var size = this.map.getSize();
+                this.map.pan(0.75*size.w, 0);
+                break; 
+            case 36: // Home. Same in all browsers.
+                var size = this.map.getSize();
+                this.map.pan(-0.75*size.w, 0);
+                break; 
+
+            case 43:  // +/= (ASCII), keypad + (ASCII, Opera)
+            case 61:  // +/= (Mozilla, Opera, some ASCII)
+            case 187: // +/= (IE)
+            case 107: // keypad + (IE, Mozilla)
+                this.map.zoomIn();
+                break; 
+            case 45:  // -/_ (ASCII, Opera), keypad - (ASCII, Opera)
+            case 109: // -/_ (Mozilla), keypad - (Mozilla, IE)
+            case 189: // -/_ (IE)
+            case 95:  // -/_ (some ASCII)
+                this.map.zoomOut();
+                break; 
+        } 
+    },
+
+    CLASS_NAME: "OpenLayers.Control.KeyboardDefaults"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/LayerSwitcher.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/LayerSwitcher.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/LayerSwitcher.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,638 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/** 
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.LayerSwitcher
+ * The LayerSwitcher control displays a table of contents for the map. This 
+ * allows the user interface to switch between BaseLasyers and to show or hide
+ * Overlays. By default the switcher is shown minimized on the right edge of 
+ * the map, the user may expand it by clicking on the handle.
+ *
+ * To create the LayerSwitcher outside of the map, pass the Id of a html div 
+ * as the first argument to the constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.LayerSwitcher = 
+  OpenLayers.Class(OpenLayers.Control, {
+
+    /**  
+     * Property: activeColor
+     * {String}
+     */
+    activeColor: "darkblue",
+    
+    /**  
+     * Property: layerStates 
+     * {Array(Object)} Basically a copy of the "state" of the map's layers 
+     *     the last time the control was drawn. We have this in order to avoid
+     *     unnecessarily redrawing the control.
+     */
+    layerStates: null,
+    
+
+  // DOM Elements
+  
+    /**
+     * Property: layersDiv
+     * {DOMElement} 
+     */
+    layersDiv: null,
+    
+    /** 
+     * Property: baseLayersDiv
+     * {DOMElement}
+     */
+    baseLayersDiv: null,
+
+    /** 
+     * Property: baseLayers
+     * {Array(<OpenLayers.Layer>)}
+     */
+    baseLayers: null,
+    
+    
+    /** 
+     * Property: dataLbl
+     * {DOMElement} 
+     */
+    dataLbl: null,
+    
+    /** 
+     * Property: dataLayersDiv
+     * {DOMElement} 
+     */
+    dataLayersDiv: null,
+
+    /** 
+     * Property: dataLayers
+     * {Array(<OpenLayers.Layer>)} 
+     */
+    dataLayers: null,
+
+
+    /** 
+     * Property: minimizeDiv
+     * {DOMElement} 
+     */
+    minimizeDiv: null,
+
+    /** 
+     * Property: maximizeDiv
+     * {DOMElement} 
+     */
+    maximizeDiv: null,
+    
+    /**
+     * APIProperty: ascending
+     * {Boolean} 
+     */
+    ascending: true,
+ 
+    /**
+     * Constructor: OpenLayers.Control.LayerSwitcher
+     * 
+     * Parameters:
+     * options - {Object}
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+        this.layerStates = [];
+    },
+
+    /**
+     * APIMethod: destroy 
+     */    
+    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.un({
+            "addlayer": this.redraw,
+            "changelayer": this.redraw,
+            "removelayer": this.redraw,
+            "changebaselayer": this.redraw,
+            scope: this
+        });
+        
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+    },
+
+    /** 
+     * Method: setMap
+     *
+     * Properties:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+        this.map.events.on({
+            "addlayer": this.redraw,
+            "changelayer": this.redraw,
+            "removelayer": this.redraw,
+            "changebaselayer": this.redraw,
+            scope: this
+        });
+    },
+
+    /**
+     * Method: draw
+     *
+     * Returns:
+     * {DOMElement} A reference to the DIV DOMElement containing the 
+     *     switcher tabs.
+     */  
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this);
+
+        // create layout divs
+        this.loadContents();
+
+        // set mode to minimize
+        if(!this.outsideViewport) {
+            this.minimizeControl();
+        }
+
+        // populate div with current info
+        this.redraw();    
+
+        return this.div;
+    },
+
+    /** 
+     * Method: clearLayersArray
+     * User specifies either "base" or "data". we then clear all the
+     *     corresponding listeners, the div, and reinitialize a new array.
+     * 
+     * Parameters:
+     * layersType - {String}  
+     */
+    clearLayersArray: function(layersType) {
+        var layers = this[layersType + "Layers"];
+        if (layers) {
+            for(var i=0, len=layers.length; i<len ; i++) {
+                var layer = layers[i];
+                OpenLayers.Event.stopObservingElement(layer.inputElem);
+                OpenLayers.Event.stopObservingElement(layer.labelSpan);
+            }
+        }
+        this[layersType + "LayersDiv"].innerHTML = "";
+        this[layersType + "Layers"] = [];
+    },
+
+
+    /**
+     * Method: checkRedraw
+     * Checks if the layer state has changed since the last redraw() call.
+     * 
+     * Returns:
+     * {Boolean} The layer state changed since the last redraw() call. 
+     */
+    checkRedraw: function() {
+        var redraw = false;
+        if ( !this.layerStates.length ||
+             (this.map.layers.length != this.layerStates.length) ) {
+            redraw = true;
+        } else {
+            for (var i=0, len=this.layerStates.length; i<len; i++) {
+                var layerState = this.layerStates[i];
+                var layer = this.map.layers[i];
+                if ( (layerState.name != layer.name) || 
+                     (layerState.inRange != layer.inRange) || 
+                     (layerState.id != layer.id) || 
+                     (layerState.visibility != layer.visibility) ) {
+                    redraw = true;
+                    break;
+                }    
+            }
+        }    
+        return redraw;
+    },
+    
+    /** 
+     * Method: redraw
+     * 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.
+     *
+     * Returns: 
+     * {DOMElement} A reference to the DIV DOMElement containing the control
+     */  
+    redraw: function() {
+        //if the state hasn't changed since last redraw, no need 
+        // to do anything. Just return the existing div.
+        if (!this.checkRedraw()) { 
+            return this.div; 
+        } 
+
+        //clear out previous layers 
+        this.clearLayersArray("base");
+        this.clearLayersArray("data");
+        
+        var containsOverlays = false;
+        var containsBaseLayers = false;
+        
+        // Save state -- for checking layer if the map state changed.
+        // We save this before redrawing, because in the process of redrawing
+        // we will trigger more visibility changes, and we want to not redraw
+        // and enter an infinite loop.
+        var len = this.map.layers.length;
+        this.layerStates = new Array(len);
+        for (var i=0; i <len; i++) {
+            var layer = this.map.layers[i];
+            this.layerStates[i] = {
+                'name': layer.name, 
+                'visibility': layer.visibility,
+                'inRange': layer.inRange,
+                'id': layer.id
+            };
+        }    
+
+        var layers = this.map.layers.slice();
+        if (!this.ascending) { layers.reverse(); }
+        for(var i=0, len=layers.length; i<len; i++) {
+            var layer = layers[i];
+            var baseLayer = layer.isBaseLayer;
+
+            if (layer.displayInLayerSwitcher) {
+
+                if (baseLayer) {
+                    containsBaseLayers = true;
+                } else {
+                    containsOverlays = true;
+                }    
+
+                // only check a baselayer if it is *the* baselayer, check data
+                //  layers if they are visible
+                var checked = (baseLayer) ? (layer == this.map.baseLayer)
+                                          : layer.getVisibility();
+    
+                // create input element
+                var inputElem = document.createElement("input");
+                inputElem.id = this.id + "_input_" + layer.name;
+                inputElem.name = (baseLayer) ? "baseLayers" : layer.name;
+                inputElem.type = (baseLayer) ? "radio" : "checkbox";
+                inputElem.value = layer.name;
+                inputElem.checked = checked;
+                inputElem.defaultChecked = checked;
+
+                if (!baseLayer && !layer.inRange) {
+                    inputElem.disabled = true;
+                }
+                var context = {
+                    'inputElem': inputElem,
+                    'layer': layer,
+                    'layerSwitcher': this
+                };
+                OpenLayers.Event.observe(inputElem, "mouseup", 
+                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
+                                                            context)
+                );
+                
+                // create span
+                var labelSpan = document.createElement("span");
+                if (!baseLayer && !layer.inRange) {
+                    labelSpan.style.color = "gray";
+                }
+                labelSpan.innerHTML = layer.name;
+                labelSpan.style.verticalAlign = (baseLayer) ? "bottom" 
+                                                            : "baseline";
+                OpenLayers.Event.observe(labelSpan, "click", 
+                    OpenLayers.Function.bindAsEventListener(this.onInputClick,
+                                                            context)
+                );
+                // create line break
+                var br = document.createElement("br");
+    
+                
+                var groupArray = (baseLayer) ? this.baseLayers
+                                             : this.dataLayers;
+                groupArray.push({
+                    'layer': layer,
+                    'inputElem': inputElem,
+                    'labelSpan': labelSpan
+                });
+                                                     
+    
+                var groupDiv = (baseLayer) ? this.baseLayersDiv
+                                           : this.dataLayersDiv;
+                groupDiv.appendChild(inputElem);
+                groupDiv.appendChild(labelSpan);
+                groupDiv.appendChild(br);
+            }
+        }
+
+        // if no overlays, dont display the overlay label
+        this.dataLbl.style.display = (containsOverlays) ? "" : "none";        
+        
+        // if no baselayers, dont display the baselayer label
+        this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";        
+
+        return this.div;
+    },
+
+    /** 
+     * Method:
+     * A label has been clicked, check or uncheck its corresponding input
+     * 
+     * Parameters:
+     * e - {Event} 
+     *
+     * Context:  
+     *  - {DOMElement} inputElem
+     *  - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
+     *  - {<OpenLayers.Layer>} layer
+     */
+
+    onInputClick: function(e) {
+
+        if (!this.inputElem.disabled) {
+            if (this.inputElem.type == "radio") {
+                this.inputElem.checked = true;
+                this.layer.map.setBaseLayer(this.layer);
+            } else {
+                this.inputElem.checked = !this.inputElem.checked;
+                this.layerSwitcher.updateMap();
+            }
+        }
+        OpenLayers.Event.stop(e);
+    },
+    
+    /**
+     * Method: onLayerClick
+     * Need to update the map accordingly whenever user clicks in either of
+     *     the layers.
+     * 
+     * Parameters: 
+     * e - {Event} 
+     */
+    onLayerClick: function(e) {
+        this.updateMap();
+    },
+
+
+    /** 
+     * Method: updateMap
+     * Cycles through the loaded data and base layer input arrays and makes
+     *     the necessary calls to the Map object such that that the map's 
+     *     visual state corresponds to what the user has selected in 
+     *     the control.
+     */
+    updateMap: function() {
+
+        // set the newly selected base layer        
+        for(var i=0, len=this.baseLayers.length; i<len; 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, len=this.dataLayers.length; i<len; i++) {
+            var layerEntry = this.dataLayers[i];   
+            layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
+        }
+
+    },
+
+    /** 
+     * Method: maximizeControl
+     * Set up the labels and divs for the control
+     * 
+     * Parameters:
+     * e - {Event} 
+     */
+    maximizeControl: function(e) {
+
+        //HACK HACK HACK - find a way to auto-size this layerswitcher
+        this.div.style.width = "20em";
+        this.div.style.height = "";
+
+        this.showControls(false);
+
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+    
+    /** 
+     * Method: minimizeControl
+     * Hide all the contents of the control, shrink the size, 
+     *     add the maximize icon
+     *
+     * Parameters:
+     * e - {Event} 
+     */
+    minimizeControl: function(e) {
+
+        this.div.style.width = "0px";
+        this.div.style.height = "0px";
+
+        this.showControls(true);
+
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+
+    /**
+     * Method: showControls
+     * Hide/Show all LayerSwitcher controls depending on whether we are
+     *     minimized or not
+     * 
+     * Parameters:
+     * minimize - {Boolean}
+     */
+    showControls: function(minimize) {
+
+        this.maximizeDiv.style.display = minimize ? "" : "none";
+        this.minimizeDiv.style.display = minimize ? "none" : "";
+
+        this.layersDiv.style.display = minimize ? "none" : "";
+    },
+    
+    /** 
+     * Method: loadContents
+     * Set up the labels and divs for the control
+     */
+    loadContents: function() {
+
+        //configure main div
+        this.div.style.position = "absolute";
+        this.div.style.top = "25px";
+        this.div.style.right = "0px";
+        this.div.style.left = "";
+        this.div.style.fontFamily = "sans-serif";
+        this.div.style.fontWeight = "bold";
+        this.div.style.marginTop = "3px";
+        this.div.style.marginLeft = "3px";
+        this.div.style.marginBottom = "3px";
+        this.div.style.fontSize = "smaller";   
+        this.div.style.color = "white";   
+        this.div.style.backgroundColor = "transparent";
+    
+        OpenLayers.Event.observe(this.div, "mouseup", 
+            OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
+        OpenLayers.Event.observe(this.div, "click",
+                      this.ignoreEvent);
+        OpenLayers.Event.observe(this.div, "mousedown",
+            OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
+        OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
+
+
+        // layers list div        
+        this.layersDiv = document.createElement("div");
+        this.layersDiv.id = this.id + "_layersDiv";
+        this.layersDiv.style.paddingTop = "5px";
+        this.layersDiv.style.paddingLeft = "10px";
+        this.layersDiv.style.paddingBottom = "5px";
+        this.layersDiv.style.paddingRight = "75px";
+        this.layersDiv.style.backgroundColor = this.activeColor;        
+
+        // had to set width/height to get transparency in IE to work.
+        // thanks -- http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html
+        //
+        this.layersDiv.style.width = "100%";
+        this.layersDiv.style.height = "100%";
+
+
+        this.baseLbl = document.createElement("div");
+        this.baseLbl.innerHTML = OpenLayers.i18n("baseLayer");
+        this.baseLbl.style.marginTop = "3px";
+        this.baseLbl.style.marginLeft = "3px";
+        this.baseLbl.style.marginBottom = "3px";
+        
+        this.baseLayersDiv = document.createElement("div");
+        this.baseLayersDiv.style.paddingLeft = "10px";
+        /*OpenLayers.Event.observe(this.baseLayersDiv, "click", 
+            OpenLayers.Function.bindAsEventListener(this.onLayerClick, this));
+        */
+                     
+
+        this.dataLbl = document.createElement("div");
+        this.dataLbl.innerHTML = OpenLayers.i18n("overlays");
+        this.dataLbl.style.marginTop = "3px";
+        this.dataLbl.style.marginLeft = "3px";
+        this.dataLbl.style.marginBottom = "3px";
+        
+        this.dataLayersDiv = document.createElement("div");
+        this.dataLayersDiv.style.paddingLeft = "10px";
+
+        if (this.ascending) {
+            this.layersDiv.appendChild(this.baseLbl);
+            this.layersDiv.appendChild(this.baseLayersDiv);
+            this.layersDiv.appendChild(this.dataLbl);
+            this.layersDiv.appendChild(this.dataLayersDiv);
+        } else {
+            this.layersDiv.appendChild(this.dataLbl);
+            this.layersDiv.appendChild(this.dataLayersDiv);
+            this.layersDiv.appendChild(this.baseLbl);
+            this.layersDiv.appendChild(this.baseLayersDiv);
+        }    
+ 
+        this.div.appendChild(this.layersDiv);
+
+        OpenLayers.Rico.Corner.round(this.div, {corners: "tl bl",
+                                        bgColor: "transparent",
+                                        color: this.activeColor,
+                                        blend: false});
+
+        OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);
+
+        var imgLocation = OpenLayers.Util.getImagesLocation();
+        var sz = new OpenLayers.Size(18,18);        
+
+        // maximize button div
+        var img = imgLocation + 'layer-switcher-maximize.png';
+        this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                    "OpenLayers_Control_MaximizeDiv", 
+                                    null, 
+                                    sz, 
+                                    img, 
+                                    "absolute");
+        this.maximizeDiv.style.top = "5px";
+        this.maximizeDiv.style.right = "0px";
+        this.maximizeDiv.style.left = "";
+        this.maximizeDiv.style.display = "none";
+        OpenLayers.Event.observe(this.maximizeDiv, "click", 
+            OpenLayers.Function.bindAsEventListener(this.maximizeControl, this)
+        );
+        
+        this.div.appendChild(this.maximizeDiv);
+
+        // minimize button div
+        var img = imgLocation + 'layer-switcher-minimize.png';
+        var sz = new OpenLayers.Size(18,18);        
+        this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                    "OpenLayers_Control_MinimizeDiv", 
+                                    null, 
+                                    sz, 
+                                    img, 
+                                    "absolute");
+        this.minimizeDiv.style.top = "5px";
+        this.minimizeDiv.style.right = "0px";
+        this.minimizeDiv.style.left = "";
+        this.minimizeDiv.style.display = "none";
+        OpenLayers.Event.observe(this.minimizeDiv, "click", 
+            OpenLayers.Function.bindAsEventListener(this.minimizeControl, this)
+        );
+
+        this.div.appendChild(this.minimizeDiv);
+    },
+    
+    /** 
+     * Method: ignoreEvent
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    ignoreEvent: function(evt) {
+        OpenLayers.Event.stop(evt);
+    },
+
+    /** 
+     * Method: mouseDown
+     * Register a local 'mouseDown' flag so that we'll know whether or not
+     *     to ignore a mouseUp event
+     * 
+     * Parameters:
+     * evt - {Event}
+     */
+    mouseDown: function(evt) {
+        this.isMouseDown = true;
+        this.ignoreEvent(evt);
+    },
+
+    /** 
+     * Method: mouseUp
+     * If the 'isMouseDown' flag has been set, that means that the drag was 
+     *     started from within the LayerSwitcher control, and thus we can 
+     *     ignore the mouseup. Otherwise, let the Event continue.
+     *  
+     * Parameters:
+     * evt - {Event} 
+     */
+    mouseUp: function(evt) {
+        if (this.isMouseDown) {
+            this.isMouseDown = false;
+            this.ignoreEvent(evt);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Measure.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Measure.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Measure.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,317 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Measure
+ * Allows for drawing of features for measurements.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * control.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * Supported control event types (in addition to those from <OpenLayers.Control>):
+     * measure - Triggered when a measurement sketch is complete.  Listeners
+     *      will receive an event with measure, units, order, and geometry
+     *      properties.
+     * measurepartial - Triggered when a new point is added to the
+     *      measurement sketch.  Listeners receive an event with measure,
+     *      units, order, and geometry.
+     */
+    EVENT_TYPES: ['measure', 'measurepartial'],
+
+    /**
+     * APIProperty: handlerOptions
+     * {Object} Used to set non-default properties on the control's handler
+     */
+    handlerOptions: null,
+    
+    /**
+     * Property: callbacks
+     * {Object} The functions that are sent to the handler for callback
+     */
+    callbacks: null,
+    
+    /**
+     * Property: displaySystem
+     * {String} Display system for output measurements.  Supported values
+     *     are 'english', 'metric', and 'geographic'.  Default is 'metric'.
+     */
+    displaySystem: 'metric',
+    
+    /**
+     * Property: geodesic
+     * {Boolean} Calculate geodesic metrics instead of planar metrics.  This
+     *     requires that geometries can be transformed into Geographic/WGS84
+     *     (if that is not already the map projection).  Default is false.
+     */
+    geodesic: false,
+    
+    /**
+     * Property: displaySystemUnits
+     * {Object} Units for various measurement systems.  Values are arrays
+     *     of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing
+     *     order of length.
+     */
+    displaySystemUnits: {
+        geographic: ['dd'],
+        english: ['mi', 'ft', 'in'],
+        metric: ['km', 'm']
+    },
+
+    /**
+     * Property: delay
+     * {Number} Number of milliseconds between clicks before the event is
+     *     considered a double-click.  The "measurepartial" event will not
+     *     be triggered if the sketch is completed within this time.  This
+     *     is required for IE where creating a browser reflow (if a listener
+     *     is modifying the DOM by displaying the measurement values) messes
+     *     with the dblclick listener in the sketch handler.
+     */
+    partialDelay: 300,
+
+    /**
+     * Property: delayedTrigger
+     * {Number} Timeout id of trigger for measurepartial.
+     */
+    delayedTrigger: null,
+    
+    /**
+     * APIProperty: persist
+     * {Boolean} Keep the temporary measurement sketch drawn after the
+     *     measurement is complete.  The geometry will persist until a new
+     *     measurement is started, the control is deactivated, or <cancel> is
+     *     called.
+     */
+    persist: false,
+
+    /**
+     * Constructor: OpenLayers.Control.Measure
+     * 
+     * Parameters:
+     * handler - {<OpenLayers.Handler>} 
+     * options - {Object} 
+     */
+    initialize: function(handler, options) {
+        // concatenate events specific to measure with those from the base
+        this.EVENT_TYPES =
+            OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat(
+            OpenLayers.Control.prototype.EVENT_TYPES
+        );
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.callbacks = OpenLayers.Util.extend(
+            {done: this.measureComplete, point: this.measurePartial},
+            this.callbacks
+        );
+
+        // let the handler options override, so old code that passes 'persist' 
+        // directly to the handler does not need an update
+        this.handlerOptions = OpenLayers.Util.extend(
+            {persist: this.persist}, this.handlerOptions
+        );
+        this.handler = new handler(this, this.callbacks, this.handlerOptions);
+    },
+    
+    /**
+     * APIMethod: cancel
+     * Stop the control from measuring.  If <persist> is true, the temporary
+     *     sketch will be erased.
+     */
+    cancel: function() {
+        this.handler.cancel();
+    },
+    
+    /**
+     * Method: updateHandler
+     *
+     * Parameters:
+     * handler - {Function} One of the sketch handler constructors.
+     * options - {Object} Options for the handler.
+     */
+    updateHandler: function(handler, options) {
+        var active = this.active;
+        if(active) {
+            this.deactivate();
+        }
+        this.handler = new handler(this, this.callbacks, options);
+        if(active) {
+            this.activate();
+        }
+    },
+
+    /**
+     * Method: measureComplete
+     * Called when the measurement sketch is done.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     */
+    measureComplete: function(geometry) {
+        if(this.delayedTrigger) {
+            window.clearTimeout(this.delayedTrigger);
+        }
+        this.measure(geometry, "measure");
+    },
+    
+    /**
+     * Method: measurePartial
+     * Called each time a new point is added to the measurement sketch.
+     *
+     * Parameters:
+     * point - {<OpenLayers.Geometry.Point>} The last point added.
+     * geometry - {<OpenLayers.Geometry>} The sketch geometry.
+     */
+    measurePartial: function(point, geometry) {
+        this.delayedTrigger = window.setTimeout(
+            OpenLayers.Function.bind(function() {
+                this.measure(geometry, "measurepartial");
+            }, this),
+            this.partialDelay
+        );
+    },
+
+    /**
+     * Method: measure
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * eventType - {String}
+     */
+    measure: function(geometry, eventType) {
+        var stat, order;
+        if(geometry.CLASS_NAME.indexOf('LineString') > -1) {
+            stat = this.getBestLength(geometry);
+            order = 1;
+        } else {
+            stat = this.getBestArea(geometry);
+            order = 2;
+        }
+        this.events.triggerEvent(eventType, {
+            measure: stat[0],
+            units: stat[1],
+            order: order,
+            geometry: geometry
+        });
+    },
+    
+    /**
+     * Method: getBestArea
+     * Based on the <displaySystem> returns the area of a geometry.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     *
+     * Returns:
+     * {Array([Float, String])}  Returns a two item array containing the
+     *     area and the units abbreviation.
+     */
+    getBestArea: function(geometry) {
+        var units = this.displaySystemUnits[this.displaySystem];
+        var unit, area;
+        for(var i=0, len=units.length; i<len; ++i) {
+            unit = units[i];
+            area = this.getArea(geometry, unit);
+            if(area > 1) {
+                break;
+            }
+        }
+        return [area, unit];
+    },
+    
+    /**
+     * Method: getArea
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * units - {String} Unit abbreviation
+     *
+     * Returns:
+     * {Float} The geometry area in the given units.
+     */
+    getArea: function(geometry, units) {
+        var area, geomUnits;
+        if(this.geodesic) {
+            area = geometry.getGeodesicArea(this.map.getProjectionObject());
+            geomUnits = "m";
+        } else {
+            area = geometry.getArea();
+            geomUnits = this.map.getUnits();
+        }
+        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
+        if(inPerDisplayUnit) {
+            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
+            area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
+        }
+        return area;
+    },
+    
+    /**
+     * Method: getBestLength
+     * Based on the <displaySystem> returns the length of a geometry.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     *
+     * Returns:
+     * {Array([Float, String])}  Returns a two item array containing the
+     *     length and the units abbreviation.
+     */
+    getBestLength: function(geometry) {
+        var units = this.displaySystemUnits[this.displaySystem];
+        var unit, length;
+        for(var i=0, len=units.length; i<len; ++i) {
+            unit = units[i];
+            length = this.getLength(geometry, unit);
+            if(length > 1) {
+                break;
+            }
+        }
+        return [length, unit];
+    },
+
+    /**
+     * Method: getLength
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * units - {String} Unit abbreviation
+     *
+     * Returns:
+     * {Float} The geometry length in the given units.
+     */
+    getLength: function(geometry, units) {
+        var length, geomUnits;
+        if(this.geodesic) {
+            length = geometry.getGeodesicLength(this.map.getProjectionObject());
+            geomUnits = "m";
+        } else {
+            length = geometry.getLength();
+            geomUnits = this.map.getUnits();
+        }
+        var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
+        if(inPerDisplayUnit) {
+            var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
+            length *= (inPerMapUnit / inPerDisplayUnit);
+        }
+        return length;
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Measure"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ModifyFeature.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ModifyFeature.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ModifyFeature.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,738 @@
+/* Copyright (c) 2006 MetaCarta, Inc., published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control/DragFeature.js
+ * @requires OpenLayers/Control/SelectFeature.js
+ * @requires OpenLayers/Handler/Keyboard.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ModifyFeature
+ * Control to modify features.  When activated, a click renders the vertices
+ *     of a feature - these vertices can then be dragged.  By default, the
+ *     delete key will delete the vertex under the mouse.  New features are
+ *     added by dragging "virtual vertices" between vertices.  Create a new
+ *     control with the <OpenLayers.Control.ModifyFeature> constructor.
+ *
+ * Inherits From:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * APIProperty: geometryTypes
+     * {Array(String)} To restrict modification to a limited set of geometry
+     *     types, send a list of strings corresponding to the geometry class
+     *     names.
+     */
+    geometryTypes: null,
+
+    /**
+     * APIProperty: clickout
+     * {Boolean} Unselect features when clicking outside any feature.
+     *     Default is true.
+     */
+    clickout: true,
+
+    /**
+     * APIProperty: toggle
+     * {Boolean} Unselect a selected feature on click.
+     *      Default is true.
+     */
+    toggle: true,
+
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>}
+     */
+    layer: null,
+    
+    /**
+     * Property: feature
+     * {<OpenLayers.Feature.Vector>} Feature currently available for modification.
+     */
+    feature: null,
+    
+    /**
+     * Property: vertices
+     * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available
+     *     for dragging.
+     */
+    vertices: null,
+    
+    /**
+     * Property: virtualVertices
+     * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle
+     *     of each edge.
+     */
+    virtualVertices: null,
+
+    /**
+     * Property: selectControl
+     * {<OpenLayers.Control.SelectFeature>}
+     */
+    selectControl: null,
+    
+    /**
+     * Property: dragControl
+     * {<OpenLayers.Control.DragFeature>}
+     */
+    dragControl: null,
+    
+    /**
+     * Property: handlers
+     * {Object}
+     */
+    handlers: null,
+    
+    /**
+     * APIProperty: deleteCodes
+     * {Array(Integer)} Keycodes for deleting verticies.  Set to null to disable
+     *     vertex deltion by keypress.  If non-null, keypresses with codes
+     *     in this array will delete vertices under the mouse. Default
+     *     is 46 and 68, the 'delete' and lowercase 'd' keys.
+     */
+    deleteCodes: null,
+
+    /**
+     * APIProperty: virtualStyle
+     * {Object} A symbolizer to be used for virtual vertices.
+     */
+    virtualStyle: null,
+
+    /**
+     * APIProperty: mode
+     * {Integer} Bitfields specifying the modification mode. Defaults to
+     *      OpenLayers.Control.ModifyFeature.RESHAPE. To set the mode to a
+     *      combination of options, use the | operator. or example, to allow
+     *      the control to both resize and rotate features, use the following
+     *      syntax
+     * (code)
+     * control.mode = OpenLayers.Control.ModifyFeature.RESIZE |
+     *                OpenLayers.Control.ModifyFeature.ROTATE;
+     *  (end)
+     */
+    mode: null,
+
+    /**
+     * Property: modified
+     * {Boolean} The currently selected feature has been modified.
+     */
+    modified: false,
+
+    /**
+     * Property: radiusHandle
+     * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature.
+     */
+    radiusHandle: null,
+
+    /**
+     * Property: dragHandle
+     * {<OpenLayers.Feature.Vector>} A handle for dragging a feature.
+     */
+    dragHandle: null,
+
+    /**
+     * APIProperty: onModificationStart 
+     * {Function} *Deprecated*.  Register for "beforefeaturemodified" instead.
+     *     The "beforefeaturemodified" event is triggered on the layer before
+     *     any modification begins.
+     *
+     * Optional function to be called when a feature is selected
+     *     to be modified. The function should expect to be called with a
+     *     feature.  This could be used for example to allow to lock the
+     *     feature on server-side.
+     */
+    onModificationStart: function() {},
+
+    /**
+     * APIProperty: onModification
+     * {Function} *Deprecated*.  Register for "featuremodified" instead.
+     *     The "featuremodified" event is triggered on the layer with each
+     *     feature modification.
+     *
+     * Optional function to be called when a feature has been
+     *     modified.  The function should expect to be called with a feature.
+     */
+    onModification: function() {},
+
+    /**
+     * APIProperty: onModificationEnd
+     * {Function} *Deprecated*.  Register for "afterfeaturemodified" instead.
+     *     The "afterfeaturemodified" event is triggered on the layer after
+     *     a feature has been modified.
+     *
+     * Optional function to be called when a feature is finished 
+     *     being modified.  The function should expect to be called with a
+     *     feature.
+     */
+    onModificationEnd: function() {},
+
+    /**
+     * Constructor: OpenLayers.Control.ModifyFeature
+     * Create a new modify feature control.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.Vector>} Layer that contains features that
+     *     will be modified.
+     * options - {Object} Optional object whose properties will be set on the
+     *     control.
+     */
+    initialize: function(layer, options) {
+        this.layer = layer;
+        this.vertices = [];
+        this.virtualVertices = [];
+        this.virtualStyle = OpenLayers.Util.extend({},
+            this.layer.style || this.layer.styleMap.createSymbolizer());
+        this.virtualStyle.fillOpacity = 0.3;
+        this.virtualStyle.strokeOpacity = 0.3;
+        this.deleteCodes = [46, 68];
+        this.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        if(!(this.deleteCodes instanceof Array)) {
+            this.deleteCodes = [this.deleteCodes];
+        }
+        var control = this;
+
+        // configure the select control
+        var selectOptions = {
+            geometryTypes: this.geometryTypes,
+            clickout: this.clickout,
+            toggle: this.toggle,
+            onBeforeSelect: this.beforeSelectFeature,
+            onSelect: this.selectFeature,
+            onUnselect: this.unselectFeature,
+            scope: this
+        };
+        this.selectControl = new OpenLayers.Control.SelectFeature(
+            layer, selectOptions
+        );
+
+        // configure the drag control
+        var dragOptions = {
+            geometryTypes: ["OpenLayers.Geometry.Point"],
+            snappingOptions: this.snappingOptions,
+            onStart: function(feature, pixel) {
+                control.dragStart.apply(control, [feature, pixel]);
+            },
+            onDrag: function(feature, pixel) {
+                control.dragVertex.apply(control, [feature, pixel]);
+            },
+            onComplete: function(feature) {
+                control.dragComplete.apply(control, [feature]);
+            }
+        };
+        this.dragControl = new OpenLayers.Control.DragFeature(
+            layer, dragOptions
+        );
+
+        // configure the keyboard handler
+        var keyboardOptions = {
+            keydown: this.handleKeypress
+        };
+        this.handlers = {
+            keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions)
+        };
+    },
+
+    /**
+     * APIMethod: destroy
+     * Take care of things that are not handled in superclass.
+     */
+    destroy: function() {
+        this.layer = null;
+        this.selectControl.destroy();
+        this.dragControl.destroy();
+        OpenLayers.Control.prototype.destroy.apply(this, []);
+    },
+
+    /**
+     * APIMethod: activate
+     * Activate the control.
+     * 
+     * Returns:
+     * {Boolean} Successfully activated the control.
+     */
+    activate: function() {
+        return (this.selectControl.activate() &&
+                this.handlers.keyboard.activate() &&
+                OpenLayers.Control.prototype.activate.apply(this, arguments));
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control.
+     *
+     * Returns: 
+     * {Boolean} Successfully deactivated the control.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        // the return from the controls is unimportant in this case
+        if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
+            this.layer.removeFeatures(this.vertices, {silent: true});
+            this.layer.removeFeatures(this.virtualVertices, {silent: true});
+            this.vertices = [];
+            this.dragControl.deactivate();
+            if(this.feature && this.feature.geometry && this.feature.layer) {
+                this.selectControl.unselect.apply(this.selectControl,
+                                                  [this.feature]);
+            }
+            this.selectControl.deactivate();
+            this.handlers.keyboard.deactivate();
+            deactivated = true;
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: beforeSelectFeature
+     * Called before a feature is selected.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected.
+     */
+    beforeSelectFeature: function(feature) {
+        return this.layer.events.triggerEvent(
+            "beforefeaturemodified", {feature: feature}
+        );
+    },
+
+    /**
+     * Method: selectFeature
+     * Called when the select feature control selects a feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} the selected feature.
+     */
+    selectFeature: function(feature) {
+        this.feature = feature;
+        this.modified = false;
+        this.resetVertices();
+        this.dragControl.activate();
+        this.onModificationStart(this.feature);
+    },
+
+    /**
+     * Method: unselectFeature
+     * Called when the select feature control unselects a feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The unselected feature.
+     */
+    unselectFeature: function(feature) {
+        this.layer.removeFeatures(this.vertices, {silent: true});
+        this.vertices = [];
+        this.layer.destroyFeatures(this.virtualVertices, {silent: true});
+        this.virtualVertices = [];
+        if(this.dragHandle) {
+            this.layer.destroyFeatures([this.dragHandle], {silent: true});
+            delete this.dragHandle;
+        }
+        if(this.radiusHandle) {
+            this.layer.destroyFeatures([this.radiusHandle], {silent: true});
+            delete this.radiusHandle;
+        }
+        this.feature = null;
+        this.dragControl.deactivate();
+        this.onModificationEnd(feature);
+        this.layer.events.triggerEvent("afterfeaturemodified", {
+            feature: feature,
+            modified: this.modified
+        });
+        this.modified = false;
+    },
+
+    /**
+     * Method: dragStart
+     * Called by the drag feature control with before a feature is dragged.
+     *     This method is used to differentiate between points and vertices
+     *     of higher order geometries.  This respects the <geometryTypes>
+     *     property and forces a select of points when the drag control is
+     *     already active (and stops events from propagating to the select
+     *     control).
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be
+     *     dragged.
+     * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
+     */
+    dragStart: function(feature, pixel) {
+        // only change behavior if the feature is not in the vertices array
+        if(feature != this.feature && !feature.geometry.parent &&
+           feature != this.dragHandle && feature != this.radiusHandle) {
+            if(this.feature) {
+                // unselect the currently selected feature
+                this.selectControl.clickFeature.apply(this.selectControl,
+                                                      [this.feature]);
+            }
+            // check any constraints on the geometry type
+            if(this.geometryTypes == null ||
+               OpenLayers.Util.indexOf(this.geometryTypes,
+                                       feature.geometry.CLASS_NAME) != -1) {
+                // select the point
+                this.selectControl.clickFeature.apply(this.selectControl,
+                                                      [feature]);
+                /**
+                 * TBD: These lines improve workflow by letting the user
+                 *     immediately start dragging after the mouse down.
+                 *     However, it is very ugly to be messing with controls
+                 *     and their handlers in this way.  I'd like a better
+                 *     solution if the workflow change is necessary.
+                 */
+                // prepare the point for dragging
+                this.dragControl.overFeature.apply(this.dragControl,
+                                                   [feature]);
+                this.dragControl.lastPixel = pixel;
+                this.dragControl.handlers.drag.started = true;
+                this.dragControl.handlers.drag.start = pixel;
+                this.dragControl.handlers.drag.last = pixel;
+            }
+        }
+    },
+    
+    /**
+     * Method: dragVertex
+     * Called by the drag feature control with each drag move of a vertex.
+     *
+     * Parameters:
+     * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
+     * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
+     */
+    dragVertex: function(vertex, pixel) {
+        this.modified = true;
+        /**
+         * Five cases:
+         * 1) dragging a simple point
+         * 2) dragging a virtual vertex
+         * 3) dragging a drag handle
+         * 4) dragging a real vertex
+         * 5) dragging a radius handle
+         */
+        if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+            // dragging a simple point
+            if(this.feature != vertex) {
+                this.feature = vertex;
+            }
+            this.layer.events.triggerEvent("vertexmodified", {
+                vertex: vertex.geometry,
+                feature: this.feature,
+                pixel: pixel
+            });
+        } else {
+            if(vertex._index) {
+                // dragging a virtual vertex
+                vertex.geometry.parent.addComponent(vertex.geometry,
+                                                    vertex._index);
+                // move from virtual to real vertex
+                delete vertex._index;
+                OpenLayers.Util.removeItem(this.virtualVertices, vertex);
+                this.vertices.push(vertex);
+            } else if(vertex == this.dragHandle) {
+                // dragging a drag handle
+                this.layer.removeFeatures(this.vertices, {silent: true});
+                this.vertices = [];
+                if(this.radiusHandle) {
+                    this.layer.destroyFeatures([this.radiusHandle], {silent: true});
+                    this.radiusHandle = null;
+                }
+            } else if(vertex !== this.radiusHandle) {
+                // dragging a real vertex
+                this.layer.events.triggerEvent("vertexmodified", {
+                    vertex: vertex.geometry,
+                    feature: this.feature,
+                    pixel: pixel
+                });
+            }
+            // dragging a radius handle - no special treatment
+            if(this.virtualVertices.length > 0) {
+                this.layer.destroyFeatures(this.virtualVertices, {silent: true});
+                this.virtualVertices = [];
+            }
+            this.layer.drawFeature(this.feature, this.selectControl.renderIntent);
+        }
+        // keep the vertex on top so it gets the mouseout after dragging
+        // this should be removed in favor of an option to draw under or
+        // maintain node z-index
+        this.layer.drawFeature(vertex);
+    },
+    
+    /**
+     * Method: dragComplete
+     * Called by the drag feature control when the feature dragging is complete.
+     *
+     * Parameters:
+     * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
+     */
+    dragComplete: function(vertex) {
+        this.resetVertices();
+        this.setFeatureState();
+        this.onModification(this.feature);
+        this.layer.events.triggerEvent("featuremodified", 
+                                       {feature: this.feature});
+    },
+    
+    /**
+     * Method: setFeatureState
+     * Called when the feature is modified.  If the current state is not
+     *     INSERT or DELETE, the state is set to UPDATE.
+     */
+    setFeatureState: function() {
+        if(this.feature.state != OpenLayers.State.INSERT &&
+           this.feature.state != OpenLayers.State.DELETE) {
+            this.feature.state = OpenLayers.State.UPDATE;
+        }
+    },
+    
+    /**
+     * Method: resetVertices
+     */
+    resetVertices: function() {
+        // if coming from a drag complete we're about to destroy the vertex
+        // that was just dragged. For that reason, the drag feature control
+        // will never detect a mouse-out on that vertex, meaning that the drag
+        // handler won't be deactivated. This can cause errors because the drag
+        // feature control still has a feature to drag but that feature is
+        // destroyed. To prevent this, we call outFeature on the drag feature
+        // control if the control actually has a feature to drag.
+        if(this.dragControl.feature) {
+            this.dragControl.outFeature(this.dragControl.feature);
+        }
+        if(this.vertices.length > 0) {
+            this.layer.removeFeatures(this.vertices, {silent: true});
+            this.vertices = [];
+        }
+        if(this.virtualVertices.length > 0) {
+            this.layer.removeFeatures(this.virtualVertices, {silent: true});
+            this.virtualVertices = [];
+        }
+        if(this.dragHandle) {
+            this.layer.destroyFeatures([this.dragHandle], {silent: true});
+            this.dragHandle = null;
+        }
+        if(this.radiusHandle) {
+            this.layer.destroyFeatures([this.radiusHandle], {silent: true});
+            this.radiusHandle = null;
+        }
+        if(this.feature &&
+           this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
+            if((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
+                this.collectDragHandle();
+            }
+            if((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
+                             OpenLayers.Control.ModifyFeature.RESIZE))) {
+                this.collectRadiusHandle();
+            }
+            if(this.mode & OpenLayers.Control.ModifyFeature.RESHAPE){
+                // Don't collect vertices when we're resizing
+                if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)){
+                    this.collectVertices();
+                }
+            }
+        }
+    },
+    
+    /**
+     * Method: handleKeypress
+     * Called by the feature handler on keypress.  This is used to delete
+     *     vertices. If the <deleteCode> property is set, vertices will
+     *     be deleted when a feature is selected for modification and
+     *     the mouse is over a vertex.
+     *
+     * Parameters:
+     * {Integer} Key code corresponding to the keypress event.
+     */
+    handleKeypress: function(evt) {
+        var code = evt.keyCode;
+        
+        // check for delete key
+        if(this.feature &&
+           OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) {
+            var vertex = this.dragControl.feature;
+            if(vertex &&
+               OpenLayers.Util.indexOf(this.vertices, vertex) != -1 &&
+               !this.dragControl.handlers.drag.dragging &&
+               vertex.geometry.parent) {
+                // remove the vertex
+                vertex.geometry.parent.removeComponent(vertex.geometry);
+                this.layer.drawFeature(this.feature,
+                                       this.selectControl.renderIntent);
+                this.resetVertices();
+                this.setFeatureState();
+                this.onModification(this.feature);
+                this.layer.events.triggerEvent("featuremodified", 
+                                               {feature: this.feature});
+            }
+        }
+    },
+
+    /**
+     * Method: collectVertices
+     * Collect the vertices from the modifiable feature's geometry and push
+     *     them on to the control's vertices array.
+     */
+    collectVertices: function() {
+        this.vertices = [];
+        this.virtualVertices = [];        
+        var control = this;
+        function collectComponentVertices(geometry) {
+            var i, vertex, component, len;
+            if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                vertex = new OpenLayers.Feature.Vector(geometry);
+                vertex._sketch = true;
+                control.vertices.push(vertex);
+            } else {
+                var numVert = geometry.components.length;
+                if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
+                    numVert -= 1;
+                }
+                for(i=0; i<numVert; ++i) {
+                    component = geometry.components[i];
+                    if(component.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                        vertex = new OpenLayers.Feature.Vector(component);
+                        vertex._sketch = true;
+                        control.vertices.push(vertex);
+                    } else {
+                        collectComponentVertices(component);
+                    }
+                }
+                
+                // add virtual vertices in the middle of each edge
+                if(geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
+                    for(i=0, len=geometry.components.length; i<len-1; ++i) {
+                        var prevVertex = geometry.components[i];
+                        var nextVertex = geometry.components[i + 1];
+                        if(prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" &&
+                           nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") {
+                            var x = (prevVertex.x + nextVertex.x) / 2;
+                            var y = (prevVertex.y + nextVertex.y) / 2;
+                            var point = new OpenLayers.Feature.Vector(
+                                new OpenLayers.Geometry.Point(x, y),
+                                null, control.virtualStyle
+                            );
+                            // set the virtual parent and intended index
+                            point.geometry.parent = geometry;
+                            point._index = i + 1;
+                            point._sketch = true;
+                            control.virtualVertices.push(point);
+                        }
+                    }
+                }
+            }
+        }
+        collectComponentVertices.call(this, this.feature.geometry);
+        this.layer.addFeatures(this.virtualVertices, {silent: true});
+        this.layer.addFeatures(this.vertices, {silent: true});
+    },
+
+    /**
+     * Method: collectDragHandle
+     * Collect the drag handle for the selected geometry.
+     */
+    collectDragHandle: function() {
+        var geometry = this.feature.geometry;
+        var center = geometry.getBounds().getCenterLonLat();
+        var originGeometry = new OpenLayers.Geometry.Point(
+            center.lon, center.lat
+        );
+        var origin = new OpenLayers.Feature.Vector(originGeometry);
+        originGeometry.move = function(x, y) {
+            OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
+            geometry.move(x, y);
+        };
+        origin._sketch = true;
+        this.dragHandle = origin;
+        this.layer.addFeatures([this.dragHandle], {silent: true});
+    },
+
+    /**
+     * Method: collectRadiusHandle
+     * Collect the radius handle for the selected geometry.
+     */
+    collectRadiusHandle: function() {
+        var geometry = this.feature.geometry;
+        var bounds = geometry.getBounds();
+        var center = bounds.getCenterLonLat();
+        var originGeometry = new OpenLayers.Geometry.Point(
+            center.lon, center.lat
+        );
+        var radiusGeometry = new OpenLayers.Geometry.Point(
+            bounds.right, bounds.bottom
+        );
+        var radius = new OpenLayers.Feature.Vector(radiusGeometry);
+        var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
+        var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
+        var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
+
+        radiusGeometry.move = function(x, y) {
+            OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
+            var dx1 = this.x - originGeometry.x;
+            var dy1 = this.y - originGeometry.y;
+            var dx0 = dx1 - x;
+            var dy0 = dy1 - y;
+            if(rotate) {
+                var a0 = Math.atan2(dy0, dx0);
+                var a1 = Math.atan2(dy1, dx1);
+                var angle = a1 - a0;
+                angle *= 180 / Math.PI;
+                geometry.rotate(angle, originGeometry);
+            }
+            if(resize) {
+                var scale, ratio;
+                // 'resize' together with 'reshape' implies that the aspect 
+                // ratio of the geometry will not be preserved whilst resizing 
+                if (reshape) {
+                    scale = dy1 / dy0;
+                    ratio = (dx1 / dx0) / scale;
+                } else {
+                    var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0));
+                    var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
+                    scale = l1 / l0;
+                }
+                geometry.resize(scale, originGeometry, ratio);
+            }
+        };
+        radius._sketch = true;
+        this.radiusHandle = radius;
+        this.layer.addFeatures([this.radiusHandle], {silent: true});
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control and all handlers.
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>} The control's map.
+     */
+    setMap: function(map) {
+        this.selectControl.setMap(map);
+        this.dragControl.setMap(map);
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ModifyFeature"
+});
+
+/**
+ * Constant: RESHAPE
+ * {Integer} Constant used to make the control work in reshape mode
+ */
+OpenLayers.Control.ModifyFeature.RESHAPE = 1;
+/**
+ * Constant: RESIZE
+ * {Integer} Constant used to make the control work in resize mode
+ */
+OpenLayers.Control.ModifyFeature.RESIZE = 2;
+/**
+ * Constant: ROTATE
+ * {Integer} Constant used to make the control work in rotate mode
+ */
+OpenLayers.Control.ModifyFeature.ROTATE = 4;
+/**
+ * Constant: DRAG
+ * {Integer} Constant used to make the control work in drag mode
+ */
+OpenLayers.Control.ModifyFeature.DRAG = 8;

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseDefaults.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseDefaults.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseDefaults.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,367 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MouseDefaults
+ * This class is DEPRECATED in 2.4 and will be removed by 3.0.
+ * If you need this functionality, use <OpenLayers.Control.Navigation> 
+ * instead!!!
+ *
+ * This class is DEPRECATED in 2.4 and will be removed by 3.0.
+ *     If you need this functionality, use Control.Navigation instead!!!
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.MouseDefaults = OpenLayers.Class(OpenLayers.Control, {
+
+    /** WARNING WARNING WARNING!!!
+        This class is DEPRECATED in 2.4 and will be removed by 3.0.
+        If you need this functionality, use Control.Navigation instead!!! */
+
+    /** 
+     * Property: performedDrag
+     * {Boolean}
+     */
+    performedDrag: false,
+
+    /** 
+     * Property: wheelObserver 
+     * {Function}
+     */
+    wheelObserver: null,
+
+    /** 
+     * Constructor: OpenLayers.Control.MouseDefaults
+     */
+    initialize: function() {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: destroy
+     */    
+    destroy: function() {
+        
+        if (this.handler) {
+            this.handler.destroy();
+        }
+        this.handler = null;
+
+        this.map.events.un({
+            "click": this.defaultClick,
+            "dblclick": this.defaultDblClick,
+            "mousedown": this.defaultMouseDown,
+            "mouseup": this.defaultMouseUp,
+            "mousemove": this.defaultMouseMove,
+            "mouseout": this.defaultMouseOut,
+            scope: this
+        });
+
+        //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);        
+    },
+
+    /**
+     * Method: draw
+     */
+    draw: function() {
+        this.map.events.on({
+            "click": this.defaultClick,
+            "dblclick": this.defaultDblClick,
+            "mousedown": this.defaultMouseDown,
+            "mouseup": this.defaultMouseUp,
+            "mousemove": this.defaultMouseMove,
+            "mouseout": this.defaultMouseOut,
+            scope: this
+        });
+
+        this.registerWheelEvents();
+
+    },
+
+    /**
+     * Method: registerWheelEvents
+     */
+    registerWheelEvents: function() {
+
+        this.wheelObserver = OpenLayers.Function.bindAsEventListener(
+            this.onWheelEvent, this
+        );
+        
+        //register mousewheel events specifically on the window and document
+        OpenLayers.Event.observe(window, "DOMMouseScroll", this.wheelObserver);
+        OpenLayers.Event.observe(window, "mousewheel", this.wheelObserver);
+        OpenLayers.Event.observe(document, "mousewheel", this.wheelObserver);
+    },
+
+    /**
+     * Method: defaultClick
+     * 
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean}
+     */
+    defaultClick: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        var notAfterDrag = !this.performedDrag;
+        this.performedDrag = false;
+        return notAfterDrag;
+    },
+
+    /**
+     * Method: defaultDblClick
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultDblClick: function (evt) {
+        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
+        this.map.setCenter(newCenter, this.map.zoom + 1);
+        OpenLayers.Event.stop(evt);
+        return false;
+    },
+
+    /**
+     * Method: defaultMouseDown
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseDown: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        this.mouseDragStart = evt.xy.clone();
+        this.performedDrag  = false;
+        if (evt.shiftKey) {
+            this.map.div.style.cursor = "crosshair";
+            this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+                                                     this.mouseDragStart,
+                                                     null,
+                                                     null,
+                                                     "absolute",
+                                                     "2px solid red");
+            this.zoomBox.style.backgroundColor = "white";
+            this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
+            this.zoomBox.style.opacity = "0.50";
+            this.zoomBox.style.fontSize = "1px";
+            this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+            this.map.viewPortDiv.appendChild(this.zoomBox);
+        }
+        document.onselectstart=function() { return false; };
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: defaultMouseMove
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseMove: function (evt) {
+        // record the mouse position, used in onWheelEvent
+        this.mousePosition = evt.xy.clone();
+
+        if (this.mouseDragStart != null) {
+            if (this.zoomBox) {
+                var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
+                var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
+                this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+                this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+                if (evt.xy.x < this.mouseDragStart.x) {
+                    this.zoomBox.style.left = evt.xy.x+"px";
+                }
+                if (evt.xy.y < this.mouseDragStart.y) {
+                    this.zoomBox.style.top = evt.xy.y+"px";
+                }
+            } else {
+                var deltaX = this.mouseDragStart.x - evt.xy.x;
+                var deltaY = this.mouseDragStart.y - evt.xy.y;
+                var size = this.map.getSize();
+                var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
+                                                 size.h / 2 + deltaY);
+                var newCenter = this.map.getLonLatFromViewPortPx( newXY ); 
+                this.map.setCenter(newCenter, null, true);
+                this.mouseDragStart = evt.xy.clone();
+                this.map.div.style.cursor = "move";
+            }
+            this.performedDrag = true;
+        }
+    },
+
+    /**
+     * Method: defaultMouseUp
+     * 
+     * Parameters:
+     * evt - {<OpenLayers.Event>} 
+     */
+    defaultMouseUp: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        if (this.zoomBox) {
+            this.zoomBoxEnd(evt);    
+        } else {
+            if (this.performedDrag) {
+                this.map.setCenter(this.map.center);
+            }
+        }
+        document.onselectstart=null;
+        this.mouseDragStart = null;
+        this.map.div.style.cursor = "";
+    },
+
+    /**
+     * Method: defaultMouseOut
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseOut: function (evt) {
+        if (this.mouseDragStart != null && 
+            OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+            if (this.zoomBox) {
+                this.removeZoomBox();
+            }
+            this.mouseDragStart = null;
+        }
+    },
+
+
+    /** 
+     * Method: defaultWheelUp
+     * User spun scroll wheel up
+     * 
+     */
+    defaultWheelUp: function(evt) {
+        if (this.map.getZoom() <= this.map.getNumZoomLevels()) {
+            this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
+                               this.map.getZoom() + 1);
+        }
+    },
+
+    /**
+     * Method: defaultWheelDown
+     * User spun scroll wheel down
+     */
+    defaultWheelDown: function(evt) {
+        if (this.map.getZoom() > 0) {
+            this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
+                               this.map.getZoom() - 1);
+        }
+    },
+
+    /**
+     * Method: zoomBoxEnd
+     * Zoombox function. 
+     */
+    zoomBoxEnd: function(evt) {
+        if (this.mouseDragStart != null) {
+            if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||    
+                Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {   
+                var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart ); 
+                var end = this.map.getLonLatFromViewPortPx( evt.xy );
+                var top = Math.max(start.lat, end.lat);
+                var bottom = Math.min(start.lat, end.lat);
+                var left = Math.min(start.lon, end.lon);
+                var right = Math.max(start.lon, end.lon);
+                var bounds = new OpenLayers.Bounds(left, bottom, right, top);
+                this.map.zoomToExtent(bounds);
+            } else {
+                var end = this.map.getLonLatFromViewPortPx( evt.xy );
+                this.map.setCenter(new OpenLayers.LonLat(
+                  (end.lon),
+                  (end.lat)
+                 ), this.map.getZoom() + 1);
+            }    
+            this.removeZoomBox();
+       }
+    },
+
+    /**
+     * Method: removeZoomBox
+     * Remove the zoombox from the screen and nullify our reference to it.
+     */
+    removeZoomBox: function() {
+        this.map.viewPortDiv.removeChild(this.zoomBox);
+        this.zoomBox = null;
+    },
+
+
+/**
+ *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+ */
+
+
+    /**
+     * Method: onWheelEvent
+     * Catch the wheel event and handle it xbrowserly
+     *
+     * Parameters: 
+     * e - {Event} 
+     */
+    onWheelEvent: function(e){
+    
+        // first determine whether or not the wheeling was inside the map
+        var inMap = false;
+        var elem = OpenLayers.Event.element(e);
+        while(elem != null) {
+            if (this.map && elem == this.map.div) {
+                inMap = true;
+                break;
+            }
+            elem = elem.parentNode;
+        }
+        
+        if (inMap) {
+            
+            var delta = 0;
+            if (!e) {
+                e = window.event;
+            }
+            if (e.wheelDelta) {
+                delta = e.wheelDelta/120; 
+                if (window.opera && window.opera.version() < 9.2) {
+                    delta = -delta;
+                }
+            } else if (e.detail) {
+                delta = -e.detail / 3;
+            }
+            if (delta) {
+                // 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
+                e.xy = this.mousePosition;
+
+                if (delta < 0) {
+                   this.defaultWheelDown(e);
+                } else {
+                   this.defaultWheelUp(e);
+                }
+            }
+            
+            //only wheel the map, not the window
+            OpenLayers.Event.stop(e);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.MouseDefaults"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseToolbar.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseToolbar.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/MouseToolbar.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,405 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Control/MouseDefaults.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MouseToolbar
+ * This class is DEPRECATED in 2.4 and will be removed by 3.0.
+ * If you need this functionality, use <OpenLayers.Control.NavToolbar>
+ * instead!!! 
+ */
+OpenLayers.Control.MouseToolbar = OpenLayers.Class(
+                                            OpenLayers.Control.MouseDefaults, {
+    
+    /**
+     * Property: mode
+     */ 
+    mode: null,
+    /**
+     * Property: buttons
+     */
+    buttons: null,
+    
+    /**
+     * APIProperty: direction
+     * {String} 'vertical' or 'horizontal'
+     */
+    direction: "vertical",
+    
+    /**
+     * Property: buttonClicked
+     * {String}
+     */
+    buttonClicked: null,
+    
+    /**
+     * Constructor: OpenLayers.Control.MouseToolbar
+     *
+     * Parameters:
+     * position - {<OpenLayers.Pixel>}
+     * direction - {String}
+     */
+    initialize: function(position, direction) {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+        this.position = new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,
+                                             OpenLayers.Control.MouseToolbar.Y);
+        if (position) {
+            this.position = position;
+        }
+        if (direction) {
+            this.direction = direction; 
+        }
+        this.measureDivs = [];
+    },
+    
+    /**
+     * APIMethod: destroy 
+     */
+    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);
+    },
+    
+    /**
+     * Method: draw
+     */
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments); 
+        OpenLayers.Control.MouseDefaults.prototype.draw.apply(this, arguments);
+        this.buttons = {};
+        var sz = new OpenLayers.Size(28,28);
+        var centered = new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,0);
+        this._addButton("zoombox", "drag-rectangle-off.png", "drag-rectangle-on.png", centered, sz, "Shift->Drag to zoom to area");
+        centered = centered.add((this.direction == "vertical" ? 0 : sz.w), (this.direction == "vertical" ? sz.h : 0));
+        this._addButton("pan", "panning-hand-off.png", "panning-hand-on.png", centered, sz, "Drag the map to pan.");
+        centered = centered.add((this.direction == "vertical" ? 0 : sz.w), (this.direction == "vertical" ? sz.h : 0));
+        this.switchModeTo("pan");
+
+        return this.div;
+    },
+    
+    /**
+     * Method: _addButton
+     */
+    _addButton:function(id, img, activeImg, xy, sz, title) {
+        var imgLocation = OpenLayers.Util.getImagesLocation() + img;
+        var activeImgLocation = OpenLayers.Util.getImagesLocation() + activeImg;
+        // var btn = new ol.AlphaImage("_"+id, imgLocation, xy, sz);
+        var btn = OpenLayers.Util.createAlphaImageDiv(
+                                    "OpenLayers_Control_MouseToolbar_" + id, 
+                                    xy, sz, imgLocation, "absolute");
+
+        //we want to add the outer div
+        this.div.appendChild(btn);
+        btn.imgLocation = imgLocation;
+        btn.activeImgLocation = activeImgLocation;
+        
+        btn.events = new OpenLayers.Events(this, btn, null, true);
+        btn.events.on({
+            "mousedown": this.buttonDown,
+            "mouseup": this.buttonUp,
+            "dblclick": OpenLayers.Event.stop,
+            scope: this
+        });
+        btn.action = id;
+        btn.title = title;
+        btn.alt = title;
+        btn.map = this.map;
+
+        //we want to remember/reference the outer div
+        this.buttons[id] = btn;
+        return btn;
+    },
+
+    /**
+     * Method: buttonDown
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    buttonDown: function(evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        this.buttonClicked = evt.element.action;
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: buttonUp
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    buttonUp: function(evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        if (this.buttonClicked != null) {
+            if (this.buttonClicked == evt.element.action) {
+                this.switchModeTo(evt.element.action);
+            }
+            OpenLayers.Event.stop(evt);
+            this.buttonClicked = null;
+        }
+    },
+    
+    /**
+     * Method: defaultDblClick 
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultDblClick: function (evt) {
+        this.switchModeTo("pan");
+        this.performedDrag = false;
+        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
+        this.map.setCenter(newCenter, this.map.zoom + 1);
+        OpenLayers.Event.stop(evt);
+        return false;
+    },
+
+    /**
+     * Method: defaultMouseDown
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseDown: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        this.mouseDragStart = evt.xy.clone();
+        this.performedDrag = false;
+        this.startViaKeyboard = false;
+        if (evt.shiftKey && this.mode !="zoombox") {
+            this.switchModeTo("zoombox");
+            this.startViaKeyboard = true;
+        } else if (evt.altKey && this.mode !="measure") {
+            this.switchModeTo("measure");
+        } else if (!this.mode) {
+            this.switchModeTo("pan");
+        }
+        
+        switch (this.mode) {
+            case "zoombox":
+                this.map.div.style.cursor = "crosshair";
+                this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+                                                         this.mouseDragStart,
+                                                         null,
+                                                         null,
+                                                         "absolute",
+                                                         "2px solid red");
+                this.zoomBox.style.backgroundColor = "white";
+                this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
+                this.zoomBox.style.opacity = "0.50";
+                this.zoomBox.style.fontSize = "1px";
+                this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+                this.map.viewPortDiv.appendChild(this.zoomBox);
+                this.performedDrag = true;
+                break;
+            case "measure":
+                var distance = "";
+                if (this.measureStart) {
+                    var measureEnd = this.map.getLonLatFromViewPortPx(this.mouseDragStart);
+                    distance = OpenLayers.Util.distVincenty(this.measureStart, measureEnd);
+                    distance = Math.round(distance * 100) / 100;
+                    distance = distance + "km";
+                    this.measureStartBox = this.measureBox;
+                }    
+                this.measureStart = this.map.getLonLatFromViewPortPx(this.mouseDragStart);;
+                this.measureBox = OpenLayers.Util.createDiv(null,
+                                                         this.mouseDragStart.add(
+                                                           -2-parseInt(this.map.layerContainerDiv.style.left),
+                                                           -2-parseInt(this.map.layerContainerDiv.style.top)),
+                                                         null,
+                                                         null,
+                                                         "absolute");
+                this.measureBox.style.width="4px";
+                this.measureBox.style.height="4px";
+                this.measureBox.style.fontSize = "1px";
+                this.measureBox.style.backgroundColor="red";
+                this.measureBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+                this.map.layerContainerDiv.appendChild(this.measureBox);
+                if (distance) {
+                    this.measureBoxDistance = OpenLayers.Util.createDiv(null,
+                                                         this.mouseDragStart.add(
+                                                           -2-parseInt(this.map.layerContainerDiv.style.left),
+                                                           2-parseInt(this.map.layerContainerDiv.style.top)),
+                                                         null,
+                                                         null,
+                                                         "absolute");
+                    
+                    this.measureBoxDistance.innerHTML = distance;
+                    this.measureBoxDistance.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+                    this.map.layerContainerDiv.appendChild(this.measureBoxDistance);
+                    this.measureDivs.push(this.measureBoxDistance);
+                }
+                this.measureBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+                this.map.layerContainerDiv.appendChild(this.measureBox);
+                this.measureDivs.push(this.measureBox);
+                break;
+            default:
+                this.map.div.style.cursor = "move";
+                break;
+        }
+        document.onselectstart = function() { return false; };
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: switchModeTo 
+     *
+     * Parameters:
+     * mode - {String} 
+     */
+    switchModeTo: function(mode) {
+        if (mode != this.mode) {
+            
+
+            if (this.mode && this.buttons[this.mode]) {
+                OpenLayers.Util.modifyAlphaImageDiv(this.buttons[this.mode], null, null, null, this.buttons[this.mode].imgLocation);
+            }
+            if (this.mode == "measure" && mode != "measure") {
+                for(var i=0, len=this.measureDivs.length; i<len; i++) {
+                    if (this.measureDivs[i]) { 
+                        this.map.layerContainerDiv.removeChild(this.measureDivs[i]);
+                    }
+                }
+                this.measureDivs = [];
+                this.measureStart = null;
+            }
+            this.mode = mode;
+            if (this.buttons[mode]) {
+                OpenLayers.Util.modifyAlphaImageDiv(this.buttons[mode], null, null, null, this.buttons[mode].activeImgLocation);
+            }
+            switch (this.mode) {
+                case "zoombox":
+                    this.map.div.style.cursor = "crosshair";
+                    break;
+                default:
+                    this.map.div.style.cursor = "";
+                    break;
+            }
+
+        } 
+    }, 
+
+    /**
+     * Method: leaveMode
+     */
+    leaveMode: function() {
+        this.switchModeTo("pan");
+    },
+    
+    /**
+     * Method: defaultMouseMove
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseMove: function (evt) {
+        if (this.mouseDragStart != null) {
+            switch (this.mode) {
+                case "zoombox": 
+                    var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
+                    var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
+                    this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+                    this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+                    if (evt.xy.x < this.mouseDragStart.x) {
+                        this.zoomBox.style.left = evt.xy.x+"px";
+                    }
+                    if (evt.xy.y < this.mouseDragStart.y) {
+                        this.zoomBox.style.top = evt.xy.y+"px";
+                    }
+                    break;
+                default:
+                    var deltaX = this.mouseDragStart.x - evt.xy.x;
+                    var deltaY = this.mouseDragStart.y - evt.xy.y;
+                    var size = this.map.getSize();
+                    var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
+                                                     size.h / 2 + deltaY);
+                    var newCenter = this.map.getLonLatFromViewPortPx( newXY ); 
+                    this.map.setCenter(newCenter, null, true);
+                    this.mouseDragStart = evt.xy.clone();
+            }
+            this.performedDrag = true;
+        }
+    },
+
+    /**
+     * Method: defaultMouseUp
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseUp: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) {
+            return;
+        }
+        switch (this.mode) {
+            case "zoombox":
+                this.zoomBoxEnd(evt);
+                if (this.startViaKeyboard) {
+                    this.leaveMode();
+                }
+                break;
+            case "pan":
+                if (this.performedDrag) {
+                    this.map.setCenter(this.map.center);
+                }        
+        }
+        document.onselectstart = null;
+        this.mouseDragStart = null;
+        this.map.div.style.cursor = "default";
+    },
+
+    /**
+     * Method: defaultMouseOut
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultMouseOut: function (evt) {
+        if (this.mouseDragStart != null
+            && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+            if (this.zoomBox) {
+                this.removeZoomBox();
+                if (this.startViaKeyboard) {
+                    this.leaveMode();
+                }
+            }
+            this.mouseDragStart = null;
+            this.map.div.style.cursor = "default";
+        }
+    },
+
+    /**
+     * Method: defaultClick
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultClick: function (evt) {
+        if (this.performedDrag)  {
+            this.performedDrag = false;
+            return false;
+        }
+    },
+    
+    CLASS_NAME: "OpenLayers.Control.MouseToolbar"
+});
+
+OpenLayers.Control.MouseToolbar.X = 6;
+OpenLayers.Control.MouseToolbar.Y = 300;

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavToolbar.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavToolbar.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavToolbar.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,54 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/Panel.js
+ * @requires OpenLayers/Control/Navigation.js
+ * @requires OpenLayers/Control/ZoomBox.js
+ */
+
+/**
+ * Class: OpenLayers.Control.NavToolbar
+ * This Toolbar is an alternative to the Navigation control that displays
+ *     the state of the control, and provides a UI for changing state to
+ *     use the zoomBox via a Panel control.
+ *
+ * If you wish to change the properties of the Navigation control used
+ *     in the NavToolbar, see: 
+ *     http://trac.openlayers.org/wiki/Toolbars#SubclassingNavToolbar 
+ * 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control.Panel>
+ */
+OpenLayers.Control.NavToolbar = OpenLayers.Class(OpenLayers.Control.Panel, {
+
+    /**
+     * Constructor: OpenLayers.Control.NavToolbar 
+     * Add our two mousedefaults controls.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);
+        this.addControls([
+          new OpenLayers.Control.Navigation(),
+          new OpenLayers.Control.ZoomBox()
+        ]);
+    },
+
+    /**
+     * Method: draw 
+     * calls the default draw, and then activates mouse defaults.
+     */
+    draw: function() {
+        var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments);
+        this.activateControl(this.controls[0]);
+        return div;
+    },
+
+    CLASS_NAME: "OpenLayers.Control.NavToolbar"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavigationHistory.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavigationHistory.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/NavigationHistory.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,399 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Control/Button.js
+ */
+
+/**
+ * Class: OpenLayers.Control.NavigationHistory
+ * A navigation history control.  This is a meta-control, that creates two
+ *     dependent controls: <previous> and <next>.  Call the trigger method
+ *     on the <previous> and <next> controls to restore previous and next
+ *     history states.  The previous and next controls will become active
+ *     when there are available states to restore and will become deactive
+ *     when there are no states to restore.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: type
+     * {String} Note that this control is not intended to be added directly
+     *     to a control panel.  Instead, add the sub-controls previous and
+     *     next.  These sub-controls are button type controls that activate
+     *     and deactivate themselves.  If this parent control is added to
+     *     a panel, it will act as a toggle.
+     */
+    type: OpenLayers.Control.TYPE_TOGGLE,
+
+    /**
+     * APIProperty: previous
+     * {<OpenLayers.Control>} A button type control whose trigger method restores
+     *     the previous state managed by this control.
+     */
+    previous: null,
+    
+    /**
+     * APIProperty: previousOptions
+     * {Object} Set this property on the options argument of the constructor
+     *     to set optional properties on the <previous> control.
+     */
+    previousOptions: null,
+    
+    /**
+     * APIProperty: next
+     * {<OpenLayers.Control>} A button type control whose trigger method restores
+     *     the next state managed by this control.
+     */
+    next: null,
+
+    /**
+     * APIProperty: nextOptions
+     * {Object} Set this property on the options argument of the constructor
+     *     to set optional properties on the <next> control.
+     */
+    nextOptions: null,
+
+    /**
+     * APIProperty: limit
+     * {Integer} Optional limit on the number of history items to retain.  If
+     *     null, there is no limit.  Default is 50.
+     */
+    limit: 50,
+
+    /**
+     * Property: activateOnDraw
+     * {Boolean} Activate the control when it is first added to the map.
+     *     Default is true.
+     */
+    activateOnDraw: true,
+
+    /**
+     * Property: clearOnDeactivate
+     * {Boolean} Clear the history when the control is deactivated.  Default
+     *     is false.
+     */
+    clearOnDeactivate: false,
+
+    /**
+     * Property: registry
+     * {Object} An object with keys corresponding to event types.  Values
+     *     are functions that return an object representing the current state.
+     */
+    registry: null,
+
+    /**
+     * Property: nextStack
+     * {Array} Array of items in the history.
+     */
+    nextStack: null,
+
+    /**
+     * Property: previousStack
+     * {Array} List of items in the history.  First item represents the current
+     *     state.
+     */
+    previousStack: null,
+    
+    /**
+     * Property: listeners
+     * {Object} An object containing properties corresponding to event types.
+     *     This object is used to configure the control and is modified on
+     *     construction.
+     */
+    listeners: null,
+    
+    /**
+     * Property: restoring
+     * {Boolean} Currently restoring a history state.  This is set to true
+     *     before calling restore and set to false after restore returns.
+     */
+    restoring: false,
+    
+    /**
+     * Constructor: OpenLayers.Control.NavigationHistory 
+     * 
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        
+        this.registry = OpenLayers.Util.extend({
+            "moveend": function() {
+                return {
+                    center: this.map.getCenter(),
+                    resolution: this.map.getResolution()                
+                };
+            }
+        }, this.registry);
+        
+        this.clear();
+
+        var previousOptions = {
+            trigger: OpenLayers.Function.bind(this.previousTrigger, this),
+            displayClass: this.displayClass + " " + this.displayClass + "Previous"
+        };
+        OpenLayers.Util.extend(previousOptions, this.previousOptions);
+        this.previous = new OpenLayers.Control.Button(previousOptions);
+        
+        var nextOptions = {
+            trigger: OpenLayers.Function.bind(this.nextTrigger, this),
+            displayClass: this.displayClass + " " + this.displayClass + "Next"
+        };
+        OpenLayers.Util.extend(nextOptions, this.nextOptions);
+        this.next = new OpenLayers.Control.Button(nextOptions);
+
+    },
+    
+    /**
+     * Method: onPreviousChange
+     * Called when the previous history stack changes.
+     *
+     * Parameters:
+     * state - {Object} An object representing the state to be restored
+     *     if previous is triggered again or null if no previous states remain.
+     * length - {Integer} The number of remaining previous states that can
+     *     be restored.
+     */
+    onPreviousChange: function(state, length) {
+        if(state && !this.previous.active) {
+            this.previous.activate();
+        } else if(!state && this.previous.active) {
+            this.previous.deactivate();
+        }
+    },
+    
+    /**
+     * Method: onNextChange
+     * Called when the next history stack changes.
+     *
+     * Parameters:
+     * state - {Object} An object representing the state to be restored
+     *     if next is triggered again or null if no next states remain.
+     * length - {Integer} The number of remaining next states that can
+     *     be restored.
+     */
+    onNextChange: function(state, length) {
+        if(state && !this.next.active) {
+            this.next.activate();
+        } else if(!state && this.next.active) {
+            this.next.deactivate();
+        }
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Destroy the control.
+     */
+    destroy: function() {
+        OpenLayers.Control.prototype.destroy.apply(this);
+        this.previous.destroy();
+        this.next.destroy();
+        this.deactivate();
+        for(var prop in this) {
+            this[prop] = null;
+        }
+    },
+    
+    /** 
+     * Method: setMap
+     * Set the map property for the control and <previous> and <next> child
+     *     controls.
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        this.map = map;
+        this.next.setMap(map);
+        this.previous.setMap(map);
+    },
+
+    /**
+     * Method: draw
+     * Called when the control is added to the map.
+     */
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        this.next.draw();
+        this.previous.draw();
+        if(this.activateOnDraw) {
+            this.activate();
+        }
+    },
+    
+    /**
+     * Method: previousTrigger
+     * Restore the previous state.  If no items are in the previous history
+     *     stack, this has no effect.
+     *
+     * Returns:
+     * {Object} Item representing state that was restored.  Undefined if no
+     *     items are in the previous history stack.
+     */
+    previousTrigger: function() {
+        var current = this.previousStack.shift();
+        var state = this.previousStack.shift();
+        if(state != undefined) {
+            this.nextStack.unshift(current);
+            this.previousStack.unshift(state);
+            this.restoring = true;
+            this.restore(state);
+            this.restoring = false;
+            this.onNextChange(this.nextStack[0], this.nextStack.length);
+            this.onPreviousChange(
+                this.previousStack[1], this.previousStack.length - 1
+            );
+        } else {
+            this.previousStack.unshift(current);
+        }
+        return state;
+    },
+    
+    /**
+     * APIMethod: nextTrigger
+     * Restore the next state.  If no items are in the next history
+     *     stack, this has no effect.  The next history stack is populated
+     *     as states are restored from the previous history stack.
+     *
+     * Returns:
+     * {Object} Item representing state that was restored.  Undefined if no
+     *     items are in the next history stack.
+     */
+    nextTrigger: function() {
+        var state = this.nextStack.shift();
+        if(state != undefined) {
+            this.previousStack.unshift(state);
+            this.restoring = true;
+            this.restore(state);
+            this.restoring = false;
+            this.onNextChange(this.nextStack[0], this.nextStack.length);
+            this.onPreviousChange(
+                this.previousStack[1], this.previousStack.length - 1
+            );
+        }
+        return state;
+    },
+    
+    /**
+     * APIMethod: clear
+     * Clear history.
+     */
+    clear: function() {
+        this.previousStack = [];
+        this.nextStack = [];
+    },
+
+    /**
+     * Method: restore
+     * Update the state with the given object.
+     *
+     * Parameters:
+     * state - {Object} An object representing the state to restore.
+     */
+    restore: function(state) {
+        var zoom = this.map.getZoomForResolution(state.resolution);
+        this.map.setCenter(state.center, zoom);
+    },
+    
+    /**
+     * Method: setListeners
+     * Sets functions to be registered in the listeners object.
+     */
+    setListeners: function() {
+        this.listeners = {};
+        for(var type in this.registry) {
+            this.listeners[type] = OpenLayers.Function.bind(function() {
+                if(!this.restoring) {
+                    var state = this.registry[type].apply(this, arguments);
+                    this.previousStack.unshift(state);
+                    if(this.previousStack.length > 1) {
+                        this.onPreviousChange(
+                            this.previousStack[1], this.previousStack.length - 1
+                        );
+                    }
+                    if(this.previousStack.length > (this.limit + 1)) {
+                        this.previousStack.pop();
+                    }
+                    if(this.nextStack.length > 0) {
+                        this.nextStack = [];
+                        this.onNextChange(null, 0);
+                    }
+                }
+                return true;
+            }, this);
+        }
+    },
+
+    /**
+     * APIMethod: activate
+     * Activate the control.  This registers any listeners.
+     *
+     * Returns:
+     * {Boolean} Control successfully activated.
+     */
+    activate: function() {
+        var activated = false;
+        if(this.map) {
+            if(OpenLayers.Control.prototype.activate.apply(this)) {
+                if(this.listeners == null) {
+                    this.setListeners();
+                }
+                for(var type in this.listeners) {
+                    this.map.events.register(type, this, this.listeners[type]);
+                }
+                activated = true;
+                if(this.previousStack.length == 0) {
+                    this.initStack();
+                }
+            }
+        }
+        return activated;
+    },
+    
+    /**
+     * Method: initStack
+     * Called after the control is activated if the previous history stack is
+     *     empty.
+     */
+    initStack: function() {
+        if(this.map.getCenter()) {
+            this.listeners.moveend();
+        }
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control.  This unregisters any listeners.
+     *
+     * Returns:
+     * {Boolean} Control successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(this.map) {
+            if(OpenLayers.Control.prototype.deactivate.apply(this)) {
+                for(var type in this.listeners) {
+                    this.map.events.unregister(
+                        type, this, this.listeners[type]
+                    );
+                }
+                if(this.clearOnDeactivate) {
+                    this.clear();
+                }
+                deactivated = true;
+            }
+        }
+        return deactivated;
+    },
+    
+    CLASS_NAME: "OpenLayers.Control.NavigationHistory"
+});
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/OverviewMap.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/OverviewMap.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/OverviewMap.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,700 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/** 
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Control.OverviewMap
+ * The OverMap control creates a small overview map, useful to display the 
+ * extent of a zoomed map and your main map and provide additional 
+ * navigation options to the User.  By default the overview map is drawn in
+ * the lower right corner of the main map. Create a new overview map with the
+ * <OpenLayers.Control.OverviewMap> constructor.
+ *
+ * Inerits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: element
+     * {DOMElement} The DOM element that contains the overview map
+     */
+    element: null,
+    
+    /**
+     * APIProperty: ovmap
+     * {<OpenLayers.Map>} A reference to the overview map itself.
+     */
+    ovmap: null,
+
+    /**
+     * APIProperty: size
+     * {<OpenLayers.Size>} The overvew map size in pixels.  Note that this is
+     * the size of the map itself - the element that contains the map (default
+     * class name olControlOverviewMapElement) may have padding or other style
+     * attributes added via CSS.
+     */
+    size: new OpenLayers.Size(180, 90),
+
+    /**
+     * APIProperty: layers
+     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
+     * If none are sent at construction, the base layer for the main map is used.
+     */
+    layers: null,
+    
+    /**
+     * APIProperty: minRectSize
+     * {Integer} The minimum width or height (in pixels) of the extent
+     *     rectangle on the overview map.  When the extent rectangle reaches
+     *     this size, it will be replaced depending on the value of the
+     *     <minRectDisplayClass> property.  Default is 15 pixels.
+     */
+    minRectSize: 15,
+    
+    /**
+     * APIProperty: minRectDisplayClass
+     * {String} Replacement style class name for the extent rectangle when
+     *     <minRectSize> is reached.  This string will be suffixed on to the
+     *     displayClass.  Default is "RectReplacement".
+     *
+     * Example CSS declaration:
+     * (code)
+     * .olControlOverviewMapRectReplacement {
+     *     overflow: hidden;
+     *     cursor: move;
+     *     background-image: url("img/overview_replacement.gif");
+     *     background-repeat: no-repeat;
+     *     background-position: center;
+     * }
+     * (end)
+     */
+    minRectDisplayClass: "RectReplacement",
+
+    /**
+     * APIProperty: minRatio
+     * {Float} The ratio of the overview map resolution to the main map
+     *     resolution at which to zoom farther out on the overview map.
+     */
+    minRatio: 8,
+
+    /**
+     * APIProperty: maxRatio
+     * {Float} The ratio of the overview map resolution to the main map
+     *     resolution at which to zoom farther in on the overview map.
+     */
+    maxRatio: 32,
+    
+    /**
+     * APIProperty: mapOptions
+     * {Object} An object containing any non-default properties to be sent to
+     *     the overview map's map constructor.  These should include any
+     *     non-default options that the main map was constructed with.
+     */
+    mapOptions: null,
+
+    /**
+     * APIProperty: autoPan
+     * {Boolean} Always pan the overview map, so the extent marker remains in
+     *     the center.  Default is false.  If true, when you drag the extent
+     *     marker, the overview map will update itself so the marker returns
+     *     to the center.
+     */
+    autoPan: false,
+    
+    /**
+     * Property: handlers
+     * {Object}
+     */
+    handlers: null,
+
+    /**
+     * Property: resolutionFactor
+     * {Object}
+     */
+    resolutionFactor: 1,
+
+    /**
+     * Constructor: OpenLayers.Control.OverviewMap
+     * Create a new overview map
+     *
+     * Parameters:
+     * object - {Object} Properties of this object will be set on the overview
+     * map object.  Note, to set options on the map object contained in this
+     * control, set <mapOptions> as one of the options properties.
+     */
+    initialize: function(options) {
+        this.layers = [];
+        this.handlers = {};
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Deconstruct the control
+     */
+    destroy: function() {
+        if (!this.mapDiv) { // we've already been destroyed
+            return;
+        }
+        this.handlers.click.destroy();
+
+        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.div.removeChild(this.element);
+        this.element = 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.un({
+            "moveend": this.update,
+            "changebaselayer": this.baseLayerDraw,
+            scope: this
+        });
+
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);    
+    },
+
+    /**
+     * Method: draw
+     * Render the control in the browser.
+     */    
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        if(!(this.layers.length > 0)) {
+            if (this.map.baseLayer) {
+                var layer = this.map.baseLayer.clone();
+                this.layers = [layer];
+            } else {
+                this.map.events.register("changebaselayer", this, this.baseLayerDraw);
+                return this.div;
+            }
+        }
+
+        // create overview map DOM elements
+        this.element = document.createElement('div');
+        this.element.className = this.displayClass + 'Element';
+        this.element.style.display = 'none';
+
+        this.mapDiv = document.createElement('div');
+        this.mapDiv.style.width = this.size.w + 'px';
+        this.mapDiv.style.height = this.size.h + 'px';
+        this.mapDiv.style.position = 'relative';
+        this.mapDiv.style.overflow = 'hidden';
+        this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
+        
+        this.extentRectangle = document.createElement('div');
+        this.extentRectangle.style.position = 'absolute';
+        this.extentRectangle.style.zIndex = 1000;  //HACK
+        this.extentRectangle.className = this.displayClass+'ExtentRectangle';
+        this.mapDiv.appendChild(this.extentRectangle);
+
+        this.element.appendChild(this.mapDiv);  
+
+        this.div.appendChild(this.element);
+
+        // Optionally add min/max buttons if the control will go in the
+        // map viewport.
+        if(!this.outsideViewport) {
+            this.div.className += " " + this.displayClass + 'Container';
+            var imgLocation = OpenLayers.Util.getImagesLocation();
+            // maximize button div
+            var img = imgLocation + 'layer-switcher-maximize.png';
+            this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                        this.displayClass + 'MaximizeButton', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
+                                        'absolute');
+            this.maximizeDiv.style.display = 'none';
+            this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
+            OpenLayers.Event.observe(this.maximizeDiv, 'click', 
+                OpenLayers.Function.bindAsEventListener(this.maximizeControl,
+                                                        this)
+            );
+            this.div.appendChild(this.maximizeDiv);
+    
+            // minimize button div
+            var img = imgLocation + 'layer-switcher-minimize.png';
+            this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                        'OpenLayers_Control_minimizeDiv', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
+                                        'absolute');
+            this.minimizeDiv.style.display = 'none';
+            this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
+            OpenLayers.Event.observe(this.minimizeDiv, 'click', 
+                OpenLayers.Function.bindAsEventListener(this.minimizeControl,
+                                                        this)
+            );
+            this.div.appendChild(this.minimizeDiv);
+            
+            var eventsToStop = ['dblclick','mousedown'];
+            
+            for (var i=0, len=eventsToStop.length; i<len; i++) {
+
+                OpenLayers.Event.observe(this.maximizeDiv, 
+                                         eventsToStop[i], 
+                                         OpenLayers.Event.stop);
+
+                OpenLayers.Event.observe(this.minimizeDiv,
+                                         eventsToStop[i], 
+                                         OpenLayers.Event.stop);
+            }
+            
+            this.minimizeControl();
+        } else {
+            // show the overview map
+            this.element.style.display = '';
+        }
+        if(this.map.getExtent()) {
+            this.update();
+        }
+        
+        this.map.events.register('moveend', this, this.update);
+
+        return this.div;
+    },
+    
+    /**
+     * Method: baseLayerDraw
+     * Draw the base layer - called if unable to complete in the initial draw
+     */
+    baseLayerDraw: function() {
+        this.draw();
+        this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
+    },
+
+    /**
+     * Method: rectDrag
+     * Handle extent rectangle drag
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} The pixel location of the drag.
+     */
+    rectDrag: function(px) {
+        var deltaX = this.handlers.drag.last.x - px.x;
+        var deltaY = this.handlers.drag.last.y - px.y;
+        if(deltaX != 0 || deltaY != 0) {
+            var rectTop = this.rectPxBounds.top;
+            var rectLeft = this.rectPxBounds.left;
+            var rectHeight = Math.abs(this.rectPxBounds.getHeight());
+            var rectWidth = this.rectPxBounds.getWidth();
+            // don't allow dragging off of parent element
+            var newTop = Math.max(0, (rectTop - deltaY));
+            newTop = Math.min(newTop,
+                              this.ovmap.size.h - this.hComp - rectHeight);
+            var newLeft = Math.max(0, (rectLeft - deltaX));
+            newLeft = Math.min(newLeft,
+                               this.ovmap.size.w - this.wComp - rectWidth);
+            this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+                                                       newTop + rectHeight,
+                                                       newLeft + rectWidth,
+                                                       newTop));
+        }
+    },
+    
+    /**
+     * Method: mapDivClick
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    mapDivClick: function(evt) {
+        var pxCenter = this.rectPxBounds.getCenterPixel();
+        var deltaX = evt.xy.x - pxCenter.x;
+        var deltaY = evt.xy.y - pxCenter.y;
+        var top = this.rectPxBounds.top;
+        var left = this.rectPxBounds.left;
+        var height = Math.abs(this.rectPxBounds.getHeight());
+        var width = this.rectPxBounds.getWidth();
+        var newTop = Math.max(0, (top + deltaY));
+        newTop = Math.min(newTop, this.ovmap.size.h - height);
+        var newLeft = Math.max(0, (left + deltaX));
+        newLeft = Math.min(newLeft, this.ovmap.size.w - width);
+        this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+                                                   newTop + height,
+                                                   newLeft + width,
+                                                   newTop));
+        this.updateMapToRect();
+    },
+
+    /**
+     * Method: maximizeControl
+     * Unhide the control.  Called when the control is in the map viewport.
+     *
+     * Parameters:
+     * e - {<OpenLayers.Event>}
+     */
+    maximizeControl: function(e) {
+        this.element.style.display = '';
+        this.showToggle(false);
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+
+    /**
+     * Method: minimizeControl
+     * Hide all the contents of the control, shrink the size, 
+     * add the maximize icon
+     * 
+     * Parameters:
+     * e - {<OpenLayers.Event>}
+     */
+    minimizeControl: function(e) {
+        this.element.style.display = 'none';
+        this.showToggle(true);
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+
+    /**
+     * Method: showToggle
+     * Hide/Show the toggle depending on whether the control is minimized
+     *
+     * Parameters:
+     * minimize - {Boolean} 
+     */
+    showToggle: function(minimize) {
+        this.maximizeDiv.style.display = minimize ? '' : 'none';
+        this.minimizeDiv.style.display = minimize ? 'none' : '';
+    },
+
+    /**
+     * Method: update
+     * Update the overview map after layers move.
+     */
+    update: function() {
+        if(this.ovmap == null) {
+            this.createMap();
+        }
+        
+        if(this.autoPan || !this.isSuitableOverview()) {
+            this.updateOverview();
+        }
+        
+        // update extent rectangle
+        this.updateRectToMap();
+    },
+    
+    /**
+     * Method: isSuitableOverview
+     * Determines if the overview map is suitable given the extent and
+     * resolution of the main map.
+     */
+    isSuitableOverview: function() {
+        var mapExtent = this.map.getExtent();
+        var maxExtent = this.map.maxExtent;
+        var testExtent = new OpenLayers.Bounds(
+                                Math.max(mapExtent.left, maxExtent.left),
+                                Math.max(mapExtent.bottom, maxExtent.bottom),
+                                Math.min(mapExtent.right, maxExtent.right),
+                                Math.min(mapExtent.top, maxExtent.top));        
+
+        if (this.ovmap.getProjection() != this.map.getProjection()) {
+            testExtent = testExtent.transform(
+                this.map.getProjectionObject(),
+                this.ovmap.getProjectionObject() );
+        }
+
+        var resRatio = this.ovmap.getResolution() / this.map.getResolution();
+        return ((resRatio > this.minRatio) &&
+                (resRatio <= this.maxRatio) &&
+                (this.ovmap.getExtent().containsBounds(testExtent)));
+    },
+    
+    /**
+     * Method updateOverview
+     * Called by <update> if <isSuitableOverview> returns true
+     */
+    updateOverview: function() {
+        var mapRes = this.map.getResolution();
+        var targetRes = this.ovmap.getResolution();
+        var resRatio = targetRes / mapRes;
+        if(resRatio > this.maxRatio) {
+            // zoom in overview map
+            targetRes = this.minRatio * mapRes;            
+        } else if(resRatio <= this.minRatio) {
+            // zoom out overview map
+            targetRes = this.maxRatio * mapRes;
+        }
+        var center;
+        if (this.ovmap.getProjection() != this.map.getProjection()) {
+            center = this.map.center.clone();
+            center.transform(this.map.getProjectionObject(),
+                this.ovmap.getProjectionObject() );
+        } else {
+            center = this.map.center;
+        }
+        this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
+            targetRes * this.resolutionFactor));
+        this.updateRectToMap();
+    },
+    
+    /**
+     * Method: createMap
+     * Construct the map that this control contains
+     */
+    createMap: function() {
+        // create the overview map
+        var options = OpenLayers.Util.extend(
+                        {controls: [], maxResolution: 'auto', 
+                         fallThrough: false}, this.mapOptions);
+        this.ovmap = new OpenLayers.Map(this.mapDiv, options);
+        
+        // prevent ovmap from being destroyed when the page unloads, because
+        // the OverviewMap control has to do this (and does it).
+        OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
+        
+        this.ovmap.addLayers(this.layers);
+        this.ovmap.zoomToMaxExtent();
+        // check extent rectangle border width
+        this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-left-width')) +
+                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-right-width'));
+        this.wComp = (this.wComp) ? this.wComp : 2;
+        this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-top-width')) +
+                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-bottom-width'));
+        this.hComp = (this.hComp) ? this.hComp : 2;
+
+        this.handlers.drag = new OpenLayers.Handler.Drag(
+            this, {move: this.rectDrag, done: this.updateMapToRect},
+            {map: this.ovmap}
+        );
+        this.handlers.click = new OpenLayers.Handler.Click(
+            this, {
+                "click": this.mapDivClick
+            },{
+                "single": true, "double": false,
+                "stopSingle": true, "stopDouble": true,
+                "pixelTolerance": 1,
+                map: this.ovmap
+            }
+        );
+        this.handlers.click.activate();
+        
+        this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
+                                                null, true);
+        this.rectEvents.register("mouseover", this, function(e) {
+            if(!this.handlers.drag.active && !this.map.dragging) {
+                this.handlers.drag.activate();
+            }
+        });
+        this.rectEvents.register("mouseout", this, function(e) {
+            if(!this.handlers.drag.dragging) {
+                this.handlers.drag.deactivate();
+            }
+        });
+
+        if (this.ovmap.getProjection() != this.map.getProjection()) {
+            var sourceUnits = this.map.getProjectionObject().getUnits() ||
+                this.map.units || this.map.baseLayer.units;
+            var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
+                this.ovmap.units || this.ovmap.baseLayer.units;
+            this.resolutionFactor = sourceUnits && targetUnits ?
+                OpenLayers.INCHES_PER_UNIT[sourceUnits] /
+                OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
+        }
+    },
+        
+    /**
+     * Method: updateRectToMap
+     * Updates the extent rectangle position and size to match the map extent
+     */
+    updateRectToMap: function() {
+        // If the projections differ we need to reproject
+        var bounds;
+        if (this.ovmap.getProjection() != this.map.getProjection()) {
+            bounds = this.map.getExtent().transform(
+                this.map.getProjectionObject(), 
+                this.ovmap.getProjectionObject() );
+        } else {
+            bounds = this.map.getExtent();
+        }
+        var pxBounds = this.getRectBoundsFromMapBounds(bounds);
+        if (pxBounds) {
+            this.setRectPxBounds(pxBounds);
+        }
+    },
+    
+    /**
+     * Method: updateMapToRect
+     * Updates the map extent to match the extent rectangle position and size
+     */
+    updateMapToRect: function() {
+        var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
+        if (this.ovmap.getProjection() != this.map.getProjection()) {
+            lonLatBounds = lonLatBounds.transform(
+                this.ovmap.getProjectionObject(),
+                this.map.getProjectionObject() );
+        }
+        this.map.panTo(lonLatBounds.getCenterLonLat());
+    },
+
+    /**
+     * Method: setRectPxBounds
+     * Set extent rectangle pixel bounds.
+     *
+     * Parameters:
+     * pxBounds - {<OpenLayers.Bounds>}
+     */
+    setRectPxBounds: function(pxBounds) {
+        var top = Math.max(pxBounds.top, 0);
+        var left = Math.max(pxBounds.left, 0);
+        var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
+                              this.ovmap.size.h - this.hComp);
+        var right = Math.min(pxBounds.left + pxBounds.getWidth(),
+                             this.ovmap.size.w - this.wComp);
+        var width = Math.max(right - left, 0);
+        var height = Math.max(bottom - top, 0);
+        if(width < this.minRectSize || height < this.minRectSize) {
+            this.extentRectangle.className = this.displayClass +
+                                             this.minRectDisplayClass;
+            var rLeft = left + (width / 2) - (this.minRectSize / 2);
+            var rTop = top + (height / 2) - (this.minRectSize / 2);
+            this.extentRectangle.style.top = Math.round(rTop) + 'px';
+            this.extentRectangle.style.left = Math.round(rLeft) + 'px';
+            this.extentRectangle.style.height = this.minRectSize + 'px';
+            this.extentRectangle.style.width = this.minRectSize + 'px';
+        } else {
+            this.extentRectangle.className = this.displayClass +
+                                             'ExtentRectangle';
+            this.extentRectangle.style.top = Math.round(top) + 'px';
+            this.extentRectangle.style.left = Math.round(left) + 'px';
+            this.extentRectangle.style.height = Math.round(height) + 'px';
+            this.extentRectangle.style.width = Math.round(width) + 'px';
+        }
+        this.rectPxBounds = new OpenLayers.Bounds(
+            Math.round(left), Math.round(bottom),
+            Math.round(right), Math.round(top)
+        );
+    },
+
+    /**
+     * Method: getRectBoundsFromMapBounds
+     * Get the rect bounds from the map bounds.
+     *
+     * Parameters:
+     * lonLatBounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
+     * translated into pixel bounds for the overview map
+     */
+    getRectBoundsFromMapBounds: function(lonLatBounds) {
+        var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
+                                                     lonLatBounds.bottom);
+        var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
+                                                   lonLatBounds.top);
+        var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
+        var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
+        var bounds = null;
+        if (leftBottomPx && rightTopPx) {
+            bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
+                                           rightTopPx.x, rightTopPx.y);
+        }
+        return bounds;
+    },
+
+    /**
+     * Method: getMapBoundsFromRectBounds
+     * Get the map bounds from the rect bounds.
+     *
+     * Parameters:
+     * pxBounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
+     * translated into lon/lat bounds for the overview map
+     */
+    getMapBoundsFromRectBounds: function(pxBounds) {
+        var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
+                                                pxBounds.bottom);
+        var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
+                                              pxBounds.top);
+        var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
+        var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
+        return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
+                                     rightTopLonLat.lon, rightTopLonLat.lat);
+    },
+
+    /**
+     * Method: getLonLatFromOverviewPx
+     * Get a map location from a pixel location
+     *
+     * Parameters:
+     * overviewMapPx - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} Location which is the passed-in overview map
+     * OpenLayers.Pixel, translated into lon/lat by the overview map
+     */
+    getLonLatFromOverviewPx: function(overviewMapPx) {
+        var size = this.ovmap.size;
+        var res  = this.ovmap.getResolution();
+        var center = this.ovmap.getExtent().getCenterLonLat();
+    
+        var delta_x = overviewMapPx.x - (size.w / 2);
+        var delta_y = overviewMapPx.y - (size.h / 2);
+        
+        return new OpenLayers.LonLat(center.lon + delta_x * res ,
+                                     center.lat - delta_y * res); 
+    },
+
+    /**
+     * Method: getOverviewPxFromLonLat
+     * Get a pixel location from a map location
+     *
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
+     * translated into overview map pixels
+     */
+    getOverviewPxFromLonLat: function(lonlat) {
+        var res  = this.ovmap.getResolution();
+        var extent = this.ovmap.getExtent();
+        var px = null;
+        if (extent) {
+            px = new OpenLayers.Pixel(
+                        Math.round(1/res * (lonlat.lon - extent.left)),
+                        Math.round(1/res * (extent.top - lonlat.lat)));
+        } 
+        return px;
+    },
+
+    CLASS_NAME: 'OpenLayers.Control.OverviewMap'
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Pan.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Pan.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Pan.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,85 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Pan
+ * The Pan control is a single button to pan the map in one direction. For
+ * a more complete control see <OpenLayers.Control.PanPanel>.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control, {
+
+    /** 
+     * APIProperty: slideFactor
+     * {Integer} Number of pixels by which we'll pan the map in any direction 
+     *     on clicking the arrow buttons. 
+     */
+    slideFactor: 50,
+
+    /** 
+     * Property: direction
+     * {String} in {'North', 'South', 'East', 'West'}
+     */
+    direction: null,
+
+    /**
+     * Property: type
+     * {String} The type of <OpenLayers.Control> -- When added to a 
+     *     <Control.Panel>, 'type' is used by the panel to determine how to 
+     *     handle our events.
+     */
+    type: OpenLayers.Control.TYPE_BUTTON,
+
+    /**
+     * Constructor: OpenLayers.Control.Pan 
+     * Control which handles the panning (in any of the cardinal directions)
+     *     of the map by a set px distance. 
+     *
+     * Parameters:
+     * direction - {String} The direction this button should pan.
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(direction, options) {
+    
+        this.direction = direction;
+        this.CLASS_NAME += this.direction;
+        
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: trigger
+     */
+    trigger: function(){
+    
+        switch (this.direction) {
+            case OpenLayers.Control.Pan.NORTH: 
+                this.map.pan(0, -this.slideFactor);
+                break;
+            case OpenLayers.Control.Pan.SOUTH: 
+                this.map.pan(0, this.slideFactor);
+                break;
+            case OpenLayers.Control.Pan.WEST: 
+                this.map.pan(-this.slideFactor, 0);
+                break;
+            case OpenLayers.Control.Pan.EAST: 
+                this.map.pan(this.slideFactor, 0);
+                break;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Pan"
+});
+
+OpenLayers.Control.Pan.NORTH = "North";
+OpenLayers.Control.Pan.SOUTH = "South";
+OpenLayers.Control.Pan.EAST = "East";
+OpenLayers.Control.Pan.WEST = "West";

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/PanPanel.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/PanPanel.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/PanPanel.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,47 @@
+/**
+ * @requires OpenLayers/Control/Panel.js
+ * @requires OpenLayers/Control/Pan.js
+ */
+
+/**
+ * Class: OpenLayers.Control.PanPanel
+ * The PanPanel is visible control for panning the map North, South, East or
+ * West in small steps. By default it is drawn in the top left corner of the
+ * map.
+ *
+ * Note: 
+ * If you wish to use this class with the default images and you want 
+ *       it to look nice in ie6, you should add the following, conditionally
+ *       added css stylesheet to your HTML file:
+ * 
+ * (code)
+ * <!--[if lte IE 6]>
+ *   <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" />
+ * <![endif]-->
+ * (end)
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control.Panel> 
+ */
+OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, {
+
+    /**
+     * Constructor: OpenLayers.Control.PanPanel 
+     * Add the four directional pan buttons.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);
+        this.addControls([
+            new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH),
+            new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH),
+            new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST),
+            new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST)
+        ]);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.PanPanel"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Panel.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Panel.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Panel.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,286 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Panel
+ * The Panel control is a container for other controls. With it toolbars
+ * may be composed.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, {
+    /**
+     * Property: controls
+     * {Array(<OpenLayers.Control>)}
+     */
+    controls: null,    
+    
+    /** 
+     * APIProperty: defaultControl
+     * {<OpenLayers.Control>} The control which is activated when the control is
+     * activated (turned on), which also happens at instantiation.
+     */
+    defaultControl: null, 
+
+    /**
+     * Constructor: OpenLayers.Control.Panel
+     * Create a new control panel.
+     * 
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.controls = [];
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+        for(var i = this.controls.length - 1 ; i >= 0; i--) {
+            if(this.controls[i].events) {
+                this.controls[i].events.un({
+                    "activate": this.redraw,
+                    "deactivate": this.redraw,
+                    scope: this
+                });
+            }
+            OpenLayers.Event.stopObservingElement(this.controls[i].panel_div);
+            this.controls[i].panel_div = null;
+        }    
+    },
+
+    /**
+     * APIMethod: activate
+     */
+    activate: function() {
+        if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
+            for(var i=0, len=this.controls.length; i<len; i++) {
+                if (this.controls[i] == this.defaultControl) {
+                    this.controls[i].activate();
+                }
+            }    
+            this.redraw();
+            return true;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * APIMethod: deactivate
+     */
+    deactivate: function() {
+        if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
+            for(var i=0, len=this.controls.length; i<len; i++) {
+                this.controls[i].deactivate();
+            }    
+            return true;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: draw
+     *
+     * Returns:
+     * {DOMElement}
+     */    
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        for (var i=0, len=this.controls.length; i<len; i++) {
+            this.map.addControl(this.controls[i]);
+            this.controls[i].deactivate();
+            this.controls[i].events.on({
+                "activate": this.redraw,
+                "deactivate": this.redraw,
+                scope: this
+            });
+        }
+        this.activate();
+        return this.div;
+    },
+
+    /**
+     * Method: redraw
+     */
+    redraw: function() {
+        this.div.innerHTML = "";
+        if (this.active) {
+            for (var i=0, len=this.controls.length; i<len; i++) {
+                var element = this.controls[i].panel_div;
+                if (this.controls[i].active) {
+                    element.className = this.controls[i].displayClass + "ItemActive";
+                } else {    
+                    element.className = this.controls[i].displayClass + "ItemInactive";
+                }    
+                this.div.appendChild(element);
+            }
+        }
+    },
+
+    /**
+     * APIMethod: activateControl
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>}
+     */
+    activateControl: function (control) {
+        if (!this.active) { return false; }
+        if (control.type == OpenLayers.Control.TYPE_BUTTON) {
+            control.trigger();
+            this.redraw();
+            return;
+        }
+        if (control.type == OpenLayers.Control.TYPE_TOGGLE) {
+            if (control.active) {
+                control.deactivate();
+            } else {
+                control.activate();
+            }
+            this.redraw();
+            return;
+        }
+        for (var i=0, len=this.controls.length; i<len; i++) {
+            if (this.controls[i] != control) {
+                if (this.controls[i].type != OpenLayers.Control.TYPE_TOGGLE) {
+                    this.controls[i].deactivate();
+                }
+            }
+        }
+        control.activate();
+    },
+
+    /**
+     * APIMethod: addControls
+     * To build a toolbar, you add a set of controls to it. addControls
+     * lets you add a single control or a list of controls to the 
+     * Control Panel.
+     *
+     * Parameters:
+     * controls - {<OpenLayers.Control>} 
+     */    
+    addControls: function(controls) {
+        if (!(controls instanceof Array)) {
+            controls = [controls];
+        }
+        this.controls = this.controls.concat(controls);
+        
+        // Give each control a panel_div which will be used later.
+        // Access to this div is via the panel_div attribute of the 
+        // control added to the panel.
+        // Also, stop mousedowns and clicks, but don't stop mouseup,
+        // since they need to pass through.
+        for (var i=0, len=controls.length; i<len; i++) {
+            var element = document.createElement("div");
+            var textNode = document.createTextNode(" ");
+            controls[i].panel_div = element;
+            if (controls[i].title != "") {
+                controls[i].panel_div.title = controls[i].title;
+            }
+            OpenLayers.Event.observe(controls[i].panel_div, "click", 
+                OpenLayers.Function.bind(this.onClick, this, controls[i]));
+            OpenLayers.Event.observe(controls[i].panel_div, "mousedown", 
+                OpenLayers.Function.bindAsEventListener(OpenLayers.Event.stop));
+        }    
+
+        if (this.map) { // map.addControl() has already been called on the panel
+            for (var i=0, len=controls.length; i<len; i++) {
+                this.map.addControl(controls[i]);
+                controls[i].deactivate();
+                controls[i].events.on({
+                    "activate": this.redraw,
+                    "deactivate": this.redraw,
+                    scope: this
+                });
+            }
+            this.redraw();
+        }
+    },
+   
+    /**
+     * Method: onClick
+     */
+    onClick: function (ctrl, evt) {
+        OpenLayers.Event.stop(evt ? evt : window.event);
+        this.activateControl(ctrl);
+    },
+
+    /**
+     * APIMethod: getControlsBy
+     * Get a list of controls with properties matching the given criteria.
+     *
+     * Parameter:
+     * property - {String} A control property to be matched.
+     * match - {String | Object} A string to match.  Can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     match.test(control[property]) evaluates to true, the control will be
+     *     included in the array returned.  If no controls are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria.
+     *     An empty array is returned if no matches are found.
+     */
+    getControlsBy: function(property, match) {
+        var test = (typeof match.test == "function");
+        var found = OpenLayers.Array.filter(this.controls, function(item) {
+            return item[property] == match || (test && match.test(item[property]));
+        });
+        return found;
+    },
+
+    /**
+     * APIMethod: getControlsByName
+     * Get a list of contorls with names matching the given name.
+     *
+     * Parameter:
+     * match - {String | Object} A control name.  The name can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     name.test(control.name) evaluates to true, the control will be included
+     *     in the list of controls returned.  If no controls are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Control>)} A list of controls matching the given name.
+     *     An empty array is returned if no matches are found.
+     */
+    getControlsByName: function(match) {
+        return this.getControlsBy("name", match);
+    },
+
+    /**
+     * APIMethod: getControlsByClass
+     * Get a list of controls of a given type (CLASS_NAME).
+     *
+     * Parameter:
+     * match - {String | Object} A control class name.  The type can also be a
+     *     regular expression literal or object.  In addition, it can be any
+     *     object with a method named test.  For reqular expressions or other,
+     *     if type.test(control.CLASS_NAME) evaluates to true, the control will
+     *     be included in the list of controls returned.  If no controls are
+     *     found, an empty array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Control>)} A list of controls matching the given type.
+     *     An empty array is returned if no matches are found.
+     */
+    getControlsByClass: function(match) {
+        return this.getControlsBy("CLASS_NAME", match);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Panel"
+});
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Permalink.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Permalink.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Permalink.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,219 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Control/ArgParser.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Permalink
+ * The Permalink control is hyperlink that will return the user to the 
+ * current map view. By default it is drawn in the lower right corner of the
+ * map. The href is updated as the map is zoomed, panned and whilst layers
+ * are switched.
+ * `
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
+    
+    /**
+     * APIProperty: argParserClass
+     * {Class} The ArgParser control class (not instance) to use with this
+     *     control.
+     */
+    argParserClass: OpenLayers.Control.ArgParser,
+
+    /** 
+     * Property: element 
+     * {DOMElement}
+     */
+    element: null,
+    
+    /** 
+     * APIProperty: base
+     * {String}
+     */
+    base: '',
+
+    /** 
+     * APIProperty: displayProjection
+     * {<OpenLayers.Projection>} Requires proj4js support.  Projection used
+     *     when creating the coordinates in the link. This will reproject the
+     *     map coordinates into display coordinates. If you are using this
+     *     functionality, the permalink which is last added to the map will
+     *     determine the coordinate type which is read from the URL, which
+     *     means you should not add permalinks with different
+     *     displayProjections to the same map. 
+     */
+    displayProjection: null, 
+
+    /**
+     * Constructor: OpenLayers.Control.Permalink
+     *
+     * Parameters: 
+     * element - {DOMElement} 
+     * base - {String} 
+     * options - {Object} options to the control. 
+     */
+    initialize: function(element, base, options) {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.element = OpenLayers.Util.getElement(element);        
+        this.base = base || document.location.href;
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    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); 
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+        //make sure we have an arg parser attached
+        for(var i=0, len=this.map.controls.length; i<len; i++) {
+            var control = this.map.controls[i];
+            if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) {
+                
+                // If a permalink is added to the map, and an ArgParser already
+                // exists, we override the displayProjection to be the one
+                // on the permalink. 
+                if (control.displayProjection != this.displayProjection) {
+                    this.displayProjection = control.displayProjection;
+                }    
+                
+                break;
+            }
+        }
+        if (i == this.map.controls.length) {
+            this.map.addControl(new this.argParserClass(
+                { 'displayProjection': this.displayProjection }));       
+        }
+
+    },
+
+    /**
+     * Method: draw
+     *
+     * Returns:
+     * {DOMElement}
+     */    
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+          
+        if (!this.element) {
+            this.div.className = this.displayClass;
+            this.element = document.createElement("a");
+            this.element.innerHTML = OpenLayers.i18n("permalink");
+            this.element.href="";
+            this.div.appendChild(this.element);
+        }
+        this.map.events.on({
+            'moveend': this.updateLink,
+            'changelayer': this.updateLink,
+            'changebaselayer': this.updateLink,
+            scope: this
+        });
+        
+        // Make it so there is at least a link even though the map may not have
+        // moved yet.
+        this.updateLink();
+        
+        return this.div;
+    },
+   
+    /**
+     * Method: updateLink 
+     */
+    updateLink: function() {
+        var href = this.base;
+        if (href.indexOf('?') != -1) {
+            href = href.substring( 0, href.indexOf('?') );
+        }
+
+        href += '?' + OpenLayers.Util.getParameterString(this.createParams());
+        this.element.href = href;
+    }, 
+    
+    /**
+     * APIMethod: createParams
+     * Creates the parameters that need to be encoded into the permalink url.
+     * 
+     * Parameters:
+     * center - {<OpenLayers.LonLat>} center to encode in the permalink.
+     *     Defaults to the current map center.
+     * zoom - {Integer} zoom level to encode in the permalink. Defaults to the
+     *     current map zoom level.
+     * layers - {Array(<OpenLayers.Layer>)} layers to encode in the permalink.
+     *     Defaults to the current map layers.
+     * 
+     * Returns:
+     * {Object} Hash of parameters that will be url-encoded into the
+     * permalink.
+     */
+    createParams: function(center, zoom, layers) {
+        center = center || this.map.getCenter();
+          
+        var params = OpenLayers.Util.getParameters(this.base);
+        
+        // If there's still no center, map is not initialized yet. 
+        // Break out of this function, and simply return the params from the
+        // base link.
+        if (center) { 
+
+            //zoom
+            params.zoom = zoom || this.map.getZoom(); 
+
+            //lon,lat
+            var lat = center.lat;
+            var lon = center.lon;
+            
+            if (this.displayProjection) {
+                var mapPosition = OpenLayers.Projection.transform(
+                  { x: lon, y: lat }, 
+                  this.map.getProjectionObject(), 
+                  this.displayProjection );
+                lon = mapPosition.x;  
+                lat = mapPosition.y;  
+            }       
+            params.lat = Math.round(lat*100000)/100000;
+            params.lon = Math.round(lon*100000)/100000;
+    
+            //layers        
+            layers = layers || this.map.layers;  
+            params.layers = '';
+            for (var i=0, len=layers.length; i<len; i++) {
+                var layer = layers[i];
+    
+                if (layer.isBaseLayer) {
+                    params.layers += (layer == this.map.baseLayer) ? "B" : "0";
+                } else {
+                    params.layers += (layer.getVisibility()) ? "T" : "F";           
+                }
+            }
+        }
+
+        return params;
+    }, 
+
+    CLASS_NAME: "OpenLayers.Control.Permalink"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Scale.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Scale.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Scale.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,77 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Scale
+ * The Scale control displays the current map scale as a ratio (e.g. Scale = 
+ * 1:1M). By default it is displayed in the lower right corner of the map.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, {
+    
+    /**
+     * Parameter: element
+     * {DOMElement}
+     */
+    element: null,
+    
+    /**
+     * Constructor: OpenLayers.Control.Scale
+     * 
+     * Parameters:
+     * element - {DOMElement} 
+     * options - {Object} 
+     */
+    initialize: function(element, options) {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.element = OpenLayers.Util.getElement(element);        
+    },
+
+    /**
+     * Method: draw
+     * 
+     * Returns:
+     * {DOMElement}
+     */    
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        if (!this.element) {
+            this.element = document.createElement("div");
+            this.div.appendChild(this.element);
+        }
+        this.map.events.register( 'moveend', this, this.updateScale);
+        this.updateScale();
+        return this.div;
+    },
+   
+    /**
+     * Method: updateScale
+     */
+    updateScale: function() {
+        var scale = this.map.getScale();
+        if (!scale) {
+            return;
+        }
+
+        if (scale >= 9500 && scale <= 950000) {
+            scale = Math.round(scale / 1000) + "K";
+        } else if (scale >= 950000) {
+            scale = Math.round(scale / 1000000) + "M";
+        } else {
+            scale = Math.round(scale);
+        }    
+        
+        this.element.innerHTML = OpenLayers.i18n("scale", {'scaleDenom':scale});
+    }, 
+
+    CLASS_NAME: "OpenLayers.Control.Scale"
+});
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ScaleLine.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ScaleLine.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ScaleLine.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,208 @@
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ScaleLine
+ * The ScaleLine displays a small line indicator representing the current 
+ * map scale on the map. By default it is drawn in the lower left corner of
+ * the map.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ *  
+ * Is a very close copy of:
+ *  - <OpenLayers.Control.Scale>
+ */
+OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: maxWidth
+     * {Integer} Maximum width of the scale line in pixels.  Default is 100.
+     */
+    maxWidth: 100,
+
+    /**
+     * Property: topOutUnits
+     * {String} Units for zoomed out on top bar.  Default is km.
+     */
+    topOutUnits: "km",
+    
+    /**
+     * Property: topInUnits
+     * {String} Units for zoomed in on top bar.  Default is m.
+     */
+    topInUnits: "m",
+
+    /**
+     * Property: bottomOutUnits
+     * {String} Units for zoomed out on bottom bar.  Default is mi.
+     */
+    bottomOutUnits: "mi",
+
+    /**
+     * Property: bottomInUnits
+     * {String} Units for zoomed in on bottom bar.  Default is ft.
+     */
+    bottomInUnits: "ft",
+    
+    /**
+     * Property: eTop
+     * {DOMElement}
+     */
+    eTop: null,
+
+    /**
+     * Property: eBottom
+     * {DOMElement}
+     */
+    eBottom:null,
+
+    /**
+     * Constructor: OpenLayers.Control.ScaleLine
+     * Create a new scale line control.
+     * 
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);     
+    },
+
+    /**
+     * Method: draw
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        if (!this.eTop) {
+            this.div.style.display = "block";
+            this.div.style.position = "absolute";
+            
+            // stick in the top bar
+            this.eTop = document.createElement("div");
+            this.eTop.className = this.displayClass + "Top";
+            var theLen = this.topInUnits.length;
+            this.div.appendChild(this.eTop);
+            if((this.topOutUnits == "") || (this.topInUnits == "")) {
+                this.eTop.style.visibility = "hidden";
+            } else {
+                this.eTop.style.visibility = "visible";
+            }
+
+            // and the bottom bar
+            this.eBottom = document.createElement("div");
+            this.eBottom.className = this.displayClass + "Bottom";
+            this.div.appendChild(this.eBottom);
+            if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
+                this.eBottom.style.visibility = "hidden";
+            } else {
+                this.eBottom.style.visibility = "visible";
+            }
+        }
+        this.map.events.register('moveend', this, this.update);
+        this.update();
+        return this.div;
+    },
+
+    /** 
+     * Method: getBarLen
+     * Given a number, round it down to the nearest 1,2,5 times a power of 10.
+     * That seems a fairly useful set of number groups to use.
+     * 
+     * Parameters:
+     * maxLen - {float}  the number we're rounding down from
+     * 
+     * Returns:
+     * {Float} the rounded number (less than or equal to maxLen)
+     */
+    getBarLen: function(maxLen) {
+        // nearest power of 10 lower than maxLen
+        var digits = parseInt(Math.log(maxLen) / Math.log(10));
+        var pow10 = Math.pow(10, digits);
+        
+        // ok, find first character
+        var firstChar = parseInt(maxLen / pow10);
+
+        // right, put it into the correct bracket
+        var barLen;
+        if(firstChar > 5) {
+            barLen = 5;
+        } else if(firstChar > 2) {
+            barLen = 2;
+        } else {
+            barLen = 1;
+        }
+
+        // scale it up the correct power of 10
+        return barLen * pow10;
+    },
+
+    /**
+     * Method: update
+     * Update the size of the bars, and the labels they contain.
+     */
+    update: function() {
+        var res = this.map.getResolution();
+        if (!res) {
+            return;
+        }
+
+        var curMapUnits = this.map.getUnits();
+        var inches = OpenLayers.INCHES_PER_UNIT;
+
+        // convert maxWidth to map units
+        var maxSizeData = this.maxWidth * res * inches[curMapUnits];  
+
+        // decide whether to use large or small scale units     
+        var topUnits;
+        var bottomUnits;
+        if(maxSizeData > 100000) {
+            topUnits = this.topOutUnits;
+            bottomUnits = this.bottomOutUnits;
+        } else {
+            topUnits = this.topInUnits;
+            bottomUnits = this.bottomInUnits;
+        }
+
+        // and to map units units
+        var topMax = maxSizeData / inches[topUnits];
+        var bottomMax = maxSizeData / inches[bottomUnits];
+
+        // now trim this down to useful block length
+        var topRounded = this.getBarLen(topMax);
+        var bottomRounded = this.getBarLen(bottomMax);
+
+        // and back to display units
+        topMax = topRounded / inches[curMapUnits] * inches[topUnits];
+        bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
+
+        // and to pixel units
+        var topPx = topMax / res;
+        var bottomPx = bottomMax / res;
+        
+        // now set the pixel widths
+        // and the values inside them
+        
+        if (this.eBottom.style.visibility == "visible"){
+            this.eBottom.style.width = Math.round(bottomPx) + "px"; 
+            this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
+        }
+            
+        if (this.eTop.style.visibility == "visible"){
+            this.eTop.style.width = Math.round(topPx) + "px";
+            this.eTop.innerHTML = topRounded + " " + topUnits;
+        }
+        
+    }, 
+
+    CLASS_NAME: "OpenLayers.Control.ScaleLine"
+});
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Snapping.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Snapping.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Snapping.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,546 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Layer/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Snapping
+ * Acts as a snapping agent while editing vector features.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * control.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * Supported control event types (in addition to those from <OpenLayers.Control>):
+     * beforesnap - Triggered before a snap occurs.  Listeners receive an
+     *     event object with *point*, *x*, *y*, *distance*, *layer*, and
+     *     *snapType* properties.  The point property will be original point
+     *     geometry considered for snapping. The x and y properties represent
+     *     coordinates the point will receive. The distance is the distance
+     *     of the snap.  The layer is the target layer.  The snapType property
+     *     will be one of "node", "vertex", or "edge". Return false to stop
+     *     snapping from occurring.
+     * snap - Triggered when a snap occurs.  Listeners receive an event with
+     *     *point*, *snapType*, *layer*, and *distance* properties.  The point
+     *     will be the location snapped to.  The snapType will be one of "node",
+     *     "vertex", or "edge".  The layer will be the target layer.  The
+     *     distance will be the distance of the snap in map units.
+     * unsnap - Triggered when a vertex is unsnapped.  Listeners receive an
+     *     event with a *point* property.
+     */
+    EVENT_TYPES: ["beforesnap", "snap", "unsnap"],
+    
+    /**
+     * CONSTANT: DEFAULTS
+     * Default target properties.
+     */
+    DEFAULTS: {
+        tolerance: 10,
+        node: true,
+        edge: true,
+        vertex: true
+    },
+    
+    /**
+     * Property: greedy
+     * {Boolean} Snap to closest feature in first layer with an eligible
+     *     feature.  Default is true.
+     */
+    greedy: true,
+    
+    /**
+     * Property: precedence
+     * {Array} List representing precedence of different snapping types.
+     *     Default is "node", "vertex", "edge".
+     */
+    precedence: ["node", "vertex", "edge"],
+    
+    /**
+     * Property: resolution
+     * {Float} The map resolution for the previously considered snap.
+     */
+    resolution: null,
+    
+    /**
+     * Property: geoToleranceCache
+     * {Object} A cache of geo-tolerances.  Tolerance values (in map units) are
+     *     calculated when the map resolution changes.
+     */
+    geoToleranceCache: null,
+    
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>} The current editable layer.  Set at
+     *     construction or after construction with <setLayer>.
+     */
+    layer: null,
+    
+    /**
+     * Property: feature
+     * {<OpenLayers.Feature.Vector>} The current editable feature.
+     */
+    feature: null,
+    
+    /**
+     * Property: point
+     * {<OpenLayers.Geometry.Point>} The currently snapped vertex.
+     */
+    point: null,
+
+    /**
+     * Constructor: OpenLayers.Control.Snapping
+     * Creates a new snapping control. A control is constructed with an editable
+     *     layer and a set of configuration objects for target layers. While the
+     *     control is active, dragging vertices while drawing new features or
+     *     modifying existing features on the editable layer will engage
+     *     snapping to features on the target layers. Whether a vertex snaps to
+     *     a feature on a target layer depends on the target layer configuration.
+     *
+     * Parameters:
+     * options - {Object} An object containing all configuration properties for
+     *     the control.
+     *
+     * Valid options:
+     * layer - {OpenLayers.Layer.Vector} The editable layer.  Features from this
+     *     layer that are digitized or modified may have vertices snapped to
+     *     features from any of the target layers.
+     * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for
+     *     configuring target layers.  See valid properties of the target
+     *     objects below.  If the items in the targets list are vector layers
+     *     (instead of configuration objects), the defaults from the <defaults>
+     *     property will apply.  The editable layer itself may be a target
+     *     layer - allowing newly created or edited features to be snapped to
+     *     existing features from the same layer.  If no targets are provided
+     *     the layer given in the constructor (as <layer>) will become the
+     *     initial target.
+     * defaults - {Object} An object with default properties to be applied
+     *     to all target objects.
+     * greedy - {Boolean} Snap to closest feature in first target layer that
+     *     applies.  Default is true.  If false, all features in all target
+     *     layers will be checked and the closest feature in all target layers
+     *     will be chosen.  The greedy property determines if the order of the
+     *     target layers is significant.  By default, the order of the target
+     *     layers is significant where layers earlier in the target layer list
+     *     have precedence over layers later in the list.  Within a single
+     *     layer, the closest feature is always chosen for snapping.  This
+     *     property only determines whether the search for a closer feature
+     *     continues after an eligible feature is found in a target layer.
+     *
+     * Valid target properties:
+     * layer - {OpenLayers.Layer.Vector} A target layer.  Features from this
+     *     layer will be eligible to act as snapping target for the editable
+     *     layer.
+     * tolerance - {Float} The distance (in pixels) at which snapping may occur.
+     *     Default is 10.
+     * node - {Boolean} Snap to nodes (first or last point in a geometry) in
+     *     target layer.  Default is true.
+     * nodeTolerance - {Float} Optional distance at which snapping may occur
+     *     for nodes specifically.  If none is provided, <tolerance> will be
+     *     used.
+     * vertex - {Boolean} Snap to vertices in target layer.  Default is true.
+     * vertexTolerance - {Float} Optional distance at which snapping may occur
+     *     for vertices specifically.  If none is provided, <tolerance> will be
+     *     used.
+     * edge - {Boolean} Snap to edges in target layer.  Default is true.
+     * edgeTolerance - {Float} Optional distance at which snapping may occur
+     *     for edges specifically.  If none is provided, <tolerance> will be
+     *     used.
+     * filter - {OpenLayers.Filter} Optional filter to evaluate to determine if
+     *     feature is eligible for snapping.  If filter evaluates to true for a
+     *     target feature a vertex may be snapped to the feature. 
+     */
+    initialize: function(options) {
+        // concatenate events specific to measure with those from the base
+        Array.prototype.push.apply(
+            this.EVENT_TYPES, OpenLayers.Control.prototype.EVENT_TYPES
+        );
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.options = options || {}; // TODO: this could be done by the super
+        
+        // set the editable layer if provided
+        if(this.options.layer) {
+            this.setLayer(this.options.layer);
+        }
+        // configure target layers
+        var defaults = OpenLayers.Util.extend({}, this.options.defaults);
+        this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS);
+        this.setTargets(this.options.targets);
+        if(this.targets.length === 0 && this.layer) {
+            this.addTargetLayer(this.layer);
+        }
+
+        this.geoToleranceCache = {};
+    },
+    
+    /**
+     * APIMethod: setLayer
+     * Set the editable layer.  Call the setLayer method if the editable layer
+     *     changes and the same control should be used on a new editable layer.
+     *     If the control is already active, it will be active after the new
+     *     layer is set.
+     *
+     * Parameters:
+     * layer - {OpenLayers.Layer.Vector}  The new editable layer.
+     */
+    setLayer: function(layer) {
+        if(this.active) {
+            this.deactivate();
+            this.layer = layer;
+            this.activate();
+        } else {
+            this.layer = layer;
+        }
+    },
+    
+    /**
+     * Method: setTargets
+     * Set the targets for the snapping agent.
+     *
+     * Parameters:
+     * targets - {Array} An array of target configs or target layers.
+     */
+    setTargets: function(targets) {
+        this.targets = [];
+        if(targets && targets.length) {
+            var target;
+            for(var i=0, len=targets.length; i<len; ++i) {
+                target = targets[i];
+                if(target instanceof OpenLayers.Layer.Vector) {
+                    this.addTargetLayer(target);
+                } else {
+                    this.addTarget(target);
+                }
+            }
+        }
+    },
+    
+    /**
+     * Method: addTargetLayer
+     * Add a target layer with the default target config.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.Vector>} A target layer.
+     */
+    addTargetLayer: function(layer) {
+        this.addTarget({layer: layer});
+    },
+    
+    /**
+     * Method: addTarget
+     * Add a configured target layer.
+     *
+     * Parameters:
+     * target - {Object} A target config.
+     */
+    addTarget: function(target) {
+        target = OpenLayers.Util.applyDefaults(target, this.defaults);
+        target.nodeTolerance = target.nodeTolerance || target.tolerance;
+        target.vertexTolerance = target.vertexTolerance || target.tolerance;
+        target.edgeTolerance = target.edgeTolerance || target.tolerance;
+        this.targets.push(target);
+    },
+    
+    /**
+     * Method: removeTargetLayer
+     * Remove a target layer.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.Vector>} The target layer to remove.
+     */
+    removeTargetLayer: function(layer) {
+        var target;
+        for(var i=this.targets.length-1; i>=0; --i) {
+            target = this.targets[i];
+            if(target.layer === layer) {
+                this.removeTarget(target);
+            }
+        }
+    },
+    
+    /**
+     * Method: removeTarget
+     * Remove a target.
+     *
+     * Parameters:
+     * target - {Object} A target config.
+     *
+     * Returns:
+     * {Array} The targets array.
+     */
+    removeTarget: function(target) {
+        return OpenLayers.Util.removeItem(this.targets, target);
+    },
+    
+    /**
+     * APIMethod: activate
+     * Activate the control.  Activating the control registers listeners for
+     *     editing related events so that during feature creation and
+     *     modification, moving vertices will trigger snapping.
+     */
+    activate: function() {
+        var activated = OpenLayers.Control.prototype.activate.call(this);
+        if(activated) {
+            if(this.layer && this.layer.events) {
+                this.layer.events.on({
+                    sketchstarted: this.onSketchModified,
+                    sketchmodified: this.onSketchModified,
+                    vertexmodified: this.onVertexModified,
+                    scope: this
+                });
+            }
+        }
+        return activated;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control.  Deactivating the control unregisters listeners
+     *     so feature editing may proceed without engaging the snapping agent.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Control.prototype.deactivate.call(this);
+        if(deactivated) {
+            if(this.layer && this.layer.events) {
+                this.layer.events.un({
+                    sketchstarted: this.onSketchModified,
+                    sketchmodified: this.onSketchModified,
+                    vertexmodified: this.onVertexModified,
+                    scope: this
+                });
+            }
+        }
+        this.feature = null;
+        this.point = null;
+        return deactivated;
+    },
+    
+    /**
+     * Method: onSketchModified
+     * Registered as a listener for the sketchmodified event on the editable
+     *     layer.
+     *
+     * Parameters:
+     * event - {Object} The sketch modified event.
+     */
+    onSketchModified: function(event) {
+        this.feature = event.feature;
+        this.considerSnapping(event.vertex, event.vertex);
+    },
+    
+    /**
+     * Method: onVertexModified
+     * Registered as a listener for the vertexmodified event on the editable
+     *     layer.
+     *
+     * Parameters:
+     * event - {Object} The vertex modified event.
+     */
+    onVertexModified: function(event) {
+        this.feature = event.feature;
+        var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel);
+        this.considerSnapping(
+            event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)
+        );
+    },
+
+    /**
+     * Method: considerSnapping
+     *
+     * Parameters:
+     * point - {<OpenLayers.Geometry.Point}} The vertex to be snapped (or
+     *     unsnapped).
+     * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map
+     *     coords.
+     */
+    considerSnapping: function(point, loc) {
+        var best = {
+            rank: Number.POSITIVE_INFINITY,
+            dist: Number.POSITIVE_INFINITY,
+            x: null, y: null
+        };
+        var snapped = false;
+        var result, target;
+        for(var i=0, len=this.targets.length; i<len; ++i) {
+            target = this.targets[i];
+            result = this.testTarget(target, loc);
+            if(result) {
+                if(this.greedy) {
+                    best = result;
+                    best.target = target; 
+                    snapped = true;
+                    break;
+                } else {
+                    if((result.rank < best.rank) ||
+                       (result.rank === best.rank && result.dist < best.dist)) {
+                        best = result;
+                        best.target = target;
+                        snapped = true;
+                    }
+                }
+            }
+        }
+        if(snapped) {
+            var proceed = this.events.triggerEvent("beforesnap", {
+                point: point, x: best.x, y: best.y, distance: best.dist,
+                layer: best.target.layer, snapType: this.precedence[best.rank]
+            });
+            if(proceed !== false) {
+                point.x = best.x;
+                point.y = best.y;
+                this.point = point;
+                this.events.triggerEvent("snap", {
+                    point: point,
+                    snapType: this.precedence[best.rank],
+                    layer: best.target.layer,
+                    distance: best.dist
+                });
+            } else {
+                snapped = false;
+            }
+        }
+        if(this.point && !snapped) {
+            point.x = loc.x;
+            point.y = loc.y;
+            this.point = null;
+            this.events.triggerEvent("unsnap", {point: point});
+        }
+    },
+    
+    /**
+     * Method: testTarget
+     *
+     * Parameters:
+     * target - {Object} Object with target layer configuration.
+     * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map
+     *     coords.
+     *
+     * Returns:
+     * {Object} A result object with rank, dist, x, and y properties.
+     *     Returns null if candidate is not eligible for snapping.
+     */
+    testTarget: function(target, loc) {
+        var tolerance = {
+            node: this.getGeoTolerance(target.nodeTolerance),
+            vertex: this.getGeoTolerance(target.vertexTolerance),
+            edge: this.getGeoTolerance(target.edgeTolerance)
+        };
+        // this could be cached if we don't support setting tolerance values directly
+        var maxTolerance = Math.max(
+            tolerance.node, tolerance.vertex, tolerance.edge
+        );
+        var result = {
+            rank: Number.POSITIVE_INFINITY, dist: Number.POSITIVE_INFINITY
+        };
+        var eligible = false;
+        var features = target.layer.features;
+        var feature, type, vertices, vertex, closest, dist, found;
+        var numTypes = this.precedence.length;
+        var ll = new OpenLayers.LonLat(loc.x, loc.y);
+        for(var i=0, len=features.length; i<len; ++i) {
+            feature = features[i];
+            if(feature !== this.feature && !feature._sketch &&
+               feature.state !== OpenLayers.State.DELETE &&
+               (!target.filter || target.filter.evaluate(feature.attributes))) {
+                if(feature.atPoint(ll, maxTolerance, maxTolerance)) {
+                    for(var j=0, stop=Math.min(result.rank+1, numTypes); j<stop; ++j) {
+                        type = this.precedence[j];
+                        if(target[type]) {
+                            if(type === "edge") {
+                                closest = feature.geometry.distanceTo(loc, {details: true});
+                                dist = closest.distance;
+                                if(dist <= tolerance[type] && dist < result.dist) {
+                                    result = {
+                                        rank: j, dist: dist,
+                                        x: closest.x0, y: closest.y0 // closest coords on feature
+                                    };
+                                    eligible = true;
+                                    // don't look for lower precedence types for this feature
+                                    break;
+                                }
+                            } else {
+                                // look for nodes or vertices
+                                vertices = feature.geometry.getVertices(type === "node");
+                                found = false;
+                                for(var k=0, klen=vertices.length; k<klen; ++k) {
+                                    vertex = vertices[k];
+                                    dist = vertex.distanceTo(loc);
+                                    if(dist <= tolerance[type] &&
+                                       (j < result.rank || (j === result.rank && dist < result.dist))) {
+                                        result = {
+                                            rank: j, dist: dist,
+                                            x: vertex.x, y: vertex.y
+                                        };
+                                        eligible = true;
+                                        found = true;
+                                    }
+                                }
+                                if(found) {
+                                    // don't look for lower precedence types for this feature
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return eligible ? result : null;
+    },
+    
+    /**
+     * Method: getGeoTolerance
+     * Calculate a tolerance in map units given a tolerance in pixels.  This
+     *     takes advantage of the <geoToleranceCache> when the map resolution
+     *     has not changed.
+     *     
+     * Parameters:
+     * tolerance - {Number} A tolerance value in pixels.
+     *
+     * Returns:
+     * {Number} A tolerance value in map units.
+     */
+    getGeoTolerance: function(tolerance) {
+        var resolution = this.layer.map.getResolution();
+        if(resolution !== this.resolution) {
+            this.resolution = resolution;
+            this.geoToleranceCache = {};
+        }
+        var geoTolerance = this.geoToleranceCache[tolerance];
+        if(geoTolerance === undefined) {
+            geoTolerance = tolerance * resolution;
+            this.geoToleranceCache[tolerance] = geoTolerance;
+        }
+        return geoTolerance;
+    },
+    
+    /**
+     * Method: destroy
+     * Clean up the control.
+     */
+    destroy: function() {
+        if(this.active) {
+            this.deactivate(); // TODO: this should be handled by the super
+        }
+        delete this.layer;
+        delete this.targets;
+        OpenLayers.Control.prototype.destroy.call(this);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Snapping"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Split.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Split.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/Split.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,497 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Path.js
+ * @requires OpenLayers/Layer/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Split
+ * Acts as a split feature agent while editing vector features.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Split = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * control.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * Supported control event types (in addition to those from <OpenLayers.Control>):
+     * beforesplit - Triggered before a split occurs.  Listeners receive an
+     *     event object with *source* and *target* properties.
+     * split - Triggered when a split occurs.  Listeners receive an event with
+     *     an *original* property and a *features* property.  The original
+     *     is a reference to the target feature that the sketch or modified
+     *     feature intersects.  The features property is a list of all features
+     *     that result from this single split.  This event is triggered before
+     *     the resulting features are added to the layer (while the layer still
+     *     has a reference to the original).
+     * aftersplit - Triggered after all splits resulting from a single sketch
+     *     or feature modification have occurred.  The original features
+     *     have been destroyed and features that result from the split
+     *     have already been added to the layer.  Listeners receive an event
+     *     with a *source* and *features* property.  The source references the
+     *     sketch or modified feature used as a splitter.  The features
+     *     property is a list of all resulting features.
+     */
+    EVENT_TYPES: ["beforesplit", "split", "aftersplit"],
+    
+    /**
+     * APIProperty: layer
+     * {<OpenLayers.Layer.Vector>} The target layer with features to be split.
+     *     Set at construction or after construction with <setLayer>.
+     */
+    layer: null,
+    
+    /**
+     * Property: source
+     * {<OpenLayers.Layer.Vector>} Optional source layer.  Any newly created
+     *     or modified features from this layer will be used to split features
+     *     on the target layer.  If not provided, a temporary sketch layer will
+     *     be created.
+     */
+    source: null,
+    
+    /**
+     * Property: sourceOptions
+     * {Options} If a temporary sketch layer is created, these layer options
+     *     will be applied.
+     */
+    sourceOptions: null,
+
+    /**
+     * APIProperty: tolerance
+     * {Number} Distance between the calculated intersection and a vertex on
+     *     the source geometry below which the existing vertex will be used
+     *     for the split.  Default is null.
+     */
+    tolerance: null,
+    
+    /**
+     * APIProperty: edge
+     * {Boolean} Allow splits given intersection of edges only.  Default is
+     *     true.  If false, a vertex on the source must be within the
+     *     <tolerance> distance of the calculated intersection for a split
+     *     to occur.
+     */
+    edge: true,
+    
+    /**
+     * APIProperty: deferDelete
+     * {Boolean} Instead of removing features from the layer, set feature
+     *     states of split features to DELETE.  This assumes a save strategy
+     *     or other component is in charge of removing features from the
+     *     layer.  Default is false.  If false, split features will be
+     *     immediately deleted from the layer.
+     */
+    deferDelete: false,
+    
+    /**
+     * APIProperty: mutual
+     * {Boolean} If source and target layers are the same, split source
+     *     features and target features where they intersect.  Default is
+     *     true.  If false, only target features will be split.
+     */
+    mutual: true,
+    
+    /**
+     * APIProperty: targetFilter
+     * {OpenLayers.Filter} Optional filter that will be evaluated
+     *     to determine if a feature from the target layer is eligible for
+     *     splitting.
+     */
+    targetFilter: null,
+    
+    /**
+     * APIProperty: sourceFilter
+     * {OpenLayers.Filter} Optional filter that will be evaluated
+     *     to determine if a feature from the target layer is eligible for
+     *     splitting.
+     */
+    sourceFilter: null,
+    
+    /**
+     * Property: handler
+     * {<OpenLayers.Handler.Path>} The temporary sketch handler created if
+     *     no source layer is provided.
+     */
+    handler: null,
+
+    /**
+     * Constructor: OpenLayers.Control.Split
+     * Creates a new split control. A control is constructed with a target
+     *     layer and an optional source layer. While the control is active,
+     *     creating new features or modifying existing features on the source
+     *     layer will result in splitting any eligible features on the target
+     *     layer.  If no source layer is provided, a temporary sketch layer will
+     *     be created to create lines for splitting features on the target.
+     *
+     * Parameters:
+     * options - {Object} An object containing all configuration properties for
+     *     the control.
+     *
+     * Valid options:
+     * layer - {OpenLayers.Layer.Vector} The target layer.  Features from this
+     *     layer will be split by new or modified features on the source layer
+     *     or temporary sketch layer.
+     * source - {OpenLayers.Layer.Vector} Optional source layer.  If provided
+     *     newly created features or modified features will be used to split
+     *     features on the target layer.  If not provided, a temporary sketch
+     *     layer will be created for drawing lines.
+     * tolerance - {Number} Optional value for the distance between a source
+     *     vertex and the calculated intersection below which the split will
+     *     occur at the vertex.
+     * edge - {Boolean} Allow splits given intersection of edges only.  Default
+     *     is true.  If false, a vertex on the source must be within the
+     *     <tolerance> distance of the calculated intersection for a split
+     *     to occur.
+     * mutual - {Boolean} If source and target are the same, split source
+     *     features and target features where they intersect.  Default is
+     *     true.  If false, only target features will be split.
+     * targetFilter - {OpenLayers.Filter} Optional filter that will be evaluated
+     *     to determine if a feature from the target layer is eligible for
+     *     splitting.
+     * sourceFilter - {OpenLayers.Filter} Optional filter that will be evaluated
+     *     to determine if a feature from the target layer is eligible for
+     *     splitting.
+     */
+    initialize: function(options) {
+        // concatenate events specific to measure with those from the base
+        Array.prototype.push.apply(
+            this.EVENT_TYPES, OpenLayers.Control.prototype.EVENT_TYPES
+        );
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+        this.options = options || {}; // TODO: this could be done by the super
+        
+        // set the source layer if provided
+        if(this.options.source) {
+            this.setSource(this.options.source);
+        }
+    },
+    
+    /**
+     * APIMethod: setSource
+     * Set the source layer for edits layer.
+     *
+     * Parameters:
+     * layer - {OpenLayers.Layer.Vector}  The new source layer layer.  If
+     *     null, a temporary sketch layer will be created.
+     */
+    setSource: function(layer) {
+        if(this.active) {
+            this.deactivate();
+            if(this.handler) {
+                this.handler.destroy();
+                delete this.handler;
+            }
+            this.source = layer;
+            this.activate();
+        } else {
+            this.source = layer;
+        }
+    },
+    
+    /**
+     * APIMethod: activate
+     * Activate the control.  Activating the control registers listeners for
+     *     editing related events so that during feature creation and
+     *     modification, features in the target will be considered for
+     *     splitting.
+     */
+    activate: function() {
+        var activated = OpenLayers.Control.prototype.activate.call(this);
+        if(activated) {
+            if(!this.source) {
+                if(!this.handler) {
+                    this.handler = new OpenLayers.Handler.Path(this,
+                        {done: function(geometry) {
+                            this.onSketchComplete({
+                                feature: new OpenLayers.Feature.Vector(geometry)
+                            });
+                        }},
+                        {layerOptions: this.sourceOptions}
+                    );
+                }
+                this.handler.activate();
+            } else if(this.source.events) {
+                this.source.events.on({
+                    sketchcomplete: this.onSketchComplete,
+                    afterfeaturemodified: this.afterFeatureModified,
+                    scope: this
+                });
+            }
+        }
+        return activated;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the control.  Deactivating the control unregisters listeners
+     *     so feature editing may proceed without engaging the split agent.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Control.prototype.deactivate.call(this);
+        if(deactivated) {
+            if(this.source && this.source.events) {
+                this.layer.events.un({
+                    sketchcomplete: this.onSketchComplete,
+                    afterfeaturemodified: this.afterFeatureModified,
+                    scope: this
+                });
+            }
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: onSketchComplete
+     * Registered as a listener for the sketchcomplete event on the editable
+     *     layer.
+     *
+     * Parameters:
+     * event - {Object} The sketch complete event.
+     *
+     * Returns:
+     * {Boolean} Stop the sketch from being added to the layer (it has been
+     *     split).
+     */
+    onSketchComplete: function(event) {
+        this.feature = null;
+        return !this.considerSplit(event.feature);
+    },
+    
+    /**
+     * Method: afterFeatureModified
+     * Registered as a listener for the afterfeaturemodified event on the
+     *     editable layer.
+     *
+     * Parameters:
+     * event - {Object} The after feature modified event.
+     */
+    afterFeatureModified: function(event) {
+        if(event.modified) {
+            var feature = event.feature;
+            if(feature.geometry instanceof OpenLayers.Geometry.LineString ||
+               feature.geometry instanceof OpenLayers.Geometry.MultiLineString) {
+                this.feature = event.feature;
+                this.considerSplit(event.feature);
+            }
+        }
+    },
+    
+    /**
+     * Method: removeByGeometry
+     * Remove a feature from a list based on the given geometry.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>} A list of features.
+     * geometry - {<OpenLayers.Geometry>} A geometry.
+     */
+    removeByGeometry: function(features, geometry) {
+        for(var i=0, len=features.length; i<len; ++i) {
+            if(features[i].geometry === geometry) {
+                features.splice(i, 1);
+                break;
+            }
+        }
+    },
+    
+    /**
+     * Method: isEligible
+     * Test if a target feature is eligible for splitting.
+     *
+     * Parameters:
+     * target - {<OpenLayers.Feature.Vector>} The target feature.
+     *
+     * Returns:
+     * {Boolean} The target is eligible for splitting.
+     */
+    isEligible: function(target) {
+        return (
+            target.state !== OpenLayers.State.DELETE
+        ) && (
+            target.geometry instanceof OpenLayers.Geometry.LineString ||
+            target.geometry instanceof OpenLayers.Geometry.MultiLineString
+        ) && (
+            this.feature !== target
+        ) && (
+            !this.targetFilter ||
+            this.targetFilter.evaluate(target.attributes)
+        );
+    },
+
+    /**
+     * Method: considerSplit
+     * Decide whether or not to split target features with the supplied
+     *     feature.  If <mutual> is true, both the source and target features
+     *     will be split if eligible.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector}} The newly created or modified
+     *     feature.
+     *
+     * Returns:
+     * {Boolean} The supplied feature was split (and destroyed).
+     */
+    considerSplit: function(feature) {
+        sourceSplit = false;
+        targetSplit = false;
+        if(!this.sourceFilter ||
+           this.sourceFilter.evaluate(feature.attributes)) {
+            var features = this.layer && this.layer.features || [];
+            var target, results, result, proceed;
+            var additions = [], removals = [];
+            var mutual = (this.layer === this.source) && this.mutual;
+            var options = {
+                edge: this.edge,
+                tolerance: this.tolerance,
+                mutual: mutual
+            };
+            var sourceParts = [feature.geometry];
+            var targetFeature, targetParts;
+            var source, parts;
+            for(var i=0, len=features.length; i<len; ++i) {
+                targetFeature = features[i];
+                if(this.isEligible(targetFeature)) {
+                    targetParts = [targetFeature.geometry];
+                    // work through source geoms - this array may change
+                    for(var j=0; j<sourceParts.length; ++j) { 
+                        source = sourceParts[j];
+                        // work through target parts - this array may change
+                        for(var k=0; k<targetParts.length; ++k) {
+                            target = targetParts[k];
+                            if(source.getBounds().intersectsBounds(target.getBounds())) {
+                                results = source.split(target, options);
+                                if(results) {
+                                    proceed = this.events.triggerEvent(
+                                        "beforesplit", {source: feature, target: targetFeature}
+                                    );
+                                    if(proceed !== false) {
+                                        if(mutual) {
+                                            parts = results[0];
+                                            // handle parts that result from source splitting
+                                            if(parts.length > 1) {
+                                                // splice in new source parts
+                                                parts.unshift(j, 1); // add args for splice below
+                                                Array.prototype.splice.apply(sourceParts, parts);
+                                                j += parts.length - 3;
+                                            }
+                                            results = results[1];
+                                        }
+                                        // handle parts that result from target splitting
+                                        if(results.length > 1) {
+                                            // splice in new target parts
+                                            results.unshift(k, 1); // add args for splice below
+                                            Array.prototype.splice.apply(targetParts, results);
+                                            k += results.length - 3;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if(targetParts && targetParts.length > 1) {
+                        this.geomsToFeatures(targetFeature, targetParts);
+                        this.events.triggerEvent("split", {
+                            original: targetFeature,
+                            features: targetParts
+                        });
+                        Array.prototype.push.apply(additions, targetParts);
+                        removals.push(targetFeature);
+                        targetSplit = true;
+                    }
+                }
+            }
+            if(sourceParts && sourceParts.length > 1) {
+                this.geomsToFeatures(feature, sourceParts);
+                this.events.triggerEvent("split", {
+                    original: feature,
+                    features: sourceParts
+                });
+                Array.prototype.push.apply(additions, sourceParts);
+                removals.push(feature);
+                sourceSplit = true;
+            }
+            if(sourceSplit || targetSplit) {
+                // remove and add feature events are suppressed
+                // listen for split event on this control instead
+                if(this.deferDelete) {
+                    // Set state instead of removing.  Take care to avoid
+                    // setting delete for features that have not yet been
+                    // inserted - those should be destroyed immediately.
+                    var feat, destroys = [];
+                    for(var i=0, len=removals.length; i<len; ++i) {
+                        feat = removals[i];
+                        if(feat.state === OpenLayers.State.INSERT) {
+                            destroys.push(feat);
+                        } else {
+                            feat.state = OpenLayers.State.DELETE;
+                            this.layer.drawFeature(feat);
+                        }
+                    }
+                    this.layer.destroyFeatures(destroys, {silent: true});
+                    for(var i=0, len=additions.length; i<len; ++i) {
+                        additions[i].state = OpenLayers.State.INSERT;
+                    }
+                } else {
+                    this.layer.destroyFeatures(removals, {silent: true});
+                }
+                this.layer.addFeatures(additions, {silent: true});
+                this.events.triggerEvent("aftersplit", {
+                    source: feature,
+                    features: additions
+                });
+            }
+        }
+        return sourceSplit;
+    },
+    
+    /**
+     * Method: geomsToFeatures
+     * Create new features given a template feature and a list of geometries.
+     *     The list of geometries is modified in place.  The result will be
+     *     a list of new features.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature to be cloned.
+     * geoms - {Array(<OpenLayers.Geometry>)} List of goemetries.  This will
+     *     become a list of new features.
+     */
+    geomsToFeatures: function(feature, geoms) {
+        var clone = feature.clone();
+        delete clone.geometry;
+        var newFeature;
+        for(var i=0, len=geoms.length; i<len; ++i) {
+            // turn results list from geoms to features
+            newFeature = clone.clone();
+            newFeature.geometry = geoms[i];
+            newFeature.state = OpenLayers.State.INSERT;
+            geoms[i] = newFeature;
+        }
+    },
+    
+    /**
+     * Method: destroy
+     * Clean up the control.
+     */
+    destroy: function() {
+        if(this.active) {
+            this.deactivate(); // TODO: this should be handled by the super
+        }
+        OpenLayers.Control.prototype.destroy.call(this);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Split"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomBox.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomBox.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomBox.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,93 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Box.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomBox
+ * The ZoomBox control enables zooming directly to a given extent, by drawing 
+ * a box on the map. The box is drawn by holding down shift, whilst dragging 
+ * the mouse.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
+    /**
+     * Property: type
+     * {OpenLayers.Control.TYPE}
+     */
+    type: OpenLayers.Control.TYPE_TOOL,
+
+    /**
+     * Property: out
+     * {Boolean} Should the control be used for zooming out?
+     */
+    out: false,
+
+    /**
+     * Property: alwaysZoom
+     * {Boolean} Always zoom in/out, when box drawed 
+     */
+    alwaysZoom: false,
+
+    /**
+     * Method: draw
+     */    
+    draw: function() {
+        this.handler = new OpenLayers.Handler.Box( this,
+                            {done: this.zoomBox}, {keyMask: this.keyMask} );
+    },
+
+    /**
+     * Method: zoomBox
+     *
+     * Parameters:
+     * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
+     */
+    zoomBox: function (position) {
+        if (position instanceof OpenLayers.Bounds) {
+            if (!this.out) {
+                var minXY = this.map.getLonLatFromPixel(
+                            new OpenLayers.Pixel(position.left, position.bottom));
+                var maxXY = this.map.getLonLatFromPixel(
+                            new OpenLayers.Pixel(position.right, position.top));
+                var bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
+                                               maxXY.lon, maxXY.lat);
+            } else {
+                var pixWidth = Math.abs(position.right-position.left);
+                var pixHeight = Math.abs(position.top-position.bottom);
+                var zoomFactor = Math.min((this.map.size.h / pixHeight),
+                    (this.map.size.w / pixWidth));
+                var extent = this.map.getExtent();
+                var center = this.map.getLonLatFromPixel(
+                    position.getCenterPixel());
+                var xmin = center.lon - (extent.getWidth()/2)*zoomFactor;
+                var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
+                var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
+                var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
+                var bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
+            }
+            // always zoom in/out 
+            var lastZoom = this.map.getZoom(); 
+            this.map.zoomToExtent(bounds);
+            if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){ 
+                this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); 
+            }
+        } else { // it's a pixel
+            if (!this.out) {
+                this.map.setCenter(this.map.getLonLatFromPixel(position),
+                               this.map.getZoom() + 1);
+            } else {
+                this.map.setCenter(this.map.getLonLatFromPixel(position),
+                               this.map.getZoom() - 1);
+            }
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ZoomBox"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomIn.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomIn.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomIn.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,34 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomIn
+ * The ZoomIn control is a button to increase the zoom level of a map.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: type
+     * {String} The type of <OpenLayers.Control> -- When added to a 
+     *     <Control.Panel>, 'type' is used by the panel to determine how to 
+     *     handle our events.
+     */
+    type: OpenLayers.Control.TYPE_BUTTON,
+    
+    /**
+     * Method: trigger
+     */
+    trigger: function(){
+        this.map.zoomIn();
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ZoomIn"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomOut.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomOut.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomOut.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,34 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomOut
+ * The ZoomOut control is a button to decrease the zoom level of a map.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: type
+     * {String} The type of <OpenLayers.Control> -- When added to a 
+     *     <Control.Panel>, 'type' is used by the panel to determine how to 
+     *     handle our events.
+     */
+    type: OpenLayers.Control.TYPE_BUTTON,
+    
+    /**
+     * Method: trigger
+     */
+    trigger: function(){
+        this.map.zoomOut();
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ZoomOut"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomPanel.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomPanel.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control/ZoomPanel.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,53 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/Panel.js
+ * @requires OpenLayers/Control/ZoomIn.js
+ * @requires OpenLayers/Control/ZoomOut.js
+ * @requires OpenLayers/Control/ZoomToMaxExtent.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomPanel
+ * The ZoomPanel control is a compact collecton of 3 zoom controls: a 
+ * <OpenLayers.Control.ZoomIn>, a <OpenLayers.Control.ZoomToMaxExtent>, and a
+ * <OpenLayers.Control.ZoomOut>. By default it is drawn in the upper left 
+ * corner of the map.
+ *
+ * Note: 
+ * If you wish to use this class with the default images and you want 
+ *       it to look nice in ie6, you should add the following, conditionally
+ *       added css stylesheet to your HTML file:
+ * 
+ * (code)
+ * <!--[if lte IE 6]>
+ *   <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" />
+ * <![endif]-->
+ * (end)
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control.Panel>
+ */
+OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, {
+
+    /**
+     * Constructor: OpenLayers.Control.ZoomPanel 
+     * Add the three zooming controls.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be used
+     *     to extend the control.
+     */
+    initialize: function(options) {
+        OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);
+        this.addControls([
+            new OpenLayers.Control.ZoomIn(),
+            new OpenLayers.Control.ZoomToMaxExtent(),
+            new OpenLayers.Control.ZoomOut()
+        ]);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ZoomPanel"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Control.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,349 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Control
+ * Controls affect the display or behavior of the map. They allow everything
+ * from panning and zooming to displaying a scale indicator. Controls by 
+ * default are added to the map they are contained within however it is
+ * possible to add a control to an external div by passing the div in the
+ * options parameter.
+ * 
+ * Example:
+ * The following example shows how to add many of the common controls
+ * to a map.
+ * 
+ * > var map = new OpenLayers.Map('map', { controls: [] });
+ * >
+ * > map.addControl(new OpenLayers.Control.PanZoomBar());
+ * > map.addControl(new OpenLayers.Control.MouseToolbar());
+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ * > map.addControl(new OpenLayers.Control.Permalink());
+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
+ * > map.addControl(new OpenLayers.Control.MousePosition());
+ * > map.addControl(new OpenLayers.Control.OverviewMap());
+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+ *
+ * The next code fragment is a quick example of how to intercept 
+ * shift-mouse click to display the extent of the bounding box
+ * dragged out by the user.  Usually controls are not created
+ * in exactly this manner.  See the source for a more complete 
+ * example:
+ *
+ * > var control = new OpenLayers.Control();
+ * > OpenLayers.Util.extend(control, {
+ * >     draw: function () {
+ * >         // this Handler.Box will intercept the shift-mousedown
+ * >         // before Control.MouseDefault gets to see it
+ * >         this.box = new OpenLayers.Handler.Box( control, 
+ * >             {"done": this.notice},
+ * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
+ * >         this.box.activate();
+ * >     },
+ * >
+ * >     notice: function (bounds) {
+ * >         OpenLayers.Console.userError(bounds);
+ * >     }
+ * > }); 
+ * > map.addControl(control);
+ * 
+ */
+OpenLayers.Control = OpenLayers.Class({
+
+    /** 
+     * Property: id 
+     * {String} 
+     */
+    id: null,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} this gets set in the addControl() function in
+     * OpenLayers.Map 
+     */
+    map: null,
+
+    /** 
+     * Property: div 
+     * {DOMElement} 
+     */
+    div: null,
+
+    /** 
+     * Property: type 
+     * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
+     * determines the type of interactions which are possible with them when
+     * they are placed into a toolbar. 
+     */
+    type: null, 
+
+    /** 
+     * Property: allowSelection
+     * {Boolean} By deafault, controls do not allow selection, because
+     * it may interfere with map dragging. If this is true, OpenLayers
+     * will not prevent selection of the control.
+     * Default is false.
+     */
+    allowSelection: false,  
+
+    /** 
+     * Property: displayClass 
+     * {string}  This property is used for CSS related to the drawing of the
+     * Control. 
+     */
+    displayClass: "",
+    
+    /**
+    * Property: title  
+    * {string}  This property is used for showing a tooltip over the  
+    * Control.  
+    */ 
+    title: "",
+
+    /** 
+     * Property: active 
+     * {Boolean} The control is active.
+     */
+    active: null,
+
+    /** 
+     * Property: handler 
+     * {<OpenLayers.Handler>} null
+     */
+    handler: null,
+
+    /**
+     * APIProperty: eventListeners
+     * {Object} If set as an option at construction, the eventListeners
+     *     object will be registered with <OpenLayers.Events.on>.  Object
+     *     structure must be a listeners object as shown in the example for
+     *     the events.on method.
+     */
+    eventListeners: null,
+
+    /** 
+     * Property: events
+     * {<OpenLayers.Events>} Events instance for triggering control specific
+     *     events.
+     */
+    events: null,
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * control.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * All event objects have at least the following properties:
+     * object - {Object} A reference to control.events.object (a reference
+     *      to the control).
+     * element - {DOMElement} A reference to control.events.element (which
+     *      will be null unless documented otherwise).
+     *
+     * Supported map event types:
+     * activate - Triggered when activated.
+     * deactivate - Triggered when deactivated.
+     */
+    EVENT_TYPES: ["activate", "deactivate"],
+
+    /**
+     * Constructor: OpenLayers.Control
+     * Create an OpenLayers Control.  The options passed as a parameter
+     * directly extend the control.  For example passing the following:
+     * 
+     * > var control = new OpenLayers.Control({div: myDiv});
+     *
+     * Overrides the default div attribute value of null.
+     * 
+     * Parameters:
+     * options - {Object} 
+     */
+    initialize: function (options) {
+        // We do this before the extend so that instances can override
+        // className in options.
+        this.displayClass = 
+            this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+        
+        OpenLayers.Util.extend(this, options);
+        
+        this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+        if(this.eventListeners instanceof Object) {
+            this.events.on(this.eventListeners);
+        }
+        if (this.id == null) {
+            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+        }
+    },
+
+    /**
+     * Method: destroy
+     * The destroy method is used to perform any clean up before the control
+     * is dereferenced.  Typically this is where event listeners are removed
+     * to prevent memory leaks.
+     */
+    destroy: function () {
+        if(this.events) {
+            if(this.eventListeners) {
+                this.events.un(this.eventListeners);
+            }
+            this.events.destroy();
+            this.events = null;
+        }
+        this.eventListeners = null;
+
+        // eliminate circular references
+        if (this.handler) {
+            this.handler.destroy();
+            this.handler = null;
+        }
+        if(this.handlers) {
+            for(var key in this.handlers) {
+                if(this.handlers.hasOwnProperty(key) &&
+                   typeof this.handlers[key].destroy == "function") {
+                    this.handlers[key].destroy();
+                }
+            }
+            this.handlers = null;
+        }
+        if (this.map) {
+            this.map.removeControl(this);
+            this.map = null;
+        }
+    },
+
+    /** 
+     * Method: setMap
+     * Set the map property for the control. This is done through an accessor
+     * so that subclasses can override this and take special action once 
+     * they have their map variable set. 
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        this.map = map;
+        if (this.handler) {
+            this.handler.setMap(map);
+        }
+    },
+  
+    /**
+     * Method: draw
+     * The draw method is called when the control is ready to be displayed
+     * on the page.  If a div has not been created one is created.  Controls
+     * with a visual component will almost always want to override this method 
+     * to customize the look of control. 
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
+     *      or null.
+     *
+     * Returns:
+     * {DOMElement} A reference to the DIV DOMElement containing the control
+     */
+    draw: function (px) {
+        if (this.div == null) {
+            this.div = OpenLayers.Util.createDiv(this.id);
+            this.div.className = this.displayClass;
+            if (!this.allowSelection) {
+                this.div.className += " olControlNoSelect";
+                this.div.setAttribute("unselectable", "on", 0);
+                this.div.onselectstart = function() { return(false); }; 
+            }    
+            if (this.title != "") {
+                this.div.title = this.title;
+            }
+        }
+        if (px != null) {
+            this.position = px.clone();
+        }
+        this.moveTo(this.position);
+        return this.div;
+    },
+
+    /**
+     * Method: moveTo
+     * Sets the left and top style attributes to the passed in pixel 
+     * coordinates.
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     */
+    moveTo: function (px) {
+        if ((px != null) && (this.div != null)) {
+            this.div.style.left = px.x + "px";
+            this.div.style.top = px.y + "px";
+        }
+    },
+
+    /**
+     * Method: activate
+     * Explicitly activates a control and it's associated
+     * handler if one has been set.  Controls can be
+     * deactivated by calling the deactivate() method.
+     * 
+     * Returns:
+     * {Boolean}  True if the control was successfully activated or
+     *            false if the control was already active.
+     */
+    activate: function () {
+        if (this.active) {
+            return false;
+        }
+        if (this.handler) {
+            this.handler.activate();
+        }
+        this.active = true;
+        if(this.map) {
+            OpenLayers.Element.addClass(
+                this.map.viewPortDiv,
+                this.displayClass.replace(/ /g, "") + "Active"
+            );
+        }
+        this.events.triggerEvent("activate");
+        return true;
+    },
+    
+    /**
+     * Method: deactivate
+     * Deactivates a control and it's associated handler if any.  The exact
+     * effect of this depends on the control itself.
+     * 
+     * Returns:
+     * {Boolean} True if the control was effectively deactivated or false
+     *           if the control was already inactive.
+     */
+    deactivate: function () {
+        if (this.active) {
+            if (this.handler) {
+                this.handler.deactivate();
+            }
+            this.active = false;
+            if(this.map) {
+                OpenLayers.Element.removeClass(
+                    this.map.viewPortDiv,
+                    this.displayClass.replace(/ /g, "") + "Active"
+                );
+            }
+            this.events.triggerEvent("deactivate");
+            return true;
+        }
+        return false;
+    },
+
+    CLASS_NAME: "OpenLayers.Control"
+});
+
+OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Control.TYPE_TOOL   = 3;

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature/WFS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature/WFS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature/WFS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,79 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Feature.js
+ */
+
+/**
+ * Class: OpenLayers.Feature.WFS
+ * WFS handling class, for use as a featureClass on the WFS layer for handling
+ * 'point' WFS types. Good for subclassing when creating a custom WFS like
+ * XML application.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Feature>
+ */
+OpenLayers.Feature.WFS = OpenLayers.Class(OpenLayers.Feature, {
+      
+    /** 
+     * Constructor: OpenLayers.Feature.WFS
+     * Create a WFS feature.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * xmlNode - {XMLNode} 
+     */
+    initialize: function(layer, xmlNode) {
+        var newArguments = arguments;
+        var data = this.processXMLNode(xmlNode);
+        newArguments = new Array(layer, data.lonlat, data);
+        OpenLayers.Feature.prototype.initialize.apply(this, newArguments);
+        this.createMarker();
+        this.layer.addMarker(this.marker);
+    },
+    
+    /** 
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        if (this.marker != null) {
+            this.layer.removeMarker(this.marker);  
+        }
+        OpenLayers.Feature.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * Method: processXMLNode
+     * When passed an xmlNode, parses it for a GML point, and passes
+     * back an object describing that point.
+     *
+     * For subclasses of Feature.WFS, this is the feature to change.
+     *
+     * Parameters:
+     * xmlNode - {XMLNode} 
+     * 
+     * Returns:
+     * {Object} Data Object with 'id', 'lonlat', and private properties set
+     */
+    processXMLNode: function(xmlNode) {
+        //this should be overridden by subclasses
+        // must return an Object with 'id' and 'lonlat' values set
+        var point = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, "http://www.opengis.net/gml", "gml", "Point");
+        var text  = OpenLayers.Util.getXmlNodeValue(OpenLayers.Ajax.getElementsByTagNameNS(point[0], "http://www.opengis.net/gml","gml", "coordinates")[0]);
+        var floats = text.split(",");
+        return {lonlat: new OpenLayers.LonLat(parseFloat(floats[0]),
+                                              parseFloat(floats[1])),
+                id: null};
+
+    },
+
+    CLASS_NAME: "OpenLayers.Feature.WFS"
+});
+  
+  
+  
+  
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Feature.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,222 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Marker.js
+ * @requires OpenLayers/Popup/AnchoredBubble.js
+ */
+
+/**
+ * Class: OpenLayers.Feature
+ * Features are combinations of geography and attributes. The OpenLayers.Feature
+ *     class specifically combines a marker and a lonlat.
+ */
+OpenLayers.Feature = OpenLayers.Class({
+
+    /** 
+     * Property: layer 
+     * {<OpenLayers.Layer>} 
+     */
+    layer: null,
+
+    /** 
+     * Property: id 
+     * {String} 
+     */
+    id: null,
+    
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} 
+     */
+    lonlat: null,
+
+    /** 
+     * Property: data 
+     * {Object} 
+     */
+    data: null,
+
+    /** 
+     * Property: marker 
+     * {<OpenLayers.Marker>} 
+     */
+    marker: null,
+
+    /**
+     * APIProperty: popupClass
+     * {<OpenLayers.Class>} The class which will be used to instantiate
+     *     a new Popup. Default is <OpenLayers.Popup.AnchoredBubble>.
+     */
+    popupClass: OpenLayers.Popup.AnchoredBubble,
+
+    /** 
+     * Property: popup 
+     * {<OpenLayers.Popup>} 
+     */
+    popup: null,
+
+    /** 
+     * Constructor: OpenLayers.Feature
+     * Constructor for features.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * lonlat - {<OpenLayers.LonLat>} 
+     * data - {Object} 
+     * 
+     * Returns:
+     * {<OpenLayers.Feature>}
+     */
+    initialize: function(layer, lonlat, data) {
+        this.layer = layer;
+        this.lonlat = lonlat;
+        this.data = (data != null) ? data : {};
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); 
+    },
+
+    /** 
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+
+        //remove the popup from the map
+        if ((this.layer != null) && (this.layer.map != null)) {
+            if (this.popup != null) {
+                this.layer.map.removePopup(this.popup);
+            }
+        }
+
+        this.layer = null;
+        this.id = null;
+        this.lonlat = null;
+        this.data = null;
+        if (this.marker != null) {
+            this.destroyMarker(this.marker);
+            this.marker = null;
+        }
+        if (this.popup != null) {
+            this.destroyPopup(this.popup);
+            this.popup = null;
+        }
+    },
+    
+    /**
+     * Method: onScreen
+     * 
+     * Returns:
+     * {Boolean} Whether or not the feature is currently visible on screen
+     *           (based on its 'lonlat' property)
+     */
+    onScreen:function() {
+        
+        var onScreen = false;
+        if ((this.layer != null) && (this.layer.map != null)) {
+            var screenBounds = this.layer.map.getExtent();
+            onScreen = screenBounds.containsLonLat(this.lonlat);
+        }    
+        return onScreen;
+    },
+    
+
+    /**
+     * Method: createMarker
+     * Based on the data associated with the Feature, create and return a marker object.
+     *
+     * Returns: 
+     * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
+     *          set in this.data. If no 'lonlat' is set, returns null. If no
+     *          'icon' is set, OpenLayers.Marker() will load the default image.
+     *          
+     *          Note - this.marker is set to return value
+     * 
+     */
+    createMarker: function() {
+
+        if (this.lonlat != null) {
+            this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
+        }
+        return this.marker;
+    },
+
+    /**
+     * Method: destroyMarker
+     * Destroys marker.
+     * If user overrides the createMarker() function, s/he should be able
+     *   to also specify an alternative function for destroying it
+     */
+    destroyMarker: function() {
+        this.marker.destroy();  
+    },
+
+    /**
+     * Method: createPopup
+     * Creates a popup object created from the 'lonlat', 'popupSize',
+     *     and 'popupContentHTML' properties set in this.data. It uses
+     *     this.marker.icon as default anchor. 
+     *  
+     *  If no 'lonlat' is set, returns null. 
+     *  If no this.marker has been created, no anchor is sent.
+     *
+     *  Note - the returned popup object is 'owned' by the feature, so you
+     *      cannot use the popup's destroy method to discard the popup.
+     *      Instead, you must use the feature's destroyPopup
+     * 
+     *  Note - this.popup is set to return value
+     * 
+     * Parameters: 
+     * closeBox - {Boolean} create popup with closebox or not
+     * 
+     * Returns:
+     * {<OpenLayers.Popup>} Returns the created popup, which is also set
+     *     as 'popup' property of this feature. Will be of whatever type
+     *     specified by this feature's 'popupClass' property, but must be
+     *     of type <OpenLayers.Popup>.
+     * 
+     */
+    createPopup: function(closeBox) {
+
+        if (this.lonlat != null) {
+            
+            var id = this.id + "_popup";
+            var anchor = (this.marker) ? this.marker.icon : null;
+
+            if (!this.popup) {
+                this.popup = new this.popupClass(id, 
+                                                 this.lonlat,
+                                                 this.data.popupSize,
+                                                 this.data.popupContentHTML,
+                                                 anchor, 
+                                                 closeBox); 
+            }    
+            if (this.data.overflow != null) {
+                this.popup.contentDiv.style.overflow = this.data.overflow;
+            }    
+            
+            this.popup.feature = this;
+        }        
+        return this.popup;
+    },
+
+    
+    /**
+     * Method: destroyPopup
+     * Destroys the popup created via createPopup.
+     *
+     * As with the marker, if user overrides the createPopup() function, s/he 
+     *   should also be able to override the destruction
+     */
+    destroyPopup: function() {
+        if (this.popup) {
+            this.popup.feature = null;
+            this.popup.destroy();
+            this.popup = null;
+        }    
+    },
+
+    CLASS_NAME: "OpenLayers.Feature"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Comparison.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Comparison.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Comparison.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,255 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+  * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Comparison
+ * This class represents a comparison filter.
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: type
+     * {String} type: type of the comparison. This is one of
+     * - OpenLayers.Filter.Comparison.EQUAL_TO                 = "==";
+     * - OpenLayers.Filter.Comparison.NOT_EQUAL_TO             = "!=";
+     * - OpenLayers.Filter.Comparison.LESS_THAN                = "<";
+     * - OpenLayers.Filter.Comparison.GREATER_THAN             = ">";
+     * - OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO    = "<=";
+     * - OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+     * - OpenLayers.Filter.Comparison.BETWEEN                  = "..";
+     * - OpenLayers.Filter.Comparison.LIKE                     = "~"; 
+     */
+    type: null,
+    
+    /**
+     * APIProperty: property
+     * {String}
+     * name of the context property to compare
+     */
+    property: null,
+    
+    /**
+     * APIProperty: value
+     * {Number} or {String}
+     * comparison value for binary comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    value: null,
+    
+    /**
+     * Property: matchCase
+     * {Boolean} Force case sensitive searches for EQUAL_TO and NOT_EQUAL_TO
+     *     comparisons.  The Filter Encoding 1.1 specification added a matchCase
+     *     attribute to ogc:PropertyIsEqualTo and ogc:PropertyIsNotEqualTo
+     *     elements.  This property will be serialized with those elements only
+     *     if using the v1.1.0 filter format. However, when evaluating filters
+     *     here, the matchCase property will always be respected (for EQUAL_TO
+     *     and NOT_EQUAL_TO).  Default is true.
+     */
+    matchCase: true,
+    
+    /**
+     * APIProperty: lowerBoundary
+     * {Number} or {String}
+     * lower boundary for between comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    lowerBoundary: null,
+    
+    /**
+     * APIProperty: upperBoundary
+     * {Number} or {String}
+     * upper boundary for between comparisons. In the case of a String, this
+     * can be a combination of text and propertyNames in the form
+     * "literal ${propertyName}"
+     */
+    upperBoundary: null,
+
+    /** 
+     * Constructor: OpenLayers.Filter.Comparison
+     * Creates a comparison rule.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           rule
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Comparison>}
+     */
+    initialize: function(options) {
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.  Should be implemented by
+     *     subclasses.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        var result = false;
+        switch(this.type) {
+            case OpenLayers.Filter.Comparison.EQUAL_TO:
+                var got = context[this.property];
+                var exp = this.value;
+                if(!this.matchCase &&
+                   typeof got == "string" && typeof exp == "string") {
+                    result = (got.toUpperCase() == exp.toUpperCase());
+                } else {
+                    result = (got == exp);
+                }
+                break;
+            case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
+                var got = context[this.property];
+                var exp = this.value;
+                if(!this.matchCase &&
+                   typeof got == "string" && typeof exp == "string") {
+                    result = (got.toUpperCase() != exp.toUpperCase());
+                } else {
+                    result = (got != exp);
+                }
+                break;
+            case OpenLayers.Filter.Comparison.LESS_THAN:
+                result = context[this.property] < this.value;
+                break;
+            case OpenLayers.Filter.Comparison.GREATER_THAN:
+                result = context[this.property] > this.value;
+                break;
+            case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
+                result = context[this.property] <= this.value;
+                break;
+            case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
+                result = context[this.property] >= this.value;
+                break;
+            case OpenLayers.Filter.Comparison.BETWEEN:
+                result = (context[this.property] >= this.lowerBoundary) &&
+                    (context[this.property] <= this.upperBoundary);
+                break;
+            case OpenLayers.Filter.Comparison.LIKE:
+                var regexp = new RegExp(this.value, "gi");
+                result = regexp.test(context[this.property]);
+                break;
+        }
+        return result;
+    },
+    
+    /**
+     * APIMethod: value2regex
+     * Converts the value of this rule into a regular expression string,
+     * according to the wildcard characters specified. This method has to
+     * be called after instantiation of this class, if the value is not a
+     * regular expression already.
+     * 
+     * Parameters:
+     * wildCard   - {<Char>} wildcard character in the above value, default
+     *              is "*"
+     * singleChar - {<Char>) single-character wildcard in the above value
+     *              default is "."
+     * escape     - {<Char>) escape character in the above value, default is
+     *              "!"
+     * 
+     * Returns:
+     * {String} regular expression string
+     */
+    value2regex: function(wildCard, singleChar, escapeChar) {
+        if (wildCard == ".") {
+            var msg = "'.' is an unsupported wildCard character for "+
+                    "OpenLayers.Filter.Comparison";
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        
+
+        // set UMN MapServer defaults for unspecified parameters
+        wildCard = wildCard ? wildCard : "*";
+        singleChar = singleChar ? singleChar : ".";
+        escapeChar = escapeChar ? escapeChar : "!";
+        
+        this.value = this.value.replace(
+                new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
+        this.value = this.value.replace(
+                new RegExp("\\"+singleChar, "g"), ".");
+        this.value = this.value.replace(
+                new RegExp("\\"+wildCard, "g"), ".*");
+        this.value = this.value.replace(
+                new RegExp("\\\\.\\*", "g"), "\\"+wildCard);
+        this.value = this.value.replace(
+                new RegExp("\\\\\\.", "g"), "\\"+singleChar);
+        
+        return this.value;
+    },
+    
+    /**
+     * Method: regex2value
+     * Convert the value of this rule from a regular expression string into an
+     *     ogc literal string using a wildCard of *, a singleChar of ., and an
+     *     escape of !.  Leaves the <value> property unmodified.
+     * 
+     * Returns:
+     * {String} A string value.
+     */
+    regex2value: function() {
+        
+        var value = this.value;
+        
+        // replace ! with !!
+        value = value.replace(/!/g, "!!");
+
+        // replace \. with !. (watching out for \\.)
+        value = value.replace(/(\\)?\\\./g, function($0, $1) {
+            return $1 ? $0 : "!.";
+        });
+        
+        // replace \* with #* (watching out for \\*)
+        value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+            return $1 ? $0 : "!*";
+        });
+        
+        // replace \\ with \
+        value = value.replace(/\\\\/g, "\\");
+
+        // convert .* to * (the sequence #.* is not allowed)
+        value = value.replace(/\.\*/g, "*");
+        
+        return value;
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Comparison>} Clone of this filter.
+     */
+    clone: function() {
+        return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this);
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter.Comparison"
+});
+
+
+OpenLayers.Filter.Comparison.EQUAL_TO                 = "==";
+OpenLayers.Filter.Comparison.NOT_EQUAL_TO             = "!=";
+OpenLayers.Filter.Comparison.LESS_THAN                = "<";
+OpenLayers.Filter.Comparison.GREATER_THAN             = ">";
+OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO    = "<=";
+OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+OpenLayers.Filter.Comparison.BETWEEN                  = "..";
+OpenLayers.Filter.Comparison.LIKE                     = "~";

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/FeatureId.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/FeatureId.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/FeatureId.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,80 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+  * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.FeatureId
+ * This class represents a ogc:FeatureId Filter, as being used for rule-based SLD
+ * styling
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.FeatureId = OpenLayers.Class(OpenLayers.Filter, {
+
+    /** 
+     * APIProperty: fids
+     * {Array(String)} Feature Ids to evaluate this rule against. To be passed
+     * To be passed inside the params object.
+     */
+    fids: null,
+    
+    /** 
+     * Constructor: OpenLayers.Filter.FeatureId
+     * Creates an ogc:FeatureId rule.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           rule
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.FeatureId>}
+     */
+    initialize: function(options) {
+        this.fids = [];
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: evaluate
+     * evaluates this rule for a specific feature
+     * 
+     * Parameters:
+     * feature - {<OpenLayers.Feature>} feature to apply the rule to.
+     *           For vector features, the check is run against the fid,
+     *           for plain features against the id.
+     * 
+     * Returns:
+     * {Boolean} true if the rule applies, false if it does not
+     */
+    evaluate: function(feature) {
+        for (var i=0, len=this.fids.length; i<len; i++) {
+            var fid = feature.fid || feature.id;
+            if (fid == this.fids[i]) {
+                return true;
+            }
+        }
+        return false;
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.FeatureId>} Clone of this filter.
+     */
+    clone: function() {
+        var filter = new OpenLayers.Filter.FeatureId();
+        OpenLayers.Util.extend(filter, this);
+        filter.fids = this.fids.slice();
+        return filter;
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter.FeatureId"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Logical.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Logical.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Logical.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,117 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+  * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Logical
+ * This class represents ogc:And, ogc:Or and ogc:Not rules.
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: filters
+     * {Array(<OpenLayers.Filter>)} Child filters for this filter.
+     */
+    filters: null, 
+     
+    /**
+     * APIProperty: type
+     * {String} type of logical operator. Available types are:
+     * - OpenLayers.Filter.Logical.AND = "&&";
+     * - OpenLayers.Filter.Logical.OR  = "||";
+     * - OpenLayers.Filter.Logical.NOT = "!";
+     */
+    type: null,
+
+    /** 
+     * Constructor: OpenLayers.Filter.Logical
+     * Creates a logical filter (And, Or, Not).
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *     filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Logical>}
+     */
+    initialize: function(options) {
+        this.filters = [];
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+    
+    /** 
+     * APIMethod: destroy
+     * Remove reference to child filters.
+     */
+    destroy: function() {
+        this.filters = null;
+        OpenLayers.Filter.prototype.destroy.apply(this);
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.  Should be implemented by
+     *     subclasses.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        switch(this.type) {
+            case OpenLayers.Filter.Logical.AND:
+                for (var i=0, len=this.filters.length; i<len; i++) {
+                    if (this.filters[i].evaluate(context) == false) {
+                        return false;
+                    }
+                }
+                return true;
+                
+            case OpenLayers.Filter.Logical.OR:
+                for (var i=0, len=this.filters.length; i<len; i++) {
+                    if (this.filters[i].evaluate(context) == true) {
+                        return true;
+                    }
+                }
+                return false;
+            
+            case OpenLayers.Filter.Logical.NOT:
+                return (!this.filters[0].evaluate(context));
+        }
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Logical>} Clone of this filter.
+     */
+    clone: function() {
+        var filters = [];        
+        for(var i=0, len=this.filters.length; i<len; ++i) {
+            filters.push(this.filters[i].clone());
+        }
+        return new OpenLayers.Filter.Logical({
+            type: this.type,
+            filters: filters
+        });
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter.Logical"
+});
+
+
+OpenLayers.Filter.Logical.AND = "&&";
+OpenLayers.Filter.Logical.OR  = "||";
+OpenLayers.Filter.Logical.NOT = "!";

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Spatial.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Spatial.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter/Spatial.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,127 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+  * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Spatial
+ * This class represents a spatial filter.
+ * Currently implemented: BBOX, DWithin and Intersects
+ * 
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, {
+
+    /**
+     * APIProperty: type
+     * {String} Type of spatial filter.
+     *
+     * The type should be one of:
+     * - OpenLayers.Filter.Spatial.BBOX
+     * - OpenLayers.Filter.Spatial.INTERSECTS
+     * - OpenLayers.Filter.Spatial.DWITHIN
+     * - OpenLayers.Filter.Spatial.WITHIN
+     * - OpenLayers.Filter.Spatial.CONTAINS
+     */
+    type: null,
+    
+    /**
+     * APIProperty: property
+     * {String} Name of the context property to compare.
+     */
+    property: null,
+    
+    /**
+     * APIProperty: value
+     * {<OpenLayers.Bounds> || <OpenLayers.Geometry>} The bounds or geometry
+     *     to be used by the filter.  Use bounds for BBOX filters and geometry
+     *     for INTERSECTS or DWITHIN filters.
+     */
+    value: null,
+
+    /**
+     * APIProperty: distance
+     * {Number} The distance to use in a DWithin spatial filter.
+     */
+    distance: null,
+
+    /**
+     * APIProperty: distanceUnits
+     * {String} The units to use for the distance, e.g. 'm'.
+     */
+    distanceUnits: null,
+    
+    /** 
+     * Constructor: OpenLayers.Filter.Spatial
+     * Creates a spatial filter.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *     filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Spatial>}
+     */
+    initialize: function(options) {
+        OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+    },
+
+   /**
+    * Method: evaluate
+    * Evaluates this filter for a specific feature.
+    * 
+    * Parameters:
+    * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to.
+    * 
+    * Returns:
+    * {Boolean} The feature meets filter criteria.
+    */
+    evaluate: function(feature) {
+        var intersect = false;
+        switch(this.type) {
+            case OpenLayers.Filter.Spatial.BBOX:
+            case OpenLayers.Filter.Spatial.INTERSECTS:
+                if(feature.geometry) {
+                    var geom = this.value;
+                    if(this.value.CLASS_NAME == "OpenLayers.Bounds") {
+                        geom = this.value.toGeometry();
+                    }
+                    if(feature.geometry.intersects(geom)) {
+                        intersect = true;
+                    }
+                }
+                break;
+            default:
+                OpenLayers.Console.error(
+                    OpenLayers.i18n("filterEvaluateNotImplemented"));
+                break;
+        }
+        return intersect;
+    },
+
+    /**
+     * APIMethod: clone
+     * Clones this filter.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter.Spatial>} Clone of this filter.
+     */
+    clone: function() {
+        var options = OpenLayers.Util.applyDefaults({
+            value: this.value && this.value.clone && this.value.clone()
+        }, this);
+        return new OpenLayers.Filter.Spatial(options);
+    },
+    CLASS_NAME: "OpenLayers.Filter.Spatial"
+});
+
+OpenLayers.Filter.Spatial.BBOX = "BBOX";
+OpenLayers.Filter.Spatial.INTERSECTS = "INTERSECTS";
+OpenLayers.Filter.Spatial.DWITHIN = "DWITHIN";
+OpenLayers.Filter.Spatial.WITHIN = "WITHIN";
+OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS";

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Filter.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,66 @@
+/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Style.js
+ */
+
+/**
+ * Class: OpenLayers.Filter
+ * This class represents an OGC Filter.
+ */
+OpenLayers.Filter = OpenLayers.Class({
+    
+    /** 
+     * Constructor: OpenLayers.Filter
+     * This is an abstract class.  Create an instance of a filter subclass.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter>}
+     */
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+    },
+
+    /** 
+     * APIMethod: destroy
+     * Remove reference to anything added.
+     */
+    destroy: function() {
+    },
+
+    /**
+     * APIMethod: evaluate
+     * Evaluates this filter in a specific context.  Should be implemented by
+     *     subclasses.
+     * 
+     * Parameters:
+     * context - {Object} Context to use in evaluating the filter.
+     * 
+     * Returns:
+     * {Boolean} The filter applies.
+     */
+    evaluate: function(context) {
+        return true;
+    },
+    
+    /**
+     * APIMethod: clone
+     * Clones this filter. Should be implementted by subclasses.
+     * 
+     * Returns:
+     * {<OpenLayers.Filter>} Clone of this filter.
+     */
+    clone: function() {
+        return null;
+    },
+    
+    CLASS_NAME: "OpenLayers.Filter"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML/Features.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML/Features.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML/Features.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,48 @@
+/* Copyright (c) 2009 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/ArcXML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.ArcXML.Features
+ * Read/Wite ArcXML features. Create a new instance with the 
+ *     <OpenLayers.Format.ArcXML.Features> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, {
+
+    /**
+     * Constructor: OpenLayers.Format.ArcXML.Features
+     * Create a new parser/writer for ArcXML Features.  Create an instance of this class
+     * to get a set of features from an ArcXML response.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {     
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: read
+     * Read data from a string of ArcXML, and return a set of OpenLayers features. 
+     * 
+     * Parameters:
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Feature.Vector>)} A collection of features.
+     */
+    read: function(data) {
+        var axl = new OpenLayers.Format.ArcXML();
+        var parsed = axl.read(data);
+        
+        return parsed.features.feature;
+    }
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/ArcXML.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,1025 @@
+/* Copyright (c) 2009 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/MultiPolygon.js
+ * @requires OpenLayers/Geometry/LinearRing.js
+ */
+
+/**
+ * Class: OpenLayers.Format.ArcXML
+ * Read/Wite ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML>
+ *     constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, {
+
+    /**
+     * Property: fontStyleKeys
+     * {Array} List of keys used in font styling.
+     */
+    fontStyleKeys: [
+        'antialiasing', 'blockout', 'font', 'fontcolor','fontsize', 'fontstyle',
+        'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency'
+    ],
+
+    /**
+     * Property: request
+     * A get_image request destined for an ArcIMS server.
+     */
+    request: null,
+    
+    /**
+     * Property: response
+     * A parsed response from an ArcIMS server.
+     */
+    response: null,
+
+    /**
+     * Constructor: OpenLayers.Format.ArcXML
+     * Create a new parser/writer for ArcXML.  Create an instance of this class
+     *    to begin authoring a request to an ArcIMS service.  This is used
+     *    primarily by the ArcIMS layer, but could be used to do other wild
+     *    stuff, like geocoding.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        this.request = new OpenLayers.Format.ArcXML.Request();
+        this.response = new OpenLayers.Format.ArcXML.Response();
+
+        if (options) {
+            if (options.requesttype == "feature") {
+                this.request.get_image = null;
+            
+                var qry = this.request.get_feature.query;
+                this.addCoordSys(qry.featurecoordsys, options.featureCoordSys);
+                this.addCoordSys(qry.filtercoordsys, options.filterCoordSys);
+            
+                if (options.polygon) {
+                    qry.isspatial = true;
+                    qry.spatialfilter.polygon = options.polygon;
+                } else if (options.envelope) {
+                    qry.isspatial = true;
+                    qry.spatialfilter.envelope = {minx:0, miny:0, maxx:0, maxy:0};
+                    this.parseEnvelope(qry.spatialfilter.envelope, options.envelope);
+                }
+            } else if (options.requesttype == "image") {
+                this.request.get_feature = null;
+            
+                var props = this.request.get_image.properties;
+                this.parseEnvelope(props.envelope, options.envelope);
+            
+                this.addLayers(props.layerlist, options.layers);
+                this.addImageSize(props.imagesize, options.tileSize);
+                this.addCoordSys(props.featurecoordsys, options.featureCoordSys);
+                this.addCoordSys(props.filtercoordsys, options.filterCoordSys);
+            } else {
+                // if an arcxml object is being created with no request type, it is
+                // probably going to consume a response, so do not throw an error if
+                // the requesttype is not defined
+                this.request = null;
+            }
+        }
+        
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: parseEnvelope
+     * Parse an array of coordinates into an ArcXML envelope structure.
+     *
+     * Parameters:
+     * env - {Object} An envelope object that will contain the parsed coordinates.
+     * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ]
+     */
+    parseEnvelope: function(env, arr) {
+        if (arr && arr.length == 4) {          
+            env.minx = arr[0];
+            env.miny = arr[1];
+            env.maxx = arr[2];
+            env.maxy = arr[3];
+        }
+    },
+    
+    /** 
+     * Method: addLayers
+     * Add a collection of layers to another collection of layers. Each layer in the list is tuple of
+     * { id, visible }.  These layer collections represent the 
+     * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML
+     *
+     * TODO: Add support for dynamic layer rendering.
+     *
+     * Parameters:
+     * ll - {Array({id,visible})} A list of layer definitions.
+     * lyrs - {Array({id,visible})} A list of layer definitions.
+     */
+    addLayers: function(ll, lyrs) {
+        for(var lind = 0, len=lyrs.length; lind < len; lind++) {
+            ll.push(lyrs[lind]);
+        }
+    },
+    
+    /**
+     * Method: addImageSize
+     * Set the size of the requested image.
+     *
+     * Parameters:
+     * imsize - {Object} An ArcXML imagesize object.
+     * olsize - {OpenLayers.Size} The image size to set.
+     */
+    addImageSize: function(imsize, olsize) {
+        if (olsize !== null) {
+            imsize.width = olsize.w;
+            imsize.height = olsize.h;
+            imsize.printwidth = olsize.w;
+            imsize.printheight = olsize.h;
+        }
+    },
+
+    /**
+     * Method: addCoordSys
+     * Add the coordinate system information to an object. The object may be 
+     *
+     * Parameters:
+     * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure.
+     * fsys - {String} or {OpenLayers.Projection} or {filtercoordsys} or 
+     * {featurecoordsys} A projection representation. If it's a {String}, 
+     * the value is assumed to be the SRID.  If it's a {OpenLayers.Projection} 
+     * AND Proj4js is available, the projection number and name are extracted 
+     * from there.  If it's a filter or feature ArcXML structure, it is copied.
+     */
+    addCoordSys: function(featOrFilt, fsys) {
+        if (typeof fsys == "string") {
+            featOrFilt.id = parseInt(fsys);
+            featOrFilt.string = fsys;
+        }
+        // is this a proj4js instance?
+        else if (typeof fsys == "object" && fsys.proj !== null){
+            featOrFilt.id = fsys.proj.srsProjNumber;
+            featOrFilt.string = fsys.proj.srsCode;
+        } else {
+            featOrFilt = fsys;
+        }
+    },
+
+    /**
+     * APIMethod: iserror
+     * Check to see if the response from the server was an error.
+     *
+     * Parameters:
+     * data - {String} or {DOMElement} data to read/parse. If nothing is supplied,
+     * the current response is examined.
+     *
+     * Returns:
+     * {Boolean} true if the response was an error.
+     */
+    iserror: function(data) {
+        var ret = null; 
+        
+        if (!data) {
+            ret = (this.response.error !== '');
+        } else {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+            var errorNodes = data.documentElement.getElementsByTagName("ERROR");
+            ret = (errorNodes !== null && errorNodes.length > 0);
+        }
+
+        return ret;
+    },
+
+    /**
+     * APIMethod: read
+     * Read data from a string, and return an response. 
+     * 
+     * Parameters:
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {OpenLayers.Format.ArcXML.Response} An ArcXML response. Note that this response
+     *     data may change in the future. 
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        
+        var arcNode = null;
+        if (data && data.documentElement) {
+            if(data.documentElement.nodeName == "ARCXML") {
+                arcNode = data.documentElement;
+            } else {
+                arcNode = data.documentElement.getElementsByTagName("ARCXML")[0];
+            }
+        }
+          
+        if (!arcNode) {
+            var error, source;
+            try {
+                error = data.firstChild.nodeValue;
+                source = data.firstChild.childNodes[1].firstChild.nodeValue;
+            } catch (err) {
+                // pass
+            }
+            throw {
+                message: "Error parsing the ArcXML request", 
+                error: error,
+                source: source
+            };
+        }
+        
+        var response = this.parseResponse(arcNode);
+        return response;
+    },
+    
+    /**
+     * APIMethod: write
+     * Generate an ArcXml document string for sending to an ArcIMS server. 
+     * 
+     * Returns:
+     * {String} A string representing the ArcXML document request.
+     */
+    write: function(request) {       
+        if (!request) {
+            request = this.request;
+        }    
+        var root = this.createElementNS("", "ARCXML");
+        root.setAttribute("version","1.1");
+
+        var reqElem = this.createElementNS("", "REQUEST");
+        
+        if (request.get_image != null) {
+            var getElem = this.createElementNS("", "GET_IMAGE");
+            reqElem.appendChild(getElem);
+
+            var propElem = this.createElementNS("", "PROPERTIES");
+            getElem.appendChild(propElem);
+
+            var props = request.get_image.properties;
+            if (props.featurecoordsys != null) {
+                var feat = this.createElementNS("", "FEATURECOORDSYS");
+                propElem.appendChild(feat);
+                
+                if (props.featurecoordsys.id === 0) {
+                    feat.setAttribute("string", props.featurecoordsys['string']);
+                }
+                else {
+                    feat.setAttribute("id", props.featurecoordsys.id);
+                }
+            }
+          
+            if (props.filtercoordsys != null) {
+                var filt = this.createElementNS("", "FILTERCOORDSYS");
+                propElem.appendChild(filt);
+
+                if (props.filtercoordsys.id === 0) {
+                    filt.setAttribute("string", props.filtercoordsys.string);
+                }
+                else {
+                    filt.setAttribute("id", props.filtercoordsys.id);
+                }
+            }
+          
+            if (props.envelope != null) {
+                var env = this.createElementNS("", "ENVELOPE");
+                propElem.appendChild(env);
+
+                env.setAttribute("minx", props.envelope.minx);
+                env.setAttribute("miny", props.envelope.miny);
+                env.setAttribute("maxx", props.envelope.maxx);
+                env.setAttribute("maxy", props.envelope.maxy);
+            }        
+          
+            var imagesz = this.createElementNS("", "IMAGESIZE");
+            propElem.appendChild(imagesz);
+          
+            imagesz.setAttribute("height", props.imagesize.height);
+            imagesz.setAttribute("width", props.imagesize.width);
+          
+            if (props.imagesize.height != props.imagesize.printheight ||
+                 props.imagesize.width != props.imagesize.printwidth) {
+                imagesz.setAttribute("printheight", props.imagesize.printheight);
+                imagesz.setArrtibute("printwidth", props.imagesize.printwidth);
+            }
+          
+            if (props.background != null) {
+                var backgrnd = this.createElementNS("", "BACKGROUND");
+                propElem.appendChild(backgrnd);
+            
+                backgrnd.setAttribute("color", 
+                    props.background.color.r + "," + 
+                    props.background.color.g + "," + 
+                    props.background.color.b);
+              
+                if (props.background.transcolor !== null) {
+                    backgrnd.setAttribute("transcolor", 
+                        props.background.transcolor.r + "," + 
+                        props.background.transcolor.g + "," + 
+                        props.background.transcolor.b);
+                }
+            }
+          
+            if (props.layerlist != null && props.layerlist.length > 0) {
+                var layerlst = this.createElementNS("", "LAYERLIST");
+                propElem.appendChild(layerlst);
+            
+                for (var ld = 0; ld < props.layerlist.length; ld++) {
+                    var ldef = this.createElementNS("", "LAYERDEF");
+                    layerlst.appendChild(ldef);
+              
+                    ldef.setAttribute("id", props.layerlist[ld].id);
+                    ldef.setAttribute("visible", props.layerlist[ld].visible);
+              
+                    if (typeof props.layerlist[ld].query == "object") {
+                        var query = props.layerlist[ld].query;
+
+                        if (query.where.length < 0) {
+                            continue;
+                        }
+                  
+                        var queryElem = null;
+                        if (typeof query.spatialfilter == "boolean" && query.spatialfilter) {
+                            // handle spatial filter madness
+                            queryElem = this.createElementNS("", "SPATIALQUERY");
+                        }
+                        else {
+                            queryElem = this.createElementNS("", "QUERY");
+                        }
+                
+                        queryElem.setAttribute("where", query.where);
+                
+                        if (typeof query.accuracy == "number" && query.accuracy > 0) {
+                            queryElem.setAttribute("accuracy", query.accuracy);
+                        }
+                        if (typeof query.featurelimit == "number" && query.featurelimit < 2000) {
+                            queryElem.setAttribute("featurelimit", query.featurelimit);
+                        }
+                        if (typeof query.subfields == "string" && query.subfields != "#ALL#") {
+                            queryElem.setAttribute("subfields", query.subfields);
+                        }
+                        if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) {
+                            queryElem.setAttribute("joinexpression", query.joinexpression);
+                        }
+                        if (typeof query.jointables == "string" && query.jointables.length > 0) {
+                            queryElem.setAttribute("jointables", query.jointables);
+                        }
+
+                        ldef.appendChild(queryElem);
+                    }
+              
+                    if (typeof props.layerlist[ld].renderer == "object") {
+                        this.addRenderer(ldef, props.layerlist[ld].renderer);                  
+                    }
+                }
+            }
+        } else if (request.get_feature != null) {
+            var getElem = this.createElementNS("", "GET_FEATURES");
+            getElem.setAttribute("outputmode", "newxml");
+            getElem.setAttribute("checkesc", "true");
+          
+            if (request.get_feature.geometry) {
+                getElem.setAttribute("geometry", request.get_feature.geometry);
+            }
+            else {
+                getElem.setAttribute("geometry", "false");
+            }
+          
+            if (request.get_feature.compact) {
+                getElem.setAttribute("compact", request.get_feature.compact);
+            }
+          
+            if (request.get_feature.featurelimit == "number") {
+                getElem.setAttribute("featurelimit", request.get_feature.featurelimit);
+            }
+          
+            getElem.setAttribute("globalenvelope", "true");
+            reqElem.appendChild(getElem);
+          
+            if (request.get_feature.layer != null && request.get_feature.layer.length > 0) {
+                var lyrElem = this.createElementNS("", "LAYER");
+                lyrElem.setAttribute("id", request.get_feature.layer);
+                getElem.appendChild(lyrElem);
+            }
+          
+            var fquery = request.get_feature.query;
+            if (fquery != null) {
+                var qElem = null;
+                if (fquery.isspatial) {
+                    qElem = this.createElementNS("", "SPATIALQUERY");
+                } else {
+                    qElem = this.createElementNS("", "QUERY");
+                }
+                getElem.appendChild(qElem);
+                
+                if (typeof fquery.accuracy == "number") {
+                    qElem.setAttribute("accuracy", fquery.accuracy);
+                }
+                //qElem.setAttribute("featurelimit", "5");
+            
+                if (fquery.featurecoordsys != null) {
+                    var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS");
+              
+                    if (fquery.featurecoordsys.id == 0) {
+                        fcsElem1.setAttribute("string", fquery.featurecoordsys.string);
+                    } else {
+                        fcsElem1.setAttribute("id", fquery.featurecoordsys.id);
+                    }
+                    qElem.appendChild(fcsElem1);
+                }
+            
+                if (fquery.filtercoordsys != null) {
+                    var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS");
+              
+                    if (fquery.filtercoordsys.id === 0) {
+                        fcsElem2.setAttribute("string", fquery.filtercoordsys.string);
+                    } else {
+                        fcsElem2.setAttribute("id", fquery.filtercoordsys.id);
+                    }
+                    qElem.appendChild(fcsElem2);
+                }
+            
+                if (fquery.buffer > 0) {   
+                    var bufElem = this.createElementNS("", "BUFFER");
+                    bufElem.setAttribute("distance", fquery.buffer);
+                    qElem.appendChild(bufElem);
+                }
+            
+                if (fquery.isspatial) {
+                    var spfElem = this.createElementNS("", "SPATIALFILTER");
+                    spfElem.setAttribute("relation", fquery.spatialfilter.relation);
+                    qElem.appendChild(spfElem);
+              
+                    if (fquery.spatialfilter.envelope) {
+                        var envElem = this.createElementNS("", "ENVELOPE"); 
+                        envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx);
+                        envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny);
+                        envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx);
+                        envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy);
+                        spfElem.appendChild(envElem);
+                    } else if(typeof fquery.spatialfilter.polygon == "object") {
+                        spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon));                
+                    }
+                }
+            
+                if (fquery.where != null && fquery.where.length > 0) {
+                    qElem.setAttribute("where", fquery.where);
+                }
+            }
+        }
+
+        root.appendChild(reqElem);
+
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+    
+    
+    addGroupRenderer: function(ldef, toprenderer) {
+        var topRelem = this.createElementNS("", "GROUPRENDERER");
+        ldef.appendChild(topRelem);
+      
+        for (var rind = 0; rind < toprenderer.length; rind++) {
+            var renderer = toprenderer[rind];
+            this.addRenderer(topRelem, renderer);
+        }
+    },
+    
+    
+    addRenderer: function(topRelem, renderer) {
+        if (renderer instanceof Array) {
+            this.addGroupRenderer(topRelem, renderer);
+        } else {
+            var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER");
+            topRelem.appendChild(renderElem);
+          
+            if (renderElem.tagName == "VALUEMAPRENDERER") {
+                this.addValueMapRenderer(renderElem, renderer);
+            } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") {
+                this.addValueMapLabelRenderer(renderElem, renderer);
+            } else if (renderElem.tagName == "SIMPLELABELRENDERER") {
+                this.addSimpleLabelRenderer(renderElem, renderer);
+            } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") {
+                this.addScaleDependentRenderer(renderElem, renderer);
+            }
+        }             
+    },
+    
+    
+    addScaleDependentRenderer: function(renderElem, renderer) {
+        if (typeof renderer.lower == "string" || typeof renderer.lower == "number") {
+            renderElem.setAttribute("lower", renderer.lower);
+        }
+        if (typeof renderer.upper == "string" || typeof renderer.upper == "number") {
+            renderElem.setAttribute("upper", renderer.upper);
+        }
+        
+        this.addRenderer(renderElem, renderer.renderer);
+    },
+    
+    
+    addValueMapLabelRenderer: function(renderElem, renderer) {
+        renderElem.setAttribute("lookupfield", renderer.lookupfield);
+        renderElem.setAttribute("labelfield", renderer.labelfield);
+      
+        if (typeof renderer.exacts == "object") {
+            for (var ext=0, extlen=renderer.exacts.length; ext<extlen; ext++) {
+                var exact = renderer.exacts[ext];
+          
+                var eelem = this.createElementNS("", "EXACT");
+          
+                if (typeof exact.value == "string") {
+                    eelem.setAttribute("value", exact.value);
+                }
+                if (typeof exact.label == "string") {
+                    eelem.setAttribute("label", exact.label);
+                }
+                if (typeof exact.method == "string") {
+                    eelem.setAttribute("method", exact.method);
+                }
+
+                renderElem.appendChild(eelem);
+            
+                if (typeof exact.symbol == "object") {
+                    var selem = null;
+                
+                    if (exact.symbol.type == "text") {
+                        selem = this.createElementNS("", "TEXTSYMBOL");
+                    }
+                
+                    if (selem != null) {
+                        var keys = this.fontStyleKeys;
+                        for (var i = 0, len = keys.length; i < len; i++) {
+                            var key = keys[i];
+                            if (exact.symbol[key]) {
+                                selem.setAttribute(key, exact.symbol[key]);
+                            }
+                        }    
+                        eelem.appendChild(selem);
+                    }
+                }
+            } // for each exact
+        }      
+    },
+    
+    addValueMapRenderer: function(renderElem, renderer) {
+        renderElem.setAttribute("lookupfield", renderer.lookupfield);
+        
+        if (typeof renderer.ranges == "object") {
+            for(var rng=0, rnglen=renderer.ranges.length; rng<rnglen; rng++) {
+                var range = renderer.ranges[rng];
+                
+                var relem = this.createElementNS("", "RANGE");
+                relem.setAttribute("lower", range.lower);
+                relem.setAttribute("upper", range.upper);
+                
+                renderElem.appendChild(relem);
+                
+                if (typeof range.symbol == "object") {
+                    var selem = null;
+              
+                    if (range.symbol.type == "simplepolygon") {
+                        selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL");
+                    }
+              
+                    if (selem != null) {
+                        if (typeof range.symbol.boundarycolor == "string") {
+                            selem.setAttribute("boundarycolor", range.symbol.boundarycolor);
+                        }
+                        if (typeof range.symbol.fillcolor == "string") {
+                            selem.setAttribute("fillcolor", range.symbol.fillcolor);
+                        }
+                        if (typeof range.symbol.filltransparency == "number") {
+                            selem.setAttribute("filltransparency", range.symbol.filltransparency);
+                        }
+                        relem.appendChild(selem);
+                    }   
+                }
+            } // for each range
+        } else if (typeof renderer.exacts == "object") {
+            for (var ext=0, extlen=renderer.exacts.length; ext<extlen; ext++) {
+                var exact = renderer.exacts[ext];
+          
+                var eelem = this.createElementNS("", "EXACT");
+                if (typeof exact.value == "string") {
+                    eelem.setAttribute("value", exact.value);
+                }
+                if (typeof exact.label == "string") {
+                    eelem.setAttribute("label", exact.label);
+                }
+                if (typeof exact.method == "string") {
+                    eelem.setAttribute("method", exact.method);
+                }
+            
+                renderElem.appendChild(eelem);
+            
+                if (typeof exact.symbol == "object") {
+                    var selem = null;
+            
+                    if (exact.symbol.type == "simplemarker") {
+                        selem = this.createElementNS("", "SIMPLEMARKERSYMBOL");
+                    }
+            
+                    if (selem != null) {
+                        if (typeof exact.symbol.antialiasing == "string") {
+                            selem.setAttribute("antialiasing", exact.symbol.antialiasing);
+                        }
+                        if (typeof exact.symbol.color == "string") {
+                            selem.setAttribute("color", exact.symbol.color);
+                        }
+                        if (typeof exact.symbol.outline == "string") {
+                            selem.setAttribute("outline", exact.symbol.outline);
+                        }
+                        if (typeof exact.symbol.overlap == "string") {
+                            selem.setAttribute("overlap", exact.symbol.overlap);
+                        }
+                        if (typeof exact.symbol.shadow == "string") {
+                            selem.setAttribute("shadow", exact.symbol.shadow);
+                        }
+                        if (typeof exact.symbol.transparency == "number") {
+                            selem.setAttribute("transparency", exact.symbol.transparency);
+                        }
+                        //if (typeof exact.symbol.type == "string")
+                        //    selem.setAttribute("type", exact.symbol.type);
+                        if (typeof exact.symbol.usecentroid == "string") {
+                            selem.setAttribute("usecentroid", exact.symbol.usecentroid);
+                        }
+                        if (typeof exact.symbol.width == "number") {
+                            selem.setAttribute("width", exact.symbol.width);
+                        }
+                
+                        eelem.appendChild(selem);
+                    }
+                }
+            } // for each exact
+        }
+    },
+    
+    
+    addSimpleLabelRenderer: function(renderElem, renderer) {
+        renderElem.setAttribute("field", renderer.field);
+        var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', 
+                    'labelpriorities', 'labelweight', 'linelabelposition',
+                    'rotationalangles'];
+        for (var i=0, len=keys.length; i<len; i++) {
+            var key = keys[i];
+            if (renderer[key]) {
+                renderElem.setAttribute(key, renderer[key]);
+            }
+        }     
+           
+        if (renderer.symbol.type == "text") {
+            var symbol = renderer.symbol;
+            var selem = this.createElementNS("", "TEXTSYMBOL");
+            renderElem.appendChild(selem);
+          
+            var keys = this.fontStyleKeys;
+            for (var i=0, len=keys.length; i<len; i++) {
+                var key = keys[i];
+                if (symbol[key]) {
+                    selem.setAttribute(key, renderer[key]);
+                }
+            }    
+        }    
+    },
+    
+    writePolygonGeometry: function(polygon) {
+        if (!(polygon instanceof OpenLayers.Geometry.Polygon)) {
+            throw { 
+                message:'Cannot write polygon geometry to ArcXML with an ' +
+                    polygon.CLASS_NAME + ' object.',
+                geometry: polygon
+            };
+        }
+        
+        var polyElem = this.createElementNS("", "POLYGON");
+      
+        for (var ln=0, lnlen=polygon.components.length; ln<lnlen; ln++) {
+            var ring = polygon.components[ln];
+            var ringElem = this.createElementNS("", "RING");
+        
+            for (var rn=0, rnlen=ring.components.length; rn<rnlen; rn++) {
+                var point = ring.components[rn];
+                var pointElem = this.createElementNS("", "POINT");
+            
+                pointElem.setAttribute("x", point.x);
+                pointElem.setAttribute("y", point.y);
+            
+                ringElem.appendChild(pointElem);
+            }
+        
+            polyElem.appendChild(ringElem);
+        }
+      
+        return polyElem;
+    },
+    
+    /**
+     * Method: parseResponse
+     * Take an ArcXML response, and parse in into this object's internal properties.
+     *
+     * Parameters:
+     * data - {String} or {DOMElement} The ArcXML response, as either a string or the
+     * top level DOMElement of the response.
+     */
+    parseResponse: function(data) {
+        if(typeof data == "string") { 
+            var newData = new OpenLayers.Format.XML();
+            data = newData.read(data);
+        }
+        var response = new OpenLayers.Format.ArcXML.Response();
+        
+        var errorNode = data.getElementsByTagName("ERROR");
+        
+        if (errorNode != null && errorNode.length > 0) {
+            response.error = this.getChildValue(errorNode, "Unknown error.");
+        } else {
+            var responseNode = data.getElementsByTagName("RESPONSE");
+          
+            if (responseNode == null || responseNode.length == 0) {
+                response.error = "No RESPONSE tag found in ArcXML response.";
+                return response;
+            }
+          
+            var rtype = responseNode[0].firstChild.nodeName;
+            if (rtype == "#text") {
+                rtype = responseNode[0].firstChild.nextSibling.nodeName;
+            }
+          
+            if (rtype == "IMAGE") {
+                var envelopeNode = data.getElementsByTagName("ENVELOPE");
+                var outputNode = data.getElementsByTagName("OUTPUT");
+                
+                if (envelopeNode == null || envelopeNode.length == 0) {
+                    response.error = "No ENVELOPE tag found in ArcXML response.";
+                } else if (outputNode == null || outputNode.length == 0) {
+                    response.error = "No OUTPUT tag found in ArcXML response.";
+                } else {
+                    var envAttr = this.parseAttributes(envelopeNode[0]);            
+                    var outputAttr = this.parseAttributes(outputNode[0]);
+                  
+                    if (typeof outputAttr.type == "string") {
+                        response.image = { 
+                            envelope: envAttr, 
+                            output: { 
+                                type: outputAttr.type, 
+                                data: this.getChildValue(outputNode[0])
+                            }
+                        };
+                    } else {
+                        response.image = { envelope: envAttr, output: outputAttr };
+                    }
+                }
+            } else if (rtype == "FEATURES") {
+                var features = responseNode[0].getElementsByTagName("FEATURES");
+            
+                // get the feature count
+                var featureCount = features[0].getElementsByTagName("FEATURECOUNT");
+                response.features.featurecount = featureCount[0].getAttribute("count");
+            
+                if (response.features.featurecount > 0) {
+                    // get the feature envelope
+                    var envelope = features[0].getElementsByTagName("ENVELOPE");
+                    response.features.envelope = this.parseAttributes(envelope[0], typeof(0));
+
+                    // get the field values per feature
+                    var featureList = features[0].getElementsByTagName("FEATURE");
+                    for (var fn = 0; fn < featureList.length; fn++) {
+                        var feature = new OpenLayers.Feature.Vector();
+                        var fields = featureList[fn].getElementsByTagName("FIELD");
+
+                        for (var fdn = 0; fdn < fields.length; fdn++) {
+                            var fieldName = fields[fdn].getAttribute("name");
+                            var fieldValue = fields[fdn].getAttribute("value");
+                            feature.attributes[ fieldName ] = fieldValue;
+                        }
+
+                        var geom = featureList[fn].getElementsByTagName("POLYGON");
+
+                        if (geom.length > 0) {
+                            // if there is a polygon, create an openlayers polygon, and assign
+                            // it to the .geometry property of the feature
+                            var ring = geom[0].getElementsByTagName("RING");
+
+                            var polys = [];
+                            for (var rn = 0; rn < ring.length; rn++) {
+                                var linearRings = [];
+                                linearRings.push(this.parsePointGeometry(ring[rn]));
+
+                                var holes = ring[rn].getElementsByTagName("HOLE");
+                                for (var hn = 0; hn < holes.length; hn++) {
+                                    linearRings.push(this.parsePointGeometry(holes[hn]));
+                                }
+                                holes = null;
+                                polys.push(new OpenLayers.Geometry.Polygon(linearRings));
+                                linearRings = null;
+                            }
+                            ring = null;
+                          
+                            if (polys.length == 1) {
+                                feature.geometry = polys[0];
+                            } else
+                            {
+                                feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys);
+                            }
+                        }
+
+                        response.features.feature.push(feature);
+                    }
+                }
+            } else {
+                response.error = "Unidentified response type.";
+            }
+        }
+        return response;
+    },
+    
+    
+    /**
+     * Method: parseAttributes
+     *
+     * Parameters:
+     * node - {<DOMElement>} An element to parse attributes from.
+     *
+     * Returns:
+     * {Object} An attributes object, with properties set to attribute values.
+     */
+    parseAttributes: function(node,type) {
+        var attributes = {};
+        for(var attr = 0; attr < node.attributes.length; attr++) {
+            if (type == "number") {
+                attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue);
+            } else {
+                attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue;
+            }
+        }
+        return attributes;
+    },
+    
+    
+    /**
+     * Method: parsePointGeometry
+     *
+     * Parameters:
+     * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from.
+     *
+     * Returns:
+     * {OpenLayers.Geometry.LinearRing} A linear ring represented by the node's points.
+     */
+    parsePointGeometry: function(node) {
+        var ringPoints = [];
+        var coords = node.getElementsByTagName("COORDS");
+
+        if (coords.length > 0) {
+            // if coords is present, it's the only coords item
+            var coordArr = this.getChildValue(coords[0]);
+            coordArr = coordArr.split(/;/);
+            for (var cn = 0; cn < coordArr.length; cn++) {
+                var coordItems = coordArr[cn].split(/ /);
+                ringPoints.push(new OpenLayers.Geometry.Point(parseFloat(coordItems[0]), parseFloat(coordItems[1])));
+            }
+            coords = null;
+        } else {
+            var point = node.getElementsByTagName("POINT");
+            if (point.length > 0) {
+                for (var pn = 0; pn < point.length; pn++) {
+                    ringPoints.push(
+                        new OpenLayers.Geometry.Point(
+                            parseFloat(point[pn].getAttribute("x")),
+                            parseFloat(point[pn].getAttribute("y"))
+                        )
+                    );
+                }
+            }
+            point = null;
+        }
+
+        return new OpenLayers.Geometry.LinearRing(ringPoints);      
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.ArcXML" 
+});
+
+OpenLayers.Format.ArcXML.Request = OpenLayers.Class({
+    initialize: function(params) {
+        var defaults = {
+            get_image: {
+                properties: {
+                    background: null,
+                    /*{ 
+                        color: { r:255, g:255, b:255 },
+                        transcolor: null
+                    },*/
+                    draw: true,
+                    envelope: {
+                        minx: 0, 
+                        miny: 0, 
+                        maxx: 0, 
+                        maxy: 0
+                    },
+                    featurecoordsys: { 
+                        id:0, 
+                        string:"",
+                        datumtransformid:0,
+                        datumtransformstring:""
+                    },
+                    filtercoordsys:{
+                        id:0,
+                        string:"",
+                        datumtransformid:0,
+                        datumtransformstring:""
+                    },
+                    imagesize:{
+                        height:0,
+                        width:0,
+                        dpi:96,
+                        printheight:0,
+                        printwidth:0,
+                        scalesymbols:false
+                    },
+                    layerlist:[],
+                    /* no support for legends */
+                    output:{
+                        baseurl:"",
+                        legendbaseurl:"",
+                        legendname:"",
+                        legendpath:"",
+                        legendurl:"",
+                        name:"",
+                        path:"",
+                        type:"jpg",
+                        url:""
+                    }
+                }
+            },
+
+            get_feature: {
+                layer: "",
+                query: {
+                    isspatial: false,
+                    featurecoordsys: {
+                        id:0,
+                        string:"",
+                        datumtransformid:0,
+                        datumtransformstring:""
+                    },
+                    filtercoordsys: {
+                        id:0,
+                        string:"",
+                        datumtransformid:0,
+                        datumtransformstring:""
+                    },
+                    buffer:0,
+                    where:"",
+                    spatialfilter: {
+                        relation: "envelope_intersection",
+                        envelope: null
+                    }
+                }
+            },
+      
+            environment: {
+                separators: {
+                    cs:" ",
+                    ts:";"
+                }
+            },
+      
+            layer: [],
+            workspaces: []
+        };
+      
+        return OpenLayers.Util.extend(this, defaults);      
+    },
+  
+    CLASS_NAME: "OpenLayers.Format.ArcXML.Request"
+});
+
+OpenLayers.Format.ArcXML.Response = OpenLayers.Class({  
+    initialize: function(params) {
+        var defaults = {
+            image: {
+                envelope:null,
+                output:''
+            },
+      
+            features: {
+                featurecount: 0,
+                envelope: null,
+                feature: []
+            },
+      
+            error:''
+        };
+  
+        return OpenLayers.Util.extend(this, defaults);
+    },
+  
+    CLASS_NAME: "OpenLayers.Format.ArcXML.Response"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,449 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/Filter.js
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter.v1
+ * Superclass for Filter version 1 parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        ogc: "http://www.opengis.net/ogc",
+        gml: "http://www.opengis.net/gml",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance"
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "ogc",
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: null,
+    
+    /**
+     * Constructor: OpenLayers.Format.Filter.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.Filter> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: read
+     *
+     * Parameters:
+     * data - {DOMElement} A Filter document element.
+     *
+     * Returns:
+     * {<OpenLayers.Filter>} A filter object.
+     */
+    read: function(data) {
+        var obj = {};
+        this.readers.ogc["Filter"].apply(this, [data, obj]);
+        return obj.filter;
+    },
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "ogc": {
+            "Filter": function(node, parent) {
+                // Filters correspond to subclasses of OpenLayers.Filter.
+                // Since they contain information we don't persist, we
+                // create a temporary object and then pass on the filter
+                // (ogc:Filter) to the parent obj.
+                var obj = {
+                    fids: [],
+                    filters: []
+                };
+                this.readChildNodes(node, obj);
+                if(obj.fids.length > 0) {
+                    parent.filter = new OpenLayers.Filter.FeatureId({
+                        fids: obj.fids
+                    });
+                } else if(obj.filters.length > 0) {
+                    parent.filter = obj.filters[0];
+                }
+            },
+            "FeatureId": function(node, obj) {
+                var fid = node.getAttribute("fid");
+                if(fid) {
+                    obj.fids.push(fid);
+                }
+            },
+            "And": function(node, obj) {
+                var filter = new OpenLayers.Filter.Logical({
+                    type: OpenLayers.Filter.Logical.AND
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "Or": function(node, obj) {
+                var filter = new OpenLayers.Filter.Logical({
+                    type: OpenLayers.Filter.Logical.OR
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "Not": function(node, obj) {
+                var filter = new OpenLayers.Filter.Logical({
+                    type: OpenLayers.Filter.Logical.NOT
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsLessThan": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.LESS_THAN
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsGreaterThan": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.GREATER_THAN
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsLessThanOrEqualTo": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsBetween": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.BETWEEN
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsLike": function(node, obj) {
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.LIKE
+                });
+                this.readChildNodes(node, filter);
+                var wildCard = node.getAttribute("wildCard");
+                var singleChar = node.getAttribute("singleChar");
+                var esc = node.getAttribute("escape");
+                filter.value2regex(wildCard, singleChar, esc);
+                obj.filters.push(filter);
+            },
+            "Literal": function(node, obj) {
+                obj.value = OpenLayers.String.numericIf(
+                    this.getChildValue(node));
+            },
+            "PropertyName": function(node, filter) {
+                filter.property = this.getChildValue(node);
+            },
+            "LowerBoundary": function(node, filter) {
+                filter.lowerBoundary = OpenLayers.String.numericIf(
+                    this.readOgcExpression(node));
+            },
+            "UpperBoundary": function(node, filter) {
+                filter.upperBoundary = OpenLayers.String.numericIf(
+                    this.readOgcExpression(node));
+            },
+            "Intersects": function(node, obj) {
+                this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS);
+            },
+            "Within": function(node, obj) {
+                this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN);
+            },
+            "Contains": function(node, obj) {
+                this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS);
+            },
+            "DWithin": function(node, obj) {
+                this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN);
+            },
+            "Distance": function(node, obj) {
+                obj.distance = parseInt(this.getChildValue(node));
+                obj.distanceUnits = node.getAttribute("units");
+            }
+        }
+    },
+    
+    /**
+     * Method: readSpatial
+     *
+     * Read a {<OpenLayers.Filter.Spatial>} filter.
+     * 
+     * Parameters:
+     * node - {DOMElement} A DOM element that contains an ogc:expression.
+     * obj - {Object} The target object.
+     * type - {String} One of the OpenLayers.Filter.Spatial.* constants.
+     *
+     * Returns:
+     * {<OpenLayers.Filter.Spatial>} The created filter.
+     */
+    readSpatial: function(node, obj, type) {
+        var filter = new OpenLayers.Filter.Spatial({
+            type: type
+        });
+        this.readChildNodes(node, filter);
+        filter.value = filter.components[0];
+        delete filter.components;
+        obj.filters.push(filter);
+    },
+
+    /**
+     * Method: readOgcExpression
+     * Limited support for OGC expressions.
+     *
+     * Parameters:
+     * node - {DOMElement} A DOM element that contains an ogc:expression.
+     *
+     * Returns:
+     * {String} A value to be used in a symbolizer.
+     */
+    readOgcExpression: function(node) {
+        var obj = {};
+        this.readChildNodes(node, obj);
+        var value = obj.value;
+        if(!value) {
+            value = this.getChildValue(node);
+        }
+        return value;
+    },
+
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * filter - {<OpenLayers.Filter>} A filter object.
+     *
+     * Returns:
+     * {DOMElement} An ogc:Filter element.
+     */
+    write: function(filter) {
+        return this.writers.ogc["Filter"].apply(this, [filter]);
+    },
+    
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "ogc": {
+            "Filter": function(filter) {
+                var node = this.createElementNSPlus("ogc:Filter");
+                var sub = filter.CLASS_NAME.split(".").pop();
+                if(sub == "FeatureId") {
+                    for(var i=0; i<filter.fids.length; ++i) {
+                        this.writeNode("FeatureId", filter.fids[i], node);
+                    }
+                } else {
+                    this.writeNode(this.getFilterType(filter), filter, node);
+                }
+                return node;
+            },
+            "FeatureId": function(fid) {
+                return this.createElementNSPlus("ogc:FeatureId", {
+                    attributes: {fid: fid}
+                });
+            },
+            "And": function(filter) {
+                var node = this.createElementNSPlus("ogc:And");
+                var childFilter;
+                for(var i=0; i<filter.filters.length; ++i) {
+                    childFilter = filter.filters[i];
+                    this.writeNode(
+                        this.getFilterType(childFilter), childFilter, node
+                    );
+                }
+                return node;
+            },
+            "Or": function(filter) {
+                var node = this.createElementNSPlus("ogc:Or");
+                var childFilter;
+                for(var i=0; i<filter.filters.length; ++i) {
+                    childFilter = filter.filters[i];
+                    this.writeNode(
+                        this.getFilterType(childFilter), childFilter, node
+                    );
+                }
+                return node;
+            },
+            "Not": function(filter) {
+                var node = this.createElementNSPlus("ogc:Not");
+                var childFilter = filter.filters[0];
+                this.writeNode(
+                    this.getFilterType(childFilter), childFilter, node
+                );
+                return node;
+            },
+            "PropertyIsLessThan": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);                
+                return node;
+            },
+            "PropertyIsGreaterThan": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);
+                return node;
+            },
+            "PropertyIsLessThanOrEqualTo": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);
+                return node;
+            },
+            "PropertyIsGreaterThanOrEqualTo": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);
+                return node;
+            },
+            "PropertyIsBetween": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsBetween");
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("LowerBoundary", filter, node);
+                this.writeNode("UpperBoundary", filter, node);
+                return node;
+            },
+            "PropertyIsLike": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsLike", {
+                    attributes: {
+                        wildCard: "*", singleChar: ".", escape: "!"
+                    }
+                });
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                // convert regex string to ogc string
+                this.writeNode("Literal", filter.regex2value(), node);
+                return node;
+            },
+            "PropertyName": function(filter) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:PropertyName", {
+                    value: filter.property
+                });
+            },
+            "Literal": function(value) {
+                // no ogc:expression handling for now
+                return this.createElementNSPlus("ogc:Literal", {
+                    value: value
+                });
+            },
+            "LowerBoundary": function(filter) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:LowerBoundary");
+                this.writeNode("Literal", filter.lowerBoundary, node);
+                return node;
+            },
+            "UpperBoundary": function(filter) {
+                // no ogc:expression handling for now
+                var node = this.createElementNSPlus("ogc:UpperBoundary");
+                this.writeNode("Literal", filter.upperBoundary, node);
+                return node;
+            },
+            "INTERSECTS": function(filter) {
+                return this.writeSpatial(filter, "Intersects");
+            },
+            "WITHIN": function(filter) {
+                return this.writeSpatial(filter, "Within");
+            },
+            "CONTAINS": function(filter) {
+                return this.writeSpatial(filter, "Contains");
+            },
+            "DWITHIN": function(filter) {
+                var node = this.writeSpatial(filter, "DWithin");
+                this.writeNode("Distance", filter, node);
+                return node;
+            },
+            "Distance": function(filter) {
+                return this.createElementNSPlus("ogc:Distance", {
+                    attributes: {
+                        units: filter.distanceUnits
+                    },
+                    value: filter.distance
+                });
+            }
+        }
+    },
+
+    /**
+     * Method: getFilterType
+     */
+    getFilterType: function(filter) {
+        var filterType = this.filterMap[filter.type];
+        if(!filterType) {
+            throw "Filter writing not supported for rule type: " + filter.type;
+        }
+        return filterType;
+    },
+    
+    /**
+     * Property: filterMap
+     * {Object} Contains a member for each filter type.  Values are node names
+     *     for corresponding OGC Filter child elements.
+     */
+    filterMap: {
+        "&&": "And",
+        "||": "Or",
+        "!": "Not",
+        "==": "PropertyIsEqualTo",
+        "!=": "PropertyIsNotEqualTo",
+        "<": "PropertyIsLessThan",
+        ">": "PropertyIsGreaterThan",
+        "<=": "PropertyIsLessThanOrEqualTo",
+        ">=": "PropertyIsGreaterThanOrEqualTo",
+        "..": "PropertyIsBetween",
+        "~": "PropertyIsLike",
+        "BBOX": "BBOX",
+        "DWITHIN": "DWITHIN",
+        "WITHIN": "WITHIN",
+        "CONTAINS": "CONTAINS",
+        "INTERSECTS": "INTERSECTS"
+    },
+
+    CLASS_NAME: "OpenLayers.Format.Filter.v1" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,158 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/Filter/v1.js
+ * @requires OpenLayers/Format/GML/v3.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter.v1_1_0
+ * Write ogc:Filter version 1.1.0.
+ *
+ * Differences from the v1.0.0 parser:
+ *  - uses GML v3 instead of GML v2
+ *  - reads matchCase attribute on ogc:PropertyIsEqual and
+ *        ogc:PropertyIsNotEqualelements.
+ *  - writes matchCase attribute from comparison filters of type EQUAL_TO and
+ *        type NOT_EQUAL_TO.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.Filter.v1>
+ */
+OpenLayers.Format.Filter.v1_1_0 = OpenLayers.Class(
+    OpenLayers.Format.GML.v3, OpenLayers.Format.Filter.v1, {
+    
+    /**
+     * Constant: VERSION
+     * {String} 1.1.0
+     */
+    VERSION: "1.1.0",
+    
+    /**
+     * Property: schemaLocation
+     * {String} http://www.opengis.net/ogc/filter/1.1.0/filter.xsd
+     */
+    schemaLocation: "http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.Filter.v1_1_0
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.Filter> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.GML.v3.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "ogc": OpenLayers.Util.applyDefaults({
+            "PropertyIsEqualTo": function(node, obj) {
+                var matchCase = node.getAttribute("matchCase");
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.EQUAL_TO,
+                    matchCase: !(matchCase === "false" || matchCase === "0")
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            },
+            "PropertyIsNotEqualTo": function(node, obj) {
+                var matchCase = node.getAttribute("matchCase");
+                var filter = new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
+                    matchCase: !(matchCase === "false" || matchCase === "0")
+                });
+                this.readChildNodes(node, filter);
+                obj.filters.push(filter);
+            }
+        }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),
+        "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"],
+        "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"]        
+    },
+
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "ogc": OpenLayers.Util.applyDefaults({
+            "PropertyIsEqualTo": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsEqualTo", {
+                    attributes: {matchCase: filter.matchCase}
+                });
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);
+                return node;
+            },
+            "PropertyIsNotEqualTo": function(filter) {
+                var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo", {
+                    attributes: {matchCase: filter.matchCase}
+                });
+                // no ogc:expression handling for now
+                this.writeNode("PropertyName", filter, node);
+                this.writeNode("Literal", filter.value, node);
+                return node;
+            },
+            "BBOX": function(filter) {
+                var node = this.createElementNSPlus("ogc:BBOX");
+                this.writeNode("PropertyName", filter, node);
+                var box = this.writeNode("gml:Envelope", filter.value);
+                if(filter.projection) {
+                    box.setAttribute("srsName", filter.projection);
+                }
+                node.appendChild(box); 
+                return node;
+            }}, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),
+            
+        "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"],
+        "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"]
+    },
+
+    /**
+     * Method: writeSpatial
+     *
+     * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML.
+     *
+     * Parameters:
+     * filter - {<OpenLayers.Filter.Spatial>} The filter.
+     * name - {String} Name of the generated XML element.
+     *
+     * Returns:
+     * {DOMElement} The created XML element.
+     */
+    writeSpatial: function(filter, name) {
+        var node = this.createElementNSPlus("ogc:"+name);
+        this.writeNode("PropertyName", filter, node);
+        var child;
+        if(filter.value instanceof OpenLayers.Geometry) {
+            child = this.writeNode("feature:_geometry", filter.value).firstChild;
+        } else {
+            child = this.writeNode("gml:Envelope", filter.value);
+        }
+        if(filter.projection) {
+            child.setAttribute("srsName", filter.projection);
+        }
+        node.appendChild(child);
+        return node;
+    },
+
+    CLASS_NAME: "OpenLayers.Format.Filter.v1_1_0" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Filter.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,114 @@
+/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Filter/FeatureId.js
+ * @requires OpenLayers/Filter/Logical.js
+ * @requires OpenLayers/Filter/Comparison.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter
+ * Read/Wite ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter>
+ *     constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.0.0".
+     */
+    defaultVersion: "1.0.0",
+    
+    /**
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
+     */
+    version: null,
+    
+    /**
+     * Property: parser
+     * {Object} Instance of the versioned parser.  Cached for multiple read and
+     *     write calls of the same version.
+     */
+    parser: null,
+
+    /**
+     * Constructor: OpenLayers.Format.Filter
+     * Create a new parser for Filter.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: write
+     * Write an ogc:Filter given a filter object.
+     *
+     * Parameters:
+     * filter - {<OpenLayers.Filter>} An filter.
+     * options - {Object} Optional configuration object.
+     *
+     * Returns:
+     * {Elment} An ogc:Filter element node.
+     */
+    write: function(filter, options) {
+        var version = (options && options.version) ||
+                      this.version || this.defaultVersion;
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.Filter[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a Filter parser for version " +
+                      version;
+            }
+            this.parser = new format(this.options);
+        }
+        return this.parser.write(filter);
+        //return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+    
+    /**
+     * APIMethod: read
+     * Read and Filter doc and return an object representing the Filter.
+     *
+     * Parameters:
+     * data - {String | DOMElement} Data to read.
+     *
+     * Returns:
+     * {<OpenLayers.Filter>} A filter object.
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var version = this.version;
+        if(!version) {
+            version = this.defaultVersion;
+        }
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.Filter[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a Filter parser for version " +
+                      version;
+            }
+            this.parser = new format(this.options);
+        }
+        var filter = this.parser.read(data);
+        return filter;
+    },
+
+    CLASS_NAME: "OpenLayers.Format.Filter" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/Base.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/Base.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/Base.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,572 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Format/GML.js
+ */
+
+/**
+ * Though required in the full build, if the GML format is excluded, we set
+ * the namespace here.
+ */
+if(!OpenLayers.Format.GML) {
+    OpenLayers.Format.GML = {};
+}
+
+/**
+ * Class: OpenLayers.Format.GML.Base
+ * Superclass for GML parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        gml: "http://www.opengis.net/gml",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance",
+        wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "gml",
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: null,
+    
+    /**
+     * APIProperty: featureType
+     * {Array(String) or String} The local (without prefix) feature typeName(s).
+     */
+    featureType: null,
+    
+    /**
+     * APIProperty: featureNS
+     * {String} The feature namespace.  Must be set in the options at
+     *     construction.
+     */
+    featureNS: null,
+
+    /**
+     * APIProperty: geometry
+     * {String} Name of geometry element.  Defaults to "geometry".
+     */
+    geometryName: "geometry",
+
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract attributes from GML.  Default is true.
+     */
+    extractAttributes: true,
+    
+    /**
+     * APIProperty: srsName
+     * {String} URI for spatial reference system.  This is optional for
+     *     single part geometries and mandatory for collections and multis.
+     *     If set, the srsName attribute will be written for all geometries.
+     *     Default is null.
+     */
+    srsName: null,
+
+    /**
+     * APIProperty: xy
+     * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
+     * Changing is not recommended, a new Format should be instantiated.
+     */ 
+    xy: true,
+
+    /**
+     * Property: geometryTypes
+     * {Object} Maps OpenLayers geometry class names to GML element names.
+     *     Use <setGeometryTypes> before accessing this property.
+     */
+    geometryTypes: null,
+
+    /**
+     * Property: singleFeatureType
+     * {Boolean} True if there is only 1 featureType, and not an array
+     *     of featuretypes.
+     */
+    singleFeatureType: null,
+
+    /**
+     * Property: regExes
+     * Compiled regular expressions for manipulating strings.
+     */
+    regExes: {
+        trimSpace: (/^\s*|\s*$/g),
+        removeSpace: (/\s*/g),
+        splitSpace: (/\s+/),
+        trimComma: (/\s*,\s*/g)
+    },
+
+    /**
+     * Constructor: OpenLayers.Format.GML.Base
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor
+     *     instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     *
+     * Valid options properties:
+     * featureType - {Array(String) or String} Local (without prefix) feature 
+     *     typeName(s) (required).
+     * featureNS - {String} Feature namespace (required).
+     * geometryName - {String} Geometry element name.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+        this.setGeometryTypes();
+        if(options && options.featureNS) {
+            this.setNamespace("feature", options.featureNS);
+        }
+        this.singleFeatureType = !options || (typeof options.featureType === "string");
+    },
+    
+    /**
+     * Method: read
+     *
+     * Parameters:
+     * data - {DOMElement} A gml:featureMember element, a gml:featureMembers
+     *     element, or an element containing either of the above at any level.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Feature.Vector>)} An array of features.
+     */
+    read: function(data) {
+        if(typeof data == "string") { 
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        if(data && data.nodeType == 9) {
+            data = data.documentElement;
+        }
+        var features = [];
+        this.readNode(data, {features: features});
+        if(features.length == 0) {
+            // look for gml:featureMember elements
+            var elements = this.getElementsByTagNameNS(
+                data, this.namespaces.gml, "featureMember"
+            );
+            if(elements.length) {
+                for(var i=0, len=elements.length; i<len; ++i) {
+                    this.readNode(elements[i], {features: features});
+                }
+            } else {
+                // look for gml:featureMembers elements (this is v3, but does no harm here)
+                var elements = this.getElementsByTagNameNS(
+                    data, this.namespaces.gml, "featureMembers"
+                );
+                if(elements.length) {
+                    // there can be only one
+                    this.readNode(elements[0], {features: features});
+                }
+            }
+        }
+        return features;
+    },
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "gml": {
+            "featureMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "featureMembers": function(node, obj) {
+                this.readChildNodes(node, obj);                
+            },
+            "name": function(node, obj) {
+                obj.name = this.getChildValue(node);
+            },
+            "boundedBy": function(node, obj) {
+                var container = {};
+                this.readChildNodes(node, container);
+                if(container.components && container.components.length > 0) {
+                    obj.bounds = container.components[0];
+                }
+            },
+            "Point": function(node, container) {
+                var obj = {points: []};
+                this.readChildNodes(node, obj);
+                if(!container.components) {
+                    container.components = [];
+                }
+                container.components.push(obj.points[0]);
+            },
+            "coordinates": function(node, obj) {
+                var str = this.getChildValue(node).replace(
+                    this.regExes.trimSpace, ""
+                );
+                str = str.replace(this.regExes.trimComma, ",");
+                var pointList = str.split(this.regExes.splitSpace);
+                var coords;
+                var numPoints = pointList.length;
+                var points = new Array(numPoints);
+                for(var i=0; i<numPoints; ++i) {
+                    coords = pointList[i].split(",");
+                    if (this.xy) {
+                        points[i] = new OpenLayers.Geometry.Point(
+                            coords[0], coords[1], coords[2]
+                        );
+                    } else {
+                        points[i] = new OpenLayers.Geometry.Point(
+                            coords[1], coords[0], coords[2]
+                        );
+                    }
+                }
+                obj.points = points;
+            },
+            "coord": function(node, obj) {
+                var coord = {};
+                this.readChildNodes(node, coord);
+                if(!obj.points) {
+                    obj.points = [];
+                }
+                obj.points.push(new OpenLayers.Geometry.Point(
+                    coord.x, coord.y, coord.z
+                ));
+            },
+            "X": function(node, coord) {
+                coord.x = this.getChildValue(node);
+            },
+            "Y": function(node, coord) {
+                coord.y = this.getChildValue(node);
+            },
+            "Z": function(node, coord) {
+                coord.z = this.getChildValue(node);
+            },
+            "MultiPoint": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                container.components = [
+                    new OpenLayers.Geometry.MultiPoint(obj.components)
+                ];
+            },
+            "pointMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "LineString": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                if(!container.components) {
+                    container.components = [];
+                }
+                container.components.push(
+                    new OpenLayers.Geometry.LineString(obj.points)
+                );
+            },
+            "MultiLineString": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                container.components = [
+                    new OpenLayers.Geometry.MultiLineString(obj.components)
+                ];
+            },
+            "lineStringMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "Polygon": function(node, container) {
+                var obj = {outer: null, inner: []};
+                this.readChildNodes(node, obj);
+                obj.inner.unshift(obj.outer);
+                if(!container.components) {
+                    container.components = [];
+                }
+                container.components.push(
+                    new OpenLayers.Geometry.Polygon(obj.inner)
+                );
+            },
+            "LinearRing": function(node, obj) {
+                var container = {};
+                this.readChildNodes(node, container);
+                obj.components = [new OpenLayers.Geometry.LinearRing(
+                    container.points
+                )];
+            },
+            "MultiPolygon": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                container.components = [
+                    new OpenLayers.Geometry.MultiPolygon(obj.components)
+                ];
+            },
+            "polygonMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "GeometryCollection": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                container.components = [
+                    new OpenLayers.Geometry.Collection(obj.components)
+                ];
+            },
+            "geometryMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            }
+        },
+        "feature": {
+            "*": function(node, obj) {
+                // The node can either be named like the featureType, or it
+                // can be a child of the feature:featureType.  Children can be
+                // geometry or attributes.
+                var name;
+                var local = node.localName || node.nodeName.split(":").pop();
+                if (!this.singleFeatureType && 
+                    (OpenLayers.Util.indexOf(this.featureType, local) != -1)) {
+                        name = "_typeName";
+                }
+                else if(local == this.featureType) {
+                    name = "_typeName";
+                } else {
+                    // Assume attribute elements have one child node and that the child
+                    // is a text node.  Otherwise assume it is a geometry node.
+                    if(node.childNodes.length == 0 ||
+                       (node.childNodes.length == 1 && node.firstChild.nodeType == 3)) {
+                        if(this.extractAttributes) {
+                            name = "_attribute";
+                        }
+                    } else {
+                        name = "_geometry";
+                    }
+                }
+                if(name) {
+                    this.readers.feature[name].apply(this, [node, obj]);
+                }
+            },
+            "_typeName": function(node, obj) {
+                var container = {components: [], attributes: {}};
+                this.readChildNodes(node, container);
+                // look for common gml namespaced elements
+                if(container.name) {
+                    container.attributes.name = container.name;
+                }
+                var feature = new OpenLayers.Feature.Vector(
+                    container.components[0], container.attributes
+                );
+                if (!this.singleFeatureType) {
+                    feature.type = node.nodeName.split(":").pop();
+                    feature.namespace = node.namespaceURI;
+                }
+                var fid = node.getAttribute("fid") ||
+                    this.getAttributeNS(node, this.namespaces["gml"], "id");
+                if(fid) {
+                    feature.fid = fid;
+                }
+                if(this.internalProjection && this.externalProjection &&
+                   feature.geometry) {
+                    feature.geometry.transform(
+                        this.externalProjection, this.internalProjection
+                    );
+                }
+                if(container.bounds) {
+                    feature.geometry.bounds = container.bounds;
+                }
+                obj.features.push(feature);
+            },
+            "_geometry": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "_attribute": function(node, obj) {
+                var local = node.localName || node.nodeName.split(":").pop();
+                var value = this.getChildValue(node);
+                obj.attributes[local] = value;
+            }
+        },
+        "wfs": {
+            "FeatureCollection": function(node, obj) {
+                this.readChildNodes(node, obj);
+            }
+        }
+    },
+    
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
+     *     An array of features or a single feature.
+     *
+     * Returns:
+     * {String} Given an array of features, a doc with a gml:featureMembers
+     *     element will be returned.  Given a single feature, a doc with a
+     *     gml:featureMember element will be returned.
+     */
+    write: function(features) {
+        var name;
+        if(features instanceof Array) {
+            name = "featureMembers";
+        } else {
+            name = "featureMember";
+        }
+        var root = this.writeNode("gml:" + name, features);
+        this.setAttributeNS(
+            root, this.namespaces["xsi"],
+            "xsi:schemaLocation", this.schemaLocation
+        );
+
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+    
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "gml": {
+            "featureMember": function(feature) {
+                var node = this.createElementNSPlus("gml:featureMember");
+                this.writeNode("feature:_typeName", feature, node);
+                return node;
+            },
+            "MultiPoint": function(geometry) {
+                var node = this.createElementNSPlus("gml:MultiPoint");
+                for(var i=0; i<geometry.components.length; ++i) {
+                    this.writeNode("pointMember", geometry.components[i], node);
+                }
+                return node;
+            },
+            "pointMember": function(geometry) {
+                var node = this.createElementNSPlus("gml:pointMember");
+                this.writeNode("Point", geometry, node);
+                return node;
+            },
+            "MultiLineString": function(geometry) {
+                var node = this.createElementNSPlus("gml:MultiLineString");
+                for(var i=0; i<geometry.components.length; ++i) {
+                    this.writeNode("lineStringMember", geometry.components[i], node);
+                }
+                return node;
+            },
+            "lineStringMember": function(geometry) {
+                var node = this.createElementNSPlus("gml:lineStringMember");
+                this.writeNode("LineString", geometry, node);
+                return node;
+            },
+            "MultiPolygon": function(geometry) {
+                var node = this.createElementNSPlus("gml:MultiPolygon");
+                for(var i=0; i<geometry.components.length; ++i) {
+                    this.writeNode(
+                        "polygonMember", geometry.components[i], node
+                    );
+                }
+                return node;
+            },
+            "polygonMember": function(geometry) {
+                var node = this.createElementNSPlus("gml:polygonMember");
+                this.writeNode("Polygon", geometry, node);
+                return node;
+            },
+            "GeometryCollection": function(geometry) {
+                var node = this.createElementNSPlus("gml:GeometryCollection");
+                for(var i=0, len=geometry.components.length; i<len; ++i) {
+                    this.writeNode("geometryMember", geometry.components[i], node);
+                }
+                return node;
+            },
+            "geometryMember": function(geometry) {
+                var node = this.createElementNSPlus("gml:geometryMember");
+                var child = this.writeNode("feature:_geometry", geometry);
+                node.appendChild(child.firstChild);
+                return node;
+            }
+        },
+        "feature": {
+            "_typeName": function(feature) {
+                var node = this.createElementNSPlus("feature:" + this.featureType, {
+                    attributes: {fid: feature.fid}
+                });
+                if(feature.geometry) {
+                    this.writeNode("feature:_geometry", feature.geometry, node);
+                }
+                for(var name in feature.attributes) {
+                    var value = feature.attributes[name];
+                    if(value != null) {
+                        this.writeNode(
+                            "feature:_attribute",
+                            {name: name, value: value}, node
+                        );
+                    }
+                }
+                return node;
+            },
+            "_geometry": function(geometry) {
+                if(this.externalProjection && this.internalProjection) {
+                    geometry = geometry.clone().transform(
+                        this.internalProjection, this.externalProjection
+                    );
+                }    
+                var node = this.createElementNSPlus(
+                    "feature:" + this.geometryName
+                );
+                var type = this.geometryTypes[geometry.CLASS_NAME];
+                var child = this.writeNode("gml:" + type, geometry, node);
+                if(this.srsName) {
+                    child.setAttribute("srsName", this.srsName);
+                }
+                return node;
+            },
+            "_attribute": function(obj) {
+                return this.createElementNSPlus("feature:" + obj.name, {
+                    value: obj.value
+                });
+            }
+        },
+        "wfs": {
+            "FeatureCollection": function(features) {
+                /**
+                 * This is only here because GML2 only describes abstract
+                 * feature collections.  Typically, you would not be using
+                 * the GML format to write wfs elements.  This just provides
+                 * some way to write out lists of features.  GML3 defines the
+                 * featureMembers element, so that is used by default instead.
+                 */
+                var node = this.createElementNSPlus("wfs:FeatureCollection");
+                for(var i=0, len=features.length; i<len; ++i) {
+                    this.writeNode("gml:featureMember", features[i], node);
+                }
+                return node;
+            }
+        }
+    },
+    
+    /**
+     * Function: setGeometryTypes
+     * Sets the <geometryTypes> mapping.
+     */
+    setGeometryTypes: function() {
+        this.geometryTypes = {
+            "OpenLayers.Geometry.Point": "Point",
+            "OpenLayers.Geometry.MultiPoint": "MultiPoint",
+            "OpenLayers.Geometry.LineString": "LineString",
+            "OpenLayers.Geometry.MultiLineString": "MultiLineString",
+            "OpenLayers.Geometry.Polygon": "Polygon",
+            "OpenLayers.Geometry.MultiPolygon": "MultiPolygon",
+            "OpenLayers.Geometry.Collection": "GeometryCollection"
+        };
+    },
+
+    CLASS_NAME: "OpenLayers.Format.GML.Base" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v2.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v2.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v2.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,192 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/GML/Base.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GML.v2
+ * Parses GML version 2.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.GML.Base>
+ */
+OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
+    
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.GML.v2
+     * Create a parser for GML v2.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     *
+     * Valid options properties:
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (required).
+     * geometryName - {String} Geometry element name.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "gml": OpenLayers.Util.applyDefaults({
+            "outerBoundaryIs": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                container.outer = obj.components[0];
+            },
+            "innerBoundaryIs": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                container.inner.push(obj.components[0]);
+            },
+            "Box": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                if(!container.components) {
+                    container.components = [];
+                }
+                var min = obj.points[0];
+                var max = obj.points[1];
+                container.components.push(
+                    new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
+                );
+            }
+        }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
+        "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
+        "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
+    },
+
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
+     *     An array of features or a single feature.
+     *
+     * Returns:
+     * {String} Given an array of features, a doc with a gml:featureMembers
+     *     element will be returned.  Given a single feature, a doc with a
+     *     gml:featureMember element will be returned.
+     */
+    write: function(features) {
+        var name;
+        if(features instanceof Array) {
+            // GML2 only has abstract feature collections
+            // wfs provides a feature collection from a well-known schema
+            name = "wfs:FeatureCollection";
+        } else {
+            name = "gml:featureMember";
+        }
+        var root = this.writeNode(name, features);
+        this.setAttributeNS(
+            root, this.namespaces["xsi"],
+            "xsi:schemaLocation", this.schemaLocation
+        );
+
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "gml": OpenLayers.Util.applyDefaults({
+            "Point": function(geometry) {
+                var node = this.createElementNSPlus("gml:Point");
+                this.writeNode("coordinates", [geometry], node);
+                return node;
+            },
+            "coordinates": function(points) {
+                var numPoints = points.length;
+                var parts = new Array(numPoints);
+                var point;
+                for(var i=0; i<numPoints; ++i) {
+                    point = points[i];
+                    if(this.xy) {
+                        parts[i] = point.x + "," + point.y;
+                    } else {
+                        parts[i] = point.y + "," + point.x;
+                    }
+                    if(point.z != undefined) { // allow null or undefined
+                        parts[i] += "," + point.z;
+                    }
+                }
+                return this.createElementNSPlus("gml:coordinates", {
+                    attributes: {
+                        decimal: ".", cs: ",", ts: " "
+                    },
+                    value: (numPoints == 1) ? parts[0] : parts.join(" ")
+                });
+            },
+            "LineString": function(geometry) {
+                var node = this.createElementNSPlus("gml:LineString");
+                this.writeNode("coordinates", geometry.components, node);
+                return node;
+            },
+            "Polygon": function(geometry) {
+                var node = this.createElementNSPlus("gml:Polygon");
+                this.writeNode("outerBoundaryIs", geometry.components[0], node);
+                for(var i=1; i<geometry.components.length; ++i) {
+                    this.writeNode(
+                        "innerBoundaryIs", geometry.components[i], node
+                    );
+                }
+                return node;
+            },
+            "outerBoundaryIs": function(ring) {
+                var node = this.createElementNSPlus("gml:outerBoundaryIs");
+                this.writeNode("LinearRing", ring, node);
+                return node;
+            },
+            "innerBoundaryIs": function(ring) {
+                var node = this.createElementNSPlus("gml:innerBoundaryIs");
+                this.writeNode("LinearRing", ring, node);
+                return node;
+            },
+            "LinearRing": function(ring) {
+                var node = this.createElementNSPlus("gml:LinearRing");
+                this.writeNode("coordinates", ring.components, node);
+                return node;
+            },
+            "Box": function(bounds) {
+                var node = this.createElementNSPlus("gml:Box");
+                this.writeNode("coordinates", [
+                    {x: bounds.left, y: bounds.bottom},
+                    {x: bounds.right, y: bounds.top}
+                ], node);
+                // srsName attribute is optional for gml:Box
+                if(this.srsName) {
+                    node.setAttribute("srsName", this.srsName);
+                }
+                return node;
+            }
+        }, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
+        "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
+        "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.GML.v2" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v3.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v3.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML/v3.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,461 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/GML/Base.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GML.v3
+ * Parses GML version 3.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.GML.Base>
+ */
+OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
+    
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.  The writers
+     *     conform with the Simple Features Profile for GML.
+     */
+    schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",
+
+    /**
+     * Property: curve
+     * {Boolean} Write gml:Curve instead of gml:LineString elements.  This also
+     *     affects the elements in multi-part geometries.  Default is false.
+     *     To write gml:Curve elements instead of gml:LineString, set curve
+     *     to true in the options to the contstructor (cannot be changed after
+     *     instantiation).
+     */
+    curve: false,
+    
+    /**
+     * Property: multiCurve
+     * {Boolean} Write gml:MultiCurve instead of gml:MultiLineString.  Since
+     *     the latter is deprecated in GML 3, the default is true.  To write
+     *     gml:MultiLineString instead of gml:MultiCurve, set multiCurve to
+     *     false in the options to the constructor (cannot be changed after
+     *     instantiation).
+     */
+    multiCurve: true,
+    
+    /**
+     * Property: surface
+     * {Boolean} Write gml:Surface instead of gml:Polygon elements.  This also
+     *     affects the elements in multi-part geometries.  Default is false.
+     *     To write gml:Surface elements instead of gml:Polygon, set surface
+     *     to true in the options to the contstructor (cannot be changed after
+     *     instantiation).
+     */
+    surface: false,
+
+    /**
+     * Property: multiSurface
+     * {Boolean} Write gml:multiSurface instead of gml:MultiPolygon.  Since
+     *     the latter is deprecated in GML 3, the default is true.  To write
+     *     gml:MultiPolygon instead of gml:multiSurface, set multiSurface to
+     *     false in the options to the constructor (cannot be changed after
+     *     instantiation).
+     */
+    multiSurface: true,
+
+    /**
+     * Constructor: OpenLayers.Format.GML.v3
+     * Create a parser for GML v3.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     *
+     * Valid options properties:
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (required).
+     * geometryName - {String} Geometry element name.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "gml": OpenLayers.Util.applyDefaults({
+            "featureMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "Curve": function(node, container) {
+                var obj = {points: []};
+                this.readChildNodes(node, obj);
+                if(!container.components) {
+                    container.components = [];
+                }
+                container.components.push(
+                    new OpenLayers.Geometry.LineString(obj.points)
+                );
+            },
+            "segments": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "LineStringSegment": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                if(obj.points) {
+                    Array.prototype.push.apply(container.points, obj.points);
+                }
+            },
+            "pos": function(node, obj) {
+                var str = this.getChildValue(node).replace(
+                    this.regExes.trimSpace, ""
+                );
+                var coords = str.split(this.regExes.splitSpace);
+                var point;
+                if(this.xy) {
+                    point = new OpenLayers.Geometry.Point(
+                        coords[0], coords[1], coords[2]
+                    );
+                } else {
+                    point = new OpenLayers.Geometry.Point(
+                        coords[1], coords[0], coords[2]
+                    );
+                }
+                obj.points = [point];
+            },
+            "posList": function(node, obj) {
+                var str = this.getChildValue(node).replace(
+                    this.regExes.trimSpace, ""
+                );
+                var coords = str.split(this.regExes.splitSpace);
+                var dim = parseInt(node.getAttribute("dimension")) || 2;
+                var j, x, y, z;
+                var numPoints = coords.length / dim;
+                var points = new Array(numPoints);
+                for(var i=0, len=coords.length; i<len; i += dim) {
+                    x = coords[i];
+                    y = coords[i+1];
+                    z = (dim == 2) ? undefined : coords[i+2];
+                    if (this.xy) {
+                        points[i/dim] = new OpenLayers.Geometry.Point(x, y, z);
+                    } else {
+                        points[i/dim] = new OpenLayers.Geometry.Point(y, x, z);
+                    }
+                }
+                obj.points = points;
+            },
+            "Surface": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "patches": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "PolygonPatch": function(node, obj) {
+                this.readers.gml.Polygon.apply(this, [node, obj]);
+            },
+            "exterior": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                container.outer = obj.components[0];
+            },
+            "interior": function(node, container) {
+                var obj = {};
+                this.readChildNodes(node, obj);
+                container.inner.push(obj.components[0]);
+            },
+            "MultiCurve": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                if(obj.components.length > 0) {
+                    container.components = [
+                        new OpenLayers.Geometry.MultiLineString(obj.components)
+                    ];
+                }
+            },
+            "curveMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "MultiSurface": function(node, container) {
+                var obj = {components: []};
+                this.readChildNodes(node, obj);
+                if(obj.components.length > 0) {
+                    container.components = [
+                        new OpenLayers.Geometry.MultiPolygon(obj.components)
+                    ];
+                }
+            },
+            "surfaceMember": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "surfaceMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "pointMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "lineStringMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "polygonMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "geometryMembers": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "Envelope": function(node, container) {
+                var obj = {points: new Array(2)};
+                this.readChildNodes(node, obj);
+                if(!container.components) {
+                    container.components = [];
+                }
+                var min = obj.points[0];
+                var max = obj.points[1];
+                container.components.push(
+                    new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
+                );
+            },
+            "lowerCorner": function(node, container) {
+                var obj = {};
+                this.readers.gml.pos.apply(this, [node, obj]);
+                container.points[0] = obj.points[0];
+            },
+            "upperCorner": function(node, container) {
+                var obj = {};
+                this.readers.gml.pos.apply(this, [node, obj]);
+                container.points[1] = obj.points[0];
+            }
+        }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),            
+        "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
+        "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
+    },
+    
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
+     *     An array of features or a single feature.
+     *
+     * Returns:
+     * {String} Given an array of features, a doc with a gml:featureMembers
+     *     element will be returned.  Given a single feature, a doc with a
+     *     gml:featureMember element will be returned.
+     */
+    write: function(features) {
+        var name;
+        if(features instanceof Array) {
+            name = "featureMembers";
+        } else {
+            name = "featureMember";
+        }
+        var root = this.writeNode("gml:" + name, features);
+        this.setAttributeNS(
+            root, this.namespaces["xsi"],
+            "xsi:schemaLocation", this.schemaLocation
+        );
+
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "gml": OpenLayers.Util.applyDefaults({
+            "featureMembers": function(features) {
+                var node = this.createElementNSPlus("gml:featureMembers");
+                for(var i=0, len=features.length; i<len; ++i) {
+                    this.writeNode("feature:_typeName", features[i], node);
+                }
+                return node;
+            },
+            "Point": function(geometry) {
+                var node = this.createElementNSPlus("gml:Point");
+                this.writeNode("pos", geometry, node);
+                return node;
+            },
+            "pos": function(point) {
+                // only 2d for simple features profile
+                var pos = (this.xy) ?
+                    (point.x + " " + point.y) : (point.y + " " + point.x);
+                return this.createElementNSPlus("gml:pos", {
+                    value: pos
+                });
+            },
+            "LineString": function(geometry) {
+                var node = this.createElementNSPlus("gml:LineString");
+                this.writeNode("posList", geometry.components, node);
+                return node;
+            },
+            "Curve": function(geometry) {
+                var node = this.createElementNSPlus("gml:Curve");
+                this.writeNode("segments", geometry, node);
+                return node;
+            },
+            "segments": function(geometry) {
+                var node = this.createElementNSPlus("gml:segments");
+                this.writeNode("LineStringSegment", geometry, node);
+                return node;
+            },
+            "LineStringSegment": function(geometry) {
+                var node = this.createElementNSPlus("gml:LineStringSegment");
+                this.writeNode("posList", geometry.components, node);
+                return node;
+            },
+            "posList": function(points) {
+                // only 2d for simple features profile
+                var len = points.length;
+                var parts = new Array(len);
+                var point;
+                for(var i=0; i<len; ++i) {
+                    point = points[i];
+                    if(this.xy) {
+                        parts[i] = point.x + " " + point.y;
+                    } else {
+                        parts[i] = point.y + " " + point.x;
+                    }
+                }
+                return this.createElementNSPlus("gml:posList", {
+                    value: parts.join(" ")
+                }); 
+            },
+            "Surface": function(geometry) {
+                var node = this.createElementNSPlus("gml:Surface");
+                this.writeNode("patches", geometry, node);
+                return node;
+            },
+            "patches": function(geometry) {
+                var node = this.createElementNSPlus("gml:patches");
+                this.writeNode("PolygonPatch", geometry, node);
+                return node;
+            },
+            "PolygonPatch": function(geometry) {
+                var node = this.createElementNSPlus("gml:PolygonPatch", {
+                    attributes: {interpolation: "planar"}
+                });
+                this.writeNode("exterior", geometry.components[0], node);
+                for(var i=1, len=geometry.components.length; i<len; ++i) {
+                    this.writeNode(
+                        "interior", geometry.components[i], node
+                    );
+                }
+                return node;
+            },
+            "Polygon": function(geometry) {
+                var node = this.createElementNSPlus("gml:Polygon");
+                this.writeNode("exterior", geometry.components[0], node);
+                for(var i=1, len=geometry.components.length; i<len; ++i) {
+                    this.writeNode(
+                        "interior", geometry.components[i], node
+                    );
+                }
+                return node;
+            },
+            "exterior": function(ring) {
+                var node = this.createElementNSPlus("gml:exterior");
+                this.writeNode("LinearRing", ring, node);
+                return node;
+            },
+            "interior": function(ring) {
+                var node = this.createElementNSPlus("gml:interior");
+                this.writeNode("LinearRing", ring, node);
+                return node;
+            },
+            "LinearRing": function(ring) {
+                var node = this.createElementNSPlus("gml:LinearRing");
+                this.writeNode("posList", ring.components, node);
+                return node;
+            },
+            "MultiCurve": function(geometry) {
+                var node = this.createElementNSPlus("gml:MultiCurve");
+                for(var i=0, len=geometry.components.length; i<len; ++i) {
+                    this.writeNode("curveMember", geometry.components[i], node);
+                }
+                return node;
+            },
+            "curveMember": function(geometry) {
+                var node = this.createElementNSPlus("gml:curveMember");
+                if(this.curve) {
+                    this.writeNode("Curve", geometry, node);
+                } else {
+                    this.writeNode("LineString", geometry, node);
+                }
+                return node;
+            },
+            "MultiSurface": function(geometry) {
+                var node = this.createElementNSPlus("gml:MultiSurface");
+                for(var i=0, len=geometry.components.length; i<len; ++i) {
+                    this.writeNode("surfaceMember", geometry.components[i], node);
+                }
+                return node;
+            },
+            "surfaceMember": function(polygon) {
+                var node = this.createElementNSPlus("gml:surfaceMember");
+                if(this.surface) {
+                    this.writeNode("Surface", polygon, node);
+                } else {
+                    this.writeNode("Polygon", polygon, node);
+                }
+                return node;
+            },
+            "Envelope": function(bounds) {
+                var node = this.createElementNSPlus("gml:Envelope");
+                this.writeNode("lowerCorner", bounds, node);
+                this.writeNode("upperCorner", bounds, node);
+                // srsName attribute is required for gml:Envelope
+                if(this.srsName) {
+                    node.setAttribute("srsName", this.srsName);
+                }
+                return node;
+            },
+            "lowerCorner": function(bounds) {
+                // only 2d for simple features profile
+                var pos = (this.xy) ?
+                    (bounds.left + " " + bounds.bottom) :
+                    (bounds.bottom + " " + bounds.left);
+                return this.createElementNSPlus("gml:lowerCorner", {
+                    value: pos
+                });
+            },
+            "upperCorner": function(bounds) {
+                // only 2d for simple features profile
+                var pos = (this.xy) ?
+                    (bounds.right + " " + bounds.top) :
+                    (bounds.top + " " + bounds.right);
+                return this.createElementNSPlus("gml:upperCorner", {
+                    value: pos
+                });
+            }
+        }, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
+        "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
+        "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
+    },
+
+    /**
+     * Function: setGeometryTypes
+     * Sets the <geometryTypes> mapping.
+     */
+    setGeometryTypes: function() {
+        this.geometryTypes = {
+            "OpenLayers.Geometry.Point": "Point",
+            "OpenLayers.Geometry.MultiPoint": "MultiPoint",
+            "OpenLayers.Geometry.LineString": (this.curve === true) ? "Curve": "LineString",
+            "OpenLayers.Geometry.MultiLineString": (this.multiCurve === false) ? "MultiLineString" : "MultiCurve",
+            "OpenLayers.Geometry.Polygon": (this.surface === true) ? "Surface" : "Polygon",
+            "OpenLayers.Geometry.MultiPolygon": (this.multiSurface === false) ? "MultiPolygon" : "MultiSurface",
+            "OpenLayers.Geometry.Collection": "GeometryCollection"
+        };
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.GML.v3" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GML.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,872 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/MultiPoint.js
+ * @requires OpenLayers/Geometry/LineString.js
+ * @requires OpenLayers/Geometry/MultiLineString.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ * @requires OpenLayers/Geometry/MultiPolygon.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GML
+ * Read/Wite GML. Create a new instance with the <OpenLayers.Format.GML>
+ *     constructor.  Supports the GML simple features profile.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /*
+     * APIProperty: featureNS
+     * {String} Namespace used for feature attributes.  Default is
+     *     "http://mapserver.gis.umn.edu/mapserver".
+     */
+    featureNS: "http://mapserver.gis.umn.edu/mapserver",
+    
+    /**
+     * APIProperty: featurePrefix
+     * {String} Namespace alias (or prefix) for feature nodes.  Default is
+     *     "feature".
+     */
+    featurePrefix: "feature",
+    
+    /*
+     * APIProperty: featureName
+     * {String} Element name for features. Default is "featureMember".
+     */
+    featureName: "featureMember", 
+    
+    /*
+     * APIProperty: layerName
+     * {String} Name of data layer. Default is "features".
+     */
+    layerName: "features",
+    
+    /**
+     * APIProperty: geometryName
+     * {String} Name of geometry element.  Defaults to "geometry".
+     */
+    geometryName: "geometry",
+    
+    /** 
+     * APIProperty: collectionName
+     * {String} Name of featureCollection element.
+     */
+    collectionName: "FeatureCollection",
+    
+    /**
+     * APIProperty: gmlns
+     * {String} GML Namespace.
+     */
+    gmlns: "http://www.opengis.net/gml",
+
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract attributes from GML.
+     */
+    extractAttributes: true,
+    
+    /**
+     * APIProperty: xy
+     * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
+     * Changing is not recommended, a new Format should be instantiated.
+     */ 
+    xy: true,
+    
+    /**
+     * Constructor: OpenLayers.Format.GML
+     * Create a new parser for GML.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        // compile regular expressions once instead of every time they are used
+        this.regExes = {
+            trimSpace: (/^\s*|\s*$/g),
+            removeSpace: (/\s*/g),
+            splitSpace: (/\s+/),
+            trimComma: (/\s*,\s*/g)
+        };
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: read
+     * Read data from a string, and return a list of features. 
+     * 
+     * Parameters:
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Feature.Vector>)} An array of features.
+     */
+    read: function(data) {
+        if(typeof data == "string") { 
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var featureNodes = this.getElementsByTagNameNS(data.documentElement,
+                                                       this.gmlns,
+                                                       this.featureName);
+        var features = [];
+        for(var i=0; i<featureNodes.length; i++) {
+            var feature = this.parseFeature(featureNodes[i]);
+            if(feature) {
+                features.push(feature);
+            }
+        }
+        return features;
+    },
+    
+    /**
+     * Method: parseFeature
+     * This function is the core of the GML parsing code in OpenLayers.
+     *    It creates the geometries that are then attached to the returned
+     *    feature, and calls parseAttributes() to get attribute data out.
+     *    
+     * Parameters:
+     * node - {DOMElement} A GML feature node. 
+     */
+    parseFeature: function(node) {
+        // only accept one geometry per feature - look for highest "order"
+        var order = ["MultiPolygon", "Polygon",
+                     "MultiLineString", "LineString",
+                     "MultiPoint", "Point", "Envelope", "Box"];
+        var type, nodeList, geometry, parser;
+        for(var i=0; i<order.length; ++i) {
+            type = order[i];
+            nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
+            if(nodeList.length > 0) {
+                // only deal with first geometry of this type
+                var parser = this.parseGeometry[type.toLowerCase()];
+                if(parser) {
+                    geometry = parser.apply(this, [nodeList[0]]);
+                    if (this.internalProjection && this.externalProjection) {
+                        geometry.transform(this.externalProjection, 
+                                           this.internalProjection); 
+                    }                       
+                } else {
+                    OpenLayers.Console.error(OpenLayers.i18n(
+                                "unsupportedGeometryType", {'geomType':type}));
+                }
+                // stop looking for different geometry types
+                break;
+            }
+        }
+        
+        // construct feature (optionally with attributes)
+        var attributes;
+        if(this.extractAttributes) {
+            attributes = this.parseAttributes(node);
+        }
+        var feature = new OpenLayers.Feature.Vector(geometry, attributes);
+        
+        feature.gml = {
+            featureType: node.firstChild.nodeName.split(":")[1],
+            featureNS: node.firstChild.namespaceURI,
+            featureNSPrefix: node.firstChild.prefix
+        };
+                
+        // assign fid - this can come from a "fid" or "id" attribute
+        var childNode = node.firstChild;
+        var fid;
+        while(childNode) {
+            if(childNode.nodeType == 1) {
+                fid = childNode.getAttribute("fid") ||
+                      childNode.getAttribute("id");
+                if(fid) {
+                    break;
+                }
+            }
+            childNode = childNode.nextSibling;
+        }
+        feature.fid = fid;
+        return feature;
+    },
+    
+    /**
+     * Property: parseGeometry
+     * Properties of this object are the functions that parse geometries based
+     *     on their type.
+     */
+    parseGeometry: {
+        
+        /**
+         * Method: parseGeometry.point
+         * Given a GML node representing a point geometry, create an OpenLayers
+         *     point geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.Point>} A point geometry.
+         */
+        point: function(node) {
+            /**
+             * Three coordinate variations to consider:
+             * 1) <gml:pos>x y z</gml:pos>
+             * 2) <gml:coordinates>x, y, z</gml:coordinates>
+             * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
+             */
+            var nodeList, coordString;
+            var coords = [];
+
+            // look for <gml:pos>
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos");
+            if(nodeList.length > 0) {
+                coordString = nodeList[0].firstChild.nodeValue;
+                coordString = coordString.replace(this.regExes.trimSpace, "");
+                coords = coordString.split(this.regExes.splitSpace);
+            }
+
+            // look for <gml:coordinates>
+            if(coords.length == 0) {
+                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "coordinates");
+                if(nodeList.length > 0) {
+                    coordString = nodeList[0].firstChild.nodeValue;
+                    coordString = coordString.replace(this.regExes.removeSpace,
+                                                      "");
+                    coords = coordString.split(",");
+                }
+            }
+
+            // look for <gml:coord>
+            if(coords.length == 0) {
+                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "coord");
+                if(nodeList.length > 0) {
+                    var xList = this.getElementsByTagNameNS(nodeList[0],
+                                                            this.gmlns, "X");
+                    var yList = this.getElementsByTagNameNS(nodeList[0],
+                                                            this.gmlns, "Y");
+                    if(xList.length > 0 && yList.length > 0) {
+                        coords = [xList[0].firstChild.nodeValue,
+                                  yList[0].firstChild.nodeValue];
+                    }
+                }
+            }
+                
+            // preserve third dimension
+            if(coords.length == 2) {
+                coords[2] = null;
+            }
+            
+            if (this.xy) {
+                return new OpenLayers.Geometry.Point(coords[0], coords[1],
+                                                 coords[2]);
+            }
+            else{
+                return new OpenLayers.Geometry.Point(coords[1], coords[0],
+                                                 coords[2]);
+            }
+        },
+        
+        /**
+         * Method: parseGeometry.multipoint
+         * Given a GML node representing a multipoint geometry, create an
+         *     OpenLayers multipoint geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
+         */
+        multipoint: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "Point");
+            var components = [];
+            if(nodeList.length > 0) {
+                var point;
+                for(var i=0; i<nodeList.length; ++i) {
+                    point = this.parseGeometry.point.apply(this, [nodeList[i]]);
+                    if(point) {
+                        components.push(point);
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.MultiPoint(components);
+        },
+        
+        /**
+         * Method: parseGeometry.linestring
+         * Given a GML node representing a linestring geometry, create an
+         *     OpenLayers linestring geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.LineString>} A linestring geometry.
+         */
+        linestring: function(node, ring) {
+            /**
+             * Two coordinate variations to consider:
+             * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
+             * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
+             */
+            var nodeList, coordString;
+            var coords = [];
+            var points = [];
+
+            // look for <gml:posList>
+            nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList");
+            if(nodeList.length > 0) {
+                coordString = this.getChildValue(nodeList[0]);
+                coordString = coordString.replace(this.regExes.trimSpace, "");
+                coords = coordString.split(this.regExes.splitSpace);
+                var dim = parseInt(nodeList[0].getAttribute("dimension"));
+                var j, x, y, z;
+                for(var i=0; i<coords.length/dim; ++i) {
+                    j = i * dim;
+                    x = coords[j];
+                    y = coords[j+1];
+                    z = (dim == 2) ? null : coords[j+2];
+                    if (this.xy) {
+                        points.push(new OpenLayers.Geometry.Point(x, y, z));
+                    } else {
+                        points.push(new OpenLayers.Geometry.Point(y, x, z));
+                    }
+                }
+            }
+
+            // look for <gml:coordinates>
+            if(coords.length == 0) {
+                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "coordinates");
+                if(nodeList.length > 0) {
+                    coordString = this.getChildValue(nodeList[0]);
+                    coordString = coordString.replace(this.regExes.trimSpace,
+                                                      "");
+                    coordString = coordString.replace(this.regExes.trimComma,
+                                                      ",");
+                    var pointList = coordString.split(this.regExes.splitSpace);
+                    for(var i=0; i<pointList.length; ++i) {
+                        coords = pointList[i].split(",");
+                        if(coords.length == 2) {
+                            coords[2] = null;
+                        }
+                        if (this.xy) {
+                            points.push(new OpenLayers.Geometry.Point(coords[0],
+                                                                  coords[1],
+                                                                  coords[2]));
+                        } else {
+                            points.push(new OpenLayers.Geometry.Point(coords[1],
+                                                                  coords[0],
+                                                                  coords[2]));
+                        }
+                    }
+                }
+            }
+
+            var line = null;
+            if(points.length != 0) {
+                if(ring) {
+                    line = new OpenLayers.Geometry.LinearRing(points);
+                } else {
+                    line = new OpenLayers.Geometry.LineString(points);
+                }
+            }
+            return line;
+        },
+        
+        /**
+         * Method: parseGeometry.multilinestring
+         * Given a GML node representing a multilinestring geometry, create an
+         *     OpenLayers multilinestring geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.MultiLineString>} A multilinestring geometry.
+         */
+        multilinestring: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "LineString");
+            var components = [];
+            if(nodeList.length > 0) {
+                var line;
+                for(var i=0; i<nodeList.length; ++i) {
+                    line = this.parseGeometry.linestring.apply(this,
+                                                               [nodeList[i]]);
+                    if(line) {
+                        components.push(line);
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.MultiLineString(components);
+        },
+        
+        /**
+         * Method: parseGeometry.polygon
+         * Given a GML node representing a polygon geometry, create an
+         *     OpenLayers polygon geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+         */
+        polygon: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "LinearRing");
+            var components = [];
+            if(nodeList.length > 0) {
+                // this assumes exterior ring first, inner rings after
+                var ring;
+                for(var i=0; i<nodeList.length; ++i) {
+                    ring = this.parseGeometry.linestring.apply(this,
+                                                        [nodeList[i], true]);
+                    if(ring) {
+                        components.push(ring);
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.Polygon(components);
+        },
+        
+        /**
+         * Method: parseGeometry.multipolygon
+         * Given a GML node representing a multipolygon geometry, create an
+         *     OpenLayers multipolygon geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A GML node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry.
+         */
+        multipolygon: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
+                                                       "Polygon");
+            var components = [];
+            if(nodeList.length > 0) {
+                var polygon;
+                for(var i=0; i<nodeList.length; ++i) {
+                    polygon = this.parseGeometry.polygon.apply(this,
+                                                               [nodeList[i]]);
+                    if(polygon) {
+                        components.push(polygon);
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.MultiPolygon(components);
+        },
+        
+        envelope: function(node) {
+            var components = [];
+            var coordString;
+            var envelope;
+            
+            var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner");
+            if (lpoint.length > 0) {
+                var coords = [];
+                
+                if(lpoint.length > 0) {
+                    coordString = lpoint[0].firstChild.nodeValue;
+                    coordString = coordString.replace(this.regExes.trimSpace, "");
+                    coords = coordString.split(this.regExes.splitSpace);
+                }
+                
+                if(coords.length == 2) {
+                    coords[2] = null;
+                }
+                if (this.xy) {
+                    var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
+                } else {
+                    var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
+                }
+            }
+            
+            var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner");
+            if (upoint.length > 0) {
+                var coords = [];
+                
+                if(upoint.length > 0) {
+                    coordString = upoint[0].firstChild.nodeValue;
+                    coordString = coordString.replace(this.regExes.trimSpace, "");
+                    coords = coordString.split(this.regExes.splitSpace);
+                }
+                
+                if(coords.length == 2) {
+                    coords[2] = null;
+                }
+                if (this.xy) {
+                    var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
+                } else {
+                    var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
+                }
+            }
+            
+            if (lowerPoint && upperPoint) {
+                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
+                components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y));
+                components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y));
+                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y));
+                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
+                
+                var ring = new OpenLayers.Geometry.LinearRing(components);
+                envelope = new OpenLayers.Geometry.Polygon([ring]);
+            }
+            return envelope; 
+        }
+    },
+    
+    /**
+     * Method: parseAttributes
+     *
+     * Parameters:
+     * node - {<DOMElement>}
+     *
+     * Returns:
+     * {Object} An attributes object.
+     */
+    parseAttributes: function(node) {
+        var attributes = {};
+        // assume attributes are children of the first type 1 child
+        var childNode = node.firstChild;
+        var children, i, child, grandchildren, grandchild, name, value;
+        while(childNode) {
+            if(childNode.nodeType == 1) {
+                // attributes are type 1 children with one type 3 child
+                children = childNode.childNodes;
+                for(i=0; i<children.length; ++i) {
+                    child = children[i];
+                    if(child.nodeType == 1) {
+                        grandchildren = child.childNodes;
+                        if(grandchildren.length == 1) {
+                            grandchild = grandchildren[0];
+                            if(grandchild.nodeType == 3 ||
+                               grandchild.nodeType == 4) {
+                                name = (child.prefix) ?
+                                        child.nodeName.split(":")[1] :
+                                        child.nodeName;
+                                value = grandchild.nodeValue.replace(
+                                                this.regExes.trimSpace, "");
+                                attributes[name] = value;
+                            }
+                        } else {
+                            // If child has no childNodes (grandchildren),
+                            // set an attribute with null value.
+                            // e.g. <prefix:fieldname/> becomes
+                            // {fieldname: null}
+                            attributes[child.nodeName.split(":").pop()] = null;
+                        }
+                    }
+                }
+                break;
+            }
+            childNode = childNode.nextSibling;
+        }
+        return attributes;
+    },
+    
+    /**
+     * APIMethod: write
+     * Generate a GML document string given a list of features. 
+     * 
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} List of features to
+     *     serialize into a string.
+     *
+     * Returns:
+     * {String} A string representing the GML document.
+     */
+    write: function(features) {
+        if(!(features instanceof Array)) {
+            features = [features];
+        }
+        var gml = this.createElementNS("http://www.opengis.net/wfs",
+                                       "wfs:" + this.collectionName);
+        for(var i=0; i<features.length; i++) {
+            gml.appendChild(this.createFeatureXML(features[i]));
+        }
+        return OpenLayers.Format.XML.prototype.write.apply(this, [gml]);
+    },
+
+    /** 
+     * Method: createFeatureXML
+     * Accept an OpenLayers.Feature.Vector, and build a GML node for it.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML.
+     *
+     * Returns:
+     * {DOMElement} A node reprensting the feature in GML.
+     */
+    createFeatureXML: function(feature) {
+        var geometry = feature.geometry;
+        var geometryNode = this.buildGeometryNode(geometry);
+        var geomContainer = this.createElementNS(this.featureNS,
+                                                 this.featurePrefix + ":" +
+                                                 this.geometryName);
+        geomContainer.appendChild(geometryNode);
+        var featureNode = this.createElementNS(this.gmlns,
+                                               "gml:" + this.featureName);
+        var featureContainer = this.createElementNS(this.featureNS,
+                                                    this.featurePrefix + ":" +
+                                                    this.layerName);
+        var fid = feature.fid || feature.id;
+        featureContainer.setAttribute("fid", fid);
+        featureContainer.appendChild(geomContainer);
+        for(var attr in feature.attributes) {
+            var attrText = this.createTextNode(feature.attributes[attr]); 
+            var nodename = attr.substring(attr.lastIndexOf(":") + 1);
+            var attrContainer = this.createElementNS(this.featureNS,
+                                                     this.featurePrefix + ":" +
+                                                     nodename);
+            attrContainer.appendChild(attrText);
+            featureContainer.appendChild(attrContainer);
+        }    
+        featureNode.appendChild(featureContainer);
+        return featureNode;
+    },
+    
+    /**
+     * APIMethod: buildGeometryNode
+     */
+    buildGeometryNode: function(geometry) {
+        if (this.externalProjection && this.internalProjection) {
+            geometry = geometry.clone();
+            geometry.transform(this.internalProjection, 
+                               this.externalProjection);
+        }    
+        var className = geometry.CLASS_NAME;
+        var type = className.substring(className.lastIndexOf(".") + 1);
+        var builder = this.buildGeometry[type.toLowerCase()];
+        return builder.apply(this, [geometry]);
+    },
+
+    /**
+     * Property: buildGeometry
+     * Object containing methods to do the actual geometry node building
+     *     based on geometry type.
+     */
+    buildGeometry: {
+        // TBD retrieve the srs from layer
+        // srsName is non-standard, so not including it until it's right.
+        // gml.setAttribute("srsName",
+        //                  "http://www.opengis.net/gml/srs/epsg.xml#4326");
+
+        /**
+         * Method: buildGeometry.point
+         * Given an OpenLayers point geometry, create a GML point.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML point node.
+         */
+        point: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:Point");
+            gml.appendChild(this.buildCoordinatesNode(geometry));
+            return gml;
+        },
+        
+        /**
+         * Method: buildGeometry.multipoint
+         * Given an OpenLayers multipoint geometry, create a GML multipoint.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML multipoint node.
+         */
+        multipoint: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:MultiPoint");
+            var points = geometry.components;
+            var pointMember, pointGeom;
+            for(var i=0; i<points.length; i++) { 
+                pointMember = this.createElementNS(this.gmlns,
+                                                   "gml:pointMember");
+                pointGeom = this.buildGeometry.point.apply(this,
+                                                               [points[i]]);
+                pointMember.appendChild(pointGeom);
+                gml.appendChild(pointMember);
+            }
+            return gml;            
+        },
+        
+        /**
+         * Method: buildGeometry.linestring
+         * Given an OpenLayers linestring geometry, create a GML linestring.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML linestring node.
+         */
+        linestring: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:LineString");
+            gml.appendChild(this.buildCoordinatesNode(geometry));
+            return gml;
+        },
+        
+        /**
+         * Method: buildGeometry.multilinestring
+         * Given an OpenLayers multilinestring geometry, create a GML
+         *     multilinestring.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring
+         *     geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML multilinestring node.
+         */
+        multilinestring: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:MultiLineString");
+            var lines = geometry.components;
+            var lineMember, lineGeom;
+            for(var i=0; i<lines.length; ++i) {
+                lineMember = this.createElementNS(this.gmlns,
+                                                  "gml:lineStringMember");
+                lineGeom = this.buildGeometry.linestring.apply(this,
+                                                                   [lines[i]]);
+                lineMember.appendChild(lineGeom);
+                gml.appendChild(lineMember);
+            }
+            return gml;
+        },
+        
+        /**
+         * Method: buildGeometry.linearring
+         * Given an OpenLayers linearring geometry, create a GML linearring.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML linearring node.
+         */
+        linearring: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:LinearRing");
+            gml.appendChild(this.buildCoordinatesNode(geometry));
+            return gml;
+        },
+        
+        /**
+         * Method: buildGeometry.polygon
+         * Given an OpenLayers polygon geometry, create a GML polygon.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML polygon node.
+         */
+        polygon: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:Polygon");
+            var rings = geometry.components;
+            var ringMember, ringGeom, type;
+            for(var i=0; i<rings.length; ++i) {
+                type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
+                ringMember = this.createElementNS(this.gmlns,
+                                                  "gml:" + type);
+                ringGeom = this.buildGeometry.linearring.apply(this,
+                                                                   [rings[i]]);
+                ringMember.appendChild(ringGeom);
+                gml.appendChild(ringMember);
+            }
+            return gml;
+        },
+        
+        /**
+         * Method: buildGeometry.multipolygon
+         * Given an OpenLayers multipolygon geometry, create a GML multipolygon.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon
+         *     geometry.
+         *
+         * Returns:
+         * {DOMElement} A GML multipolygon node.
+         */
+        multipolygon: function(geometry) {
+            var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon");
+            var polys = geometry.components;
+            var polyMember, polyGeom;
+            for(var i=0; i<polys.length; ++i) {
+                polyMember = this.createElementNS(this.gmlns,
+                                                  "gml:polygonMember");
+                polyGeom = this.buildGeometry.polygon.apply(this,
+                                                                [polys[i]]);
+                polyMember.appendChild(polyGeom);
+                gml.appendChild(polyMember);
+            }
+            return gml;
+
+        },
+ 
+        /**
+         * Method: buildGeometry.bounds
+         * Given an OpenLayers bounds, create a GML box.
+         *
+         * Parameters:
+         * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object.
+         *
+         * Returns:
+         * {DOMElement} A GML box node.
+         */
+        bounds: function(bounds) {
+            var gml = this.createElementNS(this.gmlns, "gml:Box");
+            gml.appendChild(this.buildCoordinatesNode(bounds));
+            return gml;
+        }
+    },
+
+    /**
+     * Method: buildCoordinates
+     * builds the coordinates XmlNode
+     * (code)
+     * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
+     * (end)
+     * Parameters: 
+     * geometry - {<OpenLayers.Geometry>} 
+     *
+     * Returns:
+     * {XmlNode} created xmlNode
+     */
+    buildCoordinatesNode: function(geometry) {
+        var coordinatesNode = this.createElementNS(this.gmlns,
+                                                   "gml:coordinates");
+        coordinatesNode.setAttribute("decimal", ".");
+        coordinatesNode.setAttribute("cs", ",");
+        coordinatesNode.setAttribute("ts", " ");
+
+        var parts = [];
+
+        if(geometry instanceof OpenLayers.Bounds){
+            parts.push(geometry.left + "," + geometry.bottom);
+            parts.push(geometry.right + "," + geometry.top);
+        } else {
+            var points = (geometry.components) ? geometry.components : [geometry];
+            for(var i=0; i<points.length; i++) {
+                parts.push(points[i].x + "," + points[i].y);                
+            }            
+        }
+
+        var txtNode = this.createTextNode(parts.join(" "));
+        coordinatesNode.appendChild(txtNode);
+        
+        return coordinatesNode;
+    },
+
+    CLASS_NAME: "OpenLayers.Format.GML" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GPX.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GPX.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GPX.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,179 @@
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GPX
+ * Read/write GPX parser. Create a new instance with the 
+ *     <OpenLayers.Format.GPX> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
+   /**
+    * APIProperty: extractWaypoints
+    * {Boolean} Extract waypoints from GPX. (default: true)
+    */
+    extractWaypoints: true,
+    
+   /**
+    * APIProperty: extractTracks
+    * {Boolean} Extract tracks from GPX. (default: true)
+    */
+    extractTracks: true,
+    
+   /**
+    * APIProperty: extractRoutes
+    * {Boolean} Extract routes from GPX. (default: true)
+    */
+    extractRoutes: true,
+    
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract feature attributes from GPX. (default: true)
+     *     NOTE: Attributes as part of extensions to the GPX standard may not
+     *     be extracted.
+     */
+    extractAttributes: true,
+    
+    /**
+     * Constructor: OpenLayers.Format.GPX
+     * Create a new parser for GPX.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: read
+     * Return a list of features from a GPX doc
+     *
+     * Parameters:
+     * doc - {Element} 
+     *
+     * Returns:
+     * An Array of <OpenLayers.Feature.Vector>s
+     */
+    read: function(doc) {
+        if (typeof doc == "string") { 
+            doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
+        }
+        var features = [];
+        
+        if(this.extractTracks) {
+            var tracks = doc.getElementsByTagName("trk");
+            for (var i=0, len=tracks.length; i<len; i++) {
+                // Attributes are only in trk nodes, not trkseg nodes
+                var attrs = {};
+                if(this.extractAttributes) {
+                    attrs = this.parseAttributes(tracks[i]);
+                }
+                
+                var segs = this.getElementsByTagNameNS(tracks[i], tracks[i].namespaceURI, "trkseg");
+                for (var j = 0, seglen = segs.length; j < seglen; j++) {
+                    // We don't yet support extraction of trkpt attributes
+                    // All trksegs of a trk get that trk's attributes
+                    var track = this.extractSegment(segs[j], "trkpt");
+                    features.push(new OpenLayers.Feature.Vector(track, attrs));
+                }
+            }
+        }
+        
+        if(this.extractRoutes) {
+            var routes = doc.getElementsByTagName("rte");
+            for (var k=0, klen=routes.length; k<klen; k++) {
+                var attrs = {};
+                if(this.extractAttributes) {
+                    attrs = this.parseAttributes(routes[k]);
+                }
+                var route = this.extractSegment(routes[k], "rtept");
+                features.push(new OpenLayers.Feature.Vector(route, attrs));
+            }
+        }
+        
+        if(this.extractWaypoints) {
+            var waypoints = doc.getElementsByTagName("wpt");
+            for (var l = 0, len = waypoints.length; l < len; l++) {
+                var attrs = {};
+                if(this.extractAttributes) {
+                    attrs = this.parseAttributes(waypoints[l]);
+                }
+                var wpt = new OpenLayers.Geometry.Point(waypoints[l].getAttribute("lon"), waypoints[l].getAttribute("lat"));
+                features.push(new OpenLayers.Feature.Vector(wpt, attrs));
+            }
+        }
+        
+        if (this.internalProjection && this.externalProjection) {
+            for (var g = 0, featLength = features.length; g < featLength; g++) {
+                features[g].geometry.transform(this.externalProjection,
+                                    this.internalProjection);
+            }
+        }
+        
+        return features;
+    },
+    
+   /**
+    * Method: extractSegment
+    *
+    * Parameters:
+    * segment - {<DOMElement>} a trkseg or rte node to parse
+    * segmentType - {String} nodeName of waypoints that form the line
+    *
+    * Returns:
+    * {<OpenLayers.Geometry.LineString>} A linestring geometry
+    */
+    extractSegment: function(segment, segmentType) {
+        var points = this.getElementsByTagNameNS(segment, segment.namespaceURI, segmentType);
+        var point_features = [];
+        for (var i = 0, len = points.length; i < len; i++) {
+            point_features.push(new OpenLayers.Geometry.Point(points[i].getAttribute("lon"), points[i].getAttribute("lat")));
+        }
+        return new OpenLayers.Geometry.LineString(point_features);
+    },
+    
+    /**
+     * Method: parseAttributes
+     *
+     * Parameters:
+     * node - {<DOMElement>}
+     *
+     * Returns:
+     * {Object} An attributes object.
+     */
+    parseAttributes: function(node) {
+        // node is either a wpt, trk or rte
+        // attributes are children of the form <attr>value</attr>
+        var attributes = {};
+        var attrNode = node.firstChild;
+        while(attrNode) {
+            if(attrNode.nodeType == 1) {
+                var value = attrNode.firstChild;
+                if(value.nodeType == 3 || value.nodeType == 4) {
+                    name = (attrNode.prefix) ?
+                        attrNode.nodeName.split(":")[1] :
+                        attrNode.nodeName;
+                    if(name != "trkseg" && name != "rtept") {
+                        attributes[name] = value.nodeValue;
+                    }
+                }
+            }
+            attrNode = attrNode.nextSibling;
+        }
+        return attributes;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.GPX"
+});

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

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GeoRSS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GeoRSS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/GeoRSS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,419 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GeoRSS
+ * Read/write GeoRSS parser. Create a new instance with the 
+ *     <OpenLayers.Format.GeoRSS> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: rssns
+     * {String} RSS namespace to use. Defaults to
+     *   "http://backend.userland.com/rss2"
+     */
+    rssns: "http://backend.userland.com/rss2",
+    
+    /**
+     * APIProperty: featurens
+     * {String} Feature Attributes namespace.  Defaults to
+     *    "http://mapserver.gis.umn.edu/mapserver"
+     */
+    featureNS: "http://mapserver.gis.umn.edu/mapserver",
+    
+    /**
+     * APIProperty: georssns
+     * {String} GeoRSS namespace to use.  Defaults to
+     *     "http://www.georss.org/georss"
+     */
+    georssns: "http://www.georss.org/georss",
+
+    /**
+     * APIProperty: geons
+     * {String} W3C Geo namespace to use.  Defaults to
+     *     "http://www.w3.org/2003/01/geo/wgs84_pos#"
+     */
+    geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",
+    
+    /**
+     * APIProperty: featureTitle
+     * {String} Default title for features.  Defaults to "Untitled"
+     */
+    featureTitle: "Untitled",
+    
+    /**
+     * APIProperty: featureDescription
+     * {String} Default description for features.  Defaults to "No Description"
+     */
+    featureDescription: "No Description",
+    
+    /**
+     * Property: gmlParse
+     * {Object} GML Format object for parsing features
+     * Non-API and only created if necessary
+     */
+    gmlParser: null,
+
+    /**
+     * APIProperty: xy
+     * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
+     * For GeoRSS the default is (y,x), therefore: false
+     */ 
+    xy: false,
+    
+    /**
+     * Constructor: OpenLayers.Format.GeoRSS
+     * Create a new parser for GeoRSS.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: createGeometryFromItem
+     * Return a geometry from a GeoRSS Item.
+     *
+     * Parameters:
+     * item - {DOMElement} A GeoRSS item node.
+     *
+     * Returns:
+     * {<OpenLayers.Geometry>} A geometry representing the node.
+     */
+    createGeometryFromItem: function(item) {
+        var point = this.getElementsByTagNameNS(item, this.georssns, "point");
+        var lat = this.getElementsByTagNameNS(item, this.geons, 'lat');
+        var lon = this.getElementsByTagNameNS(item, this.geons, 'long');
+        
+        var line = this.getElementsByTagNameNS(item,
+                                                this.georssns,
+                                                "line");
+        var polygon = this.getElementsByTagNameNS(item,
+                                                this.georssns,
+                                                "polygon");
+        var where = this.getElementsByTagNameNS(item, 
+                                                this.georssns, 
+                                                "where");
+        var box = this.getElementsByTagNameNS(item, 
+                                              this.georssns, 
+                                              "box");
+												
+        if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
+            var location;
+            if (point.length > 0) {
+                location = OpenLayers.String.trim(
+                                point[0].firstChild.nodeValue).split(/\s+/);
+                if (location.length !=2) {
+                    location = OpenLayers.String.trim(
+                                point[0].firstChild.nodeValue).split(/\s*,\s*/);
+                }
+            } else {
+                location = [parseFloat(lat[0].firstChild.nodeValue),
+                                parseFloat(lon[0].firstChild.nodeValue)];
+            }    
+
+            var geometry = new OpenLayers.Geometry.Point(parseFloat(location[1]),
+                                                         parseFloat(location[0]));
+              
+        } else if (line.length > 0) {
+            var coords = OpenLayers.String.trim(this.concatChildValues(line[0])).split(/\s+/);
+            var components = []; 
+            var point;
+            for (var i=0, len=coords.length; i<len; i+=2) {
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]), 
+                                                     parseFloat(coords[i]));
+                components.push(point);
+            }
+            geometry = new OpenLayers.Geometry.LineString(components);
+        } else if (polygon.length > 0) { 
+            var coords = OpenLayers.String.trim(this.concatChildValues(polygon[0])).split(/\s+/);
+            var components = []; 
+            var point;
+            for (var i=0, len=coords.length; i<len; i+=2) {
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]), 
+                                                     parseFloat(coords[i]));
+                components.push(point);
+            }
+            geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
+        } else if (where.length > 0) { 
+            if (!this.gmlParser) {
+              this.gmlParser = new OpenLayers.Format.GML({'xy': this.xy});
+            }
+            var feature = this.gmlParser.parseFeature(where[0]);
+            geometry = feature.geometry;
+        } else if (box.length  > 0) {
+            var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/);
+            var components = [];
+            var point;
+            if (coords.length > 3) {
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[1]), 
+                                                     parseFloat(coords[0]));
+                components.push(point);
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[1]), 
+                                                     parseFloat(coords[2]));
+                components.push(point);
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[3]), 
+                                                     parseFloat(coords[2]));
+                components.push(point);
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[3]), 
+                                                     parseFloat(coords[0]));
+                components.push(point);
+                point = new OpenLayers.Geometry.Point(parseFloat(coords[1]), 
+                                                     parseFloat(coords[0]));
+                components.push(point);
+            }
+            geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);									 
+        }
+        
+        if (geometry && this.internalProjection && this.externalProjection) {
+            geometry.transform(this.externalProjection, 
+                               this.internalProjection);
+        }
+
+        return geometry;
+    },        
+
+    /**
+     * Method: createFeatureFromItem
+     * Return a feature from a GeoRSS Item.
+     *
+     * Parameters:
+     * item - {DOMElement} A GeoRSS item node.
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature representing the item.
+     */
+    createFeatureFromItem: function(item) {
+        var geometry = this.createGeometryFromItem(item);
+     
+        /* Provide defaults for title and description */
+        var title = this.getChildValue(item, "*", "title", this.featureTitle);
+       
+        /* First try RSS descriptions, then Atom summaries */
+        var description = this.getChildValue(
+            item, "*", "description",
+            this.getChildValue(item, "*", "content",
+                this.getChildValue(item, "*", "summary", this.featureDescription)));
+
+        /* If no link URL is found in the first child node, try the
+           href attribute */
+        var link = this.getChildValue(item, "*", "link");
+        if(!link) {
+            try {
+                link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
+            } catch(e) {
+                link = null;
+            }
+        }
+
+        var id = this.getChildValue(item, "*", "id", null);
+        
+        var data = {
+            "title": title,
+            "description": description,
+            "link": link
+        };
+        var feature = new OpenLayers.Feature.Vector(geometry, data);
+        feature.fid = id;
+        return feature;
+    },        
+    
+    /**
+     * Method: getChildValue
+     *
+     * Parameters:
+     * node - {DOMElement}
+     * nsuri - {String} Child node namespace uri ("*" for any).
+     * name - {String} Child node name.
+     * def - {String} Optional string default to return if no child found.
+     *
+     * Returns:
+     * {String} The value of the first child with the given tag name.  Returns
+     *     default value or empty string if none found.
+     */
+    getChildValue: function(node, nsuri, name, def) {
+        var value;
+        var eles = this.getElementsByTagNameNS(node, nsuri, name);
+        if(eles && eles[0] && eles[0].firstChild
+            && eles[0].firstChild.nodeValue) {
+            value = eles[0].firstChild.nodeValue;
+        } else {
+            value = (def == undefined) ? "" : def;
+        }
+        return value;
+    },
+    
+    /**
+     * APIMethod: read
+     * Return a list of features from a GeoRSS doc
+     
+     * Parameters:
+     * data - {Element} 
+     *
+     * Returns:
+     * An Array of <OpenLayers.Feature.Vector>s
+     */
+    read: function(doc) {
+        if (typeof doc == "string") { 
+            doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
+        }
+
+        /* Try RSS items first, then Atom entries */
+        var itemlist = null;
+        itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
+        if (itemlist.length == 0) {
+            itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
+        }
+        
+        var numItems = itemlist.length;
+        var features = new Array(numItems);
+        for(var i=0; i<numItems; i++) {
+            features[i] = this.createFeatureFromItem(itemlist[i]);
+        }
+        return features;
+    },
+    
+
+    /**
+     * APIMethod: write
+     * Accept Feature Collection, and return a string. 
+     * 
+     * Parameters: 
+     * features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string.
+     */
+    write: function(features) {
+        var georss;
+        if(features instanceof Array) {
+            georss = this.createElementNS(this.rssns, "rss");
+            for(var i=0, len=features.length; i<len; i++) {
+                georss.appendChild(this.createFeatureXML(features[i]));
+            }
+        } else {
+            georss = this.createFeatureXML(features);
+        }
+        return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
+    },
+
+    /**
+     * Method: createFeatureXML
+     * Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
+     * 
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} 
+     *
+     * Returns:
+     * {DOMElement}
+     */
+    createFeatureXML: function(feature) {
+        var geometryNode = this.buildGeometryNode(feature.geometry);
+        var featureNode = this.createElementNS(this.rssns, "item");
+        var titleNode = this.createElementNS(this.rssns, "title");
+        titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : ""));
+        var descNode = this.createElementNS(this.rssns, "description");
+        descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : ""));
+        featureNode.appendChild(titleNode);
+        featureNode.appendChild(descNode);
+        if (feature.attributes.link) {
+            var linkNode = this.createElementNS(this.rssns, "link");
+            linkNode.appendChild(this.createTextNode(feature.attributes.link));
+            featureNode.appendChild(linkNode);
+        }    
+        for(var attr in feature.attributes) {
+            if (attr == "link" || attr == "title" || attr == "description") { continue; } 
+            var attrText = this.createTextNode(feature.attributes[attr]); 
+            var nodename = attr;
+            if (attr.search(":") != -1) {
+                nodename = attr.split(":")[1];
+            }    
+            var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
+            attrContainer.appendChild(attrText);
+            featureNode.appendChild(attrContainer);
+        }    
+        featureNode.appendChild(geometryNode);
+        return featureNode;
+    },    
+    
+    /** 
+     * Method: buildGeometryNode
+     * builds a GeoRSS node with a given geometry
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     *
+     * Returns:
+     * {DOMElement} A gml node.
+     */
+    buildGeometryNode: function(geometry) {
+        if (this.internalProjection && this.externalProjection) {
+            geometry = geometry.clone();
+            geometry.transform(this.internalProjection, 
+                               this.externalProjection);
+        }
+        var node;
+        // match Polygon
+        if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
+            node = this.createElementNS(this.georssns, 'georss:polygon');
+            
+            node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
+        }
+        // match LineString
+        else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
+            node = this.createElementNS(this.georssns, 'georss:line');
+            
+            node.appendChild(this.buildCoordinatesNode(geometry));
+        }
+        // match Point
+        else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+            node = this.createElementNS(this.georssns, 'georss:point');
+            node.appendChild(this.buildCoordinatesNode(geometry));
+        } else {
+            throw "Couldn't parse " + geometry.CLASS_NAME;
+        }  
+        return node;         
+    },
+    
+    /** 
+     * Method: buildCoordinatesNode
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     */
+    buildCoordinatesNode: function(geometry) {
+        var points = null;
+        
+        if (geometry.components) {
+            points = geometry.components;
+        }
+
+        var path;
+        if (points) {
+            var numPoints = points.length;
+            var parts = new Array(numPoints);
+            for (var i = 0; i < numPoints; i++) {
+                parts[i] = points[i].y + " " + points[i].x;
+            }
+            path = parts.join(" ");
+        } else {
+            path = geometry.y + " " + geometry.x;
+        }
+        return this.createTextNode(path);
+    },
+
+    CLASS_NAME: "OpenLayers.Format.GeoRSS" 
+});     

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/JSON.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/JSON.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/JSON.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,388 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Note:
+ * This work draws heavily from the public domain JSON serializer/deserializer
+ *     at http://www.json.org/json.js. Rewritten so that it doesn't modify
+ *     basic data prototypes.
+ */
+
+/**
+ * @requires OpenLayers/Format.js
+ */
+
+/**
+ * Class: OpenLayers.Format.JSON
+ * A parser to read/write JSON safely.  Create a new instance with the
+ *     <OpenLayers.Format.JSON> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, {
+    
+    /**
+     * APIProperty: indent
+     * {String} For "pretty" printing, the indent string will be used once for
+     *     each indentation level.
+     */
+    indent: "    ",
+    
+    /**
+     * APIProperty: space
+     * {String} For "pretty" printing, the space string will be used after
+     *     the ":" separating a name/value pair.
+     */
+    space: " ",
+    
+    /**
+     * APIProperty: newline
+     * {String} For "pretty" printing, the newline string will be used at the
+     *     end of each name/value pair or array item.
+     */
+    newline: "\n",
+    
+    /**
+     * Property: level
+     * {Integer} For "pretty" printing, this is incremented/decremented during
+     *     serialization.
+     */
+    level: 0,
+
+    /**
+     * Property: pretty
+     * {Boolean} Serialize with extra whitespace for structure.  This is set
+     *     by the <write> method.
+     */
+    pretty: false,
+
+    /**
+     * Constructor: OpenLayers.Format.JSON
+     * Create a new parser for JSON.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: read
+     * Deserialize a json string.
+     *
+     * Parameters:
+     * json - {String} A JSON string
+     * filter - {Function} A function which will be called for every key and
+     *     value at every level of the final result. Each value will be
+     *     replaced by the result of the filter function. This can be used to
+     *     reform generic objects into instances of classes, or to transform
+     *     date strings into Date objects.
+     *     
+     * Returns:
+     * {Object} An object, array, string, or number .
+     */
+    read: function(json, filter) {
+        /**
+         * Parsing happens in three stages. In the first stage, we run the text
+         *     against a regular expression which looks for non-JSON
+         *     characters. We are especially concerned with '()' and 'new'
+         *     because they can cause invocation, and '=' because it can cause
+         *     mutation. But just to be safe, we will reject all unexpected
+         *     characters.
+         */
+        try {
+            if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, '@').
+                                replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+                                replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+                /**
+                 * In the second stage we use the eval function to compile the
+                 *     text into a JavaScript structure. The '{' operator is
+                 *     subject to a syntactic ambiguity in JavaScript - it can
+                 *     begin a block or an object literal. We wrap the text in
+                 *     parens to eliminate the ambiguity.
+                 */
+                var object = eval('(' + json + ')');
+
+                /**
+                 * In the optional third stage, we recursively walk the new
+                 *     structure, passing each name/value pair to a filter
+                 *     function for possible transformation.
+                 */
+                if(typeof filter === 'function') {
+                    function walk(k, v) {
+                        if(v && typeof v === 'object') {
+                            for(var i in v) {
+                                if(v.hasOwnProperty(i)) {
+                                    v[i] = walk(i, v[i]);
+                                }
+                            }
+                        }
+                        return filter(k, v);
+                    }
+                    object = walk('', object);
+                }
+
+                if(this.keepData) {
+                    this.data = object;
+                }
+
+                return object;
+            }
+        } catch(e) {
+            // Fall through if the regexp test fails.
+        }
+        return null;
+    },
+
+    /**
+     * APIMethod: write
+     * Serialize an object into a JSON string.
+     *
+     * Parameters:
+     * value - {String} The object, array, string, number, boolean or date
+     *     to be serialized.
+     * pretty - {Boolean} Structure the output with newlines and indentation.
+     *     Default is false.
+     *
+     * Returns:
+     * {String} The JSON string representation of the input value.
+     */
+    write: function(value, pretty) {
+        this.pretty = !!pretty;
+        var json = null;
+        var type = typeof value;
+        if(this.serialize[type]) {
+            try {
+                json = this.serialize[type].apply(this, [value]);
+            } catch(err) {
+                OpenLayers.Console.error("Trouble serializing: " + err);
+            }
+        }
+        return json;
+    },
+    
+    /**
+     * Method: writeIndent
+     * Output an indentation string depending on the indentation level.
+     *
+     * Returns:
+     * {String} An appropriate indentation string.
+     */
+    writeIndent: function() {
+        var pieces = [];
+        if(this.pretty) {
+            for(var i=0; i<this.level; ++i) {
+                pieces.push(this.indent);
+            }
+        }
+        return pieces.join('');
+    },
+    
+    /**
+     * Method: writeNewline
+     * Output a string representing a newline if in pretty printing mode.
+     *
+     * Returns:
+     * {String} A string representing a new line.
+     */
+    writeNewline: function() {
+        return (this.pretty) ? this.newline : '';
+    },
+    
+    /**
+     * Method: writeSpace
+     * Output a string representing a space if in pretty printing mode.
+     *
+     * Returns:
+     * {String} A space.
+     */
+    writeSpace: function() {
+        return (this.pretty) ? this.space : '';
+    },
+
+    /**
+     * Property: serialize
+     * Object with properties corresponding to the serializable data types.
+     *     Property values are functions that do the actual serializing.
+     */
+    serialize: {
+        /**
+         * Method: serialize.object
+         * Transform an object into a JSON string.
+         *
+         * Parameters:
+         * object - {Object} The object to be serialized.
+         * 
+         * Returns:
+         * {String} A JSON string representing the object.
+         */
+        'object': function(object) {
+            // three special objects that we want to treat differently
+            if(object == null) {
+                return "null";
+            }
+            if(object.constructor == Date) {
+                return this.serialize.date.apply(this, [object]);
+            }
+            if(object.constructor == Array) {
+                return this.serialize.array.apply(this, [object]);
+            }
+            var pieces = ['{'];
+            this.level += 1;
+            var key, keyJSON, valueJSON;
+            
+            var addComma = false;
+            for(key in object) {
+                if(object.hasOwnProperty(key)) {
+                    // recursive calls need to allow for sub-classing
+                    keyJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
+                                                    [key, this.pretty]);
+                    valueJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
+                                                    [object[key], this.pretty]);
+                    if(keyJSON != null && valueJSON != null) {
+                        if(addComma) {
+                            pieces.push(',');
+                        }
+                        pieces.push(this.writeNewline(), this.writeIndent(),
+                                    keyJSON, ':', this.writeSpace(), valueJSON);
+                        addComma = true;
+                    }
+                }
+            }
+            
+            this.level -= 1;
+            pieces.push(this.writeNewline(), this.writeIndent(), '}');
+            return pieces.join('');
+        },
+        
+        /**
+         * Method: serialize.array
+         * Transform an array into a JSON string.
+         *
+         * Parameters:
+         * array - {Array} The array to be serialized
+         * 
+         * Returns:
+         * {String} A JSON string representing the array.
+         */
+        'array': function(array) {
+            var json;
+            var pieces = ['['];
+            this.level += 1;
+    
+            for(var i=0, len=array.length; i<len; ++i) {
+                // recursive calls need to allow for sub-classing
+                json = OpenLayers.Format.JSON.prototype.write.apply(this,
+                                                    [array[i], this.pretty]);
+                if(json != null) {
+                    if(i > 0) {
+                        pieces.push(',');
+                    }
+                    pieces.push(this.writeNewline(), this.writeIndent(), json);
+                }
+            }
+
+            this.level -= 1;    
+            pieces.push(this.writeNewline(), this.writeIndent(), ']');
+            return pieces.join('');
+        },
+        
+        /**
+         * Method: serialize.string
+         * Transform a string into a JSON string.
+         *
+         * Parameters:
+         * string - {String} The string to be serialized
+         * 
+         * Returns:
+         * {String} A JSON string representing the string.
+         */
+        'string': function(string) {
+            // If the string contains no control characters, no quote characters, and no
+            // backslash characters, then we can simply slap some quotes around it.
+            // Otherwise we must also replace the offending characters with safe
+            // sequences.    
+            var m = {
+                '\b': '\\b',
+                '\t': '\\t',
+                '\n': '\\n',
+                '\f': '\\f',
+                '\r': '\\r',
+                '"' : '\\"',
+                '\\': '\\\\'
+            };
+            if(/["\\\x00-\x1f]/.test(string)) {
+                return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+                    var c = m[b];
+                    if(c) {
+                        return c;
+                    }
+                    c = b.charCodeAt();
+                    return '\\u00' +
+                        Math.floor(c / 16).toString(16) +
+                        (c % 16).toString(16);
+                }) + '"';
+            }
+            return '"' + string + '"';
+        },
+
+        /**
+         * Method: serialize.number
+         * Transform a number into a JSON string.
+         *
+         * Parameters:
+         * number - {Number} The number to be serialized.
+         *
+         * Returns:
+         * {String} A JSON string representing the number.
+         */
+        'number': function(number) {
+            return isFinite(number) ? String(number) : "null";
+        },
+        
+        /**
+         * Method: serialize.boolean
+         * Transform a boolean into a JSON string.
+         *
+         * Parameters:
+         * bool - {Boolean} The boolean to be serialized.
+         * 
+         * Returns:
+         * {String} A JSON string representing the boolean.
+         */
+        'boolean': function(bool) {
+            return String(bool);
+        },
+        
+        /**
+         * Method: serialize.object
+         * Transform a date into a JSON string.
+         *
+         * Parameters:
+         * date - {Date} The date to be serialized.
+         * 
+         * Returns:
+         * {String} A JSON string representing the date.
+         */
+        'date': function(date) {    
+            function format(number) {
+                // Format integers to have at least two digits.
+                return (number < 10) ? '0' + number : number;
+            }
+            return '"' + date.getFullYear() + '-' +
+                    format(date.getMonth() + 1) + '-' +
+                    format(date.getDate()) + 'T' +
+                    format(date.getHours()) + ':' +
+                    format(date.getMinutes()) + ':' +
+                    format(date.getSeconds()) + '"';
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Format.JSON" 
+
+});     

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/KML.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/KML.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/KML.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,1238 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ * @requires OpenLayers/Geometry/Collection.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Format.KML
+ * Read/Wite KML. Create a new instance with the <OpenLayers.Format.KML>
+ *     constructor. 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: kmlns
+     * {String} KML Namespace to use. Defaults to 2.0 namespace.
+     */
+    kmlns: "http://earth.google.com/kml/2.0",
+    
+    /** 
+     * APIProperty: placemarksDesc
+     * {String} Name of the placemarks.  Default is "No description available."
+     */
+    placemarksDesc: "No description available",
+    
+    /** 
+     * APIProperty: foldersName
+     * {String} Name of the folders.  Default is "OpenLayers export."
+     */
+    foldersName: "OpenLayers export",
+    
+    /** 
+     * APIProperty: foldersDesc
+     * {String} Description of the folders. Default is "Exported on [date]."
+     */
+    foldersDesc: "Exported on " + new Date(),
+    
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract attributes from KML.  Default is true.
+     *           Extracting styleUrls requires this to be set to true
+     */
+    extractAttributes: true,
+    
+    /**
+     * Property: extractStyles
+     * {Boolean} Extract styles from KML.  Default is false.
+     *           Extracting styleUrls also requires extractAttributes to be
+     *           set to true
+     */
+    extractStyles: false,
+    
+    /**
+     * Property: internalns
+     * {String} KML Namespace to use -- defaults to the namespace of the
+     *     Placemark node being parsed, but falls back to kmlns. 
+     */
+    internalns: null,
+
+    /**
+     * Property: features
+     * {Array} Array of features
+     *     
+     */
+    features: null,
+
+    /**
+     * Property: styles
+     * {Object} Storage of style objects
+     *     
+     */
+    styles: null,
+    
+    /**
+     * Property: styleBaseUrl
+     * {String}
+     */
+    styleBaseUrl: "",
+
+    /**
+     * Property: fetched
+     * {Object} Storage of KML URLs that have been fetched before
+     *     in order to prevent reloading them.
+     */
+    fetched: null,
+
+    /**
+     * APIProperty: maxDepth
+     * {Integer} Maximum depth for recursive loading external KML URLs 
+     *           Defaults to 0: do no external fetching
+     */
+    maxDepth: 0,
+
+    /**
+     * Constructor: OpenLayers.Format.KML
+     * Create a new parser for KML.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        // compile regular expressions once instead of every time they are used
+        this.regExes = {
+            trimSpace: (/^\s*|\s*$/g),
+            removeSpace: (/\s*/g),
+            splitSpace: (/\s+/),
+            trimComma: (/\s*,\s*/g),
+            kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/),
+            kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/),
+            straightBracket: (/\$\[(.*?)\]/g)
+        };
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: read
+     * Read data from a string, and return a list of features. 
+     * 
+     * Parameters: 
+     * data    - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Feature.Vector>)} List of features.
+     */
+    read: function(data) {
+        this.features = [];
+        this.styles   = {};
+        this.fetched  = {};
+
+        // Set default options 
+        var options = {
+            depth: 0,
+            styleBaseUrl: this.styleBaseUrl
+        };
+
+        return this.parseData(data, options);
+    },
+
+    /**
+     * Method: parseData
+     * Read data from a string, and return a list of features. 
+     * 
+     * Parameters: 
+     * data    - {String} or {DOMElement} data to read/parse.
+     * options - {Object} Hash of options
+     *
+     * Returns:
+     * {Array(<OpenLayers.Feature.Vector>)} List of features.
+     */
+    parseData: function(data, options) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+
+        // Loop throught the following node types in this order and
+        // process the nodes found 
+        var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"];
+        for(var i=0, len=types.length; i<len; ++i) {
+            var type = types[i];
+
+            var nodes = this.getElementsByTagNameNS(data, "*", type);
+
+            // skip to next type if no nodes are found
+            if(nodes.length == 0) { 
+                continue;
+            }
+
+            switch (type.toLowerCase()) {
+
+                // Fetch external links 
+                case "link":
+                case "networklink":
+                    this.parseLinks(nodes, options);
+                    break;
+
+                // parse style information
+                case "style":
+                    if (this.extractStyles) {
+                        this.parseStyles(nodes, options);
+                    }
+                    break;
+                case "stylemap":
+                    if (this.extractStyles) {
+                        this.parseStyleMaps(nodes, options);
+                    }
+                    break;
+
+                // parse features
+                case "placemark":
+                    this.parseFeatures(nodes, options);
+                    break;
+            }
+        }
+        
+        return this.features;
+    },
+
+    /**
+     * Method: parseLinks
+     * Finds URLs of linked KML documents and fetches them
+     * 
+     * Parameters: 
+     * nodes   - {Array} of {DOMElement} data to read/parse.
+     * options - {Object} Hash of options
+     * 
+     */
+    parseLinks: function(nodes, options) {
+        
+        // Fetch external links <NetworkLink> and <Link>
+        // Don't do anything if we have reached our maximum depth for recursion
+        if (options.depth >= this.maxDepth) {
+            return false;
+        }
+
+        // increase depth
+        var newOptions = OpenLayers.Util.extend({}, options);
+        newOptions.depth++;
+
+        for(var i=0, len=nodes.length; i<len; i++) {
+            var href = this.parseProperty(nodes[i], "*", "href");
+            if(href && !this.fetched[href]) {
+                this.fetched[href] = true; // prevent reloading the same urls
+                var data = this.fetchLink(href);
+                if (data) {
+                    this.parseData(data, newOptions);
+                }
+            } 
+        }
+
+    },
+
+    /**
+     * Method: fetchLink
+     * Fetches a URL and returns the result
+     * 
+     * Parameters: 
+     * href  - {String} url to be fetched
+     * 
+     */
+    fetchLink: function(href) {
+        var request = OpenLayers.Request.GET({url: href, async: false});
+        if (request) {
+            return request.responseText;
+        }
+    },
+
+    /**
+     * Method: parseStyles
+     * Looks for <Style> nodes in the data and parses them
+     * Also parses <StyleMap> nodes, but only uses the 'normal' key
+     * 
+     * Parameters: 
+     * nodes    - {Array} of {DOMElement} data to read/parse.
+     * options  - {Object} Hash of options
+     * 
+     */
+    parseStyles: function(nodes, options) {
+        for(var i=0, len=nodes.length; i<len; i++) {
+            var style = this.parseStyle(nodes[i]);
+            if(style) {
+                styleName = (options.styleBaseUrl || "") + "#" + style.id;
+                
+                this.styles[styleName] = style;
+            }
+        }
+    },
+
+    /**
+     * Method: parseStyle
+     * Parses the children of a <Style> node and builds the style hash
+     * accordingly
+     * 
+     * Parameters: 
+     * node - {DOMElement} <Style> node
+     * 
+     */
+    parseStyle: function(node) {
+        var style = {};
+        
+        var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle"];
+        var type, nodeList, geometry, parser;
+        for(var i=0, len=types.length; i<len; ++i) {
+            type = types[i];
+            styleTypeNode = this.getElementsByTagNameNS(node, 
+                                                   "*", type)[0];
+            if(!styleTypeNode) { 
+                continue;
+            }
+
+            // only deal with first geometry of this type
+            switch (type.toLowerCase()) {
+                case "linestyle":
+                    var color = this.parseProperty(styleTypeNode, "*", "color");
+                    if (color) {
+                        var matches = (color.toString()).match(
+                                                         this.regExes.kmlColor);
+
+                        // transparency
+                        var alpha = matches[1];
+                        style["strokeOpacity"] = parseInt(alpha, 16) / 255;
+
+                        // rgb colors (google uses bgr)
+                        var b = matches[2]; 
+                        var g = matches[3]; 
+                        var r = matches[4]; 
+                        style["strokeColor"] = "#" + r + g + b;
+                    }
+                    
+                    var width = this.parseProperty(styleTypeNode, "*", "width");
+                    if (width) {
+                        style["strokeWidth"] = width;
+                    }
+
+                case "polystyle":
+                    var color = this.parseProperty(styleTypeNode, "*", "color");
+                    if (color) {
+                        var matches = (color.toString()).match(
+                                                         this.regExes.kmlColor);
+
+                        // transparency
+                        var alpha = matches[1];
+                        style["fillOpacity"] = parseInt(alpha, 16) / 255;
+
+                        // rgb colors (google uses bgr)
+                        var b = matches[2]; 
+                        var g = matches[3]; 
+                        var r = matches[4]; 
+                        style["fillColor"] = "#" + r + g + b;
+                    }
+                     // Check is fill is disabled
+                    var fill = this.parseProperty(styleTypeNode, "*", "fill");
+                    if (fill == "0") {
+                        style["fillColor"] = "none";
+                    }
+                   
+                    break;
+                case "iconstyle":
+                    // set scale
+                    var scale = parseFloat(this.parseProperty(styleTypeNode, 
+                                                          "*", "scale") || 1);
+  
+                    // set default width and height of icon
+                    var width = 32 * scale;
+                    var height = 32 * scale;
+
+                    var iconNode = this.getElementsByTagNameNS(styleTypeNode, 
+                                               "*", 
+                                               "Icon")[0];
+                    if (iconNode) {
+                        var href = this.parseProperty(iconNode, "*", "href");
+                        if (href) {                                                   
+
+                            var w = this.parseProperty(iconNode, "*", "w");
+                            var h = this.parseProperty(iconNode, "*", "h");
+
+                            // Settings for Google specific icons that are 64x64
+                            // We set the width and height to 64 and halve the
+                            // scale to prevent icons from being too big
+                            var google = "http://maps.google.com/mapfiles/kml";
+                            if (OpenLayers.String.startsWith(
+                                                 href, google) && !w && !h) {
+                                w = 64;
+                                h = 64;
+                                scale = scale / 2;
+                            }
+                                
+                            // if only dimension is defined, make sure the
+                            // other one has the same value
+                            w = w || h;
+                            h = h || w;
+
+                            if (w) {
+                                width = parseInt(w) * scale;
+                            }
+
+                            if (h) {
+                                height = parseInt(h) * scale;
+                            }
+
+                            // support for internal icons 
+                            //    (/root://icons/palette-x.png)
+                            // x and y tell the position on the palette:
+                            // - in pixels
+                            // - starting from the left bottom
+                            // We translate that to a position in the list 
+                            // and request the appropriate icon from the 
+                            // google maps website
+                            var matches = href.match(this.regExes.kmlIconPalette);
+                            if (matches)  {
+                                var palette = matches[1];
+                                var file_extension = matches[2];
+
+                                var x = this.parseProperty(iconNode, "*", "x");
+                                var y = this.parseProperty(iconNode, "*", "y");
+
+                                var posX = x ? x/32 : 0;
+                                var posY = y ? (7 - y/32) : 7;
+
+                                var pos = posY * 8 + posX;
+                                href = "http://maps.google.com/mapfiles/kml/pal" 
+                                     + palette + "/icon" + pos + file_extension;
+                            }
+
+                            style["graphicOpacity"] = 1; // fully opaque
+                            style["externalGraphic"] = href;
+                        }
+
+                    }
+
+
+                    // hotSpots define the offset for an Icon
+                    var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode, 
+                                               "*", 
+                                               "hotSpot")[0];
+                    if (hotSpotNode) {
+                        var x = parseFloat(hotSpotNode.getAttribute("x"));
+                        var y = parseFloat(hotSpotNode.getAttribute("y"));
+
+                        var xUnits = hotSpotNode.getAttribute("xunits");
+                        if (xUnits == "pixels") {
+                            style["graphicXOffset"] = -x * scale;
+                        }
+                        else if (xUnits == "insetPixels") {
+                            style["graphicXOffset"] = -width + (x * scale);
+                        }
+                        else if (xUnits == "fraction") {
+                            style["graphicXOffset"] = -width * x;
+                        }
+
+                        var yUnits = hotSpotNode.getAttribute("yunits");
+                        if (yUnits == "pixels") {
+                            style["graphicYOffset"] = -height + (y * scale) + 1;
+                        }
+                        else if (yUnits == "insetPixels") {
+                            style["graphicYOffset"] = -(y * scale) + 1;
+                        }
+                        else if (yUnits == "fraction") {
+                            style["graphicYOffset"] =  -height * (1 - y) + 1;
+                        }
+                    }
+
+                    style["graphicWidth"] = width;
+                    style["graphicHeight"] = height;
+                    break;
+
+                case "balloonstyle":
+                    var balloonStyle = OpenLayers.Util.getXmlNodeValue(
+                                            styleTypeNode);
+                    if (balloonStyle) {
+                        style["balloonStyle"] = balloonStyle.replace(
+                                       this.regExes.straightBracket, "${$1}");
+                    }
+                    break;
+                default:
+            }
+        }
+
+        // Some polygons have no line color, so we use the fillColor for that
+        if (!style["strokeColor"] && style["fillColor"]) {
+            style["strokeColor"] = style["fillColor"];
+        }
+
+        var id = node.getAttribute("id");
+        if (id && style) {
+            style.id = id;
+        }
+
+        return style;
+    },
+
+    /**
+     * Method: parseStyleMaps
+     * Looks for <Style> nodes in the data and parses them
+     * Also parses <StyleMap> nodes, but only uses the 'normal' key
+     * 
+     * Parameters: 
+     * nodes    - {Array} of {DOMElement} data to read/parse.
+     * options  - {Object} Hash of options
+     * 
+     */
+    parseStyleMaps: function(nodes, options) {
+        // Only the default or "normal" part of the StyleMap is processed now
+        // To do the select or "highlight" bit, we'd need to change lots more
+
+        for(var i=0, len=nodes.length; i<len; i++) {
+            var node = nodes[i];
+            var pairs = this.getElementsByTagNameNS(node, "*", 
+                            "Pair");
+
+            var id = node.getAttribute("id");
+            for (var j=0, jlen=pairs.length; j<jlen; j++) {
+                var pair = pairs[j];
+                // Use the shortcut in the SLD format to quickly retrieve the 
+                // value of a node. Maybe it's good to have a method in 
+                // Format.XML to do this
+                var key = this.parseProperty(pair, "*", "key");
+                var styleUrl = this.parseProperty(pair, "*", "styleUrl");
+
+                if (styleUrl && key == "normal") {
+                    this.styles[(options.styleBaseUrl || "") + "#" + id] =
+                        this.styles[(options.styleBaseUrl || "") + styleUrl];
+                }
+
+                if (styleUrl && key == "highlight") {
+                    // TODO: implement the "select" part
+                }
+
+            }
+        }
+
+    },
+
+
+    /**
+     * Method: parseFeatures
+     * Loop through all Placemark nodes and parse them.
+     * Will create a list of features
+     * 
+     * Parameters: 
+     * nodes    - {Array} of {DOMElement} data to read/parse.
+     * options  - {Object} Hash of options
+     * 
+     */
+    parseFeatures: function(nodes, options) {
+        var features = new Array(nodes.length);
+        for(var i=0, len=nodes.length; i<len; i++) {
+            var featureNode = nodes[i];
+            var feature = this.parseFeature.apply(this,[featureNode]) ;
+            if(feature) {
+
+                // Create reference to styleUrl 
+                if (this.extractStyles && feature.attributes &&
+                    feature.attributes.styleUrl) {
+                    feature.style = this.getStyle(feature.attributes.styleUrl, options);
+                }
+
+                if (this.extractStyles) {
+                    // Make sure that <Style> nodes within a placemark are 
+                    // processed as well
+                    var inlineStyleNode = this.getElementsByTagNameNS(featureNode,
+                                                        "*",
+                                                        "Style")[0];
+                    if (inlineStyleNode) {
+                        var inlineStyle= this.parseStyle(inlineStyleNode);
+                        if (inlineStyle) {
+                            feature.style = OpenLayers.Util.extend(
+                                feature.style, inlineStyle
+                            );
+                        }
+                    }
+                }
+
+                // add feature to list of features
+                features[i] = feature;
+            } else {
+                throw "Bad Placemark: " + i;
+            }
+        }
+
+        // add new features to existing feature list
+        this.features = this.features.concat(features);
+    },
+
+    /**
+     * Method: parseFeature
+     * This function is the core of the KML parsing code in OpenLayers.
+     *     It creates the geometries that are then attached to the returned
+     *     feature, and calls parseAttributes() to get attribute data out.
+     *
+     * Parameters:
+     * node - {DOMElement}
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A vector feature.
+     */
+    parseFeature: function(node) {
+        // only accept one geometry per feature - look for highest "order"
+        var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
+        var type, nodeList, geometry, parser;
+        for(var i=0, len=order.length; i<len; ++i) {
+            type = order[i];
+            this.internalns = node.namespaceURI ? 
+                    node.namespaceURI : this.kmlns;
+            nodeList = this.getElementsByTagNameNS(node, 
+                                                   this.internalns, type);
+            if(nodeList.length > 0) {
+                // only deal with first geometry of this type
+                var parser = this.parseGeometry[type.toLowerCase()];
+                if(parser) {
+                    geometry = parser.apply(this, [nodeList[0]]);
+                    if (this.internalProjection && this.externalProjection) {
+                        geometry.transform(this.externalProjection, 
+                                           this.internalProjection); 
+                    }                       
+                } else {
+                    OpenLayers.Console.error(OpenLayers.i18n(
+                                "unsupportedGeometryType", {'geomType':type}));
+                }
+                // stop looking for different geometry types
+                break;
+            }
+        }
+
+        // construct feature (optionally with attributes)
+        var attributes;
+        if(this.extractAttributes) {
+            attributes = this.parseAttributes(node);
+        }
+        var feature = new OpenLayers.Feature.Vector(geometry, attributes);
+
+        var fid = node.getAttribute("id") || node.getAttribute("name");
+        if(fid != null) {
+            feature.fid = fid;
+        }
+
+        return feature;
+    },        
+    
+    /**
+     * Method: getStyle
+     * Retrieves a style from a style hash using styleUrl as the key
+     * If the styleUrl doesn't exist yet, we try to fetch it 
+     * Internet
+     * 
+     * Parameters: 
+     * styleUrl  - {String} URL of style
+     * options   - {Object} Hash of options 
+     *
+     * Returns:
+     * {Object}  - (reference to) Style hash
+     */
+    getStyle: function(styleUrl, options) {
+
+        var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl);
+
+        var newOptions = OpenLayers.Util.extend({}, options);
+        newOptions.depth++;
+        newOptions.styleBaseUrl = styleBaseUrl;
+
+        // Fetch remote Style URLs (if not fetched before) 
+        if (!this.styles[styleUrl] 
+                && !OpenLayers.String.startsWith(styleUrl, "#") 
+                && newOptions.depth <= this.maxDepth
+                && !this.fetched[styleBaseUrl] ) {
+
+            var data = this.fetchLink(styleBaseUrl);
+            if (data) {
+                this.parseData(data, newOptions);
+            }
+
+        }
+
+        // return requested style
+        var style = OpenLayers.Util.extend({}, this.styles[styleUrl]);
+        return style;
+    },
+    
+    /**
+     * Property: parseGeometry
+     * Properties of this object are the functions that parse geometries based
+     *     on their type.
+     */
+    parseGeometry: {
+        
+        /**
+         * Method: parseGeometry.point
+         * Given a KML node representing a point geometry, create an OpenLayers
+         *     point geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A KML Point node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.Point>} A point geometry.
+         */
+        point: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.internalns,
+                                                       "coordinates");
+            var coords = [];
+            if(nodeList.length > 0) {
+                var coordString = nodeList[0].firstChild.nodeValue;
+                coordString = coordString.replace(this.regExes.removeSpace, "");
+                coords = coordString.split(",");
+            }
+
+            var point = null;
+            if(coords.length > 1) {
+                // preserve third dimension
+                if(coords.length == 2) {
+                    coords[2] = null;
+                }
+                point = new OpenLayers.Geometry.Point(coords[0], coords[1],
+                                                      coords[2]);
+            } else {
+                throw "Bad coordinate string: " + coordString;
+            }
+            return point;
+        },
+        
+        /**
+         * Method: parseGeometry.linestring
+         * Given a KML node representing a linestring geometry, create an
+         *     OpenLayers linestring geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A KML LineString node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.LineString>} A linestring geometry.
+         */
+        linestring: function(node, ring) {
+            var nodeList = this.getElementsByTagNameNS(node, this.internalns,
+                                                       "coordinates");
+            var line = null;
+            if(nodeList.length > 0) {
+                var coordString = this.getChildValue(nodeList[0]);
+
+                coordString = coordString.replace(this.regExes.trimSpace,
+                                                  "");
+                coordString = coordString.replace(this.regExes.trimComma,
+                                                  ",");
+                var pointList = coordString.split(this.regExes.splitSpace);
+                var numPoints = pointList.length;
+                var points = new Array(numPoints);
+                var coords, numCoords;
+                for(var i=0; i<numPoints; ++i) {
+                    coords = pointList[i].split(",");
+                    numCoords = coords.length;
+                    if(numCoords > 1) {
+                        if(coords.length == 2) {
+                            coords[2] = null;
+                        }
+                        points[i] = new OpenLayers.Geometry.Point(coords[0],
+                                                                  coords[1],
+                                                                  coords[2]);
+                    } else {
+                        throw "Bad LineString point coordinates: " +
+                              pointList[i];
+                    }
+                }
+                if(numPoints) {
+                    if(ring) {
+                        line = new OpenLayers.Geometry.LinearRing(points);
+                    } else {
+                        line = new OpenLayers.Geometry.LineString(points);
+                    }
+                } else {
+                    throw "Bad LineString coordinates: " + coordString;
+                }
+            }
+
+            return line;
+        },
+        
+        /**
+         * Method: parseGeometry.polygon
+         * Given a KML node representing a polygon geometry, create an
+         *     OpenLayers polygon geometry.
+         *
+         * Parameters:
+         * node - {DOMElement} A KML Polygon node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+         */
+        polygon: function(node) {
+            var nodeList = this.getElementsByTagNameNS(node, this.internalns,
+                                                       "LinearRing");
+            var numRings = nodeList.length;
+            var components = new Array(numRings);
+            if(numRings > 0) {
+                // this assumes exterior ring first, inner rings after
+                var ring;
+                for(var i=0, len=nodeList.length; i<len; ++i) {
+                    ring = this.parseGeometry.linestring.apply(this,
+                                                        [nodeList[i], true]);
+                    if(ring) {
+                        components[i] = ring;
+                    } else {
+                        throw "Bad LinearRing geometry: " + i;
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.Polygon(components);
+        },
+        
+        /**
+         * Method: parseGeometry.multigeometry
+         * Given a KML node representing a multigeometry, create an
+         *     OpenLayers geometry collection.
+         *
+         * Parameters:
+         * node - {DOMElement} A KML MultiGeometry node.
+         *
+         * Returns:
+         * {<OpenLayers.Geometry.Collection>} A geometry collection.
+         */
+        multigeometry: function(node) {
+            var child, parser;
+            var parts = [];
+            var children = node.childNodes;
+            for(var i=0, len=children.length; i<len; ++i ) {
+                child = children[i];
+                if(child.nodeType == 1) {
+                    var type = (child.prefix) ?
+                            child.nodeName.split(":")[1] :
+                            child.nodeName;
+                    var parser = this.parseGeometry[type.toLowerCase()];
+                    if(parser) {
+                        parts.push(parser.apply(this, [child]));
+                    }
+                }
+            }
+            return new OpenLayers.Geometry.Collection(parts);
+        }
+        
+    },
+
+    /**
+     * Method: parseAttributes
+     *
+     * Parameters:
+     * node - {DOMElement}
+     *
+     * Returns:
+     * {Object} An attributes object.
+     */
+    parseAttributes: function(node) {
+        var attributes = {};
+       
+        // Extended Data is parsed first.
+        var edNodes = node.getElementsByTagName("ExtendedData");
+        if (edNodes.length) {
+            attributes = this.parseExtendedData(edNodes[0]);
+        }
+        
+        // assume attribute nodes are type 1 children with a type 3 or 4 child
+        var child, grandchildren, grandchild;
+        var children = node.childNodes;
+
+        for(var i=0, len=children.length; i<len; ++i) {
+            child = children[i];
+            if(child.nodeType == 1) {
+                grandchildren = child.childNodes;
+                if(grandchildren.length == 1 || grandchildren.length == 3) {
+                    var grandchild;
+                    switch (grandchildren.length) {
+                        case 1:
+                            grandchild = grandchildren[0];
+                            break;
+                        case 3:
+                        default:
+                            grandchild = grandchildren[1];
+                            break;
+                    }
+                    if(grandchild.nodeType == 3 || grandchild.nodeType == 4) {
+                        var name = (child.prefix) ?
+                                child.nodeName.split(":")[1] :
+                                child.nodeName;
+                        var value = OpenLayers.Util.getXmlNodeValue(grandchild);
+                        if (value) {
+                            value = value.replace(this.regExes.trimSpace, "");
+                            attributes[name] = value;
+                        }
+                    }
+                } 
+            }
+        }
+        return attributes;
+    },
+
+    /**
+     * Method: parseExtendedData
+     * Parse ExtendedData from KML. No support for schemas/datatypes.
+     *     See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata
+     *     for more information on extendeddata.
+     */
+    parseExtendedData: function(node) {
+        var attributes = {};
+        var dataNodes = node.getElementsByTagName("Data");
+        for (var i = 0, len = dataNodes.length; i < len; i++) {
+            var data = dataNodes[i];
+            var key = data.getAttribute("name");
+            var ed = {};
+            var valueNode = data.getElementsByTagName("value");
+            if (valueNode.length) {
+                ed['value'] = this.getChildValue(valueNode[0]);
+            }    
+            var nameNode = data.getElementsByTagName("displayName");
+            if (nameNode.length) {
+                ed['displayName'] = this.getChildValue(nameNode[0]);
+            }
+            attributes[key] = ed;
+        }
+        return attributes;    
+    },
+    
+    /**
+     * Method: parseProperty
+     * Convenience method to find a node and return its value
+     *
+     * Parameters:
+     * xmlNode    - {<DOMElement>}
+     * namespace  - {String} namespace of the node to find
+     * tagName    - {String} name of the property to parse
+     * 
+     * Returns:
+     * {String} The value for the requested property (defaults to null)
+     */    
+    parseProperty: function(xmlNode, namespace, tagName) {
+        var value;
+        var nodeList = this.getElementsByTagNameNS(xmlNode, namespace, tagName);
+        try {
+            value = OpenLayers.Util.getXmlNodeValue(nodeList[0]);
+        } catch(e) {
+            value = null;
+        }
+     
+        return value;
+    },                                                              
+
+    /**
+     * APIMethod: write
+     * Accept Feature Collection, and return a string. 
+     * 
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>} An array of features.
+     *
+     * Returns:
+     * {String} A KML string.
+     */
+    write: function(features) {
+        if(!(features instanceof Array)) {
+            features = [features];
+        }
+        var kml = this.createElementNS(this.kmlns, "kml");
+        var folder = this.createFolderXML();
+        for(var i=0, len=features.length; i<len; ++i) {
+            folder.appendChild(this.createPlacemarkXML(features[i]));
+        }
+        kml.appendChild(folder);
+        return OpenLayers.Format.XML.prototype.write.apply(this, [kml]);
+    },
+
+    /**
+     * Method: createFolderXML
+     * Creates and returns a KML folder node
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    createFolderXML: function() {
+        // Folder name
+        var folderName = this.createElementNS(this.kmlns, "name");
+        var folderNameText = this.createTextNode(this.foldersName); 
+        folderName.appendChild(folderNameText);
+
+        // Folder description
+        var folderDesc = this.createElementNS(this.kmlns, "description");        
+        var folderDescText = this.createTextNode(this.foldersDesc); 
+        folderDesc.appendChild(folderDescText);
+
+        // Folder
+        var folder = this.createElementNS(this.kmlns, "Folder");
+        folder.appendChild(folderName);
+        folder.appendChild(folderDesc);
+        
+        return folder;
+    },
+
+    /**
+     * Method: createPlacemarkXML
+     * Creates and returns a KML placemark node representing the given feature. 
+     * 
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    createPlacemarkXML: function(feature) {        
+        // Placemark name
+        var placemarkName = this.createElementNS(this.kmlns, "name");
+        var name = (feature.attributes.name) ?
+                    feature.attributes.name : feature.id;
+        placemarkName.appendChild(this.createTextNode(name));
+
+        // Placemark description
+        var placemarkDesc = this.createElementNS(this.kmlns, "description");
+        var desc = (feature.attributes.description) ?
+                    feature.attributes.description : this.placemarksDesc;
+        placemarkDesc.appendChild(this.createTextNode(desc));
+        
+        // Placemark
+        var placemarkNode = this.createElementNS(this.kmlns, "Placemark");
+        if(feature.fid != null) {
+            placemarkNode.setAttribute("id", feature.fid);
+        }
+        placemarkNode.appendChild(placemarkName);
+        placemarkNode.appendChild(placemarkDesc);
+
+        // Geometry node (Point, LineString, etc. nodes)
+        var geometryNode = this.buildGeometryNode(feature.geometry);
+        placemarkNode.appendChild(geometryNode);        
+        
+        // TBD - deal with remaining (non name/description) attributes.
+        return placemarkNode;
+    },    
+
+    /**
+     * Method: buildGeometryNode
+     * Builds and returns a KML geometry node with the given geometry.
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    buildGeometryNode: function(geometry) {
+        if (this.internalProjection && this.externalProjection) {
+            geometry = geometry.clone();
+            geometry.transform(this.internalProjection, 
+                               this.externalProjection);
+        }                       
+        var className = geometry.CLASS_NAME;
+        var type = className.substring(className.lastIndexOf(".") + 1);
+        var builder = this.buildGeometry[type.toLowerCase()];
+        var node = null;
+        if(builder) {
+            node = builder.apply(this, [geometry]);
+        }
+        return node;
+    },
+
+    /**
+     * Property: buildGeometry
+     * Object containing methods to do the actual geometry node building
+     *     based on geometry type.
+     */
+    buildGeometry: {
+        // TBD: Anybody care about namespace aliases here (these nodes have
+        //    no prefixes)?
+
+        /**
+         * Method: buildGeometry.point
+         * Given an OpenLayers point geometry, create a KML point.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML point node.
+         */
+        point: function(geometry) {
+            var kml = this.createElementNS(this.kmlns, "Point");
+            kml.appendChild(this.buildCoordinatesNode(geometry));
+            return kml;
+        },
+        
+        /**
+         * Method: buildGeometry.multipoint
+         * Given an OpenLayers multipoint geometry, create a KML
+         *     GeometryCollection.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML GeometryCollection node.
+         */
+        multipoint: function(geometry) {
+            return this.buildGeometry.collection.apply(this, [geometry]);
+        },
+
+        /**
+         * Method: buildGeometry.linestring
+         * Given an OpenLayers linestring geometry, create a KML linestring.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML linestring node.
+         */
+        linestring: function(geometry) {
+            var kml = this.createElementNS(this.kmlns, "LineString");
+            kml.appendChild(this.buildCoordinatesNode(geometry));
+            return kml;
+        },
+        
+        /**
+         * Method: buildGeometry.multilinestring
+         * Given an OpenLayers multilinestring geometry, create a KML
+         *     GeometryCollection.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML GeometryCollection node.
+         */
+        multilinestring: function(geometry) {
+            return this.buildGeometry.collection.apply(this, [geometry]);
+        },
+
+        /**
+         * Method: buildGeometry.linearring
+         * Given an OpenLayers linearring geometry, create a KML linearring.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML linearring node.
+         */
+        linearring: function(geometry) {
+            var kml = this.createElementNS(this.kmlns, "LinearRing");
+            kml.appendChild(this.buildCoordinatesNode(geometry));
+            return kml;
+        },
+        
+        /**
+         * Method: buildGeometry.polygon
+         * Given an OpenLayers polygon geometry, create a KML polygon.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML polygon node.
+         */
+        polygon: function(geometry) {
+            var kml = this.createElementNS(this.kmlns, "Polygon");
+            var rings = geometry.components;
+            var ringMember, ringGeom, type;
+            for(var i=0, len=rings.length; i<len; ++i) {
+                type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
+                ringMember = this.createElementNS(this.kmlns, type);
+                ringGeom = this.buildGeometry.linearring.apply(this,
+                                                               [rings[i]]);
+                ringMember.appendChild(ringGeom);
+                kml.appendChild(ringMember);
+            }
+            return kml;
+        },
+        
+        /**
+         * Method: buildGeometry.multipolygon
+         * Given an OpenLayers multipolygon geometry, create a KML
+         *     GeometryCollection.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry.
+         *
+         * Returns:
+         * {DOMElement} A KML GeometryCollection node.
+         */
+        multipolygon: function(geometry) {
+            return this.buildGeometry.collection.apply(this, [geometry]);
+        },
+
+        /**
+         * Method: buildGeometry.collection
+         * Given an OpenLayers geometry collection, create a KML MultiGeometry.
+         *
+         * Parameters:
+         * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection.
+         *
+         * Returns:
+         * {DOMElement} A KML MultiGeometry node.
+         */
+        collection: function(geometry) {
+            var kml = this.createElementNS(this.kmlns, "MultiGeometry");
+            var child;
+            for(var i=0, len=geometry.components.length; i<len; ++i) {
+                child = this.buildGeometryNode.apply(this,
+                                                     [geometry.components[i]]);
+                if(child) {
+                    kml.appendChild(child);
+                }
+            }
+            return kml;
+        }
+    },
+
+    /**
+     * Method: buildCoordinatesNode
+     * Builds and returns the KML coordinates node with the given geometry
+     * <coordinates>...</coordinates>
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Return:
+     * {DOMElement}
+     */     
+    buildCoordinatesNode: function(geometry) {
+        var coordinatesNode = this.createElementNS(this.kmlns, "coordinates");
+        
+        var path;
+        var points = geometry.components;
+        if(points) {
+            // LineString or LinearRing
+            var point;
+            var numPoints = points.length;
+            var parts = new Array(numPoints);
+            for(var i=0; i<numPoints; ++i) {
+                point = points[i];
+                parts[i] = point.x + "," + point.y;
+            }
+            path = parts.join(" ");
+        } else {
+            // Point
+            path = geometry.x + "," + geometry.y;
+        }
+        
+        var txtNode = this.createTextNode(path);
+        coordinatesNode.appendChild(txtNode);
+        
+        return coordinatesNode;
+    },    
+
+    CLASS_NAME: "OpenLayers.Format.KML" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/OSM.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/OSM.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/OSM.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,452 @@
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ */
+
+/**  
+ * Class: OpenLayers.Format.OSM
+ * OSM parser. Create a new instance with the 
+ *     <OpenLayers.Format.OSM> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: checkTags
+     * {Boolean} Should tags be checked to determine whether something
+     * should be treated as a seperate node. Will slow down parsing.
+     * Default is false.
+     */
+    checkTags: false,
+
+    /**
+     * Property: interestingTagsExclude
+     * {Array} List of tags to exclude from 'interesting' checks on nodes.
+     * Must be set when creating the format. Will only be used if checkTags
+     * is set.
+     */
+    interestingTagsExclude: null, 
+    
+    /**
+     * APIProperty: areaTags
+     * {Array} List of tags indicating that something is an area.  
+     * Must be set when creating the format. Will only be used if 
+     * checkTags is true.
+     */
+    areaTags: null, 
+    
+    /**
+     * Constructor: OpenLayers.Format.OSM
+     * Create a new parser for OSM.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        var layer_defaults = {
+          'interestingTagsExclude': ['source', 'source_ref', 
+              'source:ref', 'history', 'attribution', 'created_by'],
+          'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins',
+              'historic', 'landuse', 'military', 'natural', 'sport'] 
+        };
+          
+        layer_defaults = OpenLayers.Util.extend(layer_defaults, options);
+        
+        var interesting = {};
+        for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) {
+            interesting[layer_defaults.interestingTagsExclude[i]] = true;
+        }
+        layer_defaults.interestingTagsExclude = interesting;
+        
+        var area = {};
+        for (var i = 0; i < layer_defaults.areaTags.length; i++) {
+            area[layer_defaults.areaTags[i]] = true;
+        }
+        layer_defaults.areaTags = area;
+        
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]);
+    },
+    
+    /**
+     * APIMethod: read
+     * Return a list of features from a OSM doc
+     
+     * Parameters:
+     * data - {Element} 
+     *
+     * Returns:
+     * An Array of <OpenLayers.Feature.Vector>s
+     */
+    read: function(doc) {
+        if (typeof doc == "string") { 
+            doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
+        }
+
+        var nodes = this.getNodes(doc);
+        var ways = this.getWays(doc);
+        
+        // Geoms will contain at least ways.length entries.
+        var feat_list = new Array(ways.length);
+        
+        for (var i = 0; i < ways.length; i++) {
+            // We know the minimal of this one ahead of time. (Could be -1
+            // due to areas/polygons)
+            var point_list = new Array(ways[i].nodes.length);
+            
+            var poly = this.isWayArea(ways[i]) ? 1 : 0; 
+            for (var j = 0; j < ways[i].nodes.length; j++) {
+               var node = nodes[ways[i].nodes[j]];
+               
+               var point = new OpenLayers.Geometry.Point(node.lon, node.lat);
+               
+               // Since OSM is topological, we stash the node ID internally. 
+               point.osm_id = parseInt(ways[i].nodes[j]);
+               point_list[j] = point;
+               
+               // We don't display nodes if they're used inside other 
+               // elements.
+               node.used = true; 
+            }
+            var geometry = null;
+            if (poly) { 
+                geometry = new OpenLayers.Geometry.Polygon(
+                    new OpenLayers.Geometry.LinearRing(point_list));
+            } else {    
+                geometry = new OpenLayers.Geometry.LineString(point_list);
+            }
+            if (this.internalProjection && this.externalProjection) {
+                geometry.transform(this.externalProjection, 
+                    this.internalProjection);
+            }        
+            var feat = new OpenLayers.Feature.Vector(geometry,
+                ways[i].tags);
+            feat.osm_id = parseInt(ways[i].id);
+            feat.fid = "way." + feat.osm_id;
+            feat_list[i] = feat;
+        } 
+        for (var node_id in nodes) {
+            var node = nodes[node_id];
+            if (!node.used || this.checkTags) {
+                var tags = null;
+                
+                if (this.checkTags) {
+                    var result = this.getTags(node.node, true);
+                    if (node.used && !result[1]) {
+                        continue;
+                    }
+                    tags = result[0];
+                } else { 
+                    tags = this.getTags(node.node);
+                }    
+                
+                var feat = new OpenLayers.Feature.Vector(
+                    new OpenLayers.Geometry.Point(node['lon'], node['lat']),
+                    tags);
+                if (this.internalProjection && this.externalProjection) {
+                    feat.geometry.transform(this.externalProjection, 
+                        this.internalProjection);
+                }        
+                feat.osm_id = parseInt(node_id); 
+                feat.fid = "node." + feat.osm_id;
+                feat_list.push(feat);
+            }   
+            // Memory cleanup
+            node.node = null;
+        }        
+        return feat_list;
+    },
+
+    /**
+     * Method: getNodes
+     * Return the node items from a doc.  
+     *
+     * Parameters:
+     * node - {DOMElement} node to parse tags from
+     */
+    getNodes: function(doc) {
+        var node_list = doc.getElementsByTagName("node");
+        var nodes = {};
+        for (var i = 0; i < node_list.length; i++) {
+            var node = node_list[i];
+            var id = node.getAttribute("id");
+            nodes[id] = {
+                'lat': node.getAttribute("lat"),
+                'lon': node.getAttribute("lon"),
+                'node': node
+            };
+        }
+        return nodes;
+    },
+
+    /**
+     * Method: getWays
+     * Return the way items from a doc.  
+     *
+     * Parameters:
+     * node - {DOMElement} node to parse tags from
+     */
+    getWays: function(doc) {
+        var way_list = doc.getElementsByTagName("way");
+        var return_ways = [];
+        for (var i = 0; i < way_list.length; i++) {
+            var way = way_list[i];
+            var way_object = {
+              id: way.getAttribute("id")
+            };
+            
+            way_object.tags = this.getTags(way);
+            
+            var node_list = way.getElementsByTagName("nd");
+            
+            way_object.nodes = new Array(node_list.length);
+            
+            for (var j = 0; j < node_list.length; j++) {
+                way_object.nodes[j] = node_list[j].getAttribute("ref");
+            }  
+            return_ways.push(way_object);
+        }
+        return return_ways; 
+        
+    },  
+    
+    /**
+     * Method: getTags
+     * Return the tags list attached to a specific DOM element.
+     *
+     * Parameters:
+     * node - {DOMElement} node to parse tags from
+     * interesting_tags - {Boolean} whether the return from this function should
+     *    return a boolean indicating that it has 'interesting tags' -- 
+     *    tags like attribution and source are ignored. (To change the list
+     *    of tags, see interestingTagsExclude)
+     * 
+     * Returns:
+     * tags - {Object} hash of tags
+     * interesting - {Boolean} if interesting_tags is passed, returns
+     *     whether there are any interesting tags on this element.
+     */
+    getTags: function(dom_node, interesting_tags) {
+        var tag_list = dom_node.getElementsByTagName("tag");
+        var tags = {};
+        var interesting = false;
+        for (var j = 0; j < tag_list.length; j++) {
+            var key = tag_list[j].getAttribute("k");
+            tags[key] = tag_list[j].getAttribute("v");
+            if (interesting_tags) {
+                if (!this.interestingTagsExclude[key]) {
+                    interesting = true;
+                }
+            }    
+        }  
+        return interesting_tags ? [tags, interesting] : tags;     
+    },
+
+    /** 
+     * Method: isWayArea
+     * Given a way object from getWays, check whether the tags and geometry
+     * indicate something is an area.
+     *
+     * Returns:
+     * {Boolean}
+     */
+    isWayArea: function(way) { 
+        var poly_shaped = false;
+        var poly_tags = false;
+        
+        if (way.nodes[0] == way.nodes[way.nodes.length - 1]) {
+            poly_shaped = true;
+        }
+        if (this.checkTags) {
+            for(var key in way.tags) {
+                if (this.areaTags[key]) {
+                    poly_tags = true;
+                    break;
+                }
+            }
+        }    
+        return poly_shaped && (this.checkTags ? poly_tags : true);            
+    }, 
+
+    /**
+     * APIMethod: write 
+     * Takes a list of features, returns a serialized OSM format file for use
+     * in tools like JOSM.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)}
+     */
+    write: function(features) { 
+        if (!(features instanceof Array)) {
+            features = [features];
+        }
+        
+        this.osm_id = 1;
+        this.created_nodes = {};
+        var root_node = this.createElementNS(null, "osm");
+        root_node.setAttribute("version", "0.5");
+        root_node.setAttribute("generator", "OpenLayers "+ OpenLayers.VERSION_NUMBER);
+
+        // Loop backwards, because the deserializer puts nodes last, and 
+        // we want them first if possible
+        for(var i = features.length - 1; i >= 0; i--) {
+            var nodes = this.createFeatureNodes(features[i]);
+            for (var j = 0; j < nodes.length; j++) {
+                root_node.appendChild(nodes[j]);
+            }    
+        }
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]);
+    },
+
+    /**
+     * Method: createFeatureNodes
+     * Takes a feature, returns a list of nodes from size 0->n.
+     * Will include all pieces of the serialization that are required which
+     * have not already been created. Calls out to createXML based on geometry
+     * type.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     */
+    createFeatureNodes: function(feature) {
+        var nodes = [];
+        var className = feature.geometry.CLASS_NAME;
+        var type = className.substring(className.lastIndexOf(".") + 1);
+        type = type.toLowerCase();
+        var builder = this.createXML[type];
+        if (builder) {
+            nodes = builder.apply(this, [feature]);
+        }
+        return nodes;
+    },
+    
+    /**
+     * Method: createXML
+     * Takes a feature, returns a list of nodes from size 0->n.
+     * Will include all pieces of the serialization that are required which
+     * have not already been created.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     */
+    createXML: {
+        'point': function(point) {
+            var id = null;
+            var geometry = point.geometry ? point.geometry : point;
+            var already_exists = false; // We don't return anything if the node
+                                        // has already been created
+            if (point.osm_id) {
+                id = point.osm_id;
+                if (this.created_nodes[id]) {
+                    already_exists = true;
+                }    
+            } else {
+               id = -this.osm_id;
+               this.osm_id++; 
+            }
+            if (already_exists) {
+                node = this.created_nodes[id];
+            } else {    
+                var node = this.createElementNS(null, "node");
+            }
+            this.created_nodes[id] = node;
+            node.setAttribute("id", id);
+            node.setAttribute("lon", geometry.x); 
+            node.setAttribute("lat", geometry.y);
+            if (point.attributes) {
+                this.serializeTags(point, node);
+            }
+            this.setState(point, node);
+            return already_exists ? [] : [node];
+        }, 
+        linestring: function(feature) {
+            var nodes = [];
+            var geometry = feature.geometry;
+            if (feature.osm_id) {
+                id = feature.osm_id;
+            } else {
+               id = -this.osm_id;
+               this.osm_id++; 
+            }
+            var way = this.createElementNS(null, "way");
+            way.setAttribute("id", id);
+            for (var i = 0; i < geometry.components.length; i++) {
+                var node = this.createXML['point'].apply(this, [geometry.components[i]]);
+                if (node.length) {
+                    node = node[0];
+                    var node_ref = node.getAttribute("id");
+                    nodes.push(node);
+                } else {
+                    node_ref = geometry.components[i].osm_id;
+                    node = this.created_nodes[node_ref];
+                }
+                this.setState(feature, node);
+                var nd_dom = this.createElementNS(null, "nd");
+                nd_dom.setAttribute("ref", node_ref);
+                way.appendChild(nd_dom);
+            }
+            this.serializeTags(feature, way);
+            nodes.push(way);
+            
+            return nodes;
+        },
+        polygon: function(feature) {
+            var attrs = OpenLayers.Util.extend({'area':'yes'}, feature.attributes);
+            var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); 
+            feat.osm_id = feature.osm_id;
+            return this.createXML['linestring'].apply(this, [feat]);
+        }
+    },
+
+    /**
+     * Method: serializeTags
+     * Given a feature, serialize the attributes onto the given node.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * node - {DOMNode}
+     */
+    serializeTags: function(feature, node) {
+        for (var key in feature.attributes) {
+            var tag = this.createElementNS(null, "tag");
+            tag.setAttribute("k", key);
+            tag.setAttribute("v", feature.attributes[key]);
+            node.appendChild(tag);
+        }
+    },
+
+    /**
+     * Method: setState 
+     * OpenStreetMap has a convention that 'state' is stored for modification or deletion.
+     * This allows the file to be uploaded via JOSM or the bulk uploader tool.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * node - {DOMNode}
+     */
+    setState: function(feature, node) {
+        if (feature.state) {
+            var state = null;
+            switch(feature.state) {
+                case OpenLayers.State.UPDATE:
+                    state = "modify";
+                case OpenLayers.State.DELETE:
+                    state = "delete";
+            }
+            if (state) {
+                node.setAttribute("action", state);
+            }
+        }    
+    },
+
+    CLASS_NAME: "OpenLayers.Format.OSM" 
+});     

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/SLD/v1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/SLD/v1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/SLD/v1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,883 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Rule.js
+ * @requires OpenLayers/Format/SLD.js
+ * @requires OpenLayers/Format/Filter/v1_0_0.js
+ */
+
+/**
+ * Class: OpenLayers.Format.SLD.v1
+ * Superclass for SLD version 1 parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.Filter.v1_0_0>
+ */
+OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        sld: "http://www.opengis.net/sld",
+        ogc: "http://www.opengis.net/ogc",
+        gml: "http://www.opengis.net/gml",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance"
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "sld",
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: null,
+
+    /**
+     * APIProperty: defaultSymbolizer.
+     * {Object} A symbolizer with the SLD defaults.
+     */
+    defaultSymbolizer: {
+        fillColor: "#808080",
+        fillOpacity: 1,
+        strokeColor: "#000000",
+        strokeOpacity: 1,
+        strokeWidth: 1,
+        strokeDashstyle: "solid",
+        pointRadius: 3,
+        graphicName: "square"
+    },
+    
+    /**
+     * Constructor: OpenLayers.Format.SLD.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.SLD> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: read
+     *
+     * Parameters:
+     * data - {DOMElement} An SLD document element.
+     * options - {Object} Options for the reader.
+     *
+     * Valid options:
+     * namedLayersAsArray - {Boolean}  Generate a namedLayers array.  If false,
+     *     the namedLayers property value will be an object keyed by layer name.
+     *     Default is false.
+     *
+     * Returns:
+     * {Object} An object representing the SLD.
+     */
+    read: function(data, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+        var sld = {
+            namedLayers: options.namedLayersAsArray === true ? [] : {}
+        };
+        this.readChildNodes(data, sld);
+        return sld;
+    },
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: OpenLayers.Util.applyDefaults({
+        "sld": {
+            "StyledLayerDescriptor": function(node, sld) {
+                sld.version = node.getAttribute("version");
+                this.readChildNodes(node, sld);
+            },
+            "Name": function(node, obj) {
+                obj.name = this.getChildValue(node);
+            },
+            "Title": function(node, obj) {
+                obj.title = this.getChildValue(node);
+            },
+            "Abstract": function(node, obj) {
+                obj.description = this.getChildValue(node);
+            },
+            "NamedLayer": function(node, sld) {
+                var layer = {
+                    userStyles: [],
+                    namedStyles: []
+                };
+                this.readChildNodes(node, layer);
+                // give each of the user styles this layer name
+                for(var i=0, len=layer.userStyles.length; i<len; ++i) {
+                    layer.userStyles[i].layerName = layer.name;
+                }
+                if(sld.namedLayers instanceof Array) {
+                    sld.namedLayers.push(layer);                
+                } else {
+                    sld.namedLayers[layer.name] = layer;
+                }
+            },
+            "NamedStyle": function(node, layer) {
+                layer.namedStyles.push(
+                    this.getChildName(node.firstChild)
+                );
+            },
+            "UserStyle": function(node, layer) {
+                var obj = {defaultsPerSymbolizer: true, rules: []};
+                this.readChildNodes(node, obj);
+                var style = new OpenLayers.Style(this.defaultSymbolizer, obj);
+                layer.userStyles.push(style);
+            },
+            "IsDefault": function(node, style) {
+                if(this.getChildValue(node) == "1") {
+                    style.isDefault = true;
+                }
+            },
+            "FeatureTypeStyle": function(node, style) {
+                // OpenLayers doesn't have a place for FeatureTypeStyle
+                // Name, Title, Abstract, FeatureTypeName, or
+                // SemanticTypeIdentifier so, we make a temporary object
+                // and later just use the Rule(s).
+                var obj = {
+                    rules: []
+                };
+                this.readChildNodes(node, obj);
+                style.rules = obj.rules;
+            },
+            "Rule": function(node, obj) {
+                var rule = new OpenLayers.Rule();
+                this.readChildNodes(node, rule);
+                obj.rules.push(rule);
+            },
+            "ElseFilter": function(node, rule) {
+                rule.elseFilter = true;
+            },
+            "MinScaleDenominator": function(node, rule) {
+                rule.minScaleDenominator = parseFloat(this.getChildValue(node));
+            },
+            "MaxScaleDenominator": function(node, rule) {
+                rule.maxScaleDenominator = parseFloat(this.getChildValue(node));
+            },
+            "TextSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Text"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Text"] = symbolizer;
+            },
+            "Label": function(node, symbolizer) {
+                // only supporting literal or property name
+                var obj = {};
+                this.readChildNodes(node, obj);
+                if(obj.property) {
+                    symbolizer.label = "${" + obj.property + "}";
+                } else {
+                    var value = this.readOgcExpression(node);
+                    if(value) {
+                        symbolizer.label = value;
+                    }
+                }
+            },
+            "Font": function(node, symbolizer) {
+                this.readChildNodes(node, symbolizer);
+            },
+            "Halo": function(node, symbolizer) {
+                // halo has a fill, so send fresh object
+                var obj = {};
+                this.readChildNodes(node, obj);
+                symbolizer.haloRadius = obj.haloRadius;
+                symbolizer.haloColor = obj.fillColor;
+                symbolizer.haloOpacity = obj.fillOpacity;
+            },
+            "Radius": function(node, symbolizer) {
+                var radius = this.readOgcExpression(node);
+                if(radius != null) {
+                    // radius is only used for halo
+                    symbolizer.haloRadius = radius;
+                }
+            },
+            "LineSymbolizer": function(node, rule) {
+                // OpenLayers doesn't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Line"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Line"] = symbolizer;
+            },
+            "PolygonSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Polygon"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Polygon"] = symbolizer;
+            },
+            "PointSymbolizer": function(node, rule) {
+                // OpenLayers doens't do painter's order, instead we extend
+                var symbolizer = rule.symbolizer["Point"] || {};
+                this.readChildNodes(node, symbolizer);
+                // in case it didn't exist before
+                rule.symbolizer["Point"] = symbolizer;
+            },
+            "Stroke": function(node, symbolizer) {
+                symbolizer.stroke = true;
+                this.readChildNodes(node, symbolizer);
+            },
+            "Fill": function(node, symbolizer) {
+                symbolizer.fill = true;
+                this.readChildNodes(node, symbolizer);
+            },
+            "CssParameter": function(node, symbolizer) {
+                var cssProperty = node.getAttribute("name");
+                var symProperty = this.cssMap[cssProperty];
+                if(symProperty) {
+                    // Limited support for parsing of OGC expressions
+                    var value = this.readOgcExpression(node);
+                    // always string, could be an empty string
+                    if(value) {
+                        symbolizer[symProperty] = value;
+                    }
+                }
+            },
+            "Graphic": function(node, symbolizer) {
+                symbolizer.graphic = true;
+                var graphic = {};
+                // painter's order not respected here, clobber previous with next
+                this.readChildNodes(node, graphic);
+                // directly properties with names that match symbolizer properties
+                var properties = [
+                    "strokeColor", "strokeWidth", "strokeOpacity",
+                    "strokeLinecap", "fillColor", "fillOpacity",
+                    "graphicName", "rotation", "graphicFormat"
+                ];
+                var prop, value;
+                for(var i=0, len=properties.length; i<len; ++i) {
+                    prop = properties[i];
+                    value = graphic[prop];
+                    if(value != undefined) {
+                        symbolizer[prop] = value;
+                    }
+                }
+                // set other generic properties with specific graphic property names
+                if(graphic.opacity != undefined) {
+                    symbolizer.graphicOpacity = graphic.opacity;
+                }
+                if(graphic.size != undefined) {
+                    symbolizer.pointRadius = graphic.size / 2;
+                }
+                if(graphic.href != undefined) {
+                    symbolizer.externalGraphic = graphic.href;
+                }
+                if(graphic.rotation != undefined) {
+                    symbolizer.rotation = graphic.rotation;
+                }
+            },
+            "ExternalGraphic": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "Mark": function(node, graphic) {
+                this.readChildNodes(node, graphic);
+            },
+            "WellKnownName": function(node, graphic) {
+                graphic.graphicName = this.getChildValue(node);
+            },
+            "Opacity": function(node, obj) {
+                var opacity = this.readOgcExpression(node);
+                // always string, could be empty string
+                if(opacity) {
+                    obj.opacity = opacity;
+                }
+            },
+            "Size": function(node, obj) {
+                var size = this.readOgcExpression(node);
+                // always string, could be empty string
+                if(size) {
+                    obj.size = size;
+                }
+            },
+            "Rotation": function(node, obj) {
+                var rotation = this.readOgcExpression(node);
+                // always string, could be empty string
+                if(rotation) {
+                    obj.rotation = rotation;
+                }
+            },
+            "OnlineResource": function(node, obj) {
+                obj.href = this.getAttributeNS(
+                    node, this.namespaces.xlink, "href"
+                );
+            },
+            "Format": function(node, graphic) {
+                graphic.graphicFormat = this.getChildValue(node);
+            }
+        }
+    }, OpenLayers.Format.Filter.v1_0_0.prototype.readers),
+    
+    /**
+     * Property: cssMap
+     * {Object} Object mapping supported css property names to OpenLayers
+     *     symbolizer property names.
+     */
+    cssMap: {
+        "stroke": "strokeColor",
+        "stroke-opacity": "strokeOpacity",
+        "stroke-width": "strokeWidth",
+        "stroke-linecap": "strokeLinecap",
+        "stroke-dasharray": "strokeDashstyle",
+        "fill": "fillColor",
+        "fill-opacity": "fillOpacity",
+        "font-family": "fontFamily",
+        "font-size": "fontSize",
+        "font-weight": "fontWeight",
+        "font-style": "fontStyle"
+    },
+    
+    /**
+     * Method: getCssProperty
+     * Given a symbolizer property, get the corresponding CSS property
+     *     from the <cssMap>.
+     *
+     * Parameters:
+     * sym - {String} A symbolizer property name.
+     *
+     * Returns:
+     * {String} A CSS property name or null if none found.
+     */
+    getCssProperty: function(sym) {
+        var css = null;
+        for(var prop in this.cssMap) {
+            if(this.cssMap[prop] == sym) {
+                css = prop;
+                break;
+            }
+        }
+        return css;
+    },
+    
+    /**
+     * Method: getGraphicFormat
+     * Given a href for an external graphic, try to determine the mime-type.
+     *     This method doesn't try too hard, and will fall back to
+     *     <defautlGraphicFormat> if one of the known <graphicFormats> is not
+     *     the file extension of the provided href.
+     *
+     * Parameters:
+     * href - {String}
+     *
+     * Returns:
+     * {String} The graphic format.
+     */
+    getGraphicFormat: function(href) {
+        var format, regex;
+        for(var key in this.graphicFormats) {
+            if(this.graphicFormats[key].test(href)) {
+                format = key;
+                break;
+            }
+        }
+        return format || this.defautlGraphicFormat;
+    },
+    
+    /**
+     * Property: defaultGraphicFormat
+     * {String} If none other can be determined from <getGraphicFormat>, this
+     *     default will be returned.
+     */
+    defaultGraphicFormat: "image/png",
+    
+    /**
+     * Property: graphicFormats
+     * {Object} Mapping of image mime-types to regular extensions matching 
+     *     well-known file extensions.
+     */
+    graphicFormats: {
+        "image/jpeg": /\.jpe?g$/i,
+        "image/gif": /\.gif$/i,
+        "image/png": /\.png$/i
+    },
+
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * sld - {Object} An object representing the SLD.
+     *
+     * Returns:
+     * {DOMElement} The root of an SLD document.
+     */
+    write: function(sld) {
+        return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]);
+    },
+    
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: OpenLayers.Util.applyDefaults({
+        "sld": {
+            "StyledLayerDescriptor": function(sld) {
+                var root = this.createElementNSPlus(
+                    "StyledLayerDescriptor",
+                    {attributes: {
+                        "version": this.VERSION,
+                        "xsi:schemaLocation": this.schemaLocation
+                    }}
+                );
+                // add in optional name
+                if(sld.name) {
+                    this.writeNode("Name", sld.name, root);
+                }
+                // add in optional title
+                if(sld.title) {
+                    this.writeNode("Title", sld.title, root);
+                }
+                // add in optional description
+                if(sld.description) {
+                    this.writeNode("Abstract", sld.description, root);
+                }
+                // add in named layers
+                // allow namedLayers to be an array
+                if(sld.namedLayers instanceof Array) {
+                    for(var i=0, len=sld.namedLayers.length; i<len; ++i) {
+                        this.writeNode("NamedLayer", sld.namedLayers[i], root);
+                    }
+                } else {
+                    for(var name in sld.namedLayers) {
+                        this.writeNode("NamedLayer", sld.namedLayers[name], root);
+                    }
+                }
+                return root;
+            },
+            "Name": function(name) {
+                return this.createElementNSPlus("Name", {value: name});
+            },
+            "Title": function(title) {
+                return this.createElementNSPlus("Title", {value: title});
+            },
+            "Abstract": function(description) {
+                return this.createElementNSPlus(
+                    "Abstract", {value: description}
+                );
+            },
+            "NamedLayer": function(layer) {
+                var node = this.createElementNSPlus("NamedLayer");
+
+                // add in required name
+                this.writeNode("Name", layer.name, node);
+
+                // optional sld:LayerFeatureConstraints here
+
+                // add in named styles
+                if(layer.namedStyles) {
+                    for(var i=0, len=layer.namedStyles.length; i<len; ++i) {
+                        this.writeNode(
+                            "NamedStyle", layer.namedStyles[i], node
+                        );
+                    }
+                }
+                
+                // add in user styles
+                if(layer.userStyles) {
+                    for(var i=0, len=layer.userStyles.length; i<len; ++i) {
+                        this.writeNode(
+                            "UserStyle", layer.userStyles[i], node
+                        );
+                    }
+                }
+                
+                return node;
+            },
+            "NamedStyle": function(name) {
+                var node = this.createElementNSPlus("NamedStyle");
+                this.writeNode("Name", name, node);
+                return node;
+            },
+            "UserStyle": function(style) {
+                var node = this.createElementNSPlus("UserStyle");
+
+                // add in optional name
+                if(style.name) {
+                    this.writeNode("Name", style.name, node);
+                }
+                // add in optional title
+                if(style.title) {
+                    this.writeNode("Title", style.title, node);
+                }
+                // add in optional description
+                if(style.description) {
+                    this.writeNode("Abstract", style.description, node);
+                }
+                
+                // add isdefault
+                if(style.isDefault) {
+                    this.writeNode("IsDefault", style.isDefault, node);
+                }
+                
+                // add FeatureTypeStyles
+                this.writeNode("FeatureTypeStyle", style, node);
+                
+                return node;
+            },
+            "IsDefault": function(bool) {
+                return this.createElementNSPlus(
+                    "IsDefault", {value: (bool) ? "1" : "0"}
+                );
+            },
+            "FeatureTypeStyle": function(style) {
+                var node = this.createElementNSPlus("FeatureTypeStyle");
+                
+                // OpenLayers currently stores no Name, Title, Abstract,
+                // FeatureTypeName, or SemanticTypeIdentifier information
+                // related to FeatureTypeStyle
+                
+                // add in rules
+                for(var i=0, len=style.rules.length; i<len; ++i) {
+                    this.writeNode("Rule", style.rules[i], node);
+                }
+                
+                return node;
+            },
+            "Rule": function(rule) {
+                var node = this.createElementNSPlus("Rule");
+
+                // add in optional name
+                if(rule.name) {
+                    this.writeNode("Name", rule.name, node);
+                }
+                // add in optional title
+                if(rule.title) {
+                    this.writeNode("Title", rule.title, node);
+                }
+                // add in optional description
+                if(rule.description) {
+                    this.writeNode("Abstract", rule.description, node);
+                }
+                
+                // add in LegendGraphic here
+                
+                // add in optional filters
+                if(rule.elseFilter) {
+                    this.writeNode("ElseFilter", null, node);
+                } else if(rule.filter) {
+                    this.writeNode("ogc:Filter", rule.filter, node);
+                }
+                
+                // add in scale limits
+                if(rule.minScaleDenominator != undefined) {
+                    this.writeNode(
+                        "MinScaleDenominator", rule.minScaleDenominator, node
+                    );
+                }
+                if(rule.maxScaleDenominator != undefined) {
+                    this.writeNode(
+                        "MaxScaleDenominator", rule.maxScaleDenominator, node
+                    );
+                }
+                
+                // add in symbolizers (relies on geometry type keys)
+                var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
+                var type, symbolizer;
+                for(var i=0, len=types.length; i<len; ++i) {
+                    type = types[i];
+                    symbolizer = rule.symbolizer[type];
+                    if(symbolizer) {
+                        this.writeNode(
+                            type + "Symbolizer", symbolizer, node
+                        );
+                    }
+                }
+                return node;
+
+            },
+            "ElseFilter": function() {
+                return this.createElementNSPlus("ElseFilter");
+            },
+            "MinScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MinScaleDenominator", {value: scale}
+                );
+            },
+            "MaxScaleDenominator": function(scale) {
+                return this.createElementNSPlus(
+                    "MaxScaleDenominator", {value: scale}
+                );
+            },
+            "LineSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("LineSymbolizer");
+                this.writeNode("Stroke", symbolizer, node);
+                return node;
+            },
+            "Stroke": function(symbolizer) {
+                var node = this.createElementNSPlus("Stroke");
+
+                // GraphicFill here
+                // GraphicStroke here
+
+                // add in CssParameters
+                if(symbolizer.strokeColor != undefined) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeColor"},
+                        node
+                    );
+                }
+                if(symbolizer.strokeOpacity != undefined) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeOpacity"},
+                        node
+                    );
+                }
+                if(symbolizer.strokeWidth != undefined) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "strokeWidth"},
+                        node
+                    );
+                }
+                return node;
+            },
+            "CssParameter": function(obj) {
+                // not handling ogc:expressions for now
+                return this.createElementNSPlus("CssParameter", {
+                    attributes: {name: this.getCssProperty(obj.key)},
+                    value: obj.symbolizer[obj.key]
+                });
+            },
+            "TextSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("TextSymbolizer");
+                // add in optional Label
+                if(symbolizer.label != null) {
+                    this.writeNode("Label", symbolizer.label, node);
+                }
+                // add in optional Font
+                if(symbolizer.fontFamily != null ||
+                   symbolizer.fontSize != null ||
+                   symbolizer.fontWeight != null ||
+                   symbolizer.fontStyle != null) {
+                    this.writeNode("Font", symbolizer, node);
+                }
+                // add in optional Halo
+                if(symbolizer.haloRadius != null ||
+                   symbolizer.haloColor != null ||
+                   symbolizer.haloOpacity != null) {
+                    this.writeNode("Halo", symbolizer, node);
+                }
+                // add in optional Fill
+                if(symbolizer.fillColor != null ||
+                   symbolizer.fillOpacity != null) {
+                    this.writeNode("Fill", symbolizer, node);
+                }
+                return node;
+            },
+            "Font": function(symbolizer) {
+                var node = this.createElementNSPlus("Font");
+                // add in CssParameters
+                if(symbolizer.fontFamily) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fontFamily"},
+                        node
+                    );
+                }
+                if(symbolizer.fontSize) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fontSize"},
+                        node
+                    );
+                }
+                if(symbolizer.fontWeight) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fontWeight"},
+                        node
+                    );
+                }
+                if(symbolizer.fontStyle) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fontStyle"},
+                        node
+                    );
+                }
+                return node;
+            },
+            "Label": function(label) {
+                // only the simplest of ogc:expression handled
+                // {label: "some text and a ${propertyName}"}
+                var node = this.createElementNSPlus("Label");
+                var tokens = label.split("${");
+                node.appendChild(this.createTextNode(tokens[0]));
+                var item, last;
+                for(var i=1, len=tokens.length; i<len; i++) {
+                    item = tokens[i];
+                    last = item.indexOf("}"); 
+                    if(last > 0) {
+                        this.writeNode(
+                            "ogc:PropertyName",
+                            {property: item.substring(0, last)},
+                            node
+                        );
+                        node.appendChild(
+                            this.createTextNode(item.substring(++last))
+                        );
+                    } else {
+                        // no ending }, so this is a literal ${
+                        node.appendChild(
+                            this.createTextNode("${" + item)
+                        );
+                    }
+                }
+                return node;
+            },
+            "Halo": function(symbolizer) {
+                var node = this.createElementNSPlus("Halo");
+                if(symbolizer.haloRadius) {
+                    this.writeNode("Radius", symbolizer.haloRadius, node);
+                }
+                if(symbolizer.haloColor || symbolizer.haloOpacity) {
+                    this.writeNode("Fill", {
+                        fillColor: symbolizer.haloColor,
+                        fillOpacity: symbolizer.haloOpacity
+                    }, node);
+                }
+                return node;
+            },
+            "Radius": function(value) {
+                return node = this.createElementNSPlus("Radius", {
+                    value: value
+                });
+            },
+            "PolygonSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PolygonSymbolizer");
+                if(symbolizer.fillColor != undefined ||
+                   symbolizer.fillOpacity != undefined) {
+                    this.writeNode("Fill", symbolizer, node);
+                }
+                if(symbolizer.strokeWidth != undefined ||
+                   symbolizer.strokeColor != undefined ||
+                   symbolizer.strokeOpacity != undefined ||
+                   symbolizer.strokeDashstyle != undefined) {
+                    this.writeNode("Stroke", symbolizer, node);
+                }
+                return node;
+            },
+            "Fill": function(symbolizer) {
+                var node = this.createElementNSPlus("Fill");
+                
+                // GraphicFill here
+                
+                // add in CssParameters
+                if(symbolizer.fillColor) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fillColor"},
+                        node
+                    );
+                }
+                if(symbolizer.fillOpacity != null) {
+                    this.writeNode(
+                        "CssParameter",
+                        {symbolizer: symbolizer, key: "fillOpacity"},
+                        node
+                    );
+                }
+                return node;
+            },
+            "PointSymbolizer": function(symbolizer) {
+                var node = this.createElementNSPlus("PointSymbolizer");
+                this.writeNode("Graphic", symbolizer, node);
+                return node;
+            },
+            "Graphic": function(symbolizer) {
+                var node = this.createElementNSPlus("Graphic");
+                if(symbolizer.externalGraphic != undefined) {
+                    this.writeNode("ExternalGraphic", symbolizer, node);
+                } else {
+                    this.writeNode("Mark", symbolizer, node);
+                }
+                
+                if(symbolizer.graphicOpacity != undefined) {
+                    this.writeNode("Opacity", symbolizer.graphicOpacity, node);
+                }
+                if(symbolizer.pointRadius != undefined) {
+                    this.writeNode("Size", symbolizer.pointRadius * 2, node);
+                }
+                if(symbolizer.rotation != undefined) {
+                    this.writeNode("Rotation", symbolizer.rotation, node);
+                }
+                return node;
+            },
+            "ExternalGraphic": function(symbolizer) {
+                var node = this.createElementNSPlus("ExternalGraphic");
+                this.writeNode(
+                    "OnlineResource", symbolizer.externalGraphic, node
+                );
+                var format = symbolizer.graphicFormat ||
+                             this.getGraphicFormat(symbolizer.externalGraphic);
+                this.writeNode("Format", format, node);
+                return node;
+            },
+            "Mark": function(symbolizer) {
+                var node = this.createElementNSPlus("Mark");
+                if(symbolizer.graphicName) {
+                    this.writeNode("WellKnownName", symbolizer.graphicName, node);
+                }
+                this.writeNode("Fill", symbolizer, node);
+                this.writeNode("Stroke", symbolizer, node);
+                return node;
+            },
+            "WellKnownName": function(name) {
+                return this.createElementNSPlus("WellKnownName", {
+                    value: name
+                });
+            },
+            "Opacity": function(value) {
+                return this.createElementNSPlus("Opacity", {
+                    value: value
+                });
+            },
+            "Size": function(value) {
+                return this.createElementNSPlus("Size", {
+                    value: value
+                });
+            },
+            "Rotation": function(value) {
+                return this.createElementNSPlus("Rotation", {
+                    value: value
+                });
+            },
+            "OnlineResource": function(href) {
+                return this.createElementNSPlus("OnlineResource", {
+                    attributes: {
+                        "xlink:type": "simple",
+                        "xlink:href": href
+                    }
+                });
+            },
+            "Format": function(format) {
+                return this.createElementNSPlus("Format", {
+                    value: format
+                });
+            }
+        }
+    }, OpenLayers.Format.Filter.v1_0_0.prototype.writers),
+    
+    CLASS_NAME: "OpenLayers.Format.SLD.v1" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Text.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Text.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/Text.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,151 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Geometry/Point.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Text
+ * Read Text format. Create a new instance with the <OpenLayers.Format.Text>
+ *     constructor. This reads text which is formatted like CSV text, using
+ *     tabs as the seperator by default. It provides parsing of data originally
+ *     used in the MapViewerService, described on the wiki. This Format is used
+ *     by the <OpenLayers.Layer.Text> class.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, {
+    
+    /**
+     * APIProperty: defaultStyle
+     * defaultStyle allows one to control the default styling of the features.
+     *    It should be a symbolizer hash. By default, this is set to match the
+     *    Layer.Text behavior, which is to use the default OpenLayers Icon.
+     */
+    defaultStyle: null,
+     
+    /**
+     * APIProperty: extractStyles
+     * set to true to extract styles from the TSV files, using information
+     * from the image or icon, iconSize and iconOffset fields. This will result
+     * in features with a symbolizer (style) property set, using the
+     * default symbolizer specified in <defaultStyle>. Set to false if you
+     * wish to use a styleMap or OpenLayers.Style options to style your
+     * layer instead.
+     */
+    extractStyles: true,
+
+    /**
+     * Constructor: OpenLayers.Format.Text
+     * Create a new parser for TSV Text.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        options = options || {};
+
+        if(options.extractStyles !== false) {
+            options.defaultStyle = {
+                'externalGraphic': OpenLayers.Util.getImagesLocation() +
+                                                                "marker.png",
+                'graphicWidth': 21,
+                'graphicHeight': 25,
+                'graphicXOffset': -10.5,
+                'graphicYOffset': -12.5
+            };
+        }
+        
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+    }, 
+
+    /**
+     * APIMethod: read
+     * Return a list of features from a Tab Seperated Values text string.
+     * 
+     * Parameters:
+     * data - {String} 
+     *
+     * Returns:
+     * An Array of <OpenLayers.Feature.Vector>s
+     */
+    read: function(text) {
+        var lines = text.split('\n');
+        var columns;
+        var features = [];
+        // length - 1 to allow for trailing new line
+        for (var lcv = 0; lcv < (lines.length - 1); lcv++) {
+            var currLine = lines[lcv].replace(/^\s*/,'').replace(/\s*$/,'');
+        
+            if (currLine.charAt(0) != '#') { /* not a comment */
+            
+                if (!columns) {
+                    //First line is columns
+                    columns = currLine.split('\t');
+                } else {
+                    var vals = currLine.split('\t');
+                    var geometry = new OpenLayers.Geometry.Point(0,0);
+                    var attributes = {};
+                    var style = this.defaultStyle ? 
+                        OpenLayers.Util.applyDefaults({}, this.defaultStyle) :
+                        null;  
+                    var icon, iconSize, iconOffset, overflow;
+                    var set = false;
+                    for (var valIndex = 0; valIndex < vals.length; valIndex++) {
+                        if (vals[valIndex]) {
+                            if (columns[valIndex] == 'point') {
+                                var coords = vals[valIndex].split(',');
+                                geometry.y = parseFloat(coords[0]);
+                                geometry.x = parseFloat(coords[1]);
+                                set = true;
+                            } else if (columns[valIndex] == 'lat') {
+                                geometry.y = parseFloat(vals[valIndex]);
+                                set = true;
+                            } else if (columns[valIndex] == 'lon') {
+                                geometry.x = parseFloat(vals[valIndex]);
+                                set = true;
+                            } else if (columns[valIndex] == 'title')
+                                attributes['title'] = vals[valIndex];
+                            else if (columns[valIndex] == 'image' ||
+                                     columns[valIndex] == 'icon' && style) {
+                                style['externalGraphic'] = vals[valIndex];
+                            } else if (columns[valIndex] == 'iconSize' && style) {
+                                var size = vals[valIndex].split(',');
+                                style['graphicWidth'] = parseFloat(size[0]);
+                                style['graphicHeight'] = parseFloat(size[1]);
+                            } else if (columns[valIndex] == 'iconOffset' && style) {
+                                var offset = vals[valIndex].split(',');
+                                style['graphicXOffset'] = parseFloat(offset[0]);
+                                style['graphicYOffset'] = parseFloat(offset[1]);
+                            } else if (columns[valIndex] == 'description') {
+                                attributes['description'] = vals[valIndex];
+                            } else if (columns[valIndex] == 'overflow') {
+                                attributes['overflow'] = vals[valIndex];
+                            } else {
+                                // For StyleMap filtering, allow additional
+                                // columns to be stored as attributes.
+                                attributes[columns[valIndex]] = vals[valIndex];
+                            }    
+                        }
+                    }
+                    if (set) {
+                      if (this.internalProjection && this.externalProjection) {
+                          geometry.transform(this.externalProjection, 
+                                             this.internalProjection); 
+                      }
+                      var feature = new OpenLayers.Feature.Vector(geometry, attributes, style);
+                      features.push(feature);
+                    }
+                }
+            }
+        }
+        return features;
+    },   
+
+    CLASS_NAME: "OpenLayers.Format.Text" 
+});    

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,31 @@
+/**
+ * @requires OpenLayers/Format/WFSCapabilities/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities/v1_1_0
+ * Read WFS Capabilities version 1.1.0.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.WFSCapabilities>
+ */
+OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(
+    OpenLayers.Format.WFSCapabilities.v1, {
+    
+    /**
+     * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0
+     * Create a new parser for WFS capabilities version 1.1.0.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFSCapabilities.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,75 @@
+/**
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities
+ * Read WFS Capabilities.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.1.0".
+     */
+    defaultVersion: "1.1.0",
+    
+    /**
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
+     */
+    version: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WFSCapabilities
+     * Create a new parser for WFS capabilities.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+        this.options = options;
+    },
+
+    /**
+     * APIMethod: read
+     * Read capabilities data from a string, and return a list of layers. 
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array} List of named layers.
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var root = data.documentElement;
+        var version = this.version;
+        if(!version) {
+            version = root.getAttribute("version");
+            if(!version) {
+                version = this.defaultVersion;
+            }
+        }
+        var constr = OpenLayers.Format.WFSCapabilities[
+            "v" + version.replace(/\./g, "_")
+        ];
+        if(!constr) {
+            throw "Can't find a WFS capabilities parser for version " + version;
+        }
+        var parser = new constr(this.options);
+        var capabilities = parser.read(data);
+        capabilities.version = version;
+        return capabilities;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.WFSCapabilities" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,358 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Format/WFST.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFST.v1
+ * Superclass for WFST parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance",
+        wfs: "http://www.opengis.net/wfs",
+        gml: "http://www.opengis.net/gml",
+        ogc: "http://www.opengis.net/ogc"
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "wfs",
+
+    /**
+     * Property: version
+     * {String} WFS version number.
+     */
+    version: null,
+
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocations: null,
+    
+    /**
+     * APIProperty: srsName
+     * {String} URI for spatial reference system.
+     */
+    srsName: null,
+
+    /**
+     * APIProperty: extractAttributes
+     * {Boolean} Extract attributes from GML.  Default is true.
+     */
+    extractAttributes: true,
+    
+    /**
+     * APIProperty: xy
+     * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
+     * Changing is not recommended, a new Format should be instantiated.
+     */ 
+    xy: true,
+
+    /**
+     * Property: stateName
+     * {Object} Maps feature states to node names.
+     */
+    stateName: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WFST.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
+     *     constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        // set state name mapping
+        this.stateName = {};
+        this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
+        this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
+        this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: getSrsName
+     */
+    getSrsName: function(feature, options) {
+        var srsName = options && options.srsName;
+        if(!srsName) {
+            if(feature && feature.layer) {
+                srsName = feature.layer.projection.getCode();
+            } else {
+                srsName = this.srsName;
+            }
+        }
+        return srsName;
+    },
+
+    /**
+     * Method: read
+     * Parse the response from a transaction.  Because WFS is split into
+     *     Transaction requests (create, update, and delete) and GetFeature
+     *     requests (read), this method handles parsing of both types of
+     *     responses.
+     */
+    read: function(data) {
+        if(typeof data == "string") { 
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        if(data && data.nodeType == 9) {
+            data = data.documentElement;
+        }
+        var obj = {};
+        this.readNode(data, obj);
+        if(obj.features) {
+            obj = obj.features;
+        }
+        return obj;
+    },
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "wfs": {
+            "FeatureCollection": function(node, obj) {
+                obj.features = [];
+                this.readChildNodes(node, obj);
+            }
+        }
+    },
+    
+    /**
+     * Method: write
+     * Given an array of features, write a WFS transaction.  This assumes
+     *     the features have a state property that determines the operation
+     *     type - insert, update, or delete.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} A list of features.
+     *
+     * Returns:
+     * {String} A serialized WFS transaction.
+     */
+    write: function(features) {
+        var node = this.writeNode("wfs:Transaction", features);
+        var value = this.schemaLocationAttr();
+        if(value) {
+            this.setAttributeNS(
+                node, this.namespaces["xsi"], "xsi:schemaLocation",  value
+            )
+        }
+        return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
+    },
+    
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "wfs": {
+            "GetFeature": function(options) {
+                var node = this.createElementNSPlus("wfs:GetFeature", {
+                    attributes: {
+                        service: "WFS",
+                        version: this.version,
+                        maxFeatures: options && options.maxFeatures,
+                        "xsi:schemaLocation": this.schemaLocationAttr(options)
+                    }
+                });
+                this.writeNode("Query", options, node);
+                return node;
+            },
+            "Query": function(options) {
+                options = OpenLayers.Util.extend({
+                    featureNS: this.featureNS,
+                    featurePrefix: this.featurePrefix,
+                    featureType: this.featureType,
+                    srsName: this.srsName
+                }, options);
+                // TODO: this is still version specific and should be separated out
+                // v1.0.0 does not allow srsName on wfs:Query
+                var node = this.createElementNSPlus("wfs:Query", {
+                    attributes: {
+                        typeName: (options.featureNS ? options.featurePrefix + ":" : "") +
+                            options.featureType,
+                        srsName: options.srsName
+                    }
+                });
+                if(options.featureNS) {
+                    node.setAttribute("xmlns:" + options.featurePrefix, options.featureNS);
+                }
+                if(options.filter) {
+                    this.setFilterProperty(options.filter);
+                    this.writeNode("ogc:Filter", options.filter, node);
+                }
+                return node;
+            },
+            "Transaction": function(features) {
+                var node = this.createElementNSPlus("wfs:Transaction", {
+                    attributes: {
+                        service: "WFS",
+                        version: this.version
+                    }
+                });
+                if(features) {
+                    var name, feature;
+                    for(var i=0, len=features.length; i<len; ++i) {
+                        feature = features[i];
+                        name = this.stateName[feature.state];
+                        if(name) {
+                            this.writeNode(name, feature, node);
+                        }
+                    }
+                }
+                return node;
+            },
+            "Insert": function(feature) {
+                var node = this.createElementNSPlus("wfs:Insert");
+                this.srsName = this.getSrsName(feature);
+                this.writeNode("feature:_typeName", feature, node);
+                return node;
+            },
+            "Update": function(feature) {
+                var node = this.createElementNSPlus("wfs:Update", {
+                    attributes: {
+                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+                            this.featureType
+                    }
+                });
+                if(this.featureNS) {
+                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+                }
+                
+                // add in geometry
+                this.writeNode(
+                    "Property", {name: this.geometryName, value: feature}, node
+                );
+        
+                // add in attributes
+                for(var key in feature.attributes) {
+                    this.writeNode(
+                        "Property", {name: key, value: feature.attributes[key]}, node
+                    );
+                }
+                
+                // add feature id filter
+                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+                    fids: [feature.fid]
+                }), node);
+        
+                return node;
+            },
+            "Property": function(obj) {
+                var node = this.createElementNSPlus("wfs:Property");
+                this.writeNode("Name", obj.name, node);
+                this.writeNode("Value", obj.value, node);
+                return node;
+            },
+            "Name": function(name) {
+                return this.createElementNSPlus("wfs:Name", {value: name});
+            },
+            "Value": function(obj) {
+                var node;
+                if(obj instanceof OpenLayers.Feature.Vector) {
+                    node = this.createElementNSPlus("wfs:Value");
+                    this.srsName = this.getSrsName(obj);
+                    var geom = this.writeNode("feature:_geometry", obj.geometry).firstChild;
+                    node.appendChild(geom);
+                } else {
+                    node = this.createElementNSPlus("wfs:Value", {value: obj});                
+                }
+                return node;
+            },
+            "Delete": function(feature) {
+                var node = this.createElementNSPlus("wfs:Delete", {
+                    attributes: {
+                        typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+                            this.featureType
+                    }
+                });
+                if(this.featureNS) {
+                    node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+                }
+                this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+                    fids: [feature.fid]
+                }), node);
+                return node;
+            }
+        }
+    },
+
+    /**
+     * Method: schemaLocationAttr
+     * Generate the xsi:schemaLocation attribute value.
+     *
+     * Returns:
+     * {String} The xsi:schemaLocation attribute or undefined if none.
+     */
+    schemaLocationAttr: function(options) {
+        options = OpenLayers.Util.extend({
+            featurePrefix: this.featurePrefix,
+            schema: this.schema
+        }, options);
+        var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
+        if(options.schema) {
+            schemaLocations[options.featurePrefix] = options.schema;
+        }
+        var parts = [];
+        var uri;
+        for(var key in schemaLocations) {
+            uri = this.namespaces[key];
+            if(uri) {
+                parts.push(uri + " " + schemaLocations[key]);
+            }
+        }
+        var value = parts.join(" ") || undefined;
+        return value;
+    },
+    
+    /**
+     * Method: setFilterProperty
+     * Set the property of each spatial filter.
+     *
+     * Parameters:
+     * filter - {<OpenLayers.Filter>}
+     */
+    setFilterProperty: function(filter) {
+        if(filter.filters) {
+            for(var i=0, len=filter.filters.length; i<len; ++i) {
+                this.setFilterProperty(filter.filters[i]);
+            }
+        } else {
+            if(filter instanceof OpenLayers.Filter.Spatial) {
+                // got a spatial filter, set its property
+                filter.property = this.geometryName;
+            }
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WFST.v1" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,137 @@
+/**
+ * @requires OpenLayers/Format/WFST/v1.js
+ * @requires OpenLayers/Format/Filter/v1_1_0.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFST.v1_1_0
+ * A format for creating WFS v1.1.0 transactions.  Create a new instance with the
+ *     <OpenLayers.Format.WFST.v1_1_0> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.Filter.v1_1_0>
+ *  - <OpenLayers.Format.WFST.v1>
+ */
+OpenLayers.Format.WFST.v1_1_0 = OpenLayers.Class(
+    OpenLayers.Format.Filter.v1_1_0, OpenLayers.Format.WFST.v1, {
+    
+    /**
+     * Property: version
+     * {String} WFS version number.
+     */
+    version: "1.1.0",
+    
+    /**
+     * Property: schemaLocations
+     * {Object} Properties are namespace aliases, values are schema locations.
+     */
+    schemaLocations: {
+        "wfs": "http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"
+    },
+    
+    /**
+     * Constructor: OpenLayers.Format.WFST.v1_1_0
+     * A class for parsing and generating WFS v1.1.0 transactions.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options properties:
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (optional).
+     * featurePrefix - {String} Feature namespace alias (optional - only used
+     *     if featureNS is provided).  Default is 'feature'.
+     * geometryName - {String} Name of geometry attribute.  Default is 'the_geom'.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this, [options]);
+        OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {
+        "wfs": OpenLayers.Util.applyDefaults({
+            "TransactionResponse": function(node, obj) {
+                obj.insertIds = [];
+                obj.success = false;
+                this.readChildNodes(node, obj);
+            },
+            "TransactionSummary": function(node, obj) {
+                // this is a limited test of success
+                obj.success = true;
+            },
+            "InsertResults": function(node, obj) {
+                this.readChildNodes(node, obj);
+            },
+            "Feature": function(node, container) {
+                var obj = {fids: []};
+                this.readChildNodes(node, obj);
+                container.insertIds.push(obj.fids[0]);
+            }
+        }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),
+        "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"],
+        "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"],
+        "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.readers["ogc"]
+    },
+
+    /**
+     * Property: writers
+     * As a compliment to the readers property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {
+        "wfs": OpenLayers.Util.applyDefaults({
+            "Query": function(options) {
+                options = OpenLayers.Util.extend({
+                    featureNS: this.featureNS,
+                    featurePrefix: this.featurePrefix,
+                    featureType: this.featureType,
+                    srsName: this.srsName
+                }, options);
+                var node = this.createElementNSPlus("wfs:Query", {
+                    attributes: {
+                        typeName: (options.featureNS ? options.featurePrefix + ":" : "") +
+                            options.featureType,
+                        srsName: options.srsName
+                    }
+                });
+                if(options.featureNS) {
+                    node.setAttribute("xmlns:" + options.featurePrefix, options.featureNS);
+                }
+                if(options.propertyNames) {
+                    for(var i=0,len = options.propertyNames.length; i<len; i++) {
+                        this.writeNode(
+                            "wfs:PropertyName", 
+                            {property: options.propertyNames[i]},
+                            node
+                        );
+                    }
+                }
+                if(options.filter) {
+                    this.setFilterProperty(options.filter);
+                    this.writeNode("ogc:Filter", options.filter, node);
+                }
+                return node;
+            },
+            "PropertyName": function(obj) {
+                return this.createElementNSPlus("wfs:PropertyName", {
+                    value: obj.property
+                });
+            }            
+        }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),
+        "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"],
+        "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"],
+        "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"]
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WFST.v1_1_0" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WFST.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,33 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format.js
+ */
+
+/**
+ * Function: OpenLayers.Format.WFST
+ * Used to create a versioned WFS protocol.  Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Format>} A WFST format of the given version.
+ */
+OpenLayers.Format.WFST = function(options) {
+    options = OpenLayers.Util.applyDefaults(
+        options, OpenLayers.Format.WFST.DEFAULTS
+    );
+    var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
+    if(!cls) {
+        throw "Unsupported WFST version: " + options.version;
+    }
+    return new cls(options);
+};
+
+/**
+ * Constant: OpenLayers.Format.WFST.DEFAULTS
+ * {Object} Default properties for the WFST format.
+ */
+OpenLayers.Format.WFST.DEFAULTS = {
+    "version": "1.0.0"
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WKT.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WKT.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WKT.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,353 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WKT
+ * Class for reading and writing Well-Known Text.  Create a new instance
+ * with the <OpenLayers.Format.WKT> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
+    
+    /**
+     * Constructor: OpenLayers.Format.WKT
+     * Create a new parser for WKT
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *           this instance
+     *
+     * Returns:
+     * {<OpenLayers.Format.WKT>} A new WKT parser.
+     */
+    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]);
+    },
+
+    /**
+     * Method: read
+     * Deserialize a WKT string and return a vector feature or an
+     * array of vector features.  Supports WKT for POINT, MULTIPOINT,
+     * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
+     * GEOMETRYCOLLECTION.
+     *
+     * Parameters:
+     * wkt - {String} A WKT string
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
+     * GEOMETRYCOLLECTION WKT.
+     */
+    read: function(wkt) {
+        var features, type, str;
+        var matches = this.regExes.typeStr.exec(wkt);
+        if(matches) {
+            type = matches[1].toLowerCase();
+            str = matches[2];
+            if(this.parse[type]) {
+                features = this.parse[type].apply(this, [str]);
+            }
+            if (this.internalProjection && this.externalProjection) {
+                if (features && 
+                    features.CLASS_NAME == "OpenLayers.Feature.Vector") {
+                    features.geometry.transform(this.externalProjection,
+                                                this.internalProjection);
+                } else if (features &&
+                           type != "geometrycollection" &&
+                           typeof features == "object") {
+                    for (var i=0, len=features.length; i<len; i++) {
+                        var component = features[i];
+                        component.geometry.transform(this.externalProjection,
+                                                     this.internalProjection);
+                    }
+                }
+            }
+        }    
+        return features;
+    },
+
+    /**
+     * Method: write
+     * Serialize a feature or array of features into a WKT string.
+     *
+     * Parameters:
+     * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
+     *            features
+     *
+     * Returns:
+     * {String} The WKT string representation of the input geometries
+     */
+    write: function(features) {
+        var collection, geometry, type, data, isCollection;
+        if(features.constructor == Array) {
+            collection = features;
+            isCollection = true;
+        } else {
+            collection = [features];
+            isCollection = false;
+        }
+        var pieces = [];
+        if(isCollection) {
+            pieces.push('GEOMETRYCOLLECTION(');
+        }
+        for(var i=0, len=collection.length; i<len; ++i) {
+            if(isCollection && i>0) {
+                pieces.push(',');
+            }
+            geometry = collection[i].geometry;
+            type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
+            if(!this.extract[type]) {
+                return null;
+            }
+            if (this.internalProjection && this.externalProjection) {
+                geometry = geometry.clone();
+                geometry.transform(this.internalProjection, 
+                                   this.externalProjection);
+            }                       
+            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, len=multipoint.components.length; i<len; ++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, len=linestring.components.length; i<len; ++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, len=multilinestring.components.length; i<len; ++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, len=polygon.components.length; i<len; ++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, len=multipolygon.components.length; i<len; ++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 feature given a point WKT fragment.
+         * @param {String} str A WKT fragment representing the point
+         * @returns {<OpenLayers.Feature.Vector>} A point feature
+         * @private
+         */
+        'point': function(str) {
+            var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.Point(coords[0], coords[1])
+            );
+        },
+
+        /**
+         * Return a multipoint feature given a multipoint WKT fragment.
+         * @param {String} A WKT fragment representing the multipoint
+         * @returns {<OpenLayers.Feature.Vector>} A multipoint feature
+         * @private
+         */
+        'multipoint': function(str) {
+            var points = OpenLayers.String.trim(str).split(',');
+            var components = [];
+            for(var i=0, len=points.length; i<len; ++i) {
+                components.push(this.parse.point.apply(this, [points[i]]).geometry);
+            }
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.MultiPoint(components)
+            );
+        },
+        
+        /**
+         * Return a linestring feature given a linestring WKT fragment.
+         * @param {String} A WKT fragment representing the linestring
+         * @returns {<OpenLayers.Feature.Vector>} A linestring feature
+         * @private
+         */
+        'linestring': function(str) {
+            var points = OpenLayers.String.trim(str).split(',');
+            var components = [];
+            for(var i=0, len=points.length; i<len; ++i) {
+                components.push(this.parse.point.apply(this, [points[i]]).geometry);
+            }
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.LineString(components)
+            );
+        },
+
+        /**
+         * Return a multilinestring feature given a multilinestring WKT fragment.
+         * @param {String} A WKT fragment representing the multilinestring
+         * @returns {<OpenLayers.Feature.Vector>} A multilinestring feature
+         * @private
+         */
+        'multilinestring': function(str) {
+            var line;
+            var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
+            var components = [];
+            for(var i=0, len=lines.length; i<len; ++i) {
+                line = lines[i].replace(this.regExes.trimParens, '$1');
+                components.push(this.parse.linestring.apply(this, [line]).geometry);
+            }
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.MultiLineString(components)
+            );
+        },
+        
+        /**
+         * Return a polygon feature given a polygon WKT fragment.
+         * @param {String} A WKT fragment representing the polygon
+         * @returns {<OpenLayers.Feature.Vector>} A polygon feature
+         * @private
+         */
+        'polygon': function(str) {
+            var ring, linestring, linearring;
+            var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
+            var components = [];
+            for(var i=0, len=rings.length; i<len; ++i) {
+                ring = rings[i].replace(this.regExes.trimParens, '$1');
+                linestring = this.parse.linestring.apply(this, [ring]).geometry;
+                linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
+                components.push(linearring);
+            }
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.Polygon(components)
+            );
+        },
+
+        /**
+         * Return a multipolygon feature given a multipolygon WKT fragment.
+         * @param {String} A WKT fragment representing the multipolygon
+         * @returns {<OpenLayers.Feature.Vector>} A multipolygon feature
+         * @private
+         */
+        'multipolygon': function(str) {
+            var polygon;
+            var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
+            var components = [];
+            for(var i=0, len=polygons.length; i<len; ++i) {
+                polygon = polygons[i].replace(this.regExes.trimParens, '$1');
+                components.push(this.parse.polygon.apply(this, [polygon]).geometry);
+            }
+            return new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.MultiPolygon(components)
+            );
+        },
+
+        /**
+         * Return an array of features given a geometrycollection WKT fragment.
+         * @param {String} A WKT fragment representing the geometrycollection
+         * @returns {Array} An array of OpenLayers.Feature.Vector
+         * @private
+         */
+        'geometrycollection': function(str) {
+            // separate components of the collection with |
+            str = str.replace(/,\s*([A-Za-z])/g, '|$1');
+            var wktArray = OpenLayers.String.trim(str).split('|');
+            var components = [];
+            for(var i=0, len=wktArray.length; i<len; ++i) {
+                components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
+            }
+            return components;
+        }
+
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WKT" 
+});     

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,860 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMC.js
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMC.v1
+ * Superclass for WMC version 1 parsers.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WMC.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.
+     */
+    namespaces: {
+        ol: "http://openlayers.org/context",
+        wmc: "http://www.opengis.net/context",
+        sld: "http://www.opengis.net/sld",
+        xlink: "http://www.w3.org/1999/xlink",
+        xsi: "http://www.w3.org/2001/XMLSchema-instance"
+    },
+    
+    /**
+     * Property: schemaLocation
+     * {String} Schema location for a particular minor version.
+     */
+    schemaLocation: "",
+
+    /**
+     * Method: getNamespacePrefix
+     * Get the namespace prefix for a given uri from the <namespaces> object.
+     *
+     * Returns:
+     * {String} A namespace prefix or null if none found.
+     */
+    getNamespacePrefix: function(uri) {
+        var prefix = null;
+        if(uri == null) {
+            prefix = this.namespaces[this.defaultPrefix];
+        } else {
+            for(prefix in this.namespaces) {
+                if(this.namespaces[prefix] == uri) {
+                    break;
+                }
+            }
+        }
+        return prefix;
+    },
+    
+    /**
+     * Property: defaultPrefix
+     */
+    defaultPrefix: "wmc",
+
+    /**
+     * Property: rootPrefix
+     * {String} Prefix on the root node that maps to the context namespace URI.
+     */
+    rootPrefix: null,
+    
+    /**
+     * Property: defaultStyleName
+     * {String} Style name used if layer has no style param.  Default is "".
+     */
+    defaultStyleName: "",
+    
+    /**
+     * Property: defaultStyleTitle
+     * {String} Default style title.  Default is "Default".
+     */
+    defaultStyleTitle: "Default",
+    
+    /**
+     * Constructor: OpenLayers.Format.WMC.v1
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.WMC> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * Method: read
+     * Read capabilities data from a string, and return a list of layers. 
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array} List of named layers.
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var root = data.documentElement;
+        this.rootPrefix = root.prefix;
+        var context = {
+            version: root.getAttribute("version")
+        };
+        this.runChildNodes(context, root);
+        return context;
+    },
+    
+    /**
+     * Method: runChildNodes
+     */
+    runChildNodes: function(obj, node) {
+        var children = node.childNodes;
+        var childNode, processor, prefix, local;
+        for(var i=0, len=children.length; i<len; ++i) {
+            childNode = children[i];
+            if(childNode.nodeType == 1) {
+                prefix = this.getNamespacePrefix(childNode.namespaceURI);
+                local = childNode.nodeName.split(":").pop();
+                processor = this["read_" + prefix + "_" + local];
+                if(processor) {
+                    processor.apply(this, [obj, childNode]);
+                }
+            }
+        }
+    },
+    
+    /**
+     * Method: read_wmc_General
+     */
+    read_wmc_General: function(context, node) {
+        this.runChildNodes(context, node);
+    },
+    
+    /**
+     * Method: read_wmc_BoundingBox
+     */
+    read_wmc_BoundingBox: function(context, node) {
+        context.projection = node.getAttribute("SRS");
+        context.bounds = new OpenLayers.Bounds(
+            parseFloat(node.getAttribute("minx")),
+            parseFloat(node.getAttribute("miny")),
+            parseFloat(node.getAttribute("maxx")),
+            parseFloat(node.getAttribute("maxy"))
+        );
+    },
+    
+    /**
+     * Method: read_wmc_LayerList
+     */
+    read_wmc_LayerList: function(context, node) {
+        context.layers = [];
+        this.runChildNodes(context, node);
+    },
+    
+    /**
+     * Method: read_wmc_Layer
+     */
+    read_wmc_Layer: function(context, node) {
+        var layerInfo = {
+            params: this.layerParams || {},
+            options: {
+                visibility: (node.getAttribute("hidden") != "1"),
+                queryable: (node.getAttribute("queryable") == "1")
+                
+            },
+            formats: [],
+            styles: []
+        };
+        this.runChildNodes(layerInfo, node);
+        // set properties common to multiple objects on layer options/params
+        layerInfo.params.layers = layerInfo.name;
+        layerInfo.options.maxExtent = layerInfo.maxExtent;
+        // create the layer
+        var layer = this.getLayerFromInfo(layerInfo);
+        context.layers.push(layer);
+    },
+    
+    /**
+     * Method: getLayerFromInfo
+     * Create a WMS layer from a layerInfo object.
+     *
+     * Parameters:
+     * layerInfo - {Object} An object representing a WMS layer.
+     *
+     * Returns:
+     * {<OpenLayers.Layer.WMS>} A WMS layer.
+     */
+    getLayerFromInfo: function(layerInfo) {
+        var options = layerInfo.options;
+        if (this.layerOptions) {
+            OpenLayers.Util.applyDefaults(options, this.layerOptions);
+        }
+        var layer = new OpenLayers.Layer.WMS(
+            layerInfo.title,
+            layerInfo.href,
+            layerInfo.params,
+            options
+        );
+        return layer;
+    },
+    
+    /**
+     * Method: read_wmc_Extension
+     */
+    read_wmc_Extension: function(obj, node) {
+        this.runChildNodes(obj, node);
+    },
+
+    /**
+     * Method: read_ol_units
+     */
+    read_ol_units: function(layerInfo, node) {
+        layerInfo.options.units = this.getChildValue(node);
+    },
+    
+    /**
+     * Method: read_ol_maxExtent
+     */
+    read_ol_maxExtent: function(obj, node) {
+        var bounds = new OpenLayers.Bounds(
+            node.getAttribute("minx"), node.getAttribute("miny"),
+            node.getAttribute("maxx"), node.getAttribute("maxy")
+        );
+        obj.maxExtent = bounds;
+    },
+    
+    /**
+     * Method: read_ol_transparent
+     */
+    read_ol_transparent: function(layerInfo, node) {
+        layerInfo.params.transparent = this.getChildValue(node);
+    },
+
+    /**
+     * Method: read_ol_numZoomLevels
+     */
+    read_ol_numZoomLevels: function(layerInfo, node) {
+        layerInfo.options.numZoomLevels = parseInt(this.getChildValue(node));
+    },
+
+    /**
+     * Method: read_ol_opacity
+     */
+    read_ol_opacity: function(layerInfo, node) {
+        layerInfo.options.opacity = parseFloat(this.getChildValue(node));
+    },
+
+    /**
+     * Method: read_ol_singleTile
+     */
+    read_ol_singleTile: function(layerInfo, node) {
+        layerInfo.options.singleTile = (this.getChildValue(node) == "true");
+    },
+
+    /**
+     * Method: read_ol_isBaseLayer
+     */
+    read_ol_isBaseLayer: function(layerInfo, node) {
+        layerInfo.options.isBaseLayer = (this.getChildValue(node) == "true");
+    },
+
+    /**
+     * Method: read_ol_displayInLayerSwitcher
+     */
+    read_ol_displayInLayerSwitcher: function(layerInfo, node) {
+        layerInfo.options.displayInLayerSwitcher =
+            (this.getChildValue(node) == "true");
+    },
+
+    /**
+     * Method: read_wmc_Server
+     */
+    read_wmc_Server: function(layerInfo, node) {
+        layerInfo.params.version = node.getAttribute("version");
+        this.runChildNodes(layerInfo, node);
+    },
+
+    /**
+     * Method: read_wmc_FormatList
+     */
+    read_wmc_FormatList: function(layerInfo, node) {
+        this.runChildNodes(layerInfo, node);
+    },
+
+    /**
+     * Method: read_wmc_Format
+     */
+    read_wmc_Format: function(layerInfo, node) {
+        var format = this.getChildValue(node);
+        layerInfo.formats.push(format);
+        if(node.getAttribute("current") == "1") {
+            layerInfo.params.format = format;
+        }
+    },
+    
+    /**
+     * Method: read_wmc_StyleList
+     */
+    read_wmc_StyleList: function(layerInfo, node) {
+        this.runChildNodes(layerInfo, node);
+    },
+
+    /**
+     * Method: read_wmc_Style
+     */
+    read_wmc_Style: function(layerInfo, node) {
+        var style = {};
+        this.runChildNodes(style, node);
+        if(node.getAttribute("current") == "1") {
+            // three style types to consider
+            // 1) linked SLD
+            // 2) inline SLD
+            // 3) named style
+            // running child nodes always gets name, optionally gets href or body
+            if(style.href) {
+                layerInfo.params.sld = style.href;
+            } else if(style.body) {
+                layerInfo.params.sld_body = style.body;
+            } else {
+                layerInfo.params.styles = style.name;
+            }
+        }
+        layerInfo.styles.push(style);
+    },
+    
+    /**
+     * Method: read_wmc_SLD
+     */
+    read_wmc_SLD: function(style, node) {
+        this.runChildNodes(style, node);
+        // style either comes back with an href or a body property
+    },
+    
+    /**
+     * Method: read_sld_StyledLayerDescriptor
+     */
+    read_sld_StyledLayerDescriptor: function(sld, node) {
+        var xml = OpenLayers.Format.XML.prototype.write.apply(this, [node]);
+        sld.body = xml;
+    },
+
+    /**
+     * Method: read_wmc_OnlineResource
+     */
+    read_wmc_OnlineResource: function(obj, node) {
+        obj.href = this.getAttributeNS(
+            node, this.namespaces.xlink, "href"
+        );
+    },
+    
+    /**
+     * Method: read_wmc_Name
+     */
+    read_wmc_Name: function(obj, node) {
+        var name = this.getChildValue(node);
+        if(name) {
+            obj.name = name;
+        }
+    },
+
+    /**
+     * Method: read_wmc_Title
+     */
+    read_wmc_Title: function(obj, node) {
+        var title = this.getChildValue(node);
+        if(title) {
+            obj.title = title;
+        }
+    },
+
+    /**
+     * Method: read_wmc_MetadataURL
+     */
+    read_wmc_MetadataURL: function(layerInfo, node) {
+        var metadataURL = {};
+        var links = node.getElementsByTagName("OnlineResource");
+        if(links.length > 0) {
+            this.read_wmc_OnlineResource(metadataURL, links[0]);
+        }
+        layerInfo.options.metadataURL = metadataURL.href;
+
+    },
+
+    /**
+     * Method: read_wmc_Abstract
+     */
+    read_wmc_Abstract: function(obj, node) {
+        var abst = this.getChildValue(node);
+        if(abst) {
+            obj["abstract"] = abst;
+        }
+    },
+    
+    /**
+     * Method: read_wmc_LatLonBoundingBox
+     */
+    read_wmc_LatLonBoundingBox: function(layer, node) {
+        layer.llbbox = [
+            parseFloat(node.getAttribute("minx")),
+            parseFloat(node.getAttribute("miny")),
+            parseFloat(node.getAttribute("maxx")),
+            parseFloat(node.getAttribute("maxy"))
+        ];
+    },
+
+    /**
+     * Method: read_wmc_LegendURL
+     */
+    read_wmc_LegendURL: function(style, node) {
+        var legend = {
+            width: node.getAttribute('width'),
+            height: node.getAttribute('height')
+        };
+        var links = node.getElementsByTagName("OnlineResource");
+        if(links.length > 0) {
+            this.read_wmc_OnlineResource(legend, links[0]);
+        }
+        style.legend = legend;
+    },
+    
+    /**
+     * Method: write
+     *
+     * Parameters:
+     * context - {Object} An object representing the map context.
+     * options - {Object} Optional object.
+     *
+     * Returns:
+     * {String} A WMC document string.
+     */
+    write: function(context, options) {
+        var root = this.createElementDefaultNS("ViewContext");
+        this.setAttributes(root, {
+            version: this.VERSION,
+            id: (options && typeof options.id == "string") ?
+                    options.id :
+                    OpenLayers.Util.createUniqueID("OpenLayers_Context_")
+        });
+        
+        // add schemaLocation attribute
+        this.setAttributeNS(
+            root, this.namespaces.xsi,
+            "xsi:schemaLocation", this.schemaLocation
+        );
+        
+        // required General element
+        root.appendChild(this.write_wmc_General(context));
+
+        // required LayerList element
+        root.appendChild(this.write_wmc_LayerList(context));
+
+        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+    },
+    
+    /**
+     * Method: createElementDefaultNS
+     * Shorthand for createElementNS with namespace from <defaultPrefix>.
+     *     Can optionally be used to set attributes and a text child value.
+     *
+     * Parameters:
+     * name - {String} The qualified node name.
+     * childValue - {String} Optional value for text child node.
+     * attributes - {Object} Optional object representing attributes.
+     *
+     * Returns:
+     * {Element} An element node.
+     */
+    createElementDefaultNS: function(name, childValue, attributes) {
+        var node = this.createElementNS(
+            this.namespaces[this.defaultPrefix],
+            name
+        );
+        if(childValue) {
+            node.appendChild(this.createTextNode(childValue));
+        }
+        if(attributes) {
+            this.setAttributes(node, attributes);
+        }
+        return node;
+    },
+    
+    /**
+     * Method: setAttributes
+     * Set multiple attributes given key value pairs from an object.
+     *
+     * Parameters:
+     * node - {Element} An element node.
+     * obj - {Object} An object whose properties represent attribute names and
+     *     values represent attribute values.
+     */
+    setAttributes: function(node, obj) {
+        var value;
+        for(var name in obj) {
+            value = obj[name].toString();
+            if(value.match(/[A-Z]/)) {
+                // safari lowercases attributes with setAttribute
+                this.setAttributeNS(node, null, name, value);
+            } else {
+                node.setAttribute(name, value);
+            }
+        }
+    },
+
+    /**
+     * Method: write_wmc_General
+     * Create a General node given an context object.
+     *
+     * Parameters:
+     * context - {Object} Context object.
+     *
+     * Returns:
+     * {Element} A WMC General element node.
+     */
+    write_wmc_General: function(context) {
+        var node = this.createElementDefaultNS("General");
+
+        // optional Window element
+        if(context.size) {
+            node.appendChild(this.createElementDefaultNS(
+                "Window", null,
+                {
+                    width: context.size.w,
+                    height: context.size.h
+                }
+            ));
+        }
+        
+        // required BoundingBox element
+        var bounds = context.bounds;
+        node.appendChild(this.createElementDefaultNS(
+            "BoundingBox", null,
+            {
+                minx: bounds.left.toPrecision(10),
+                miny: bounds.bottom.toPrecision(10),
+                maxx: bounds.right.toPrecision(10),
+                maxy: bounds.top.toPrecision(10),
+                SRS: context.projection
+            }
+        ));
+
+        // required Title element
+        node.appendChild(this.createElementDefaultNS(
+            "Title", context.title
+        ));
+        
+        // OpenLayers specific map properties
+        node.appendChild(this.write_ol_MapExtension(context));
+        
+        return node;
+    },
+    
+    /**
+     * Method: write_ol_MapExtension
+     */
+    write_ol_MapExtension: function(context) {
+        var node = this.createElementDefaultNS("Extension");
+        
+        var bounds = context.maxExtent;
+        if(bounds) {
+            var maxExtent = this.createElementNS(
+                this.namespaces.ol, "ol:maxExtent"
+            );
+            this.setAttributes(maxExtent, {
+                minx: bounds.left.toPrecision(10),
+                miny: bounds.bottom.toPrecision(10),
+                maxx: bounds.right.toPrecision(10),
+                maxy: bounds.top.toPrecision(10)
+            });
+            node.appendChild(maxExtent);
+        }
+        
+        return node;
+    },
+    
+    /**
+     * Method: write_wmc_LayerList
+     * Create a LayerList node given an context object.
+     *
+     * Parameters:
+     * context - {Object} Context object.
+     *
+     * Returns:
+     * {Element} A WMC LayerList element node.
+     */
+    write_wmc_LayerList: function(context) {
+        var list = this.createElementDefaultNS("LayerList");
+        
+        var layer;
+        for(var i=0, len=context.layers.length; i<len; ++i) {
+            layer = context.layers[i];
+            if(layer instanceof OpenLayers.Layer.WMS) {
+                list.appendChild(this.write_wmc_Layer(layer));
+            }
+        }
+        
+        return list;
+    },
+
+    /**
+     * Method: write_wmc_Layer
+     * Create a Layer node given a layer object.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC Layer element node.
+     */
+    write_wmc_Layer: function(layer) {
+        var node = this.createElementDefaultNS(
+            "Layer", null, {
+                queryable: layer.queryable ? "1" : "0",
+                hidden: layer.visibility ? "0" : "1"
+            }
+        );
+        
+        // required Server element
+        node.appendChild(this.write_wmc_Server(layer));
+
+        // required Name element
+        node.appendChild(this.createElementDefaultNS(
+            "Name", layer.params["LAYERS"]
+        ));
+        
+        // required Title element
+        node.appendChild(this.createElementDefaultNS(
+            "Title", layer.name
+        ));
+
+        // optional MetadataURL element
+        if (layer.metadataURL) {
+            node.appendChild(this.write_wmc_MetadataURL(layer));
+        }
+        
+        // optional FormatList element
+        node.appendChild(this.write_wmc_FormatList(layer));
+
+        // optional StyleList element
+        node.appendChild(this.write_wmc_StyleList(layer));
+        
+        // OpenLayers specific properties go in an Extension element
+        node.appendChild(this.write_wmc_LayerExtension(layer));
+
+        return node;
+    },
+    
+    /**
+     * Method: write_wmc_LayerExtension
+     * Add OpenLayers specific layer parameters to an Extension element.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} A WMS layer.
+     *
+     * Returns:
+     * {Element} A WMC Extension element (for a layer).
+     */
+    write_wmc_LayerExtension: function(layer) {
+        var node = this.createElementDefaultNS("Extension");
+        
+        var bounds = layer.maxExtent;
+        var maxExtent = this.createElementNS(
+            this.namespaces.ol, "ol:maxExtent"
+        );
+        this.setAttributes(maxExtent, {
+            minx: bounds.left.toPrecision(10),
+            miny: bounds.bottom.toPrecision(10),
+            maxx: bounds.right.toPrecision(10),
+            maxy: bounds.top.toPrecision(10)
+        });
+        node.appendChild(maxExtent);
+        
+        var param = layer.params["TRANSPARENT"];
+        if(param) {
+            var trans = this.createElementNS(
+                this.namespaces.ol, "ol:transparent"
+            );
+            trans.appendChild(this.createTextNode(param));
+            node.appendChild(trans);
+        }
+        
+        var properties = [
+            "numZoomLevels", "units", "isBaseLayer",
+            "opacity", "displayInLayerSwitcher", "singleTile"
+        ];
+        var child;
+        for(var i=0, len=properties.length; i<len; ++i) {
+            child = this.createOLPropertyNode(layer, properties[i]);
+            if(child) {
+                node.appendChild(child);
+            }
+        }
+
+        return node;
+    },
+    
+    /**
+     * Method: createOLPropertyNode
+     * Create a node representing an OpenLayers property.  If the property is
+     *     null or undefined, null will be returned.
+     *
+     * Parameters:
+     * object - {Object} An object.
+     * prop - {String} A property.
+     *
+     * Returns:
+     * {Element} A property node.
+     */
+    createOLPropertyNode: function(obj, prop) {
+        var node = null;
+        if(obj[prop] != null) {
+            node = this.createElementNS(this.namespaces.ol, "ol:" + prop);
+            node.appendChild(this.createTextNode(obj[prop].toString()));
+        }
+        return node;
+    },
+
+    /**
+     * Method: write_wmc_Server
+     * Create a Server node given a layer object.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC Server element node.
+     */
+    write_wmc_Server: function(layer) {
+        var node = this.createElementDefaultNS("Server");
+        this.setAttributes(node, {
+            service: "OGC:WMS",
+            version: layer.params["VERSION"]
+        });
+        
+        // required OnlineResource element
+        node.appendChild(this.write_wmc_OnlineResource(layer.url));
+        
+        return node;
+    },
+
+    /**
+     * Method: write_wmc_MetadataURL
+     * Create a MetadataURL node given a layer object.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC metadataURL element node.
+     */
+    write_wmc_MetadataURL: function(layer) {
+        var node = this.createElementDefaultNS("MetadataURL");
+
+        // required OnlineResource element
+        node.appendChild(this.write_wmc_OnlineResource(layer.metadataURL));
+
+        return node;
+    },
+
+    /**
+     * Method: write_wmc_FormatList
+     * Create a FormatList node given a layer.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC FormatList element node.
+     */
+    write_wmc_FormatList: function(layer) {
+        var node = this.createElementDefaultNS("FormatList");
+        node.appendChild(this.createElementDefaultNS(
+            "Format", layer.params["FORMAT"], {current: "1"}
+        ));
+
+        return node;
+    },
+
+    /**
+     * Method: write_wmc_StyleList
+     * Create a StyleList node given a layer.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC StyleList element node.
+     */
+    write_wmc_StyleList: function(layer) {
+        var node = this.createElementDefaultNS("StyleList");
+        var style = this.createElementDefaultNS(
+            "Style", null, {current: "1"}
+        );
+        
+        // Style can come from one of three places (prioritized as below):
+        // 1) an SLD parameter
+        // 2) and SLD_BODY parameter
+        // 3) the STYLES parameter
+        
+        if(layer.params["SLD"]) {
+            // create link from SLD parameter
+            var sld = this.createElementDefaultNS("SLD");
+            var link = this.write_wmc_OnlineResource(layer.params["SLD"]);
+            sld.appendChild(link);
+            style.appendChild(sld);
+        } else if(layer.params["SLD_BODY"]) {
+            // include sld fragment from SLD_BODY parameter
+            var sld = this.createElementDefaultNS("SLD");
+            var body = layer.params["SLD_BODY"];
+            // read in body as xml doc - assume proper namespace declarations
+            var doc = OpenLayers.Format.XML.prototype.read.apply(this, [body]);
+            // append to StyledLayerDescriptor node
+            var imported = doc.documentElement;
+            if(sld.ownerDocument && sld.ownerDocument.importNode) {
+                imported = sld.ownerDocument.importNode(imported, true);
+            }
+            sld.appendChild(imported);
+            style.appendChild(sld);            
+        } else {
+            // use name(s) from STYLES parameter
+            var name = layer.params["STYLES"] ?
+                layer.params["STYLES"] : this.defaultStyleName;
+            
+            style.appendChild(this.createElementDefaultNS("Name", name));
+            style.appendChild(this.createElementDefaultNS(
+                "Title", this.defaultStyleTitle
+            ));
+        }
+        node.appendChild(style);
+        return node;
+    },
+
+    /**
+     * Method: write_wmc_OnlineResource
+     * Create an OnlineResource node given a URL.
+     *
+     * Parameters:
+     * href - {String} URL for the resource.
+     *
+     * Returns:
+     * {Element} A WMC OnlineResource element node.
+     */
+    write_wmc_OnlineResource: function(href) {
+        var node = this.createElementDefaultNS("OnlineResource");
+        this.setAttributeNS(node, this.namespaces.xlink, "xlink:type", "simple");
+        this.setAttributeNS(node, this.namespaces.xlink, "xlink:href", href);
+        return node;
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMC.v1" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_0_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_0_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_0_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,49 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMC/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMC.v1_0_0
+ * Read and write WMC version 1.0.0.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.WMC.v1>
+ */
+OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class(
+    OpenLayers.Format.WMC.v1, {
+    
+    /**
+     * Constant: VERSION
+     * {String} 1.0.0
+     */
+    VERSION: "1.0.0",
+    
+    /**
+     * Property: schemaLocation
+     * {String} http://www.opengis.net/context
+     *     http://schemas.opengis.net/context/1.0.0/context.xsd
+     */
+    schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.WMC.v1_0_0
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.WMC> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.WMC.v1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,116 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WMC/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMC.v1_1_0
+ * Read and write WMC version 1.1.0.
+ *
+ * Differences between 1.1.0 and 1.0.0:
+ *     - 1.1.0 Layers have optional sld:MinScaleDenominator and
+ *       sld:MaxScaleDenominator
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.WMC.v1>
+ */
+OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class(
+    OpenLayers.Format.WMC.v1, {
+    
+    /**
+     * Constant: VERSION
+     * {String} 1.1.0
+     */
+    VERSION: "1.1.0",
+
+    /**
+     * Property: schemaLocation
+     * {String} http://www.opengis.net/context
+     *     http://schemas.opengis.net/context/1.1.0/context.xsd
+     */
+    schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd",
+
+    /**
+     * Constructor: OpenLayers.Format.WMC.v1_1_0
+     * Instances of this class are not created directly.  Use the
+     *     <OpenLayers.Format.WMC> constructor instead.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.WMC.v1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    /**
+     * Method: read_sld_MinScaleDenominator
+     * Read a sld:MinScaleDenominator node.
+     *
+     * Parameters:
+     * layerInfo - {Object} An object representing a layer.
+     * node - {Element} An element node.
+     */
+    read_sld_MinScaleDenominator: function(layerInfo, node) {
+        layerInfo.options.maxScale = this.getChildValue(node);
+    },
+
+    /**
+     * Method: read_sld_MaxScaleDenominator
+     * Read a sld:MaxScaleDenominator node.
+     *
+     * Parameters:
+     * layerInfo - {Object} An object representing a layer.
+     * node - {Element} An element node.
+     */
+    read_sld_MaxScaleDenominator: function(layerInfo, node) {
+        layerInfo.options.minScale = this.getChildValue(node);
+    },
+
+    /**
+     * Method: write_wmc_Layer
+     * Create a Layer node given a layer object.  This method adds elements
+     *     specific to version 1.1.0.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer.WMS>} Layer object.
+     *
+     * Returns:
+     * {Element} A WMC Layer element node.
+     */
+    write_wmc_Layer: function(layer) {
+        var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(
+            this, [layer]
+        );
+        
+        // min/max scale denominator elements go before the 4th element in v1
+        if(layer.options.resolutions || layer.options.scales ||
+           layer.options.minResolution || layer.options.maxScale) {
+            var minSD = this.createElementNS(
+                this.namespaces.sld, "sld:MinScaleDenominator"
+            );
+            minSD.appendChild(this.createTextNode(layer.maxScale.toPrecision(10)));
+            node.insertBefore(minSD, node.childNodes[3]);
+        }
+        
+        if(layer.options.resolutions || layer.options.scales ||
+           layer.options.maxResolution || layer.options.minScale) {
+            var maxSD = this.createElementNS(
+                this.namespaces.sld, "sld:MaxScaleDenominator"
+            );
+            maxSD.appendChild(this.createTextNode(layer.minScale.toPrecision(10)));
+            node.insertBefore(maxSD, node.childNodes[4]);
+        }
+        
+        return node;
+        
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMC.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,214 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMC
+ * Read and write Web Map Context documents.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WMC = OpenLayers.Class({
+    
+    /**
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.1.0".
+     */
+    defaultVersion: "1.1.0",
+    
+    /**
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
+     */
+    version: null,
+
+    /**
+     * Property: layerOptions
+     * {Object} Default options for layers created by the parser. These
+     *     options are overridden by the options which are read from the 
+     *     capabilities document.
+     */
+    layerOptions: null, 
+
+    /**
+     * Property: layerParams
+     * {Object} Default parameters for layers created by the parser. This
+     *     can be used to override DEFAULT_PARAMS for OpenLayers.Layer.WMS.
+     */
+    layerParams: null,
+    
+    /**
+     * Property: parser
+     * {Object} Instance of the versioned parser.  Cached for multiple read and
+     *     write calls of the same version.
+     */
+    parser: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WMC
+     * Create a new parser for WMC docs.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+        this.options = options;
+    },
+
+    /**
+     * APIMethod: read
+     * Read WMC data from a string, and return an object with map properties
+     *     and a list of layers. 
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     * options - {Object} The options object must contain a map property.  If
+     *     the map property is a string, it must be the id of a dom element
+     *     where the new map will be placed.  If the map property is an
+     *     <OpenLayers.Map>, the layers from the context document will be added
+     *     to the map.
+     *
+     * Returns:
+     * {<OpenLayers.Map>} A map based on the context.
+     */
+    read: function(data, options) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var root = data.documentElement;
+        var version = this.version;
+        if(!version) {
+            version = root.getAttribute("version");
+            if(!version) {
+                version = this.defaultVersion;
+            }
+        }
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.WMC[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a WMC parser for version " +
+                      version;
+            }
+            this.parser = new format(this.options);
+        }
+        var context = this.parser.read(data, options);
+        var map;
+        if(options.map) {
+            this.context = context;
+            if(options.map instanceof OpenLayers.Map) {
+                map = this.mergeContextToMap(context, options.map);
+            } else {
+                map = this.contextToMap(context, options.map);
+            }
+        } else {
+            // not documented as part of the API, provided as a non-API option
+            map = context;
+        }
+        return map;
+    },
+    
+    /**
+     * Method: contextToMap
+     * Create a map given a context object.
+     *
+     * Parameters:
+     * context - {Object} The context object.
+     * id - {String | Element} The dom element or element id that will contain
+     *     the map.
+     *
+     * Returns:
+     * {<OpenLayers.Map>} A map based on the context object.
+     */
+    contextToMap: function(context, id) {
+        var map = new OpenLayers.Map(id, {
+            maxExtent: context.maxExtent,
+            projection: context.projection
+        });
+        map.addLayers(context.layers);
+        map.setCenter(
+            context.bounds.getCenterLonLat(),
+            map.getZoomForExtent(context.bounds, true)
+        );
+        return map;
+    },
+    
+    /**
+     * Method: mergeContextToMap
+     * Add layers from a context object to a map.
+     *
+     * Parameters:
+     * context - {Object} The context object.
+     * map - {<OpenLayers.Map>} The map.
+     *
+     * Returns:
+     * {<OpenLayers.Map>} The same map with layers added.
+     */
+    mergeContextToMap: function(context, map) {
+        map.addLayers(context.layers);
+        return map;
+    },
+
+    /**
+     * APIMethod: write
+     * Write a WMC document given a map.
+     *
+     * Parameters:
+     * obj - {<OpenLayers.Map> | Object} A map or context object.
+     * options - {Object} Optional configuration object.
+     *
+     * Returns:
+     * {String} A WMC document string.
+     */
+    write: function(obj, options) {
+        if(obj.CLASS_NAME == "OpenLayers.Map") {
+            obj = this.mapToContext(obj);
+        }
+        var version = (options && options.version) ||
+                      this.version || this.defaultVersion;
+        if(!this.parser || this.parser.VERSION != version) {
+            var format = OpenLayers.Format.WMC[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!format) {
+                throw "Can't find a WMS capabilities parser for version " +
+                      version;
+            }
+            this.parser = new format(this.options);
+        }
+        var wmc = this.parser.write(obj, options);
+        return wmc;
+    },
+    
+    /**
+     * Method: mapToContext
+     * Create a context object given a map.
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>} The map.
+     *
+     * Returns:
+     * {Object} A context object.
+     */
+    mapToContext: function(map) {
+        var context = {
+            bounds: map.getExtent(),
+            maxExtent: map.maxExtent,
+            projection: map.projection,
+            layers: map.layers,
+            size: map.getSize()
+        };
+        return context;
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMC" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,266 @@
+/**
+ * @requires OpenLayers/Format/WMSCapabilities.js
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities.v1_1
+ * Abstract class not to be instantiated directly.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class(
+    OpenLayers.Format.XML, {
+    
+    /**
+     * Constructor: OpenLayers.Format.WMSCapabilities.v1_1
+     * Create an instance of one of the subclasses.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+        this.options = options;
+    },
+
+    /**
+     * APIMethod: read
+     * Read capabilities data from a string, and return a list of layers. 
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array} List of named layers.
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var capabilities = {};
+        var root = data.documentElement;
+        this.runChildNodes(capabilities, root);
+        return capabilities;
+    },
+    
+    /**
+     * Method: runChildNodes
+     */
+    runChildNodes: function(obj, node) {
+        var children = node.childNodes;
+        var childNode, processor;
+        for(var i=0; i<children.length; ++i) {
+            childNode = children[i];
+            if(childNode.nodeType == 1) {
+                processor = this["read_cap_" + childNode.nodeName];
+                if(processor) {
+                    processor.apply(this, [obj, childNode]);
+                }
+            }
+        }
+    },
+    
+    /**
+     * Method: read_cap_Capability
+     */
+    read_cap_Capability: function(capabilities, node) {
+        var capability = {
+            layers: []
+        };
+        this.runChildNodes(capability, node);
+        capabilities.capability = capability;
+    },
+    
+    /**
+     * Method: read_cap_Request
+     */
+    read_cap_Request: function(obj, node) {
+        var request = {};
+        this.runChildNodes(request, node);
+        obj.request = request;
+    },
+    
+    /**
+     * Method: read_cap_GetMap
+     */
+    read_cap_GetMap: function(request, node) {
+        var getmap = {
+            formats: []
+        };
+        this.runChildNodes(getmap, node);
+        request.getmap = getmap;
+    },
+    
+    /**
+     * Method: read_cap_Format
+     */
+    read_cap_Format: function(obj, node) {
+        if(obj.formats) {
+            obj.formats.push(this.getChildValue(node));
+        }
+    },
+    
+    /**
+     * Method: read_cap_DCPType
+     * Super simplified HTTP href extractor.  Assumes the first online resource
+     *     will work.
+     */
+    read_cap_DCPType: function(obj, node) {
+        var children = node.getElementsByTagName("OnlineResource");
+        if(children.length > 0) {
+            this.read_cap_OnlineResource(obj, children[0]);
+        }
+    },
+
+    /**
+     * Method: read_cap_Service
+     */
+    read_cap_Service: function(capabilities, node) {
+        var service = {};
+        this.runChildNodes(service, node);
+        capabilities.service = service;
+    },
+
+    /**
+     * Method: read_cap_Layer
+     */
+    read_cap_Layer: function(capability, node, parentLayer) {
+        var layer = {
+            formats: capability.request.getmap.formats || [],
+            styles: [],
+            queryable: (node.getAttribute("queryable") === "1" 
+                        || node.getAttribute("queryable") === "true")
+        };
+        // deal with property inheritance
+        if(parentLayer) {
+            // add style
+            layer.styles = layer.styles.concat(parentLayer.styles);
+            // use llbbox
+            layer.llbbox = parentLayer.llbbox;
+            // use min/maxScale
+            layer.minScale = parentLayer.minScale;
+            layer.maxScale = parentLayer.maxScale;
+        }
+        var children = node.childNodes;
+        var childNode, nodeName, processor;
+        for(var i=0; i<children.length; ++i) {
+            childNode = children[i];
+            nodeName = childNode.nodeName;
+            processor = this["read_cap_" + childNode.nodeName];
+            if(processor) {
+                if(nodeName == "Layer") {
+                    processor.apply(this, [capability, childNode, layer]);
+                } else {
+                    processor.apply(this, [layer, childNode]);
+                }
+            }
+        }
+        if(layer.name) {
+            var index = layer.name.indexOf(":");
+            if(index > 0) {
+                layer.prefix = layer.name.substring(0, index);
+            }
+            capability.layers.push(layer);
+        }
+    },
+    
+    /**
+     * Method: read_cap_ScaleHint
+     * The Layer ScaleHint element has min and max attributes that relate to
+     *     the minimum and maximum resolution that the server supports.  The
+     *     values are pixel diagonals measured in meters (on the ground).
+     */
+    read_cap_ScaleHint: function(layer, node) {
+        var min = node.getAttribute("min");
+        var max = node.getAttribute("max");
+        var rad2 = Math.pow(2, 0.5);
+        var ipm = OpenLayers.INCHES_PER_UNIT["m"];
+        layer.maxScale = parseFloat(
+            ((rad2 * min) * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)
+        );
+        layer.minScale = parseFloat(
+            ((rad2 * max) * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)
+        );
+    },
+    
+    /**
+     * Method: read_cap_Name
+     */
+    read_cap_Name: function(obj, node) {
+        var name = this.getChildValue(node);
+        if(name) {
+            obj.name = name;
+        }
+    },
+
+    /**
+     * Method: read_cap_Title
+     */
+    read_cap_Title: function(obj, node) {
+        var title = this.getChildValue(node);
+        if(title) {
+            obj.title = title;
+        }
+    },
+
+    /**
+     * Method: read_cap_Abstract
+     */
+    read_cap_Abstract: function(obj, node) {
+        var abst = this.getChildValue(node);
+        if(abst) {
+            obj["abstract"] = abst;
+        }
+    },
+    
+    /**
+     * Method: read_cap_LatLonBoundingBox
+     */
+    read_cap_LatLonBoundingBox: function(layer, node) {
+        layer.llbbox = [
+            parseFloat(node.getAttribute("minx")),
+            parseFloat(node.getAttribute("miny")),
+            parseFloat(node.getAttribute("maxx")),
+            parseFloat(node.getAttribute("maxy"))
+        ];
+    },
+
+    /**
+     * Method: read_cap_Style
+     */
+    read_cap_Style: function(layer, node) {
+        var style = {};
+        this.runChildNodes(style, node);
+        layer.styles.push(style);
+    },
+
+    /**
+     * Method: read_cap_LegendURL
+     */
+    read_cap_LegendURL: function(style, node) {
+        var legend = {
+            width: node.getAttribute('width'),
+            height: node.getAttribute('height')
+        };
+        var links = node.getElementsByTagName("OnlineResource");
+        if(links.length > 0) {
+            this.read_cap_OnlineResource(legend, links[0]);
+        }
+        style.legend = legend;
+    },
+    
+    /**
+     * Method: read_cap_OnlineResource
+     */
+    read_cap_OnlineResource: function(obj, node) {
+        obj.href = this.getAttributeNS(
+            node, "http://www.w3.org/1999/xlink", "href"
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,37 @@
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1_1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_1_0
+ * Read WMS Capabilities version 1.1.0.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.WMSCapabilities.v1_1>
+ */
+OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class(
+    OpenLayers.Format.WMSCapabilities.v1_1, {
+    
+    /**
+     * Property: version
+     * {String} The specific parser version.
+     */
+    version: "1.1.0",
+    
+    /**
+     * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0
+     * Create a new parser for WMS capabilities version 1.1.0.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,37 @@
+/**
+ * @requires OpenLayers/Format/WMSCapabilities/v1_1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities/v1_1_1
+ * Read WMS Capabilities version 1.1.1.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.WMSCapabilities.v1_1>
+ */
+OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class(
+    OpenLayers.Format.WMSCapabilities.v1_1, {
+    
+    /**
+     * Property: version
+     * {String} The specific parser version.
+     */
+    version: "1.1.1",
+    
+    /**
+     * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1
+     * Create a new parser for WMS capabilities version 1.1.1.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply(
+            this, [options]
+        );
+    },
+
+    CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSCapabilities.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,77 @@
+/**
+ * @requires OpenLayers/Format.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSCapabilities
+ * Read WMS Capabilities.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML, {
+    
+    /**
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.1.1".
+     */
+    defaultVersion: "1.1.1",
+    
+    /**
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
+     */
+    version: null,
+    
+    /**
+     * Property: parser
+     * {<OpenLayers.Format>} A cached versioned format used for reading.
+     */
+    parser: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WMSCapabilities
+     * Create a new parser for WMS capabilities.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+        this.options = options;
+    },
+
+    /**
+     * APIMethod: read
+     * Read capabilities data from a string, and return a list of layers. 
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array} List of named layers.
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var root = data.documentElement;
+        var version = this.version || root.getAttribute("version") || this.defaultVersion;
+        if(!this.parser || this.parser.version !== version) {
+            var constr = OpenLayers.Format.WMSCapabilities[
+                "v" + version.replace(/\./g, "_")
+            ];
+            if(!constr) {
+                throw "Can't find a WMS capabilities parser for version " + version;
+            }
+            var parser = new constr(this.options);
+        }
+        var capabilities = parser.read(data);
+        capabilities.version = version;
+        return capabilities;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.WMSCapabilities" 
+
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSDescribeLayer.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSDescribeLayer.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/WMSDescribeLayer.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,90 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WMSDescribeLayer
+ * Read SLD WMS DescribeLayer response
+ * DescribeLayer is meant to couple WMS to WFS and WCS
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML, {
+
+    /**
+     * APIProperty: defaultVersion
+     * {String} Version number to assume if none found.  Default is "1.1.1".
+     */
+    defaultVersion: "1.1.1",
+   
+    /**
+     * APIProperty: version
+     * {String} Specify a version string if one is known.
+     */
+    version: null,
+
+    /**
+     * Constructor: OpenLayers.Format.WMSDescribeLayer
+     * Create a new parser for WMS DescribeLayer responses.
+     *
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *     this instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+        this.options = options;
+    },
+
+    /**
+     * APIMethod: read
+     * Read DescribeLayer data from a string, and return the response. 
+     * The OGC currently defines 2 formats which are allowed for output,
+     * so we need to parse these 2 types
+     * 
+     * Parameters: 
+     * data - {String} or {DOMElement} data to read/parse.
+     *
+     * Returns:
+     * {Array} Array of {<LayerDescription>} objects which have:
+     * - {String} owsType: WFS/WCS
+     * - {String} owsURL: the online resource
+     * - {String} typeName: the name of the typename on the service
+     */
+    read: function(data) {
+        if(typeof data == "string") {
+            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+        }
+        var root = data.documentElement;
+        var version = this.version;
+        if(!version) {
+            version = root.getAttribute("version");
+            if(!version) {
+                version = this.defaultVersion;
+            }
+        }
+        // these are identical to us, but some WMS use 1.1.1 and some use 1.1.0
+        if (version == "1.1.1" || version == "1.1.0") {
+            version = "1.1";
+        }
+        var constructor = OpenLayers.Format.WMSDescribeLayer[
+            "v" + version.replace(/\./g, "_")
+        ];
+        if(!constructor) {
+            throw "Can't find a WMS DescribeLayer parser for version " + 
+                version;
+        }
+        var parser = new constructor(this.options);
+        var describelayer = parser.read(data);
+        describelayer.version = version;
+        return describelayer;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" 
+
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/XML.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/XML.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format/XML.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,880 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format.js
+ */
+
+/**
+ * Class: OpenLayers.Format.XML
+ * Read and write XML.  For cross-browser XML generation, use methods on an
+ *     instance of the XML format class instead of on <code>document<end>.
+ *     The DOM creation and traversing methods exposed here all mimic the
+ *     W3C XML DOM methods.  Create a new parser with the
+ *     <OpenLayers.Format.XML> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Format>
+ */
+OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
+    
+    /**
+     * Property: namespaces
+     * {Object} Mapping of namespace aliases to namespace URIs.  Properties
+     *     of this object should not be set individually.  Read-only.  All
+     *     XML subclasses should have their own namespaces object.  Use
+     *     <setNamespace> to add or set a namespace alias after construction.
+     */
+    namespaces: null,
+    
+    /**
+     * Property: namespaceAlias
+     * {Object} Mapping of namespace URI to namespace alias.  This object
+     *     is read-only.  Use <setNamespace> to add or set a namespace alias.
+     */
+    namespaceAlias: null,
+    
+    /**
+     * Property: defaultPrefix
+     * {String} The default namespace alias for creating element nodes.
+     */
+    defaultPrefix: null,
+    
+    /**
+     * Property: readers
+     * Contains public functions, grouped by namespace prefix, that will
+     *     be applied when a namespaced node is found matching the function
+     *     name.  The function will be applied in the scope of this parser
+     *     with two arguments: the node being read and a context object passed
+     *     from the parent.
+     */
+    readers: {},
+    
+    /**
+     * Property: writers
+     * As a compliment to the <readers> property, this structure contains public
+     *     writing functions grouped by namespace alias and named like the
+     *     node names they produce.
+     */
+    writers: {},
+
+    /**
+     * Property: xmldom
+     * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
+     *     object.  It is not intended to be a browser sniffing property.
+     *     Instead, the xmldom property is used instead of <code>document<end>
+     *     where namespaced node creation methods are not supported. In all
+     *     other browsers, this remains null.
+     */
+    xmldom: null,
+
+    /**
+     * Constructor: OpenLayers.Format.XML
+     * Construct an XML parser.  The parser is used to read and write XML.
+     *     Reading XML from a string returns a DOM element.  Writing XML from
+     *     a DOM element returns a string.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on
+     *     the object.
+     */
+    initialize: function(options) {
+        if(window.ActiveXObject) {
+            this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
+        }
+        OpenLayers.Format.prototype.initialize.apply(this, [options]);
+        // clone the namespace object and set all namespace aliases
+        this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
+        this.namespaceAlias = {};
+        for(var alias in this.namespaces) {
+            this.namespaceAlias[this.namespaces[alias]] = alias;
+        }
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up.
+     */
+    destroy: function() {
+        this.xmldom = null;
+        OpenLayers.Format.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * Method: setNamespace
+     * Set a namespace alias and URI for the format.
+     *
+     * Parameters:
+     * alias - {String} The namespace alias (prefix).
+     * uri - {String} The namespace URI.
+     */
+    setNamespace: function(alias, uri) {
+        this.namespaces[alias] = uri;
+        this.namespaceAlias[uri] = alias;
+    },
+
+    /**
+     * APIMethod: read
+     * Deserialize a XML string and return a DOM node.
+     *
+     * Parameters:
+     * text - {String} A XML string
+     
+     * Returns:
+     * {DOMElement} A DOM node
+     */
+    read: function(text) {
+        var index = text.indexOf('<');
+        if(index > 0) {
+            text = text.substring(index);
+        }
+        var node = OpenLayers.Util.Try(
+            OpenLayers.Function.bind((
+                function() {
+                    var xmldom;
+                    /**
+                     * Since we want to be able to call this method on the prototype
+                     * itself, this.xmldom may not exist even if in IE.
+                     */
+                    if(window.ActiveXObject && !this.xmldom) {
+                        xmldom = new ActiveXObject("Microsoft.XMLDOM");
+                    } else {
+                        xmldom = this.xmldom;
+                        
+                    }
+                    xmldom.loadXML(text);
+                    return xmldom;
+                }
+            ), this),
+            function() {
+                return new DOMParser().parseFromString(text, 'text/xml');
+            },
+            function() {
+                var req = new XMLHttpRequest();
+                req.open("GET", "data:" + "text/xml" +
+                         ";charset=utf-8," + encodeURIComponent(text), false);
+                if(req.overrideMimeType) {
+                    req.overrideMimeType("text/xml");
+                }
+                req.send(null);
+                return req.responseXML;
+            }
+        );
+
+        if(this.keepData) {
+            this.data = node;
+        }
+
+        return node;
+    },
+
+    /**
+     * APIMethod: write
+     * Serialize a DOM node into a XML string.
+     * 
+     * Parameters:
+     * node - {DOMElement} A DOM node.
+     *
+     * Returns:
+     * {String} The XML string representation of the input node.
+     */
+    write: function(node) {
+        var data;
+        if(this.xmldom) {
+            data = node.xml;
+        } else {
+            var serializer = new XMLSerializer();
+            if (node.nodeType == 1) {
+                // Add nodes to a document before serializing. Everything else
+                // is serialized as is. This may need more work. See #1218 .
+                var doc = document.implementation.createDocument("", "", null);
+                if (doc.importNode) {
+                    node = doc.importNode(node, true);
+                }
+                doc.appendChild(node);
+                data = serializer.serializeToString(doc);
+            } else {
+                data = serializer.serializeToString(node);
+            }
+        }
+        return data;
+    },
+
+    /**
+     * APIMethod: createElementNS
+     * Create a new element with namespace.  This node can be appended to
+     *     another node with the standard node.appendChild method.  For
+     *     cross-browser support, this method must be used instead of
+     *     document.createElementNS.
+     *
+     * Parameters:
+     * uri - {String} Namespace URI for the element.
+     * name - {String} The qualified name of the element (prefix:localname).
+     * 
+     * Returns:
+     * {Element} A DOM element with namespace.
+     */
+    createElementNS: function(uri, name) {
+        var element;
+        if(this.xmldom) {
+            if(typeof uri == "string") {
+                element = this.xmldom.createNode(1, name, uri);
+            } else {
+                element = this.xmldom.createNode(1, name, "");
+            }
+        } else {
+            element = document.createElementNS(uri, name);
+        }
+        return element;
+    },
+
+    /**
+     * APIMethod: createTextNode
+     * Create a text node.  This node can be appended to another node with
+     *     the standard node.appendChild method.  For cross-browser support,
+     *     this method must be used instead of document.createTextNode.
+     * 
+     * Parameters:
+     * text - {String} The text of the node.
+     * 
+     * Returns: 
+     * {DOMElement} A DOM text node.
+     */
+    createTextNode: function(text) {
+        var node;
+        if(this.xmldom) {
+            node = this.xmldom.createTextNode(text);
+        } else {
+            node = document.createTextNode(text);
+        }
+        return node;
+    },
+
+    /**
+     * APIMethod: getElementsByTagNameNS
+     * Get a list of elements on a node given the namespace URI and local name.
+     *     To return all nodes in a given namespace, use '*' for the name
+     *     argument.  To return all nodes of a given (local) name, regardless
+     *     of namespace, use '*' for the uri argument.
+     * 
+     * Parameters:
+     * node - {Element} Node on which to search for other nodes.
+     * uri - {String} Namespace URI.
+     * name - {String} Local name of the tag (without the prefix).
+     * 
+     * Returns:
+     * {NodeList} A node list or array of elements.
+     */
+    getElementsByTagNameNS: function(node, uri, name) {
+        var elements = [];
+        if(node.getElementsByTagNameNS) {
+            elements = node.getElementsByTagNameNS(uri, name);
+        } else {
+            // brute force method
+            var allNodes = node.getElementsByTagName("*");
+            var potentialNode, fullName;
+            for(var i=0, len=allNodes.length; i<len; ++i) {
+                potentialNode = allNodes[i];
+                fullName = (potentialNode.prefix) ?
+                           (potentialNode.prefix + ":" + name) : name;
+                if((name == "*") || (fullName == potentialNode.nodeName)) {
+                    if((uri == "*") || (uri == potentialNode.namespaceURI)) {
+                        elements.push(potentialNode);
+                    }
+                }
+            }
+        }
+        return elements;
+    },
+
+    /**
+     * APIMethod: getAttributeNodeNS
+     * Get an attribute node given the namespace URI and local name.
+     * 
+     * Parameters:
+     * node - {Element} Node on which to search for attribute nodes.
+     * uri - {String} Namespace URI.
+     * name - {String} Local name of the attribute (without the prefix).
+     * 
+     * Returns:
+     * {DOMElement} An attribute node or null if none found.
+     */
+    getAttributeNodeNS: function(node, uri, name) {
+        var attributeNode = null;
+        if(node.getAttributeNodeNS) {
+            attributeNode = node.getAttributeNodeNS(uri, name);
+        } else {
+            var attributes = node.attributes;
+            var potentialNode, fullName;
+            for(var i=0, len=attributes.length; i<len; ++i) {
+                potentialNode = attributes[i];
+                if(potentialNode.namespaceURI == uri) {
+                    fullName = (potentialNode.prefix) ?
+                               (potentialNode.prefix + ":" + name) : name;
+                    if(fullName == potentialNode.nodeName) {
+                        attributeNode = potentialNode;
+                        break;
+                    }
+                }
+            }
+        }
+        return attributeNode;
+    },
+
+    /**
+     * APIMethod: getAttributeNS
+     * Get an attribute value given the namespace URI and local name.
+     * 
+     * Parameters:
+     * node - {Element} Node on which to search for an attribute.
+     * uri - {String} Namespace URI.
+     * name - {String} Local name of the attribute (without the prefix).
+     * 
+     * Returns:
+     * {String} An attribute value or and empty string if none found.
+     */
+    getAttributeNS: function(node, uri, name) {
+        var attributeValue = "";
+        if(node.getAttributeNS) {
+            attributeValue = node.getAttributeNS(uri, name) || "";
+        } else {
+            var attributeNode = this.getAttributeNodeNS(node, uri, name);
+            if(attributeNode) {
+                attributeValue = attributeNode.nodeValue;
+            }
+        }
+        return attributeValue;
+    },
+    
+    /**
+     * APIMethod: getChildValue
+     * Get the textual value of the node if it exists, or return an
+     *     optional default string.  Returns an empty string if no first child
+     *     exists and no default value is supplied.
+     *
+     * Parameters:
+     * node - {DOMElement} The element used to look for a first child value.
+     * def - {String} Optional string to return in the event that no
+     *     first child value exists.
+     *
+     * Returns:
+     * {String} The value of the first child of the given node.
+     */
+    getChildValue: function(node, def) {
+        var value = def || "";
+        if(node) {
+            for(var child=node.firstChild; child; child=child.nextSibling) {
+                switch(child.nodeType) {
+                    case 3: // text node
+                    case 4: // cdata section
+                        value += child.nodeValue;
+                }
+            }
+        }
+        return value;
+    },
+
+    /**
+     * APIMethod: concatChildValues
+     * *Deprecated*. Use <getChildValue> instead.
+     *
+     * Concatenate the value of all child nodes if any exist, or return an
+     *     optional default string.  Returns an empty string if no children
+     *     exist and no default value is supplied.  Not optimized for large
+     *     numbers of child nodes.
+     *
+     * Parameters:
+     * node - {DOMElement} The element used to look for child values.
+     * def - {String} Optional string to return in the event that no
+     *     child exist.
+     *
+     * Returns:
+     * {String} The concatenated value of all child nodes of the given node.
+     */
+    concatChildValues: function(node, def) {
+        var value = "";
+        var child = node.firstChild;
+        var childValue;
+        while(child) {
+            childValue = child.nodeValue;
+            if(childValue) {
+                value += childValue;
+            }
+            child = child.nextSibling;
+        }
+        if(value == "" && def != undefined) {
+            value = def;
+        }
+        return value;
+    },
+    
+    /**
+     * APIMethod: isSimpleContent
+     * Test if the given node has only simple content (i.e. no child element
+     *     nodes).
+     *
+     * Parameters:
+     * node - {DOMElement} An element node.
+     *
+     * Returns:
+     * {Boolean} The node has no child element nodes (nodes of type 1). 
+     */
+    isSimpleContent: function(node) {
+        var simple = true;
+        for(var child=node.firstChild; child; child=child.nextSibling) {
+            if(child.nodeType === 1) {
+                simple = false;
+                break;
+            }
+        }
+        return simple;
+    },
+    
+    /**
+     * APIMethod: contentType
+     * Determine the content type for a given node.
+     *
+     * Parameters:
+     * node - {DOMElement}
+     *
+     * Returns:
+     * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
+     *     if the node has no, simple, complex, or mixed content.
+     */
+    contentType: function(node) {
+        var simple = false,
+            complex = false;
+            
+        var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
+
+        for(var child=node.firstChild; child; child=child.nextSibling) {
+            switch(child.nodeType) {
+                case 1: // element
+                    complex = true;
+                    break;
+                case 8: // comment
+                    break;
+                default:
+                    simple = true;
+            }
+            if(complex && simple) {
+                break;
+            }
+        }
+        
+        if(complex && simple) {
+            type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
+        } else if(complex) {
+            return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
+        } else if(simple) {
+            return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
+        }
+        return type;
+    },
+
+    /**
+     * APIMethod: hasAttributeNS
+     * Determine whether a node has a particular attribute matching the given
+     *     name and namespace.
+     * 
+     * Parameters:
+     * node - {Element} Node on which to search for an attribute.
+     * uri - {String} Namespace URI.
+     * name - {String} Local name of the attribute (without the prefix).
+     * 
+     * Returns:
+     * {Boolean} The node has an attribute matching the name and namespace.
+     */
+    hasAttributeNS: function(node, uri, name) {
+        var found = false;
+        if(node.hasAttributeNS) {
+            found = node.hasAttributeNS(uri, name);
+        } else {
+            found = !!this.getAttributeNodeNS(node, uri, name);
+        }
+        return found;
+    },
+    
+    /**
+     * APIMethod: setAttributeNS
+     * Adds a new attribute or changes the value of an attribute with the given
+     *     namespace and name.
+     *
+     * Parameters:
+     * node - {Element} Element node on which to set the attribute.
+     * uri - {String} Namespace URI for the attribute.
+     * name - {String} Qualified name (prefix:localname) for the attribute.
+     * value - {String} Attribute value.
+     */
+    setAttributeNS: function(node, uri, name, value) {
+        if(node.setAttributeNS) {
+            node.setAttributeNS(uri, name, value);
+        } else {
+            if(this.xmldom) {
+                if(uri) {
+                    var attribute = node.ownerDocument.createNode(
+                        2, name, uri
+                    );
+                    attribute.nodeValue = value;
+                    node.setAttributeNode(attribute);
+                } else {
+                    node.setAttribute(name, value);
+                }
+            } else {
+                throw "setAttributeNS not implemented";
+            }
+        }
+    },
+
+    /**
+     * Method: createElementNSPlus
+     * Shorthand for creating namespaced elements with optional attributes and
+     *     child text nodes.
+     *
+     * Parameters:
+     * name - {String} The qualified node name.
+     * options - {Object} Optional object for node configuration.
+     *
+     * Valid options:
+     * uri - {String} Optional namespace uri for the element - supply a prefix
+     *     instead if the namespace uri is a property of the format's namespace
+     *     object.
+     * attributes - {Object} Optional attributes to be set using the
+     *     <setAttributes> method.
+     * value - {String} Optional text to be appended as a text node.
+     *
+     * Returns:
+     * {Element} An element node.
+     */
+    createElementNSPlus: function(name, options) {
+        options = options || {};
+        // order of prefix preference
+        // 1. in the uri option
+        // 2. in the prefix option
+        // 3. in the qualified name
+        // 4. from the defaultPrefix
+        var uri = options.uri || this.namespaces[options.prefix];
+        if(!uri) {
+            var loc = name.indexOf(":");
+            uri = this.namespaces[name.substring(0, loc)];
+        }
+        if(!uri) {
+            uri = this.namespaces[this.defaultPrefix];
+        }
+        var node = this.createElementNS(uri, name);
+        if(options.attributes) {
+            this.setAttributes(node, options.attributes);
+        }
+        var value = options.value;
+        if(value != null) {
+            if(typeof value == "boolean") {
+                value = String(value);
+            }
+            node.appendChild(this.createTextNode(value));
+        }
+        return node;
+    },
+    
+    /**
+     * Method: setAttributes
+     * Set multiple attributes given key value pairs from an object.
+     *
+     * Parameters:
+     * node - {Element} An element node.
+     * obj - {Object || Array} An object whose properties represent attribute
+     *     names and values represent attribute values.  If an attribute name
+     *     is a qualified name ("prefix:local"), the prefix will be looked up
+     *     in the parsers {namespaces} object.  If the prefix is found,
+     *     setAttributeNS will be used instead of setAttribute.
+     */
+    setAttributes: function(node, obj) {
+        var value, uri;
+        for(var name in obj) {
+            if(obj[name] != null && obj[name].toString) {
+                value = obj[name].toString();
+                // check for qualified attribute name ("prefix:local")
+                uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
+                this.setAttributeNS(node, uri, name, value);
+            }
+        }
+    },
+
+    /**
+     * Method: readNode
+     * Shorthand for applying one of the named readers given the node
+     *     namespace and local name.  Readers take two args (node, obj) and
+     *     generally extend or modify the second.
+     *
+     * Parameters:
+     * node - {DOMElement} The node to be read (required).
+     * obj - {Object} The object to be modified (optional).
+     *
+     * Returns:
+     * {Object} The input object, modified (or a new one if none was provided).
+     */
+    readNode: function(node, obj) {
+        if(!obj) {
+            obj = {};
+        }
+        var group = this.readers[this.namespaceAlias[node.namespaceURI]];
+        if(group) {
+            var local = node.localName || node.nodeName.split(":").pop();
+            var reader = group[local] || group["*"];
+            if(reader) {
+                reader.apply(this, [node, obj]);
+            }
+        }
+        return obj;
+    },
+
+    /**
+     * Method: readChildNodes
+     * Shorthand for applying the named readers to all children of a node.
+     *     For each child of type 1 (element), <readSelf> is called.
+     *
+     * Parameters:
+     * node - {DOMElement} The node to be read (required).
+     * obj - {Object} The object to be modified (optional).
+     *
+     * Returns:
+     * {Object} The input object, modified.
+     */
+    readChildNodes: function(node, obj) {
+        if(!obj) {
+            obj = {};
+        }
+        var children = node.childNodes;
+        var child;
+        for(var i=0, len=children.length; i<len; ++i) {
+            child = children[i];
+            if(child.nodeType == 1) {
+                this.readNode(child, obj);
+            }
+        }
+        return obj;
+    },
+
+    /**
+     * Method: writeNode
+     * Shorthand for applying one of the named writers and appending the
+     *     results to a node.  If a qualified name is not provided for the
+     *     second argument (and a local name is used instead), the namespace
+     *     of the parent node will be assumed.
+     *
+     * Parameters:
+     * name - {String} The name of a node to generate.  If a qualified name
+     *     (e.g. "pre:Name") is used, the namespace prefix is assumed to be
+     *     in the <writers> group.  If a local name is used (e.g. "Name") then
+     *     the namespace of the parent is assumed.  If a local name is used
+     *     and no parent is supplied, then the default namespace is assumed.
+     * obj - {Object} Structure containing data for the writer.
+     * parent - {DOMElement} Result will be appended to this node.  If no parent
+     *     is supplied, the node will not be appended to anything.
+     *
+     * Returns:
+     * {DOMElement} The child node.
+     */
+    writeNode: function(name, obj, parent) {
+        var prefix, local;
+        var split = name.indexOf(":");
+        if(split > 0) {
+            prefix = name.substring(0, split);
+            local = name.substring(split + 1);
+        } else {
+            if(parent) {
+                prefix = this.namespaceAlias[parent.namespaceURI];
+            } else {
+                prefix = this.defaultPrefix;
+            }
+            local = name;
+        }
+        var child = this.writers[prefix][local].apply(this, [obj]);
+        if(parent) {
+            parent.appendChild(child);
+        }
+        return child;
+    },
+
+    /**
+     * APIMethod: getChildEl
+     * Get the first child element.  Optionally only return the first child
+     *     if it matches the given name and namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The parent node.
+     * name - {String} Optional node name (local) to search for.
+     * uri - {String} Optional namespace URI to search for.
+     *
+     * Returns:
+     * {DOMElement} The first child.  Returns null if no element is found, if
+     *     something significant besides an element is found, or if the element
+     *     found does not match the optional name and uri.
+     */
+    getChildEl: function(node, name, uri) {
+        return node && this.getThisOrNextEl(node.firstChild, name, uri);
+    },
+    
+    /**
+     * APIMethod: getNextEl
+     * Get the next sibling element.  Optionally get the first sibling only
+     *     if it matches the given local name and namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The node.
+     * name - {String} Optional local name of the sibling to search for.
+     * uri - {String} Optional namespace URI of the sibling to search for.
+     *
+     * Returns:
+     * {DOMElement} The next sibling element.  Returns null if no element is
+     *     found, something significant besides an element is found, or the
+     *     found element does not match the optional name and uri.
+     */
+    getNextEl: function(node, name, uri) {
+        return node && this.getThisOrNextEl(node.nextSibling, name, uri);
+    },
+    
+    /**
+     * Method: getThisOrNextEl
+     * Return this node or the next element node.  Optionally get the first
+     *     sibling with the given local name or namespace URI.
+     *
+     * Parameters:
+     * node - {DOMElement} The node.
+     * name - {String} Optional local name of the sibling to search for.
+     * uri - {String} Optional namespace URI of the sibling to search for.
+     *
+     * Returns:
+     * {DOMElement} The next sibling element.  Returns null if no element is
+     *     found, something significant besides an element is found, or the
+     *     found element does not match the query.
+     */
+    getThisOrNextEl: function(node, name, uri) {
+        outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
+            switch(sibling.nodeType) {
+                case 1: // Element
+                    if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
+                       (!uri || uri === sibling.namespaceURI)) {
+                        // matches
+                        break outer;
+                    }
+                    sibling = null;
+                    break outer;
+                case 3: // Text
+                    if(/^\s*$/.test(sibling.nodeValue)) {
+                        break;
+                    }
+                case 4: // CDATA
+                case 6: // ENTITY_NODE
+                case 12: // NOTATION_NODE
+                case 10: // DOCUMENT_TYPE_NODE
+                case 11: // DOCUMENT_FRAGMENT_NODE
+                    sibling = null;
+                    break outer;
+            } // ignore comments and processing instructions
+        }
+        return sibling || null;
+    },
+    
+    /**
+     * APIMethod: lookupNamespaceURI
+     * Takes a prefix and returns the namespace URI associated with it on the given
+     *     node if found (and null if not). Supplying null for the prefix will
+     *     return the default namespace.
+     *
+     * For browsers that support it, this calls the native lookupNamesapceURI
+     *     function.  In other browsers, this is an implementation of
+     *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+     *
+     * For browsers that don't support the attribute.ownerElement property, this
+     *     method cannot be called on attribute nodes.
+     *     
+     * Parameters:
+     * node - {DOMElement} The node from which to start looking.
+     * prefix - {String} The prefix to lookup or null to lookup the default namespace.
+     * 
+     * Returns:
+     * {String} The namespace URI for the given prefix.  Returns null if the prefix
+     *     cannot be found or the node is the wrong type.
+     */
+    lookupNamespaceURI: function(node, prefix) {
+        var uri = null;
+        if(node) {
+            if(node.lookupNamespaceURI) {
+                uri = node.lookupNamespaceURI(prefix);
+            } else {
+                outer: switch(node.nodeType) {
+                    case 1: // ELEMENT_NODE
+                        if(node.namespaceURI !== null && node.prefix === prefix) {
+                            uri = node.namespaceURI;
+                            break outer;
+                        }
+                        var len = node.attributes.length;
+                        if(len) {
+                            var attr;
+                            for(var i=0; i<len; ++i) {
+                                attr = node.attributes[i];
+                                if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
+                                    uri = attr.value || null;
+                                    break outer;
+                                } else if(attr.name === "xmlns" && prefix === null) {
+                                    uri = attr.value || null;
+                                    break outer;
+                                }
+                            }
+                        }
+                        uri = this.lookupNamespaceURI(node.parentNode, prefix);
+                        break outer;
+                    case 2: // ATTRIBUTE_NODE
+                        uri = this.lookupNamespaceURI(node.ownerElement, prefix);
+                        break outer;
+                    case 9: // DOCUMENT_NODE
+                        uri = this.lookupNamespaceURI(node.documentElement, prefix);
+                        break outer;
+                    case 6: // ENTITY_NODE
+                    case 12: // NOTATION_NODE
+                    case 10: // DOCUMENT_TYPE_NODE
+                    case 11: // DOCUMENT_FRAGMENT_NODE
+                        break outer;
+                    default: 
+                        // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
+                        // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
+                        uri =  this.lookupNamespaceURI(node.parentNode, prefix);
+                        break outer;
+                }
+            }
+        }
+        return uri;
+    },
+    
+    CLASS_NAME: "OpenLayers.Format.XML" 
+
+});     
+
+OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
+
+/**
+ * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
+ * Takes a prefix and returns the namespace URI associated with it on the given
+ *     node if found (and null if not). Supplying null for the prefix will
+ *     return the default namespace.
+ *
+ * For browsers that support it, this calls the native lookupNamesapceURI
+ *     function.  In other browsers, this is an implementation of
+ *     http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+ *
+ * For browsers that don't support the attribute.ownerElement property, this
+ *     method cannot be called on attribute nodes.
+ *     
+ * Parameters:
+ * node - {DOMElement} The node from which to start looking.
+ * prefix - {String} The prefix to lookup or null to lookup the default namespace.
+ * 
+ * Returns:
+ * {String} The namespace URI for the given prefix.  Returns null if the prefix
+ *     cannot be found or the node is the wrong type.
+ */
+OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
+    OpenLayers.Format.XML.prototype.lookupNamespaceURI,
+    OpenLayers.Format.XML.prototype
+);

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Format.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,122 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Format
+ * Base class for format reading/writing a variety of formats.  Subclasses
+ *     of OpenLayers.Format are expected to have read and write methods.
+ */
+OpenLayers.Format = OpenLayers.Class({
+    
+    /**
+     * Property: options
+     * {Object} A reference to options passed to the constructor.
+     */
+    options: null,
+    
+    /**
+     * APIProperty: externalProjection
+     * {<OpenLayers.Projection>} When passed a externalProjection and
+     *     internalProjection, the format will reproject the geometries it
+     *     reads or writes. The externalProjection is the projection used by
+     *     the content which is passed into read or which comes out of write.
+     *     In order to reproject, a projection transformation function for the
+     *     specified projections must be available. This support may be 
+     *     provided via proj4js or via a custom transformation function. See
+     *     {<OpenLayers.Projection.addTransform>} for more information on
+     *     custom transformations.
+     */
+    externalProjection: null,
+
+    /**
+     * APIProperty: internalProjection
+     * {<OpenLayers.Projection>} When passed a externalProjection and
+     *     internalProjection, the format will reproject the geometries it
+     *     reads or writes. The internalProjection is the projection used by
+     *     the geometries which are returned by read or which are passed into
+     *     write.  In order to reproject, a projection transformation function
+     *     for the specified projections must be available. This support may be
+     *     provided via proj4js or via a custom transformation function. See
+     *     {<OpenLayers.Projection.addTransform>} for more information on
+     *     custom transformations.
+     */
+    internalProjection: null,
+
+    /**
+     * APIProperty: data
+     * {Object} When <keepData> is true, this is the parsed string sent to
+     *     <read>.
+     */
+    data: null,
+
+    /**
+     * APIProperty: keepData
+     * {Object} Maintain a reference (<data>) to the most recently read data.
+     *     Default is false.
+     */
+    keepData: false,
+
+    /**
+     * Constructor: OpenLayers.Format
+     * Instances of this class are not useful.  See one of the subclasses.
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           format
+     *
+     * Valid options:
+     * keepData - {Boolean} If true, upon <read>, the data property will be
+     *     set to the parsed object (e.g. the json or xml object).
+     *
+     * Returns:
+     * An instance of OpenLayers.Format
+     */
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+        this.options = options;
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up.
+     */
+    destroy: function() {
+    },
+
+    /**
+     * Method: read
+     * Read data from a string, and return an object whose type depends on the
+     * subclass. 
+     * 
+     * Parameters:
+     * data - {string} Data to read/parse.
+     *
+     * Returns:
+     * Depends on the subclass
+     */
+    read: function(data) {
+        OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
+    },
+    
+    /**
+     * Method: write
+     * Accept an object, and return a string. 
+     *
+     * Parameters:
+     * object - {Object} Object to be serialized
+     *
+     * Returns:
+     * {String} A string representation of the object.
+     */
+    write: function(object) {
+        OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
+    },
+
+    CLASS_NAME: "OpenLayers.Format"
+});     

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/LinearRing.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/LinearRing.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/LinearRing.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,414 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.LinearRing
+ * 
+ * A Linear Ring is a special LineString which is closed. It closes itself 
+ * automatically on every addPoint/removePoint by adding a copy of the first
+ * point as the last point. 
+ * 
+ * Also, as it is the first in the line family to close itself, a getArea()
+ * function is defined to calculate the enclosed area of the linearRing
+ * 
+ * Inherits:
+ *  - <OpenLayers.Geometry.LineString>
+ */
+OpenLayers.Geometry.LinearRing = OpenLayers.Class(
+  OpenLayers.Geometry.LineString, {
+
+    /**
+     * Property: componentTypes
+     * {Array(String)} 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.
+     */
+    componentTypes: ["OpenLayers.Geometry.Point"],
+
+    /**
+     * Constructor: OpenLayers.Geometry.LinearRing
+     * 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.
+     * 
+     * Parameters:
+     * points - {Array(<OpenLayers.Geometry.Point>)} points
+     */
+    initialize: function(points) {
+        OpenLayers.Geometry.LineString.prototype.initialize.apply(this, 
+                                                                  arguments);
+    },
+
+    /**
+     * APIMethod: addComponent
+     * 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.
+     *
+     * Parameter:
+     * point - {<OpenLayers.Geometry.Point>}
+     * index - {Integer} Index into the array to insert the component
+     * 
+     * Returns:
+     * {Boolean} Was the Point successfully added?
+     */
+    addComponent: function(point, index) {
+        var added = false;
+
+        //remove last point
+        var lastPoint = this.components.pop();
+
+        // 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.Collection.prototype.addComponent.apply(this, 
+                                                                [firstPoint]);
+        
+        return added;
+    },
+    
+    /**
+     * APIMethod: removeComponent
+     * Removes a point from geometry components.
+     *
+     * Parameters:
+     * point - {<OpenLayers.Geometry.Point>}
+     */
+    removeComponent: function(point) {
+        if (this.components.length > 4) {
+
+            //remove last point
+            this.components.pop();
+            
+            //remove our point
+            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
+                                                                    arguments);
+            //append copy of first point
+            var firstPoint = this.components[0];
+            OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
+                                                                [firstPoint]);
+        }
+    },
+    
+    /**
+     * APIMethod: move
+     * Moves a geometry by the given displacement along positive x and y axes.
+     *     This modifies the position of the geometry and clears the cached
+     *     bounds.
+     *
+     * Parameters:
+     * x - {Float} Distance to move geometry in positive x direction. 
+     * y - {Float} Distance to move geometry in positive y direction.
+     */
+    move: function(x, y) {
+        for(var i = 0, len=this.components.length; i<len - 1; i++) {
+            this.components[i].move(x, y);
+        }
+    },
+
+    /**
+     * APIMethod: rotate
+     * Rotate a geometry around some origin
+     *
+     * Parameters:
+     * angle - {Float} Rotation angle in degrees (measured counterclockwise
+     *                 from the positive x-axis)
+     * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
+     */
+    rotate: function(angle, origin) {
+        for(var i=0, len=this.components.length; i<len - 1; ++i) {
+            this.components[i].rotate(angle, origin);
+        }
+    },
+
+    /**
+     * APIMethod: resize
+     * Resize a geometry relative to some origin.  Use this method to apply
+     *     a uniform scaling to a geometry.
+     *
+     * Parameters:
+     * scale - {Float} Factor by which to scale the geometry.  A scale of 2
+     *                 doubles the size of the geometry in each dimension
+     *                 (lines, for example, will be twice as long, and polygons
+     *                 will have four times the area).
+     * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
+     * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
+     * 
+     * Returns:
+     * {OpenLayers.Geometry} - The current geometry. 
+     */
+    resize: function(scale, origin, ratio) {
+        for(var i=0, len=this.components.length; i<len - 1; ++i) {
+            this.components[i].resize(scale, origin, ratio);
+        }
+        return this;
+    },
+    
+    /**
+     * APIMethod: transform
+     * Reproject the components geometry from source to dest.
+     *
+     * Parameters:
+     * source - {<OpenLayers.Projection>}
+     * dest - {<OpenLayers.Projection>}
+     * 
+     * Returns:
+     * {<OpenLayers.Geometry>} 
+     */
+    transform: function(source, dest) {
+        if (source && dest) {
+            for (var i=0, len=this.components.length; i<len - 1; i++) {
+                var component = this.components[i];
+                component.transform(source, dest);
+            }
+            this.bounds = null;
+        }
+        return this;
+    },
+    
+    /**
+     * APIMethod: getCentroid
+     *
+     * Returns:
+     * {<OpenLayers.Geometry.Point>} The centroid of the collection
+     */
+    getCentroid: function() {
+        if ( this.components && (this.components.length > 2)) {
+            var sumX = 0.0;
+            var sumY = 0.0;
+            for (var i = 0; i < this.components.length - 1; i++) {
+                var b = this.components[i];
+                var c = this.components[i+1];
+                sumX += (b.x + c.x) * (b.x * c.y - c.x * b.y);
+                sumY += (b.y + c.y) * (b.x * c.y - c.x * b.y);
+            }
+            var area = -1 * this.getArea();
+            var x = sumX / (6 * area);
+            var y = sumY / (6 * area);
+        }
+        return new OpenLayers.Geometry.Point(x, y);
+    },
+
+    /**
+     * APIMethod: getArea
+     * Note - The area is positive if the ring is oriented CW, otherwise
+     *         it will be negative.
+     * 
+     * Returns:
+     * {Float} The signed area for a ring.
+     */
+    getArea: function() {
+        var area = 0.0;
+        if ( this.components && (this.components.length > 2)) {
+            var sum = 0.0;
+            for (var i=0, len=this.components.length; i<len - 1; i++) {
+                var b = this.components[i];
+                var c = this.components[i+1];
+                sum += (b.x + c.x) * (c.y - b.y);
+            }
+            area = - sum / 2.0;
+        }
+        return area;
+    },
+    
+    /**
+     * APIMethod: getGeodesicArea
+     * Calculate the approximate area of the polygon were it projected onto
+     *     the earth.  Note that this area will be positive if ring is oriented
+     *     clockwise, otherwise it will be negative.
+     *
+     * Parameters:
+     * projection - {<OpenLayers.Projection>} The spatial reference system
+     *     for the geometry coordinates.  If not provided, Geographic/WGS84 is
+     *     assumed.
+     * 
+     * Reference:
+     * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
+     *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
+     *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
+     *
+     * Returns:
+     * {float} The approximate signed geodesic area of the polygon in square
+     *     meters.
+     */
+    getGeodesicArea: function(projection) {
+        var ring = this;  // so we can work with a clone if needed
+        if(projection) {
+            var gg = new OpenLayers.Projection("EPSG:4326");
+            if(!gg.equals(projection)) {
+                ring = this.clone().transform(projection, gg);
+            }
+        }
+        var area = 0.0;
+        var len = ring.components && ring.components.length;
+        if(len > 2) {
+            var p1, p2;
+            for(var i=0; i<len-1; i++) {
+                p1 = ring.components[i];
+                p2 = ring.components[i+1];
+                area += OpenLayers.Util.rad(p2.x - p1.x) *
+                        (2 + Math.sin(OpenLayers.Util.rad(p1.y)) +
+                        Math.sin(OpenLayers.Util.rad(p2.y)));
+            }
+            area = area * 6378137.0 * 6378137.0 / 2.0;
+        }
+        return area;
+    },
+    
+    /**
+     * Method: containsPoint
+     * Test if a point is inside a linear ring.  For the case where a point
+     *     is coincident with a linear ring edge, returns 1.  Otherwise,
+     *     returns boolean.
+     *
+     * Parameters:
+     * point - {<OpenLayers.Geometry.Point>}
+     *
+     * Returns:
+     * {Boolean | Number} The point is inside the linear ring.  Returns 1 if
+     *     the point is coincident with an edge.  Returns boolean otherwise.
+     */
+    containsPoint: function(point) {
+        var approx = OpenLayers.Number.limitSigDigs;
+        var digs = 14;
+        var px = approx(point.x, digs);
+        var py = approx(point.y, digs);
+        function getX(y, x1, y1, x2, y2) {
+            return (((x1 - x2) * y) + ((x2 * y1) - (x1 * y2))) / (y1 - y2);
+        }
+        var numSeg = this.components.length - 1;
+        var start, end, x1, y1, x2, y2, cx, cy;
+        var crosses = 0;
+        for(var i=0; i<numSeg; ++i) {
+            start = this.components[i];
+            x1 = approx(start.x, digs);
+            y1 = approx(start.y, digs);
+            end = this.components[i + 1];
+            x2 = approx(end.x, digs);
+            y2 = approx(end.y, digs);
+            
+            /**
+             * The following conditions enforce five edge-crossing rules:
+             *    1. points coincident with edges are considered contained;
+             *    2. an upward edge includes its starting endpoint, and
+             *    excludes its final endpoint;
+             *    3. a downward edge excludes its starting endpoint, and
+             *    includes its final endpoint;
+             *    4. horizontal edges are excluded; and
+             *    5. the edge-ray intersection point must be strictly right
+             *    of the point P.
+             */
+            if(y1 == y2) {
+                // horizontal edge
+                if(py == y1) {
+                    // point on horizontal line
+                    if(x1 <= x2 && (px >= x1 && px <= x2) || // right or vert
+                       x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert
+                        // point on edge
+                        crosses = -1;
+                        break;
+                    }
+                }
+                // ignore other horizontal edges
+                continue;
+            }
+            cx = approx(getX(py, x1, y1, x2, y2), digs);
+            if(cx == px) {
+                // point on line
+                if(y1 < y2 && (py >= y1 && py <= y2) || // upward
+                   y1 > y2 && (py <= y1 && py >= y2)) { // downward
+                    // point on edge
+                    crosses = -1;
+                    break;
+                }
+            }
+            if(cx <= px) {
+                // no crossing to the right
+                continue;
+            }
+            if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) {
+                // no crossing
+                continue;
+            }
+            if(y1 < y2 && (py >= y1 && py < y2) || // upward
+               y1 > y2 && (py < y1 && py >= y2)) { // downward
+                ++crosses;
+            }
+        }
+        var contained = (crosses == -1) ?
+            // on edge
+            1 :
+            // even (out) or odd (in)
+            !!(crosses & 1);
+
+        return contained;
+    },
+
+    /**
+     * APIMethod: intersects
+     * Determine if the input geometry intersects this one.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>} Any type of geometry.
+     *
+     * Returns:
+     * {Boolean} The input geometry intersects this one.
+     */
+    intersects: function(geometry) {
+        var intersect = false;
+        if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+            intersect = this.containsPoint(geometry);
+        } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
+            intersect = geometry.intersects(this);
+        } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
+            intersect = OpenLayers.Geometry.LineString.prototype.intersects.apply(
+                this, [geometry]
+            );
+        } else {
+            // check for component intersections
+            for(var i=0, len=geometry.components.length; i<len; ++ i) {
+                intersect = geometry.components[i].intersects(this);
+                if(intersect) {
+                    break;
+                }
+            }
+        }
+        return intersect;
+    },
+
+    /**
+     * APIMethod: getVertices
+     * Return a list of all points in this geometry.
+     *
+     * Parameters:
+     * nodes - {Boolean} For lines, only return vertices that are
+     *     endpoints.  If false, for lines, only vertices that are not
+     *     endpoints will be returned.  If not provided, all vertices will
+     *     be returned.
+     *
+     * Returns:
+     * {Array} A list of all vertices in the geometry.
+     */
+    getVertices: function(nodes) {
+        return (nodes === true) ? [] : this.components.slice(0, this.components.length-1);
+    },
+
+    CLASS_NAME: "OpenLayers.Geometry.LinearRing"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiLineString.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiLineString.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiLineString.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,261 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry/Collection.js
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.MultiLineString
+ * A MultiLineString is a geometry with multiple <OpenLayers.Geometry.LineString>
+ * components.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Geometry.Collection>
+ *  - <OpenLayers.Geometry> 
+ */
+OpenLayers.Geometry.MultiLineString = OpenLayers.Class(
+  OpenLayers.Geometry.Collection, {
+
+    /**
+     * Property: componentTypes
+     * {Array(String)} 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.
+     */
+    componentTypes: ["OpenLayers.Geometry.LineString"],
+
+    /**
+     * Constructor: OpenLayers.Geometry.MultiLineString
+     * Constructor for a MultiLineString Geometry.
+     *
+     * Parameters: 
+     * components - {Array(<OpenLayers.Geometry.LineString>)} 
+     *
+     */
+    initialize: function(components) {
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);        
+    },
+    
+    /**
+     * Method: split
+     * Use this geometry (the source) to attempt to split a target geometry.
+     * 
+     * Parameters:
+     * target - {<OpenLayers.Geometry>} The target geometry.
+     * options - {Object} Properties of this object will be used to determine
+     *     how the split is conducted.
+     *
+     * Valid options:
+     * mutual - {Boolean} Split the source geometry in addition to the target
+     *     geometry.  Default is false.
+     * edge - {Boolean} Allow splitting when only edges intersect.  Default is
+     *     true.  If false, a vertex on the source must be within the tolerance
+     *     distance of the intersection to be considered a split.
+     * tolerance - {Number} If a non-null value is provided, intersections
+     *     within the tolerance distance of an existing vertex on the source
+     *     will be assumed to occur at the vertex.
+     * 
+     * Returns:
+     * {Array} A list of geometries (of this same type as the target) that
+     *     result from splitting the target with the source geometry.  The
+     *     source and target geometry will remain unmodified.  If no split
+     *     results, null will be returned.  If mutual is true and a split
+     *     results, return will be an array of two arrays - the first will be
+     *     all geometries that result from splitting the source geometry and
+     *     the second will be all geometries that result from splitting the
+     *     target geometry.
+     */
+    split: function(geometry, options) {
+        var results = null;
+        var mutual = options && options.mutual;
+        var splits, sourceLine, sourceLines, sourceSplit, targetSplit;
+        var sourceParts = [];
+        var targetParts = [geometry];
+        for(var i=0, len=this.components.length; i<len; ++i) {
+            sourceLine = this.components[i];
+            sourceSplit = false;
+            for(var j=0; j < targetParts.length; ++j) { 
+                splits = sourceLine.split(targetParts[j], options);
+                if(splits) {
+                    if(mutual) {
+                        sourceLines = splits[0];
+                        for(var k=0, klen=sourceLines.length; k<klen; ++k) {
+                            if(k===0 && sourceParts.length) {
+                                sourceParts[sourceParts.length-1].addComponent(
+                                    sourceLines[k]
+                                );
+                            } else {
+                                sourceParts.push(
+                                    new OpenLayers.Geometry.MultiLineString([
+                                        sourceLines[k]
+                                    ])
+                                );
+                            }
+                        }
+                        sourceSplit = true;
+                        splits = splits[1];
+                    }
+                    if(splits.length) {
+                        // splice in new target parts
+                        splits.unshift(j, 1);
+                        Array.prototype.splice.apply(targetParts, splits);
+                        break;
+                    }
+                }
+            }
+            if(!sourceSplit) {
+                // source line was not hit
+                if(sourceParts.length) {
+                    // add line to existing multi
+                    sourceParts[sourceParts.length-1].addComponent(
+                        sourceLine.clone()
+                    );
+                } else {
+                    // create a fresh multi
+                    sourceParts = [
+                        new OpenLayers.Geometry.MultiLineString(
+                            sourceLine.clone()
+                        )
+                    ];
+                }
+            }
+        }
+        if(sourceParts && sourceParts.length > 1) {
+            sourceSplit = true;
+        } else {
+            sourceParts = [];
+        }
+        if(targetParts && targetParts.length > 1) {
+            targetSplit = true;
+        } else {
+            targetParts = [];
+        }
+        if(sourceSplit || targetSplit) {
+            if(mutual) {
+                results = [sourceParts, targetParts];
+            } else {
+                results = targetParts;
+            }
+        }
+        return results;
+    },
+    
+    /**
+     * Method: splitWith
+     * Split this geometry (the target) with the given geometry (the source).
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>} A geometry used to split this
+     *     geometry (the source).
+     * options - {Object} Properties of this object will be used to determine
+     *     how the split is conducted.
+     *
+     * Valid options:
+     * mutual - {Boolean} Split the source geometry in addition to the target
+     *     geometry.  Default is false.
+     * edge - {Boolean} Allow splitting when only edges intersect.  Default is
+     *     true.  If false, a vertex on the source must be within the tolerance
+     *     distance of the intersection to be considered a split.
+     * tolerance - {Number} If a non-null value is provided, intersections
+     *     within the tolerance distance of an existing vertex on the source
+     *     will be assumed to occur at the vertex.
+     * 
+     * Returns:
+     * {Array} A list of geometries (of this same type as the target) that
+     *     result from splitting the target with the source geometry.  The
+     *     source and target geometry will remain unmodified.  If no split
+     *     results, null will be returned.  If mutual is true and a split
+     *     results, return will be an array of two arrays - the first will be
+     *     all geometries that result from splitting the source geometry and
+     *     the second will be all geometries that result from splitting the
+     *     target geometry.
+     */
+    splitWith: function(geometry, options) {
+        var results = null;
+        var mutual = options && options.mutual;
+        var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts;
+        if(geometry instanceof OpenLayers.Geometry.LineString) {
+            targetParts = [];
+            sourceParts = [geometry];
+            for(var i=0, len=this.components.length; i<len; ++i) {
+                targetSplit = false;
+                targetLine = this.components[i];
+                for(var j=0; j<sourceParts.length; ++j) {
+                    splits = sourceParts[j].split(targetLine, options);
+                    if(splits) {
+                        if(mutual) {
+                            sourceLines = splits[0];
+                            if(sourceLines.length) {
+                                // splice in new source parts
+                                sourceLines.unshift(j, 1);
+                                Array.prototype.splice.apply(sourceParts, sourceLines);
+                                j += sourceLines.length - 2;
+                            }
+                            splits = splits[1];
+                            if(splits.length === 0) {
+                                splits = [targetLine.clone()];
+                            }
+                        }
+                        for(var k=0, klen=splits.length; k<klen; ++k) {
+                            if(k===0 && targetParts.length) {
+                                targetParts[targetParts.length-1].addComponent(
+                                    splits[k]
+                                );
+                            } else {
+                                targetParts.push(
+                                    new OpenLayers.Geometry.MultiLineString([
+                                        splits[k]
+                                    ])
+                                );
+                            }
+                        }
+                        targetSplit = true;                    
+                    }
+                }
+                if(!targetSplit) {
+                    // target component was not hit
+                    if(targetParts.length) {
+                        // add it to any existing multi-line
+                        targetParts[targetParts.length-1].addComponent(
+                            targetLine.clone()
+                        );
+                    } else {
+                        // or start with a fresh multi-line
+                        targetParts = [
+                            new OpenLayers.Geometry.MultiLineString([
+                                targetLine.clone()
+                            ])
+                        ];
+                    }
+                    
+                }
+            }
+        } else {
+            results = geometry.split(this);
+        }
+        if(sourceParts && sourceParts.length > 1) {
+            sourceSplit = true;
+        } else {
+            sourceParts = [];
+        }
+        if(targetParts && targetParts.length > 1) {
+            targetSplit = true;
+        } else {
+            targetParts = [];
+        }
+        if(sourceSplit || targetSplit) {
+            if(mutual) {
+                results = [sourceParts, targetParts];
+            } else {
+                results = targetParts;
+            }
+        }
+        return results;
+    },
+
+    CLASS_NAME: "OpenLayers.Geometry.MultiLineString"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiPolygon.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiPolygon.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/MultiPolygon.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,45 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry/Collection.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.MultiPolygon
+ * MultiPolygon is a geometry with multiple <OpenLayers.Geometry.Polygon>
+ * components.  Create a new instance with the <OpenLayers.Geometry.MultiPolygon>
+ * constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Geometry.Collection>
+ */
+OpenLayers.Geometry.MultiPolygon = OpenLayers.Class(
+  OpenLayers.Geometry.Collection, {
+
+    /**
+     * Property: componentTypes
+     * {Array(String)} 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.
+     */
+    componentTypes: ["OpenLayers.Geometry.Polygon"],
+
+    /**
+     * Constructor: OpenLayers.Geometry.MultiPolygon
+     * Create a new MultiPolygon geometry
+     *
+     * Parameters:
+     * components - {Array(<OpenLayers.Geometry.Polygon>)} An array of polygons
+     *              used to generate the MultiPolygon
+     *
+     */
+    initialize: function(components) {
+        OpenLayers.Geometry.Collection.prototype.initialize.apply(this, 
+                                                                  arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Geometry.MultiPolygon"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Point.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Point.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Point.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,282 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.Point
+ * Point geometry class. 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Geometry> 
+ */
+OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, {
+
+    /** 
+     * APIProperty: x 
+     * {float} 
+     */
+    x: null,
+
+    /** 
+     * APIProperty: y 
+     * {float} 
+     */
+    y: null,
+
+    /**
+     * Constructor: OpenLayers.Geometry.Point
+     * Construct a point geometry.
+     *
+     * Parameters:
+     * x - {float} 
+     * y - {float}
+     * 
+     */
+    initialize: function(x, y) {
+        OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
+        
+        this.x = parseFloat(x);
+        this.y = parseFloat(y);
+    },
+
+    /**
+     * APIMethod: clone
+     * 
+     * Returns:
+     * {<OpenLayers.Geometry.Point>} An exact clone of this OpenLayers.Geometry.Point
+     */
+    clone: function(obj) {
+        if (obj == null) {
+            obj = new OpenLayers.Geometry.Point(this.x, this.y);
+        }
+
+        // catch any randomly tagged-on properties
+        OpenLayers.Util.applyDefaults(obj, this);
+
+        return obj;
+    },
+
+    /** 
+     * Method: calculateBounds
+     * Create a new Bounds based on the lon/lat
+     */
+    calculateBounds: function () {
+        this.bounds = new OpenLayers.Bounds(this.x, this.y,
+                                            this.x, this.y);
+    },
+
+    /**
+     * APIMethod: distanceTo
+     * Calculate the closest distance between two geometries (on the x-y plane).
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>} The target geometry.
+     * options - {Object} Optional properties for configuring the distance
+     *     calculation.
+     *
+     * Valid options:
+     * details - {Boolean} Return details from the distance calculation.
+     *     Default is false.
+     * edge - {Boolean} Calculate the distance from this geometry to the
+     *     nearest edge of the target geometry.  Default is true.  If true,
+     *     calling distanceTo from a geometry that is wholly contained within
+     *     the target will result in a non-zero distance.  If false, whenever
+     *     geometries intersect, calling distanceTo will return 0.  If false,
+     *     details cannot be returned.
+     *
+     * Returns:
+     * {Number | Object} The distance between this geometry and the target.
+     *     If details is true, the return will be an object with distance,
+     *     x0, y0, x1, and x2 properties.  The x0 and y0 properties represent
+     *     the coordinates of the closest point on this geometry. The x1 and y1
+     *     properties represent the coordinates of the closest point on the
+     *     target geometry.
+     */
+    distanceTo: function(geometry, options) {
+        var edge = !(options && options.edge === false);
+        var details = edge && options && options.details;
+        var distance, x0, y0, x1, y1, result;
+        if(geometry instanceof OpenLayers.Geometry.Point) {
+            x0 = this.x;
+            y0 = this.y;
+            x1 = geometry.x;
+            y1 = geometry.y;
+            distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
+            result = !details ?
+                distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance};
+        } else {
+            result = geometry.distanceTo(this, options);
+            if(details) {
+                // switch coord order since this geom is target
+                result = {
+                    x0: result.x1, y0: result.y1,
+                    x1: result.x0, y1: result.y0,
+                    distance: result.distance
+                };
+            }
+        }
+        return result;
+    },
+    
+    /** 
+     * APIMethod: equals
+     * Determine whether another geometry is equivalent to this one.  Geometries
+     *     are considered equivalent if all components have the same coordinates.
+     * 
+     * Parameters:
+     * geom - {<OpenLayers.Geometry.Point>} The geometry to test. 
+     *
+     * Returns:
+     * {Boolean} The supplied geometry is equivalent to this geometry.
+     */
+    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;
+    },
+    
+    /**
+     * Method: toShortString
+     *
+     * Returns:
+     * {String} Shortened String representation of Point object. 
+     *         (ex. <i>"5, 42"</i>)
+     */
+    toShortString: function() {
+        return (this.x + ", " + this.y);
+    },
+    
+    /**
+     * APIMethod: move
+     * Moves a geometry by the given displacement along positive x and y axes.
+     *     This modifies the position of the geometry and clears the cached
+     *     bounds.
+     *
+     * Parameters:
+     * x - {Float} Distance to move geometry in positive x direction. 
+     * y - {Float} Distance to move geometry in positive y direction.
+     */
+    move: function(x, y) {
+        this.x = this.x + x;
+        this.y = this.y + y;
+        this.clearBounds();
+    },
+
+    /**
+     * APIMethod: rotate
+     * Rotate a point around another.
+     *
+     * Parameters:
+     * angle - {Float} Rotation angle in degrees (measured counterclockwise
+     *                 from the positive x-axis)
+     * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
+     */
+    rotate: function(angle, origin) {
+        angle *= Math.PI / 180;
+        var radius = this.distanceTo(origin);
+        var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x);
+        this.x = origin.x + (radius * Math.cos(theta));
+        this.y = origin.y + (radius * Math.sin(theta));
+        this.clearBounds();
+    },
+    
+    /**
+     * APIMethod: getCentroid
+     *
+     * Returns:
+     * {<OpenLayers.Geometry.Point>} The centroid of the collection
+     */
+    getCentroid: function() {
+        return new OpenLayers.Geometry.Point(this.x, this.y);
+    },
+
+    /**
+     * APIMethod: resize
+     * Resize a point relative to some origin.  For points, this has the effect
+     *     of scaling a vector (from the origin to the point).  This method is
+     *     more useful on geometry collection subclasses.
+     *
+     * Parameters:
+     * scale - {Float} Ratio of the new distance from the origin to the old
+     *                 distance from the origin.  A scale of 2 doubles the
+     *                 distance between the point and origin.
+     * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
+     * ratio - {Float} Optional x:y ratio for resizing.  Default ratio is 1.
+     * 
+     * Returns:
+     * {OpenLayers.Geometry} - The current geometry. 
+     */
+    resize: function(scale, origin, ratio) {
+        ratio = (ratio == undefined) ? 1 : ratio;
+        this.x = origin.x + (scale * ratio * (this.x - origin.x));
+        this.y = origin.y + (scale * (this.y - origin.y));
+        this.clearBounds();
+        return this;
+    },
+    
+    /**
+     * APIMethod: intersects
+     * Determine if the input geometry intersects this one.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>} Any type of geometry.
+     *
+     * Returns:
+     * {Boolean} The input geometry intersects this one.
+     */
+    intersects: function(geometry) {
+        var intersect = false;
+        if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+            intersect = this.equals(geometry);
+        } else {
+            intersect = geometry.intersects(this);
+        }
+        return intersect;
+    },
+    
+    /**
+     * APIMethod: transform
+     * Translate the x,y properties of the point from source to dest.
+     * 
+     * Parameters:
+     * source - {<OpenLayers.Projection>} 
+     * dest - {<OpenLayers.Projection>}
+     * 
+     * Returns:
+     * {<OpenLayers.Geometry>} 
+     */
+    transform: function(source, dest) {
+        if ((source && dest)) {
+            OpenLayers.Projection.transform(
+                this, source, dest); 
+            this.bounds = null;
+        }       
+        return this;
+    },
+
+    /**
+     * APIMethod: getVertices
+     * Return a list of all points in this geometry.
+     *
+     * Parameters:
+     * nodes - {Boolean} For lines, only return vertices that are
+     *     endpoints.  If false, for lines, only vertices that are not
+     *     endpoints will be returned.  If not provided, all vertices will
+     *     be returned.
+     *
+     * Returns:
+     * {Array} A list of all vertices in the geometry.
+     */
+    getVertices: function(nodes) {
+        return [this];
+    },
+
+    CLASS_NAME: "OpenLayers.Geometry.Point"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Rectangle.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Rectangle.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Rectangle.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,98 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.Rectangle
+ * This class is *not supported*, and probably isn't what you're looking for.
+ *     Instead, most users probably want something like:
+ *     (code)
+ *     var poly = new OpenLayers.Bounds(0,0,10,10).toGeometry();
+ *     (end)
+ *     This will create a rectangular Polygon geometry. 
+ * 
+ * Inherits:
+ *  - <OpenLayers.Geometry>
+ */
+
+OpenLayers.Geometry.Rectangle = OpenLayers.Class(OpenLayers.Geometry, {
+
+    /** 
+     * Property: x
+     * {Float}
+     */
+    x: null,
+
+    /** 
+     * Property: y
+     * {Float}
+     */
+    y: null,
+
+    /** 
+     * Property: width
+     * {Float}
+     */
+    width: null,
+
+    /** 
+     * Property: height
+     * {Float}
+     */
+    height: null,
+
+    /**
+     * Constructor: OpenLayers.Geometry.Rectangle
+     * 
+     * Parameters:
+     * points - {Array(<OpenLayers.Geometry.Point>}
+     */
+    initialize: function(x, y, width, height) {
+        OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
+        
+        this.x = x;
+        this.y = y;
+
+        this.width = width;
+        this.height = height;
+    },
+    
+    /**
+     * Method: calculateBounds
+     * Recalculate the bounds for the geometry.
+     */
+    calculateBounds: function() {
+        this.bounds = new OpenLayers.Bounds(this.x, this.y,
+                                            this.x + this.width, 
+                                            this.y + this.height);
+    },
+    
+    
+    /**
+     * APIMethod: getLength
+     * 
+     * Returns:
+     * {Float} The length of the geometry
+     */
+    getLength: function() {
+        var length = (2 * this.width) + (2 * this.height);
+        return length;
+    },
+
+    /**
+     * APIMethod: getArea
+     * 
+     * Returns:
+     * {Float} The area of the geometry
+     */
+    getArea: function() {
+        var area = this.width * this.height;
+        return area;
+    },    
+
+    CLASS_NAME: "OpenLayers.Geometry.Rectangle"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Surface.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Surface.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Geometry/Surface.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,16 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry.js
+ */
+
+OpenLayers.Geometry.Surface = OpenLayers.Class(OpenLayers.Geometry, {
+
+    initialize: function() {
+        OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Geometry.Surface"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Box.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Box.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Box.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,209 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Box
+ * Handler for dragging a rectangle across the map.  Box is displayed 
+ * on mouse down, moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler> 
+ */
+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
+
+    /** 
+     * Property: dragHandler 
+     * {<OpenLayers.Handler.Drag>} 
+     */
+    dragHandler: null,
+
+    /**
+     * APIProperty: boxDivClassName
+     * {String} The CSS class to use for drawing the box. Default is
+     *     olHandlerBoxZoomBox
+     */
+    boxDivClassName: 'olHandlerBoxZoomBox',
+    
+    /**
+     * Property: boxCharacteristics
+     * {Object} Caches some box characteristics from css. This is used
+     *     by the getBoxCharacteristics method.
+     */
+    boxCharacteristics: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Box
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} 
+     * callbacks - {Object} An object containing a single function to be
+     *                          called when the drag operation is finished.
+     *                          The callback should expect to recieve a single
+     *                          argument, the point geometry.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        var callbacks = {
+            "down": this.startBox, 
+            "move": this.moveBox, 
+            "out":  this.removeBox,
+            "up":   this.endBox
+        };
+        this.dragHandler = new OpenLayers.Handler.Drag(
+                                this, callbacks, {keyMask: this.keyMask});
+    },
+
+    /**
+     * Method: setMap
+     */
+    setMap: function (map) {
+        OpenLayers.Handler.prototype.setMap.apply(this, arguments);
+        if (this.dragHandler) {
+            this.dragHandler.setMap(map);
+        }
+    },
+
+    /**
+    * Method: startBox
+    *
+    * Parameters:
+    * evt - {Event} 
+    */
+    startBox: function (xy) {
+        this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+                                                 this.dragHandler.start);
+        this.zoomBox.className = this.boxDivClassName;                                         
+        this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+        this.map.viewPortDiv.appendChild(this.zoomBox);
+
+        OpenLayers.Element.addClass(
+            this.map.viewPortDiv, "olDrawBox"
+        );
+    },
+
+    /**
+    * Method: moveBox
+    */
+    moveBox: function (xy) {
+        var startX = this.dragHandler.start.x;
+        var startY = this.dragHandler.start.y;
+        var deltaX = Math.abs(startX - xy.x);
+        var deltaY = Math.abs(startY - xy.y);
+        this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+        this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+        this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
+        this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
+
+        // depending on the box model, modify width and height to take borders
+        // of the box into account
+        var box = this.getBoxCharacteristics();
+        if (box.newBoxModel) {
+            if (xy.x > startX) {
+                this.zoomBox.style.width =
+                    Math.max(1, deltaX - box.xOffset) + "px";
+            }
+            if (xy.y > startY) {
+                this.zoomBox.style.height =
+                    Math.max(1, deltaY - box.yOffset) + "px";
+            }
+        }
+    },
+
+    /**
+    * Method: endBox
+    */
+    endBox: function(end) {
+        var result;
+        if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||    
+            Math.abs(this.dragHandler.start.y - end.y) > 5) {   
+            var start = this.dragHandler.start;
+            var top = Math.min(start.y, end.y);
+            var bottom = Math.max(start.y, end.y);
+            var left = Math.min(start.x, end.x);
+            var right = Math.max(start.x, end.x);
+            result = new OpenLayers.Bounds(left, bottom, right, top);
+        } else {
+            result = this.dragHandler.start.clone(); // i.e. OL.Pixel
+        } 
+        this.removeBox();
+
+        this.callback("done", [result]);
+    },
+
+    /**
+     * Method: removeBox
+     * Remove the zoombox from the screen and nullify our reference to it.
+     */
+    removeBox: function() {
+        this.map.viewPortDiv.removeChild(this.zoomBox);
+        this.zoomBox = null;
+        this.boxCharacteristics = null;
+        OpenLayers.Element.removeClass(
+            this.map.viewPortDiv, "olDrawBox"
+        );
+
+    },
+
+    /**
+     * Method: activate
+     */
+    activate: function () {
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragHandler.activate();
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Method: deactivate
+     */
+    deactivate: function () {
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.dragHandler.deactivate();
+            return true;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: getCharacteristics
+     * Determines offset and box model for a box.
+     * 
+     * Returns:
+     * {Object} a hash with the following properties:
+     *     - xOffset - Corner offset in x-direction
+     *     - yOffset - Corner offset in y-direction
+     *     - newBoxModel - true for all browsers except IE in quirks mode
+     */
+    getBoxCharacteristics: function() {
+        if (!this.boxCharacteristics) {
+            var xOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
+                "border-left-width")) + parseInt(OpenLayers.Element.getStyle(
+                this.zoomBox, "border-right-width")) + 1;
+            var yOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
+                "border-top-width")) + parseInt(OpenLayers.Element.getStyle(
+                this.zoomBox, "border-bottom-width")) + 1;
+            // all browsers use the new box model, except IE in quirks mode
+            var newBoxModel = OpenLayers.Util.getBrowserName() == "msie" ?
+                document.compatMode != "BackCompat" : true;
+            this.boxCharacteristics = {
+                xOffset: xOffset,
+                yOffset: yOffset,
+                newBoxModel: newBoxModel
+            };
+        }
+        return this.boxCharacteristics;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Box"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Click.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Click.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Click.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,324 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Click
+ * A handler for mouse clicks.  The intention of this handler is to give
+ *     controls more flexibility with handling clicks.  Browsers trigger
+ *     click events twice for a double-click.  In addition, the mousedown,
+ *     mousemove, mouseup sequence fires a click event.  With this handler,
+ *     controls can decide whether to ignore clicks associated with a double
+ *     click.  By setting a <pixelTolerance>, controls can also ignore clicks
+ *     that include a drag.  Create a new instance with the
+ *     <OpenLayers.Handler.Click> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler> 
+ */
+OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
+
+    /**
+     * APIProperty: delay
+     * {Number} Number of milliseconds between clicks before the event is
+     *     considered a double-click.
+     */
+    delay: 300,
+    
+    /**
+     * APIProperty: single
+     * {Boolean} Handle single clicks.  Default is true.  If false, clicks
+     * will not be reported.  If true, single-clicks will be reported.
+     */
+    single: true,
+    
+    /**
+     * APIProperty: double
+     * {Boolean} Handle double-clicks.  Default is false.
+     */
+    'double': false,
+    
+    /**
+     * APIProperty: pixelTolerance
+     * {Number} Maximum number of pixels between mouseup and mousedown for an
+     *     event to be considered a click.  Default is 0.  If set to an
+     *     integer value, clicks with a drag greater than the value will be
+     *     ignored.  This property can only be set when the handler is
+     *     constructed.
+     */
+    pixelTolerance: 0,
+    
+    /**
+     * APIProperty: stopSingle
+     * {Boolean} Stop other listeners from being notified of clicks.  Default
+     *     is false.  If true, any click listeners registered before this one
+     *     will not be notified of *any* click event (associated with double
+     *     or single clicks).
+     */
+    stopSingle: false,
+    
+    /**
+     * APIProperty: stopDouble
+     * {Boolean} Stop other listeners from being notified of double-clicks.
+     *     Default is false.  If true, any click listeners registered before
+     *     this one will not be notified of *any* double-click events.
+     * 
+     * The one caveat with stopDouble is that given a map with two click
+     *     handlers, one with stopDouble true and the other with stopSingle
+     *     true, the stopSingle handler should be activated last to get
+     *     uniform cross-browser performance.  Since IE triggers one click
+     *     with a dblclick and FF triggers two, if a stopSingle handler is
+     *     activated first, all it gets in IE is a single click when the
+     *     second handler stops propagation on the dblclick.
+     */
+    stopDouble: false,
+
+    /**
+     * Property: timerId
+     * {Number} The id of the timeout waiting to clear the <delayedCall>.
+     */
+    timerId: null,
+    
+    /**
+     * Property: down
+     * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
+     */
+    down: null,
+    
+    /**
+     * Property: rightclickTimerId
+     * {Number} The id of the right mouse timeout waiting to clear the 
+     *     <delayedEvent>.
+     */
+    rightclickTimerId: null,
+    
+    /**
+     * Constructor: OpenLayers.Handler.Click
+     * Create a new click handler.
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that is making use of
+     *     this handler.  If a handler is being used without a control, the
+     *     handler's setMap method must be overridden to deal properly with
+     *     the map.
+     * callbacks - {Object} An object with keys corresponding to callbacks
+     *     that will be called by the handler. The callbacks should
+     *     expect to recieve a single argument, the click event.
+     *     Callbacks for 'click' and 'dblclick' are supported.
+     * options - {Object} Optional object whose properties will be set on the
+     *     handler.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        // optionally register for mouseup and mousedown
+        if(this.pixelTolerance != null) {
+            this.mousedown = function(evt) {
+                this.down = evt.xy;
+                return true;
+            };
+        }
+    },
+    
+    /**
+     * Method: mousedown
+     * Handle mousedown.  Only registered as a listener if pixelTolerance is
+     *     a non-zero value at construction.
+     *
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    mousedown: null,
+
+    /**
+     * Method: mouseup
+     * Handle mouseup.  Installed to support collection of right mouse events.
+     * 
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    mouseup:  function (evt) {
+        var propagate = true;
+
+        // Collect right mouse clicks from the mouseup
+        //  IE - ignores the second right click in mousedown so using
+        //  mouseup instead
+        if (this.checkModifiers(evt) && 
+            this.control.handleRightClicks && 
+            OpenLayers.Event.isRightClick(evt)) {
+          propagate = this.rightclick(evt);
+        }
+
+        return propagate;
+    },
+    
+    /**
+     * Method: rightclick
+     * Handle rightclick.  For a dblrightclick, we get two clicks so we need 
+     *     to always register for dblrightclick to properly handle single 
+     *     clicks.
+     *     
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    rightclick: function(evt) {
+        if(this.passesTolerance(evt)) {
+           if(this.rightclickTimerId != null) {
+                //Second click received before timeout this must be 
+                // a double click
+                this.clearTimer();      
+                this.callback('dblrightclick', [evt]);
+                return !this.stopDouble;
+            } else { 
+                //Set the rightclickTimerId, send evt only if double is 
+                // true else trigger single
+                var clickEvent = this['double'] ?
+                    OpenLayers.Util.extend({}, evt) : 
+                    this.callback('rightclick', [evt]);
+
+                var delayedRightCall = OpenLayers.Function.bind(
+                    this.delayedRightCall, 
+                    this, 
+                    clickEvent
+                );
+                this.rightclickTimerId = window.setTimeout(
+                    delayedRightCall, this.delay
+                );
+            } 
+        }
+        return !this.stopSingle;
+    },
+    
+    /**
+     * Method: delayedRightCall
+     * Sets <rightclickTimerId> to null.  And optionally triggers the 
+     *     rightclick callback if evt is set.
+     */
+    delayedRightCall: function(evt) {
+        this.rightclickTimerId = null;
+        if (evt) {
+           this.callback('rightclick', [evt]);
+        }
+        return !this.stopSingle;
+    },
+    
+    /**
+     * Method: dblclick
+     * Handle dblclick.  For a dblclick, we get two clicks in some browsers
+     *     (FF) and one in others (IE).  So we need to always register for
+     *     dblclick to properly handle single clicks.
+     *     
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    dblclick: function(evt) {
+        if(this.passesTolerance(evt)) {
+            if(this["double"]) {
+                this.callback('dblclick', [evt]);
+            }
+            this.clearTimer();
+        }
+        return !this.stopDouble;
+    },
+    
+    /**
+     * Method: click
+     * Handle click.
+     *
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    click: function(evt) {
+        if(this.passesTolerance(evt)) {
+            if(this.timerId != null) {
+                // already received a click
+                this.clearTimer();
+            } else {
+                // set the timer, send evt only if single is true
+                //use a clone of the event object because it will no longer 
+                //be a valid event object in IE in the timer callback
+                var clickEvent = this.single ?
+                    OpenLayers.Util.extend({}, evt) : null;
+                this.timerId = window.setTimeout(
+                    OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
+                    this.delay
+                );
+            }
+        }
+        return !this.stopSingle;
+    },
+    
+    /**
+     * Method: passesTolerance
+     * Determine whether the event is within the optional pixel tolerance.  Note
+     *     that the pixel tolerance check only works if mousedown events get to
+     *     the listeners registered here.  If they are stopped by other elements,
+     *     the <pixelTolerance> will have no effect here (this method will always
+     *     return true).
+     *
+     * Returns:
+     * {Boolean} The click is within the pixel tolerance (if specified).
+     */
+    passesTolerance: function(evt) {
+        var passes = true;
+        if(this.pixelTolerance != null && this.down) {
+            var dpx = Math.sqrt(
+                Math.pow(this.down.x - evt.xy.x, 2) +
+                Math.pow(this.down.y - evt.xy.y, 2)
+            );
+            if(dpx > this.pixelTolerance) {
+                passes = false;
+            }
+        }
+        return passes;
+    },
+
+    /**
+     * Method: clearTimer
+     * Clear the timer and set <timerId> to null.
+     */
+    clearTimer: function() {
+        if(this.timerId != null) {
+            window.clearTimeout(this.timerId);
+            this.timerId = null;
+        }
+        if(this.rightclickTimerId != null) {
+            window.clearTimeout(this.rightclickTimerId);
+            this.rightclickTimerId = null;
+        }
+    },
+    
+    /**
+     * Method: delayedCall
+     * Sets <timerId> to null.  And optionally triggers the click callback if
+     *     evt is set.
+     */
+    delayedCall: function(evt) {
+        this.timerId = null;
+        if(evt) {
+            this.callback('click', [evt]);
+        }
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Deactivate the handler.
+     *
+     * Returns:
+     * {Boolean} The handler was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.clearTimer();
+            this.down = null;
+            deactivated = true;
+        }
+        return deactivated;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Click"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Drag.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Drag.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Drag.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,350 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Drag
+ * The drag handler is used to deal with sequences of browser events related
+ *     to dragging.  The handler is used by controls that want to know when
+ *     a drag sequence begins, when a drag is happening, and when it has
+ *     finished.
+ *
+ * Controls that use the drag handler typically construct it with callbacks
+ *     for 'down', 'move', and 'done'.  Callbacks for these keys are called
+ *     when the drag begins, with each move, and when the drag is done.  In
+ *     addition, controls can have callbacks keyed to 'up' and 'out' if they
+ *     care to differentiate between the types of events that correspond with
+ *     the end of a drag sequence.  If no drag actually occurs (no mouse move)
+ *     the 'down' and 'up' callbacks will be called, but not the 'done'
+ *     callback.
+ *
+ * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
+  
+    /** 
+     * Property: started
+     * {Boolean} When a mousedown event is received, we want to record it, but
+     *     not set 'dragging' until the mouse moves after starting. 
+     */
+    started: false,
+    
+    /**
+     * Property: stopDown
+     * {Boolean} Stop propagation of mousedown events from getting to listeners
+     *     on the same element.  Default is true.
+     */
+    stopDown: true,
+
+    /** 
+     * Property: dragging 
+     * {Boolean} 
+     */
+    dragging: false,
+
+    /** 
+     * Property: last
+     * {<OpenLayers.Pixel>} The last pixel location of the drag.
+     */
+    last: null,
+
+    /** 
+     * Property: start
+     * {<OpenLayers.Pixel>} The first pixel location of the drag.
+     */
+    start: null,
+
+    /**
+     * Property: oldOnselectstart
+     * {Function}
+     */
+    oldOnselectstart: null,
+    
+    /**
+     * Property: interval
+     * {Integer} In order to increase performance, an interval (in 
+     *     milliseconds) can be set to reduce the number of drag events 
+     *     called. If set, a new drag event will not be set until the 
+     *     interval has passed. 
+     *     Defaults to 0, meaning no interval. 
+     */
+    interval: 0,
+    
+    /**
+     * Property: timeoutId
+     * {String} The id of the timeout used for the mousedown interval.
+     *     This is "private", and should be left alone.
+     */
+    timeoutId: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Drag
+     * Returns OpenLayers.Handler.Drag
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that is making use of
+     *     this handler.  If a handler is being used without a control, the
+     *     handlers setMap method must be overridden to deal properly with
+     *     the map.
+     * callbacks - {Object} An object containing a single function to be
+     *     called when the drag operation is finished. The callback should
+     *     expect to recieve a single argument, the pixel location of the event.
+     *     Callbacks for 'move' and 'done' are supported. You can also speficy
+     *     callbacks for 'down', 'up', and 'out' to respond to those events.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * The four methods below (down, move, up, and out) are used by subclasses
+     *     to do their own processing related to these mouse events.
+     */
+    
+    /**
+     * Method: down
+     * This method is called during the handling of the mouse down event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse down event
+     */
+    down: function(evt) {
+    },
+    
+    /**
+     * Method: move
+     * This method is called during the handling of the mouse move event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse move event
+     *
+     */
+    move: function(evt) {
+    },
+
+    /**
+     * Method: up
+     * This method is called during the handling of the mouse up event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse up event
+     */
+    up: function(evt) {
+    },
+
+    /**
+     * Method: out
+     * This method is called during the handling of the mouse out event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse out event
+     */
+    out: function(evt) {
+    },
+
+    /**
+     * The methods below are part of the magic of event handling.  Because
+     *     they are named like browser events, they are registered as listeners
+     *     for the events they represent.
+     */
+
+    /**
+     * Method: mousedown
+     * Handle mousedown events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mousedown: function (evt) {
+        var propagate = true;
+        this.dragging = false;
+        if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
+            this.started = true;
+            this.start = evt.xy;
+            this.last = evt.xy;
+            OpenLayers.Element.addClass(
+                this.map.viewPortDiv, "olDragDown"
+            );
+            this.down(evt);
+            this.callback("down", [evt.xy]);
+            OpenLayers.Event.stop(evt);
+            
+            if(!this.oldOnselectstart) {
+                this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : function() { return true; };
+                document.onselectstart = function() {return false;};
+            }
+            
+            propagate = !this.stopDown;
+        } else {
+            this.started = false;
+            this.start = null;
+            this.last = null;
+        }
+        return propagate;
+    },
+
+    /**
+     * Method: mousemove
+     * Handle mousemove events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mousemove: function (evt) {
+        if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) {
+            if (this.interval > 0) {
+                this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval);
+            }
+            this.dragging = true;
+            this.move(evt);
+            this.callback("move", [evt.xy]);
+            if(!this.oldOnselectstart) {
+                this.oldOnselectstart = document.onselectstart;
+                document.onselectstart = function() {return false;};
+            }
+            this.last = this.evt.xy;
+        }
+        return true;
+    },
+    
+    /**
+     * Method: removeTimeout
+     * Private. Called by mousemove() to remove the drag timeout.
+     */
+    removeTimeout: function() {
+        this.timeoutId = null;
+    },
+
+    /**
+     * Method: mouseup
+     * Handle mouseup events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mouseup: function (evt) {
+        if (this.started) {
+            var dragged = (this.start != this.last);
+            this.started = false;
+            this.dragging = false;
+            OpenLayers.Element.removeClass(
+                this.map.viewPortDiv, "olDragDown"
+            );
+            this.up(evt);
+            this.callback("up", [evt.xy]);
+            if(dragged) {
+                this.callback("done", [evt.xy]);
+            }
+            document.onselectstart = this.oldOnselectstart;
+        }
+        return true;
+    },
+
+    /**
+     * Method: mouseout
+     * Handle mouseout events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mouseout: function (evt) {
+        if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+            var dragged = (this.start != this.last);
+            this.started = false; 
+            this.dragging = false;
+            OpenLayers.Element.removeClass(
+                this.map.viewPortDiv, "olDragDown"
+            );
+            this.out(evt);
+            this.callback("out", []);
+            if(dragged) {
+                this.callback("done", [evt.xy]);
+            }
+            if(document.onselectstart) {
+                document.onselectstart = this.oldOnselectstart;
+            }
+        }
+        return true;
+    },
+
+    /**
+     * Method: click
+     * 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.
+     * 
+     * Parameters: 
+     * evt - {Event} 
+     * 
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    click: function (evt) {
+        // let the click event propagate only if the mouse moved
+        return (this.start == this.last);
+    },
+
+    /**
+     * Method: activate
+     * Activate the handler.
+     * 
+     * Returns:
+     * {Boolean} The handler was successfully activated.
+     */
+    activate: function() {
+        var activated = false;
+        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragging = false;
+            activated = true;
+        }
+        return activated;
+    },
+
+    /**
+     * Method: deactivate 
+     * Deactivate the handler.
+     * 
+     * Returns:
+     * {Boolean} The handler was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.started = false;
+            this.dragging = false;
+            this.start = null;
+            this.last = null;
+            deactivated = true;
+            OpenLayers.Element.removeClass(
+                this.map.viewPortDiv, "olDragDown"
+            );
+        }
+        return deactivated;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Drag"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Feature.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Feature.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Feature.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,387 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Feature 
+ * Handler to respond to mouse events related to a drawn feature.  Callbacks
+ *     with the following keys will be notified of the following events
+ *     associated with features: click, clickout, over, out, and dblclick.
+ *
+ * This handler stops event propagation for mousedown and mouseup if those
+ *     browser events target features that can be selected.
+ */
+OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
+
+    /**
+     * Property: EVENTMAP
+     * {Object} A object mapping the browser events to objects with callback
+     *     keys for in and out.
+     */
+    EVENTMAP: {
+        'click': {'in': 'click', 'out': 'clickout'},
+        'mousemove': {'in': 'over', 'out': 'out'},
+        'dblclick': {'in': 'dblclick', 'out': null},
+        'mousedown': {'in': null, 'out': null},
+        'mouseup': {'in': null, 'out': null}
+    },
+
+    /**
+     * Property: feature
+     * {<OpenLayers.Feature.Vector>} The last feature that was hovered.
+     */
+    feature: null,
+
+    /**
+     * Property: lastFeature
+     * {<OpenLayers.Feature.Vector>} The last feature that was handled.
+     */
+    lastFeature: null,
+
+    /**
+     * Property: down
+     * {<OpenLayers.Pixel>} The location of the last mousedown.
+     */
+    down: null,
+
+    /**
+     * Property: up
+     * {<OpenLayers.Pixel>} The location of the last mouseup.
+     */
+    up: null,
+    
+    /**
+     * Property: clickTolerance
+     * {Number} The number of pixels the mouse can move between mousedown
+     *     and mouseup for the event to still be considered a click.
+     *     Dragging the map should not trigger the click and clickout callbacks
+     *     unless the map is moved by less than this tolerance. Defaults to 4.
+     */
+    clickTolerance: 4,
+
+    /**
+     * Property: geometryTypes
+     * To restrict dragging to a limited set of geometry types, send a list
+     * of strings corresponding to the geometry class names.
+     * 
+     * @type Array(String)
+     */
+    geometryTypes: null,
+
+    /**
+     * Property: stopClick
+     * {Boolean} If stopClick is set to true, handled clicks do not
+     *      propagate to other click listeners. Otherwise, handled clicks
+     *      do propagate. Unhandled clicks always propagate, whatever the
+     *      value of stopClick. Defaults to true.
+     */
+    stopClick: true,
+
+    /**
+     * Property: stopDown
+     * {Boolean} If stopDown is set to true, handled mousedowns do not
+     *      propagate to other mousedown listeners. Otherwise, handled
+     *      mousedowns do propagate. Unhandled mousedowns always propagate,
+     *      whatever the value of stopDown. Defaults to true.
+     */
+    stopDown: true,
+
+    /**
+     * Property: stopUp
+     * {Boolean} If stopUp is set to true, handled mouseups do not
+     *      propagate to other mouseup listeners. Otherwise, handled mouseups
+     *      do propagate. Unhandled mouseups always propagate, whatever the
+     *      value of stopUp. Defaults to false.
+     */
+    stopUp: false,
+    
+    /**
+     * Constructor: OpenLayers.Handler.Feature
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} 
+     * layer - {<OpenLayers.Layer.Vector>}
+     * callbacks - {Object} An object with a 'over' property whos value is
+     *     a function to be called when the mouse is over a feature. The 
+     *     callback should expect to recieve a single argument, the feature.
+     * options - {Object} 
+     */
+    initialize: function(control, layer, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
+        this.layer = layer;
+    },
+
+
+    /**
+     * Method: mousedown
+     * Handle mouse down.  Stop propagation if a feature is targeted by this
+     *     event (stops map dragging during feature selection).
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    mousedown: function(evt) {
+        this.down = evt.xy;
+        return this.handle(evt) ? !this.stopDown : true;
+    },
+    
+    /**
+     * Method: mouseup
+     * Handle mouse up.  Stop propagation if a feature is targeted by this
+     *     event.
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    mouseup: function(evt) {
+        this.up = evt.xy;
+        return this.handle(evt) ? !this.stopUp : true;
+    },
+
+    /**
+     * Method: click
+     * Handle click.  Call the "click" callback if click on a feature,
+     *     or the "clickout" callback if click outside any feature.
+     * 
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean}
+     */
+    click: function(evt) {
+        return this.handle(evt) ? !this.stopClick : true;
+    },
+        
+    /**
+     * Method: mousemove
+     * Handle mouse moves.  Call the "over" callback if moving in to a feature,
+     *     or the "out" callback if moving out of a feature.
+     * 
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean}
+     */
+    mousemove: function(evt) {
+        if (!this.callbacks['over'] && !this.callbacks['out']) {
+            return true;
+        }     
+        this.handle(evt);
+        return true;
+    },
+    
+    /**
+     * Method: dblclick
+     * Handle dblclick.  Call the "dblclick" callback if dblclick on a feature.
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean}
+     */
+    dblclick: function(evt) {
+        return !this.handle(evt);
+    },
+
+    /**
+     * Method: geometryTypeMatches
+     * Return true if the geometry type of the passed feature matches
+     *     one of the geometry types in the geometryTypes array.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Vector.Feature>}
+     *
+     * Returns:
+     * {Boolean}
+     */
+    geometryTypeMatches: function(feature) {
+        return this.geometryTypes == null ||
+            OpenLayers.Util.indexOf(this.geometryTypes,
+                                    feature.geometry.CLASS_NAME) > -1;
+    },
+
+    /**
+     * Method: handle
+     *
+     * Parameters:
+     * evt - {Event}
+     *
+     * Returns:
+     * {Boolean} The event occurred over a relevant feature.
+     */
+    handle: function(evt) {
+        if(this.feature && !this.feature.layer) {
+            // feature has been destroyed
+            this.feature = null;
+        }
+        var type = evt.type;
+        var handled = false;
+        var previouslyIn = !!(this.feature); // previously in a feature
+        var click = (type == "click" || type == "dblclick");
+        this.feature = this.layer.getFeatureFromEvent(evt);
+        if(this.feature && !this.feature.layer) {
+            // feature has been destroyed
+            this.feature = null;
+        }
+        if(this.lastFeature && !this.lastFeature.layer) {
+            // last feature has been destroyed
+            this.lastFeature = null;
+        }
+        if(this.feature) {
+            var inNew = (this.feature != this.lastFeature);
+            if(this.geometryTypeMatches(this.feature)) {
+                // in to a feature
+                if(previouslyIn && inNew) {
+                    // out of last feature and in to another
+                    if(this.lastFeature) {
+                        this.triggerCallback(type, 'out', [this.lastFeature]);
+                    }
+                    this.triggerCallback(type, 'in', [this.feature]);
+                } else if(!previouslyIn || click) {
+                    // in feature for the first time
+                    this.triggerCallback(type, 'in', [this.feature]);
+                }
+                this.lastFeature = this.feature;
+                handled = true;
+            } else {
+                // not in to a feature
+                if(this.lastFeature && (previouslyIn && inNew || click)) {
+                    // out of last feature for the first time
+                    this.triggerCallback(type, 'out', [this.lastFeature]);
+                }
+                // next time the mouse goes in a feature whose geometry type
+                // doesn't match we don't want to call the 'out' callback
+                // again, so let's set this.feature to null so that
+                // previouslyIn will evaluate to false the next time
+                // we enter handle. Yes, a bit hackish...
+                this.feature = null;
+            }
+        } else {
+            if(this.lastFeature && (previouslyIn || click)) {
+                this.triggerCallback(type, 'out', [this.lastFeature]);
+            }
+        }
+        return handled;
+    },
+    
+    /**
+     * Method: triggerCallback
+     * Call the callback keyed in the event map with the supplied arguments.
+     *     For click and clickout, the <clickTolerance> is checked first.
+     *
+     * Parameters:
+     * type - {String}
+     */
+    triggerCallback: function(type, mode, args) {
+        var key = this.EVENTMAP[type][mode];
+        if(key) {
+            if(type == 'click' && this.up && this.down) {
+                // for click/clickout, only trigger callback if tolerance is met
+                var dpx = Math.sqrt(
+                    Math.pow(this.up.x - this.down.x, 2) +
+                    Math.pow(this.up.y - this.down.y, 2)
+                );
+                if(dpx <= this.clickTolerance) {
+                    this.callback(key, args);
+                }
+            } else {
+                this.callback(key, args);
+            }
+        }
+    },
+
+    /**
+     * Method: activate 
+     * Turn on the handler.  Returns false if the handler was already active.
+     *
+     * Returns:
+     * {Boolean}
+     */
+    activate: function() {
+        var activated = false;
+        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.moveLayerToTop();
+            this.map.events.on({
+                "removelayer": this.handleMapEvents,
+                "changelayer": this.handleMapEvents,
+                scope: this
+            });
+            activated = true;
+        }
+        return activated;
+    },
+    
+    /**
+     * Method: deactivate 
+     * Turn off the handler.  Returns false if the handler was already active.
+     *
+     * Returns: 
+     * {Boolean}
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.moveLayerBack();
+            this.feature = null;
+            this.lastFeature = null;
+            this.down = null;
+            this.up = null;
+            this.map.events.un({
+                "removelayer": this.handleMapEvents,
+                "changelayer": this.handleMapEvents,
+                scope: this
+            });
+            deactivated = true;
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method handleMapEvents
+     * 
+     * Parameters:
+     * evt - {Object}
+     */
+    handleMapEvents: function(evt) {
+        if (!evt.property || evt.property == "order") {
+            this.moveLayerToTop();
+        }
+    },
+    
+    /**
+     * Method: moveLayerToTop
+     * Moves the layer for this handler to the top, so mouse events can reach
+     * it.
+     */
+    moveLayerToTop: function() {
+        var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
+            this.layer.getZIndex()) + 1;
+        this.layer.setZIndex(index);
+        
+    },
+    
+    /**
+     * Method: moveLayerBack
+     * Moves the layer back to the position determined by the map's layers
+     * array.
+     */
+    moveLayerBack: function() {
+        var index = this.layer.getZIndex() - 1;
+        if (index >= this.map.Z_INDEX_BASE['Feature']) {
+            this.layer.setZIndex(index);
+        } else {
+            this.map.setLayerZIndex(this.layer,
+                this.map.getLayerIndex(this.layer));
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Feature"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Keyboard.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Keyboard.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Keyboard.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,108 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.handler.Keyboard
+ * A handler for keyboard events.  Create a new instance with the
+ *     <OpenLayers.Handler.Keyboard> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler> 
+ */
+OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {
+
+    /* http://www.quirksmode.org/js/keys.html explains key x-browser
+        key handling quirks in pretty nice detail */
+
+    /** 
+     * Constant: KEY_EVENTS
+     * keydown, keypress, keyup
+     */
+    KEY_EVENTS: ["keydown", "keyup"],
+
+    /** 
+    * Property: eventListener
+    * {Function}
+    */
+    eventListener: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Keyboard
+     * Returns a new keyboard handler.
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that is making use of
+     *     this handler.  If a handler is being used without a control, the
+     *     handlers setMap method must be overridden to deal properly with
+     *     the map.
+     * callbacks - {Object} An object containing a single function to be
+     *     called when the drag operation is finished. The callback should
+     *     expect to recieve a single argument, the pixel location of the event.
+     *     Callbacks for 'keydown', 'keypress', and 'keyup' are supported.
+     * options - {Object} Optional object whose properties will be set on the
+     *     handler.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        // cache the bound event listener method so it can be unobserved later
+        this.eventListener = OpenLayers.Function.bindAsEventListener(
+            this.handleKeyEvent, this
+        );
+    },
+    
+    /**
+     * Method: destroy
+     */
+    destroy: function() {
+        this.deactivate();
+        this.eventListener = null;
+        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * Method: activate
+     */
+    activate: function() {
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
+                OpenLayers.Event.observe(
+                    document, this.KEY_EVENTS[i], this.eventListener);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Method: deactivate
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
+                OpenLayers.Event.stopObserving(
+                    document, this.KEY_EVENTS[i], this.eventListener);
+            }
+            deactivated = true;
+        }
+        return deactivated;
+    },
+
+    /**
+     * Method: handleKeyEvent 
+     */
+    handleKeyEvent: function (evt) {
+        if (this.checkModifiers(evt)) {
+            this.callback(evt.type, [evt]);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Keyboard"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/MouseWheel.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/MouseWheel.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/MouseWheel.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,242 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.MouseWheel
+ * Handler for wheel up/down events.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
+    /** 
+     * Property: wheelListener 
+     * {function} 
+     */
+    wheelListener: null,
+
+    /** 
+     * Property: mousePosition
+     * {<OpenLayers.Pixel>} 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: OpenLayers.Handler.MouseWheel
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} 
+     * callbacks - {Object} An object containing a single function to be
+     *                          called when the drag operation is finished.
+     *                          The callback should expect to recieve a single
+     *                          argument, the point geometry.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        this.wheelListener = OpenLayers.Function.bindAsEventListener(
+            this.onWheelEvent, this
+        );
+    },
+
+    /**
+     * Method: destroy
+     */    
+    destroy: function() {
+        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+        this.wheelListener = null;
+    },
+
+    /**
+     *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+     */
+
+    /** 
+     * Method: onWheelEvent
+     * Catch the wheel event and handle it xbrowserly
+     * 
+     * Parameters:
+     * e - {Event} 
+     */
+    onWheelEvent: function(e){
+        
+        // make sure we have a map and check keyboard modifiers
+        if (!this.map || !this.checkModifiers(e)) {
+            return;
+        }
+        
+        // Ride up the element's DOM hierarchy to determine if it or any of 
+        //  its ancestors was: 
+        //   * specifically marked as scrollable
+        //   * one of our layer divs
+        //   * the map div
+        //
+        var overScrollableDiv = false;
+        var overLayerDiv = false;
+        var overMapDiv = false;
+        
+        var elem = OpenLayers.Event.element(e);
+        while((elem != null) && !overMapDiv && !overScrollableDiv) {
+
+            if (!overScrollableDiv) {
+                try {
+                    if (elem.currentStyle) {
+                        overflow = elem.currentStyle["overflow"];
+                    } else {
+                        var style = 
+                            document.defaultView.getComputedStyle(elem, null);
+                        var overflow = style.getPropertyValue("overflow");
+                    }
+                    overScrollableDiv = ( overflow && 
+                        (overflow == "auto") || (overflow == "scroll") );
+                } catch(err) {
+                    //sometimes when scrolling in a popup, this causes 
+                    // obscure browser error
+                }
+            }
+
+            if (!overLayerDiv) {
+                for(var i=0, len=this.map.layers.length; i<len; i++) {
+                    // Are we in the layer div? Note that we have two cases
+                    // here: one is to catch EventPane layers, which have a 
+                    // pane above the layer (layer.pane)
+                    if (elem == this.map.layers[i].div 
+                        || elem == this.map.layers[i].pane) { 
+                        overLayerDiv = true;
+                        break;
+                    }
+                }
+            }
+            overMapDiv = (elem == this.map.div);
+
+            elem = elem.parentNode;
+        }
+        
+        // Logic below is the following:
+        //
+        // If we are over a scrollable div or not over the map div:
+        //  * do nothing (let the browser handle scrolling)
+        //
+        //    otherwise 
+        // 
+        //    If we are over the layer div: 
+        //     * zoom/in out
+        //     then
+        //     * kill event (so as not to also scroll the page after zooming)
+        //
+        //       otherwise
+        //
+        //       Kill the event (dont scroll the page if we wheel over the 
+        //        layerswitcher or the pan/zoom control)
+        //
+        if (!overScrollableDiv && overMapDiv) {
+            if (overLayerDiv) {
+                this.wheelZoom(e);
+            }
+            OpenLayers.Event.stop(e);
+        }
+    },
+
+    /**
+     * Method: wheelZoom
+     * Given the wheel event, we carry out the appropriate zooming in or out,
+     *     based on the 'wheelDelta' or 'detail' property of the event.
+     * 
+     * Parameters:
+     * e - {Event}
+     */
+    wheelZoom: function(e) {
+        
+        var delta = 0;
+        if (!e) {
+            e = window.event;
+        }
+        if (e.wheelDelta) {
+            delta = e.wheelDelta/120; 
+            if (window.opera && window.opera.version() < 9.2) {
+                delta = -delta;
+            }
+        } else if (e.detail) {
+            delta = -e.detail / 3;
+        }
+        if (delta) {
+            // 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
+            if (this.mousePosition) {
+                e.xy = this.mousePosition;
+            } 
+            if (!e.xy) {
+                // If the mouse hasn't moved over the map yet, then
+                // we don't have a mouse position (in FF), so we just
+                // act as if the mouse was at the center of the map.
+                // Note that we can tell we are in the map -- and 
+                // this.map is ensured to be true above.
+                e.xy = this.map.getPixelFromLonLat(
+                    this.map.getCenter()
+                );
+            }
+            if (delta < 0) {
+               this.callback("down", [e, delta]);
+            } else {
+               this.callback("up", [e, delta]);
+            }
+        }
+    },
+    
+    /**
+     * Method: mousemove
+     * Update the stored mousePosition on every move.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    mousemove: function (evt) {
+        this.mousePosition = evt.xy;
+    },
+
+    /**
+     * Method: activate 
+     */
+    activate: function (evt) {
+        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;
+        }
+    },
+
+    /**
+     * Method: deactivate 
+     */
+    deactivate: function (evt) {
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            // unregister mousewheel events specifically on the window and document
+            var wheelListener = this.wheelListener;
+            OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
+            OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
+            OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.MouseWheel"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Path.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Path.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Path.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,301 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Point.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Path
+ * Handler to draw a path on the map.  Path is displayed on mouse down,
+ * moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler.Point>
+ */
+OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, {
+    
+    /**
+     * Property: line
+     * {<OpenLayers.Feature.Vector>}
+     */
+    line: null,
+    
+    /**
+     * Property: freehand
+     * {Boolean} In freehand mode, the handler starts the path on mouse down,
+     * adds a point for every mouse move, and finishes the path on mouse up.
+     * Outside of freehand mode, a point is added to the path on every mouse
+     * click and double-click finishes the path.
+     */
+    freehand: false,
+    
+    /**
+     * Property: freehandToggle
+     * {String} If set, freehandToggle is checked on mouse events and will set
+     * the freehand mode to the opposite of this.freehand.  To disallow
+     * toggling between freehand and non-freehand mode, set freehandToggle to
+     * null.  Acceptable toggle values are 'shiftKey', 'ctrlKey', and 'altKey'.
+     */
+    freehandToggle: 'shiftKey',
+
+    /**
+     * Constructor: OpenLayers.Handler.Path
+     * Create a new path hander
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that owns this handler
+     * callbacks - {Object} An object with a properties whose values are
+     *     functions.  Various callbacks described below.
+     * options - {Object} An optional object with properties to be set on the
+     *           handler
+     *
+     * Named callbacks:
+     * create - Called when a sketch is first created.  Callback called with
+     *     the creation point geometry and sketch feature.
+     * modify - Called with each move of a vertex with the vertex (point)
+     *     geometry and the sketch feature.
+     * point - Called as each point is added.  Receives the new point geometry.
+     * done - Called when the point drawing is finished.  The callback will
+     *     recieve a single argument, the linestring geometry.
+     * cancel - Called when the handler is deactivated while drawing.  The
+     *     cancel callback will receive a geometry.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
+    },
+        
+    /**
+     * Method: createFeature
+     * Add temporary geometries
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
+     *     feature.
+     */
+    createFeature: function(pixel) {
+        var lonlat = this.control.map.getLonLatFromPixel(pixel);
+        this.point = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+        );
+        this.line = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.LineString([this.point.geometry])
+        );
+        this.callback("create", [this.point.geometry, this.getSketch()]);
+        this.point.geometry.clearBounds();
+        this.layer.addFeatures([this.line, this.point], {silent: true});
+    },
+        
+    /**
+     * Method: destroyFeature
+     * Destroy temporary geometries
+     */
+    destroyFeature: function() {
+        OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);
+        this.line = null;
+    },
+
+    /**
+     * Method: removePoint
+     * Destroy the temporary point.
+     */
+    removePoint: function() {
+        if(this.point) {
+            this.layer.removeFeatures([this.point]);
+        }
+    },
+    
+    /**
+     * Method: addPoint
+     * Add point to geometry.  Send the point index to override
+     * the behavior of LinearRing that disregards adding duplicate points.
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
+     */
+    addPoint: function(pixel) {
+        this.layer.removeFeatures([this.point]);
+        var lonlat = this.control.map.getLonLatFromPixel(pixel);
+        this.point = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+        );
+        this.line.geometry.addComponent(
+            this.point.geometry, this.line.geometry.components.length
+        );
+        this.callback("point", [this.point.geometry, this.getGeometry()]);
+        this.callback("modify", [this.point.geometry, this.getSketch()]);
+        this.drawFeature();
+    },
+    
+    /**
+     * Method: freehandMode
+     * Determine whether to behave in freehand mode or not.
+     *
+     * Returns:
+     * {Boolean}
+     */
+    freehandMode: function(evt) {
+        return (this.freehandToggle && evt[this.freehandToggle]) ?
+                    !this.freehand : this.freehand;
+    },
+
+    /**
+     * Method: modifyFeature
+     * Modify the existing geometry given the new point
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
+     *     point.
+     */
+    modifyFeature: function(pixel) {
+        var lonlat = this.control.map.getLonLatFromPixel(pixel);
+        this.point.geometry.x = lonlat.lon;
+        this.point.geometry.y = lonlat.lat;
+        this.callback("modify", [this.point.geometry, this.getSketch()]);
+        this.point.geometry.clearBounds();
+        this.drawFeature();
+    },
+
+    /**
+     * Method: drawFeature
+     * Render geometries on the temporary layer.
+     */
+    drawFeature: function() {
+        this.layer.drawFeature(this.line, this.style);
+        this.layer.drawFeature(this.point, this.style);
+    },
+
+    /**
+     * Method: getSketch
+     * Return the sketch feature.
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>}
+     */
+    getSketch: function() {
+        return this.line;
+    },
+
+    /**
+     * Method: getGeometry
+     * Return the sketch geometry.  If <multi> is true, this will return
+     *     a multi-part geometry.
+     *
+     * Returns:
+     * {<OpenLayers.Geometry.LineString>}
+     */
+    getGeometry: function() {
+        var geometry = this.line && this.line.geometry;
+        if(geometry && this.multi) {
+            geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
+        }
+        return geometry;
+    },
+
+    /**
+     * Method: mousedown
+     * Handle mouse down.  Add a new point to the geometry and
+     * render it. Return determines whether to propagate the event on the map.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    mousedown: function(evt) {
+        // ignore double-clicks
+        if (this.lastDown && this.lastDown.equals(evt.xy)) {
+            return false;
+        }
+        if(this.lastDown == null) {
+            if(this.persist) {
+                this.destroyFeature();
+            }
+            this.createFeature(evt.xy);
+        } else if((this.lastUp == null) || !this.lastUp.equals(evt.xy)) {
+            this.addPoint(evt.xy);
+        }
+        this.mouseDown = true;
+        this.lastDown = evt.xy;
+        this.drawing = true;
+        return false;
+    },
+
+    /**
+     * Method: mousemove
+     * Handle mouse move.  Adjust the geometry and redraw.
+     * Return determines whether to propagate the event on the map.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    mousemove: function (evt) {
+        if(this.drawing) { 
+            if(this.mouseDown && this.freehandMode(evt)) {
+                this.addPoint(evt.xy);
+            } else {
+                this.modifyFeature(evt.xy);
+            }
+        }
+        return true;
+    },
+    
+    /**
+     * Method: mouseup
+     * Handle mouse up.  Send the latest point in the geometry to
+     * the control. Return determines whether to propagate the event on the map.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    mouseup: function (evt) {
+        this.mouseDown = false;
+        if(this.drawing) {
+            if(this.freehandMode(evt)) {
+                this.removePoint();
+                this.finalize();
+            } else {
+                if(this.lastUp == null) {
+                   this.addPoint(evt.xy);
+                }
+                this.lastUp = evt.xy;
+            }
+            return false;
+        }
+        return true;
+    },
+  
+    /**
+     * Method: dblclick 
+     * Handle double-clicks.  Finish the geometry and send it back
+     * to the control.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    dblclick: function(evt) {
+        if(!this.freehandMode(evt)) {
+            var index = this.line.geometry.components.length - 1;
+            this.line.geometry.removeComponent(this.line.geometry.components[index]);
+            this.removePoint();
+            this.finalize();
+        }
+        return false;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Path"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Polygon.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Polygon.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Handler/Polygon.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,143 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Path.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Polygon
+ * Handler to draw a polygon on the map.  Polygon is displayed on mouse down,
+ * moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler.Path>
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {
+    
+    /**
+     * Parameter: polygon
+     * {<OpenLayers.Feature.Vector>}
+     */
+    polygon: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Polygon
+     * Create a Polygon Handler.
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that owns this handler
+     * callbacks - {Object} An object with a properties whose values are
+     *     functions.  Various callbacks described below.
+     * options - {Object} An optional object with properties to be set on the
+     *           handler
+     *
+     * Named callbacks:
+     * create - Called when a sketch is first created.  Callback called with
+     *     the creation point geometry and sketch feature.
+     * modify - Called with each move of a vertex with the vertex (point)
+     *     geometry and the sketch feature.
+     * point - Called as each point is added.  Receives the new point geometry.
+     * done - Called when the point drawing is finished.  The callback will
+     *     recieve a single argument, the polygon geometry.
+     * cancel - Called when the handler is deactivated while drawing.  The
+     *     cancel callback will receive a geometry.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.Path.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * Method: createFeature
+     * Add temporary geometries
+     *
+     * Parameters:
+     * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
+     *     feature.
+     */
+    createFeature: function(pixel) {
+        var lonlat = this.control.map.getLonLatFromPixel(pixel);
+        this.point = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+        );
+        this.line = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.LinearRing([this.point.geometry])
+        );
+        this.polygon = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Polygon([this.line.geometry])
+        );
+        this.callback("create", [this.point.geometry, this.getSketch()]);
+        this.point.geometry.clearBounds();
+        this.layer.addFeatures([this.polygon, this.point], {silent: true});
+    },
+
+    /**
+     * Method: destroyFeature
+     * Destroy temporary geometries
+     */
+    destroyFeature: function() {
+        OpenLayers.Handler.Path.prototype.destroyFeature.apply(this);
+        this.polygon = null;
+    },
+
+    /**
+     * Method: drawFeature
+     * Render geometries on the temporary layer.
+     */
+    drawFeature: function() {
+        this.layer.drawFeature(this.polygon, this.style);
+        this.layer.drawFeature(this.point, this.style);
+    },
+    
+    /**
+     * Method: getSketch
+     * Return the sketch feature.
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>}
+     */
+    getSketch: function() {
+        return this.polygon;
+    },
+
+    /**
+     * Method: getGeometry
+     * Return the sketch geometry.  If <multi> is true, this will return
+     *     a multi-part geometry.
+     *
+     * Returns:
+     * {<OpenLayers.Geometry.Polygon>}
+     */
+    getGeometry: function() {
+        var geometry = this.polygon && this.polygon.geometry;
+        if(geometry && this.multi) {
+            geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);
+        }
+        return geometry;
+    },
+
+    /**
+     * Method: dblclick
+     * Handle double-clicks.  Finish the geometry and send it back
+     * to the control.
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    dblclick: function(evt) {
+        if(!this.freehandMode(evt)) {
+            // remove the penultimate point
+            var index = this.line.geometry.components.length - 2;
+            this.line.geometry.removeComponent(this.line.geometry.components[index]);
+            this.removePoint();
+            this.finalize();
+        }
+        return false;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Polygon"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Icon.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Icon.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Icon.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,227 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Class: OpenLayers.Icon
+ * 
+ * The icon represents a graphical icon on the screen.  Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
+ *
+ * An icon has a url, size and position.  It also contains an offset which 
+ * allows the center point to be represented correctly.  This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset. 
+ * 
+ */
+OpenLayers.Icon = OpenLayers.Class({
+    
+    /** 
+     * Property: url 
+     * {String}  image url
+     */
+    url: null,
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} 
+     */
+    size: null,
+
+    /** 
+     * Property: offset 
+     * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
+     */
+    offset: null,    
+    
+    /** 
+     * Property: calculateOffset 
+     * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size) 
+     */
+    calculateOffset: null,    
+    
+    /** 
+     * Property: imageDiv 
+     * {DOMElement} 
+     */
+    imageDiv: null,
+
+    /** 
+     * Property: px 
+     * {<OpenLayers.Pixel>} 
+     */
+    px: null,
+    
+    /** 
+     * Constructor: OpenLayers.Icon
+     * Creates an icon, which is an image tag in a div.  
+     *
+     * url - {String} 
+     * size - {<OpenLayers.Size>} 
+     * offset - {<OpenLayers.Pixel>}
+     * calculateOffset - {Function} 
+     */
+    initialize: function(url, size, offset, calculateOffset) {
+        this.url = url;
+        this.size = (size) ? size : new OpenLayers.Size(20,20);
+        this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+        this.calculateOffset = calculateOffset;
+
+        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+    },
+    
+    /** 
+     * Method: destroy
+     * Nullify references and remove event listeners to prevent circular 
+     * references and memory leaks
+     */
+    destroy: function() {
+        // erase any drawn elements
+        this.erase();
+
+        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); 
+        this.imageDiv.innerHTML = "";
+        this.imageDiv = null;
+    },
+
+    /** 
+     * Method: clone
+     * 
+     * Returns:
+     * {<OpenLayers.Icon>} A fresh copy of the icon.
+     */
+    clone: function() {
+        return new OpenLayers.Icon(this.url, 
+                                   this.size, 
+                                   this.offset, 
+                                   this.calculateOffset);
+    },
+    
+    /**
+     * Method: setSize
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>} 
+     */
+    setSize: function(size) {
+        if (size != null) {
+            this.size = size;
+        }
+        this.draw();
+    },
+    
+    /**
+     * Method: setUrl
+     * 
+     * Parameters:
+     * url - {String} 
+     */
+    setUrl: function(url) {
+        if (url != null) {
+            this.url = url;
+        }
+        this.draw();
+    },
+
+    /** 
+     * Method: draw
+     * Move the div to the given pixel.
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     * 
+     * Returns:
+     * {DOMElement} A new DOM Image of this icon set at the location passed-in
+     */
+    draw: function(px) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, 
+                                            null, 
+                                            null, 
+                                            this.size, 
+                                            this.url, 
+                                            "absolute");
+        this.moveTo(px);
+        return this.imageDiv;
+    }, 
+
+    /** 
+     * Method: erase
+     * Erase the underlying image element.
+     *
+     */
+    erase: function() {
+        if (this.imageDiv != null && this.imageDiv.parentNode != null) {
+            OpenLayers.Element.remove(this.imageDiv);
+        }
+    }, 
+    
+    /** 
+     * Method: setOpacity
+     * Change the icon's opacity
+     *
+     * Parameters:
+     * opacity - {float} 
+     */
+    setOpacity: function(opacity) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
+                                            null, null, null, null, opacity);
+
+    },
+    
+    /**
+     * Method: moveTo
+     * move icon to passed in px.
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     */
+    moveTo: function (px) {
+        //if no px passed in, use stored location
+        if (px != null) {
+            this.px = px;
+        }
+
+        if (this.imageDiv != null) {
+            if (this.px == null) {
+                this.display(false);
+            } else {
+                if (this.calculateOffset) {
+                    this.offset = this.calculateOffset(this.size);  
+                }
+                var offsetPx = this.px.offset(this.offset);
+                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
+            }
+        }
+    },
+    
+    /** 
+     * Method: display
+     * Hide or show the icon
+     *
+     * Parameters:
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.imageDiv.style.display = (display) ? "" : "none"; 
+    },
+    
+
+    /**
+     * APIMethod: isDrawn
+     * 
+     * Returns:
+     * {Boolean} Whether or not the icon is drawn.
+     */
+    isDrawn: function() {
+        // nodeType 11 for ie, whose nodes *always* have a parentNode
+        // (of type document fragment)
+        var isDrawn = (this.imageDiv && this.imageDiv.parentNode && 
+                       (this.imageDiv.parentNode.nodeType != 11));    
+
+        return isDrawn;   
+    },
+
+    CLASS_NAME: "OpenLayers.Icon"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/ca.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/ca.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/ca.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,124 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["ca"]
+ * Dictionary for Catalan, UTF8 encoding. Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.ca = {
+
+    'unhandledRequest': "Resposta a petició no gestionada ${statusText}",
+
+    'permalink': "Enllaç permanent",
+
+    'overlays': "Capes addicionals",
+
+    'baseLayer': "Capa Base",
+
+    'sameProjection':
+        "El mapa de referència només funciona si té la mateixa projecció que el mapa principal",
+
+    'readNotImplemented': "Lectura no implementada.",
+
+    'writeNotImplemented': "Escriptura no implementada.",
+
+    'noFID': "No es pot actualitzar un element per al que no existeix FID.",
+
+    'errorLoadingGML': "Error caregant el fitxer GML ${url}",
+
+    'browserNotSupported':
+        "El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualmente són:\n${renderers}",
+
+    'componentShouldBe': "addFeatures : el component ha de ser de tipus ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent ha estat cridat a una capa sense renderizador. Això normalment vol dir que " +
+        "s'ha eliminat una capa, però no el handler associat a ella.",
+
+    // console message
+    'minZoomLevelError':
+        "La propietat minZoomLevel s'ha d'utilitzar només " +
+        "amb les capes que tenen FixedZoomLevels. El fet que " +
+        "una capa wfs comprovi minZoomLevel és una reliquia del " +
+        "passat. No podem, però, eliminar-la sense trencar " +
+        "les aplicacions d'OpenLayers que en puguin dependre. " +
+        "Així doncs estem fent-la obsoleta -- la comprovació " +
+        "minZoomLevel s'eliminarà a la versió 3.0. Feu servir " +
+        "els paràmetres min/max resolution en substitució, tal com es descriu aquí: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "Transacció WFS: CORRECTA ${response}",
+
+    'commitFailed': "Transacció WFS: HA FALLAT ${response}",
+
+    'googleWarning':
+        "La capa Google no s'ha pogut carregar correctament.<br><br>" +
+        "Per evitar aquest missatge, sel·leccioneu una nova Capa Base " +
+        "al gestor de capes de la cantonada superior dreta.<br><br>" +
+        "Probablement això és degut a que l'script de la biblioteca de " +
+    "Google Maps no ha estat inclòs a la vostra pàgina, o no " +
+    "conté la clau de l'API correcta per a la vostra adreça.<br><br>" +
+        "Desenvolupadors: Per obtenir consells sobre com fer anar això, " +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>féu clic aquí</a>",
+
+    'getLayerWarning':
+        "Per evitar aquest missatge, sel·leccioneu una nova Capa Base " +
+        "al gestor de capes de la cantonada superior dreta.<br><br>" +
+        "Probablement això és degut a que l'script de la biblioteca " +
+        "${layerLib} " +
+        "no ha estat inclòs a la vostra pàgina.<br><br>" +
+        "Desenvolupadors: Per obtenir consells sobre com fer anar això, " +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>féu clic aquí</a>",
+
+    'scale': "Escala = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "Heu intentat afegir la capa: ${layerName} al mapa, pero ja ha estat afegida anteriorment",
+
+    // console message
+    'reprojectDeprecated':
+        "Esteu fent servir l'opció 'reproject' a la capa " +
+        "${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut " +
+        "per suportar la visualització de dades sobre mapes base comercials, " + 
+        "però aquesta funcionalitat s'hauria d'assolir ara mitjançant el suport " +
+        "de la projecció Spherical Mercator. Més informació disponible a " +
+        "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "Aquest mètode és obsolet i s'eliminará a la versió 3.0. " +
+        "Si us plau feu servir em mètode alternatiu ${newMethod}.",
+
+    // console message
+    'boundsAddError': "Ha de proporcionar els valors x i y a la funció add.",
+
+    // console message
+    'lonlatAddError': "Ha de proporcionar els valors lon i lat a la funció add.",
+
+    // console message
+    'pixelAddError': "Ha de proporcionar els valors x i y a la funció add.",
+
+    // console message
+    'unsupportedGeometryType': "Tipus de geometria no suportada: ${geomType}",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition ha fallat: l'element amb id ${elemId} pot estar fora de lloc.",
+                    
+    // console message
+    'filterEvaluateNotImplemented': "evaluate no està implementat per aquest tipus de filtre.",
+
+    'end': ''
+
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/cs-CZ.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/cs-CZ.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/cs-CZ.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,120 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["cs-CZ"]
+ * Dictionary for Czech.  Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang["cs-CZ"] = {
+
+    'unhandledRequest': "Nezpracovaná návratová hodnota ${statusText}",
+
+    'permalink': "Odkaz na aktuální mapu",
+
+    'overlays': "Překryvné vrstvy",
+
+    'baseLayer': "Podkladové vrstvy",
+
+    'sameProjection':
+        "Přehledka pracuje správně pouze pokud je ve stejné projekci, jako hlavní mapa",
+
+    'readNotImplemented': "Read není implementováno.",
+
+    'writeNotImplemented': "Write není implementováno.",
+
+    'noFID': "Nelze aktualizovat prvek, pro který neexistuje FID.",
+
+    'errorLoadingGML': "Chyba při načítání souboru GML ${url}",
+
+    'browserNotSupported':
+        "Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}",
+
+    'componentShouldBe': "addFeatures : komponenta by měla být ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent bylo zavoláno na vrstvě, která nemá vykreslovač. To obyčejně znamená, že " +
+        "jste odstranil vrstvu, ale ne rutinu s ní asociovanou.",
+
+    // console message
+    'minZoomLevelError':
+        "Vlastnost minZoomLevel by se měla používat pouze " +
+        "s potomky FixedZoomLevels vrstvami. To znamená, že " +
+        "vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti." +
+        "Nelze to ovšem vyjmout bez možnosti, že bychom rozbili " +
+        "aplikace postavené na OL, které by na tom mohly záviset. " +
+        "Proto tuto vlastnost nedoporučujeme používat --  kontrola minZoomLevel " +
+        "bude odstraněna ve verzi 3.0. Použijte prosím " +
+        "raději nastavení min/max podle příkaldu popsaného na: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "WFS Transaction: ÚSPĚCH ${response}",
+
+    'commitFailed': "WFS Transaction: CHYBA ${response}",
+
+    'googleWarning':
+        "Nepodařilo se správně načíst vrstvu Google.<br><br>" +
+        "Abyste se zbavili této zprávy, zvolte jinou základní vrstvu " +
+        "v přepínači vrstev.<br><br>" +
+        "To se většinou stává, pokud " +
+        "nebyl načten skript, nebo neobsahuje správný " +
+        "klíč pro API pro tuto stránku.<br><br>" +
+        "Vývojáři: Pro pomoc, aby tohle fungovalo , " +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>klikněte sem</a>",
+
+    'getLayerWarning':
+        "The ${layerType} Layer was unable to load correctly.<br><br>" +
+        "To get rid of this message, select a new BaseLayer " +
+        "in the layer switcher in the upper-right corner.<br><br>" +
+        "Most likely, this is because the ${layerLib} library " +
+        "script was either not correctly included.<br><br>" +
+        "Developers: For help getting this working correctly, " +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>click here</a>",
+
+    'scale': "Měřítko = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "Pokusili jste se přidat vrstvu: ${layerName} do mapy, ale tato vrstva je již v mapě přítomna.",
+
+    // console message
+    'reprojectDeprecated':
+        "Použil jste volbu 'reproject' " +
+        "ve vrstvě ${layerName}. Tato volba není doporučená: " +
+        "byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, " + 
+        "ale tato funkce je nyní zajištěna pomocí podpory " +
+        "Spherical Mercator. Více informací naleznete na " +
+        "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "Tato metodat není doporučená a bude vyjmuta ve verzi 3.0. " +
+        "Prosím, použijte raději ${newMethod}.",
+
+    // console message
+    'boundsAddError': "Pro přídavnou funkci musíte zadat obě souřadnice x a y.",
+
+    // console message
+    'lonlatAddError': "Pro přídavnou funkci musíte zadat obě souřadnice lon a lat.",
+
+    // console message
+    'pixelAddError': "Pro přídavnou funkci musíte zadat obě souřadnice x a y.",
+
+    // console message
+    'unsupportedGeometryType': "Nepodporovaný typ geometrie: ${geomType}",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition selhalo: element s  id ${elemId} je asi umístěn chybně.",
+                    
+    'end': ''
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/en.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/en.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/en.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,123 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["en"]
+ * Dictionary for English.  Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.en = {
+
+    'unhandledRequest': "Unhandled request return ${statusText}",
+
+    'permalink': "Permalink",
+
+    'overlays': "Overlays",
+
+    'baseLayer': "Base Layer",
+
+    'sameProjection':
+        "The overview map only works when it is in the same projection as the main map",
+
+    'readNotImplemented': "Read not implemented.",
+
+    'writeNotImplemented': "Write not implemented.",
+
+    'noFID': "Can't update a feature for which there is no FID.",
+
+    'errorLoadingGML': "Error in loading GML file ${url}",
+
+    'browserNotSupported':
+        "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
+
+    'componentShouldBe': "addFeatures : component should be an ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent called on layer with no renderer. This usually means you " +
+        "destroyed a layer, but not some handler which is associated with it.",
+
+    // console message
+    'minZoomLevelError':
+        "The minZoomLevel property is only intended for use " +
+        "with the FixedZoomLevels-descendent layers. That this " +
+        "wfs layer checks for minZoomLevel is a relic of the" +
+        "past. We cannot, however, remove it without possibly " +
+        "breaking OL based applications that may depend on it." +
+        " Therefore we are deprecating it -- the minZoomLevel " +
+        "check below will be removed at 3.0. Please instead " +
+        "use min/max resolution setting as described here: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "WFS Transaction: SUCCESS ${response}",
+
+    'commitFailed': "WFS Transaction: FAILED ${response}",
+
+    'googleWarning':
+        "The Google Layer was unable to load correctly.<br><br>" +
+        "To get rid of this message, select a new BaseLayer " +
+        "in the layer switcher in the upper-right corner.<br><br>" +
+        "Most likely, this is because the Google Maps library " +
+        "script was either not included, or does not contain the " +
+        "correct API key for your site.<br><br>" +
+        "Developers: For help getting this working correctly, " +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>click here</a>",
+
+    'getLayerWarning':
+        "The ${layerType} Layer was unable to load correctly.<br><br>" +
+        "To get rid of this message, select a new BaseLayer " +
+        "in the layer switcher in the upper-right corner.<br><br>" +
+        "Most likely, this is because the ${layerLib} library " +
+        "script was not correctly included.<br><br>" +
+        "Developers: For help getting this working correctly, " +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>click here</a>",
+
+    'scale': "Scale = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "You tried to add the layer: ${layerName} to the map, but it has already been added",
+
+    // console message
+    'reprojectDeprecated':
+        "You are using the 'reproject' option " +
+        "on the ${layerName} layer. This option is deprecated: " +
+        "its use was designed to support displaying data over commercial " + 
+        "basemaps, but that functionality should now be achieved by using " +
+        "Spherical Mercator support. More information is available from " +
+        "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "This method has been deprecated and will be removed in 3.0. " +
+        "Please use ${newMethod} instead.",
+
+    // console message
+    'boundsAddError': "You must pass both x and y values to the add function.",
+
+    // console message
+    'lonlatAddError': "You must pass both lon and lat values to the add function.",
+
+    // console message
+    'pixelAddError': "You must pass both x and y values to the add function.",
+
+    // console message
+    'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
+                    
+    'end': '',
+
+    // console message
+    'filterEvaluateNotImplemented': "evaluate is not implemented for this filter type."
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/pt-BR.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/pt-BR.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/pt-BR.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,122 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["pt-BR"]
+ * Dictionary for Brazilian Portuguese.  Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang["pt-BR"] = {
+
+    'unhandledRequest': "A requisição retornou um erro não tratado: ${statusText}",
+
+    'permalink': "Link para essa página",
+
+    'overlays': "Camadas de Sobreposição",
+
+    'baseLayer': "Camada Base",
+
+    'sameProjection':
+        "O mapa de referência só funciona quando ele está na mesma projeção do mapa principal",
+
+    'readNotImplemented': "Leitura não implementada.",
+
+    'writeNotImplemented': "Escrita não implementada.",
+
+    'noFID': "Não é possível atualizar uma feição que não tenha um FID.",
+
+    'errorLoadingGML': "Erro ao carregar o arquivo GML ${url}",
+
+    'browserNotSupported':
+        "Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}",
+
+    'componentShouldBe': "addFeatures: o componente deve ser do tipo ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent foi executado mas nenhum renderizador foi encontrado. " +
+        "Isso pode indicar que você destruiu uma camana, mas não o handler associado a ela.",
+
+    // console message
+    'minZoomLevelError':
+        "A propriedade minZoomLevel é de uso restrito das camadas "+
+        "descendentes de FixedZoomLevels. A verificação dessa propriedade " +
+        "pelas camadas wfs é um resíduo do passado. Não podemos, entretanto " +
+        "não é possível removê-la sem possívelmente quebrar o funcionamento " +
+        "de aplicações OL que possuem depência com ela. Portanto estamos " +
+        "tornando seu uso obsoleto -- a verificação desse atributo será " +
+        "removida na versão 3.0. Ao invés, use as opções de resolução " +
+        "min/max como descrito em: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "Transação WFS : SUCESSO ${response}",
+
+    'commitFailed': "Transação WFS : ERRO ${response}",
+
+    'googleWarning':
+        "Não foi possível carregar a camada Google corretamente.<br><br>" +
+        "Para se livrar dessa mensagem, selecione uma nova Camada Base, " +
+        "na ferramenta de alternação de camadas localização do canto " +
+        "superior direito.<br><br>" +
+        "Muito provavelmente, isso foi causado porque o script da " +
+        "biblioteca do Google Maps não foi incluído, ou porque ele não " +
+        "contém a chave correta da API para o seu site.<br><br>" +
+        "Desenvolvedores: Para obter ajuda em solucionar esse problema " +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>cliquem aqui</a>",
+
+    'getLayerWarning':
+        "Não foi possível carregar a camada ${layerType} corretamente.<br><br>" +
+        "Para se livrar dessa mensagem, selecione uma nova Camada Base, " +
+        "na ferramenta de alternação de camadas localização do canto " +
+        "superior direito.<br><br>" +
+        "Muito provavelmente, isso foi causado porque o script da " +
+        "biblioteca ${layerLib} não foi incluído corretamente.<br><br>" +
+        "Desenvolvedores: Para obter ajuda em solucionar esse problema " +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>cliquem aqui</a>",
+
+    'scale': "Escala = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "Você tentou adicionar a camada: ${layerName} ao mapa, mas ela já foi adicionada",
+
+    // console message
+    'reprojectDeprecated':
+        "Você está usando a opção 'reproject' na camada ${layerName}. " +
+        "Essa opção está obsoleta: seu uso foi projetado para suportar " +
+        "a visualização de dados sobre bases de mapas comerciais, " +
+        "entretanto essa funcionalidade deve agora ser alcançada usando " +
+        "o suporte à projeção Mercator. Mais informação está disponível em: " +
+        "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "Esse método está obsoleto e será removido na versão 3.0. " +
+        "Ao invés, por favor use ${newMethod}.",
+
+    // console message
+    'boundsAddError': "Você deve informar ambos os valores x e y para a função add.",
+
+    // console message
+    'lonlatAddError': "Você deve informar ambos os valores lon e lat para a função add.",
+
+    // console message
+    'pixelAddError': "Você deve informar ambos os valores x e y para a função add.",
+
+    // console message
+    'unsupportedGeometryType': "Tipo geométrico não suportado: ${geomType}.",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition falhou: o elemento de id ${elemId} deve estar fora do lugar.",
+                    
+    'end': ''
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/sv-SE.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/sv-SE.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/sv-SE.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,121 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["sv-SE"]
+ * Dictionary for swedish (Sweden).  Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang["sv-SE"] = {
+
+    'unhandledRequest': "Ej hanterad fråga retur ${statusText}",
+
+    'permalink': "Permalänk",
+
+    'overlays': "Kartlager",
+
+    'baseLayer': "Bakgrundskarta",
+
+    'sameProjection':
+        "Översiktskartan fungerar endast när den har samma projektion som huvudkartan",
+
+    'readNotImplemented': "Läsning ej implementerad.",
+
+    'writeNotImplemented': "Skrivning ej implementerad.",
+
+    'noFID': "Kan ej uppdatera feature (objekt) för vilket FID saknas.",
+
+    'errorLoadingGML': "Fel i laddning av GML-fil ${url}",
+
+    'browserNotSupported':
+        "Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}",
+
+    'componentShouldBe': "addFeatures : komponenten skall vara en ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent anropad för lager utan utritning. Detta betyder oftast att man " +
+        "raderat ett lager, men inte en hanterare som är knuten till lagret.",
+
+    // console message
+    'minZoomLevelError':
+        "Egenskapen minZoomLevel är endast avsedd att användas " +
+        "med lager med FixedZoomLevels. Att detta WFS-lager " +
+        "kontrollerar minZoomLevel är en relik från äldre versioner. " +
+        "Vi kan dock inte ta bort det utan att riskera att " +
+        "OL-baserade tillämpningar som använder detta slutar " +
+        "fungera. Därför är det satt som deprecated, minZoomLevel " +
+        "kommer att tas bort i version 3.0. Använd i stället " +
+        "inställning av min/max resolution som beskrivs här: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "WFS-transaktion: LYCKADES ${response}",
+
+    'commitFailed': "WFS-transaktion: MISSLYCKADES ${response}",
+
+    'googleWarning':
+        "Google-lagret kunde inte laddas korrekt.<br><br>" + 
+        "För att slippa detta meddelande, välj en annan bakgrundskarta " +
+        "i lagerväljaren i övre högra hörnet.<br><br>" +
+        "Sannolikt beror felet på att Google Maps-biblioteket " + 
+        "inte är inkluderat på webbsidan eller på att sidan " +
+        "inte anger korrekt API-nyckel för webbplatsen.<br><br>" +
+        "Utvecklare: hjälp för att åtgärda detta, " +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>klicka här</a>.",
+
+    'getLayerWarning':
+        "${layerType}-lagret kunde inte laddas korrekt.<br><br>" + 
+        "För att slippa detta meddelande, välj en annan bakgrundskarta " +
+        "i lagerväljaren i övre högra hörnet.<br><br>" +
+        "Sannolikt beror felet på att ${layerLib}-biblioteket " + 
+        "inte är inkluderat på webbsidan.<br><br>" +
+        "Utvecklare: hjälp för att åtgärda detta, " +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>klicka här</a>.",
+
+    'scale': "<strong>Skala</strong> 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "Du försökte lägga till lagret: ${layerName} på kartan, men det har lagts till tidigare",
+
+    // console message
+    'reprojectDeprecated':
+        "Du använder inställningen 'reproject' på lagret ${layerName}. " +
+        "Denna inställning markerad som deprecated: den var avsedd " +
+        "att användas för att stödja visning av kartdata på kommersiella " +
+        "bakgrundskartor, men nu bör man i stället " +
+        "använda Spherical Mercator-stöd för den funktionaliteten. " +
+        "Mer information finns " +   
+        "på http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "Denna metod är markerad som deprecated och kommer att tas bort i 3.0. " +
+        "Använd ${newMethod} i stället.",
+
+    // console message
+    'boundsAddError': "Du måste skicka både x- och y-värde till funktionen add.",
+
+    // console message
+    'lonlatAddError': "Du måste skicka både lon- och lat-värde till funktionen add.",
+
+    // console message
+    'pixelAddError': "Du måste skicka både x- och y-värde till funktionen add.",
+
+    // console message
+    'unsupportedGeometryType': "Stöd saknas för geometritypen: ${geomType}",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition misslyckades: elementet med id ${elemId} kan placeras fel.",
+                    
+    'end': ''
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-CN.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-CN.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-CN.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,120 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["zh-CN"]
+ * Dictionary for Simplified Chinese.  Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang["zh-CN"] = {
+
+    'unhandledRequest': "未处理的请求,返回值为 ${statusText}",
+
+    'permalink': "永久链接",
+
+    'overlays': "叠加层",
+
+    'baseLayer': "基础图层",
+
+    'sameProjection':
+        "鹰眼地图只有在和主地图使用相同的投影的时候才能正常共工作",
+
+    'readNotImplemented': "读取功能没有实现。",
+
+    'writeNotImplemented': "写入功能没有实现。",
+
+    'noFID': "无法更新feature,缺少FID。",
+
+    'errorLoadingGML': "加载GML文件 ${url} 出现错误。",
+
+    'browserNotSupported':
+        "你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}",
+
+    'componentShouldBe': "addFeatures : 组件类型应该是 ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent方法在一个没有渲染器的图层上被调用。 这通常意味着您" +
+        "销毁了一个图层,但并未销毁其关联的handler。",
+
+    // console message
+    'minZoomLevelError':
+        "minZoomLevel属性仅适合用于" +
+        "使用了固定缩放级别的图层。这个 " +
+        "wfs 图层检查 minZoomLevel 是过去遗留下来的。" +
+        "然而,我们不能移除它," +
+        "而破坏依赖于它的基于OL的应用程序。" +
+        "因此,我们废除了它 -- minZoomLevel " +
+        "将会在3.0中被移除。请改用 " +
+        "min/max resolution 设置,参考:" +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "WFS Transaction: 成功。 ${response}",
+
+    'commitFailed': "WFS Transaction: 失败。 ${response}",
+
+    'googleWarning':
+        "Google图层不能正确加载。<br><br>" +
+        "要消除这个信息,请在右上角的" +
+        "图层控制面板中选择其他的基础图层。<br><br>" +
+        "这种情况很可能是没有正确的包含Google地图脚本库," +
+        "或者是没有包含在你的站点上" +
+        "使用的正确的Google Maps API密匙。<br><br>" +
+        "开发者:获取使其正确工作的帮助信息," +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>点击这里</a>",
+
+    'getLayerWarning':
+        "${layerType} 图层不能正确加载。<br><br>" +
+        "要消除这个信息,请在右上角的" +
+        "图层控制面板中选择其他的基础图层。<br><br>" +
+        "这种情况很可能是没有正确的包含" +
+        "${layerLib} 脚本库。<br><br>" +
+        "开发者:获取使其正确工作的帮助信息," +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>点击这里</a>",
+
+    'scale': "比例尺 = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "你尝试添加图层: ${layerName} 到地图中,但是它之前就已经被添加。",
+
+    // console message
+    'reprojectDeprecated':
+        "你正在使用 ${layerName} 图层上的'reproject'选项。" +
+        "这个选项已经不再使用:" +
+        "它是被设计用来支持显示商业的地图数据," + 
+        "不过现在该功能可以通过使用Spherical Mercator来实现。" +
+        "更多信息可以参阅" +
+        "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+    // console message
+    'methodDeprecated':
+        "该方法已经不再被支持,并且将在3.0中被移除。" +
+        "请使用 ${newMethod} 方法来替代。",
+
+    // console message
+    'boundsAddError': "您必须传递 x 和 y 两个参数值到 add 方法。",
+
+    // console message
+    'lonlatAddError': "您必须传递 lon 和 lat 两个参数值到 add 方法。",
+
+    // console message
+    'pixelAddError': "您必须传递 x and y 两个参数值到 add 方法。",
+
+    // console message
+    'unsupportedGeometryType': "不支持的几何体类型: ${geomType}",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition 失败:id 为 ${elemId} 的元素可能被错置。",
+                    
+    'end': ''
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-TW.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-TW.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang/zh-TW.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,121 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["zh-TW"]
+ * Dictionary for Traditional Chinese. (Used Mainly in Taiwan) 
+ * Keys for entries are used in calls to
+ *     <OpenLayers.Lang.translate>.  Entry bodies are normal strings or
+ *     strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang["zh-TW"] = {
+
+    'unhandledRequest': "未處理的請求,傳回值為 ${statusText}。",
+
+    'permalink': "永久連結",
+
+    'overlays': "額外圖層",
+
+    'baseLayer': "基礎圖層",
+
+    'sameProjection':
+        "地圖縮覽(OverviewMap)只能在跟主地圖相同投影時起作用。",
+
+    'readNotImplemented': "沒有實作讀取的功能。",
+
+    'writeNotImplemented': "沒有實作寫入的功能。",
+
+    'noFID': "因為沒有 FID 所以無法更新 feature。",
+
+    'errorLoadingGML': "讀取GML檔案 ${url} 錯誤。",
+
+    'browserNotSupported':
+        "您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}",
+
+    'componentShouldBe': "addFeatures : 元件應該為 ${geomType}",
+
+    // console message
+    'getFeatureError':
+        "getFeatureFromEvent 在一個沒有被渲染的圖層裡被呼叫。這通常意味著您 " +
+        "摧毀了一個圖層,但並未摧毀相關的handler。",
+
+    // console message
+    'minZoomLevelError':
+        "minZoomLevel 屬性僅適合用在 " +
+        "FixedZoomLevels-descendent 類型的圖層. 這個" +
+        "wfs layer 的 minZoomLevel 是過去所遺留下來的," +
+        "然而我們不能移除它而不讓它將" +
+        "過去的程式相容性給破壞掉。" +
+        "因此我們將會迴避使用它 -- minZoomLevel " +
+        "會在3.0被移除,請改" +
+        "用在這邊描述的 min/max resolution 設定: " +
+        "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+    'commitSuccess': "WFS Transaction: 成功 ${response}",
+
+    'commitFailed': "WFS Transaction: 失敗 ${response}",
+
+    'googleWarning':
+        "The Google Layer 圖層無法被正確的載入。<br><br>" +
+        "要迴避這個訊息, 請在右上角的圖層改變器裡," +
+        "選一個新的基礎圖層。<br><br>" +
+        "很有可能是因為 Google Maps 的函式庫" +
+        "腳本沒有被正確的置入,或沒有包含 " +
+        "您網站上正確的 API key <br><br>" +
+        "開發者: 要幫助這個行為正確完成," +
+        "<a href='http://trac.openlayers.org/wiki/Google' " +
+        "target='_blank'>請按這裡</a>",
+
+    'getLayerWarning':
+        "${layerType} 圖層無法被正確的載入。<br><br>" +
+        "要迴避這個訊息, 請在右上角的圖層改變器裡," +
+        "選一個新的基礎圖層。<br><br>" +
+        "很有可能是因為 ${layerLib} 的函式庫" +
+        "腳本沒有被正確的置入。<br><br>" +
+        "開發者: 要幫助這個行為正確完成," +
+        "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+        "target='_blank'>請按這裡</a>",
+
+    'scale': "Scale = 1 : ${scaleDenom}",
+
+    // console message
+    'layerAlreadyAdded':
+        "你試著新增圖層: ${layerName} 到地圖上,但圖層之前就已經被新增了。",
+
+    // console message
+    'reprojectDeprecated':
+        "你正使用 'reproject' 這個選項 " +
+        "在 ${layerName} 層。這個選項已經不再使用:" +
+        "它的使用原本是設計用來支援在商業地圖上秀出資料," + 
+        "但這個功能已經被" +
+        "Spherical Mercator所取代。更多的資訊可以在 " +
+        "http://trac.openlayers.org/wiki/SphericalMercator 找到。",
+
+    // console message
+    'methodDeprecated':
+        "這個方法已經不再使用且在3.0將會被移除," +
+        "請使用 ${newMethod} 來代替。",
+
+    // console message
+    'boundsAddError': "您必須傳入 x 跟 y 兩者的值進 add 函數。",
+
+    // console message
+    'lonlatAddError': "您必須傳入 lon 跟 lat 兩者的值進 add 函數。",
+
+    // console message
+    'pixelAddError': "您必須傳入 x 跟 y 兩者的值進 add 函數。",
+
+    // console message
+    'unsupportedGeometryType': "未支援的幾何型別: ${geomType}。",
+
+    // console message
+    'pagePositionFailed':
+        "OpenLayers.Util.pagePosition 失敗: id ${elemId} 的 element 可能被錯置。",
+                    
+    'end': ''
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Lang.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,132 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang
+ * Internationalization namespace.  Contains dictionaries in various languages
+ *     and methods to set and get the current language.
+ */
+OpenLayers.Lang = {
+    
+    /** 
+     * Property: code
+     * {String}  Current language code to use in OpenLayers.  Use the
+     *     <setCode> method to set this value and the <getCode> method to
+     *     retrieve it.
+     */
+    code: null,
+
+    /** 
+     * APIProperty: defaultCode
+     * {String} Default language to use when a specific language can't be
+     *     found.  Default is "en".
+     */
+    defaultCode: "en",
+        
+    /**
+     * APIFunction: getCode
+     * Get the current language code.
+     *
+     * Returns:
+     * The current language code.
+     */
+    getCode: function() {
+        if(!OpenLayers.Lang.code) {
+            OpenLayers.Lang.setCode();
+        }
+        return OpenLayers.Lang.code;
+    },
+    
+    /**
+     * APIFunction: setCode
+     * Set the language code for string translation.  This code is used by
+     *     the <OpenLayers.Lang.translate> method.
+     *
+     * Parameters-
+     * code - {String} These codes follow the IETF recommendations at
+     *     http://www.ietf.org/rfc/rfc3066.txt.  If no value is set, the
+     *     browser's language setting will be tested.  If no <OpenLayers.Lang>
+     *     dictionary exists for the code, the <OpenLayers.String.defaultLang>
+     *     will be used.
+     */
+    setCode: function(code) {
+        var lang;
+        if(!code) {
+            code = (OpenLayers.Util.getBrowserName() == "msie") ?
+                navigator.userLanguage : navigator.language;
+        }
+        var parts = code.split('-');
+        parts[0] = parts[0].toLowerCase();
+        if(typeof OpenLayers.Lang[parts[0]] == "object") {
+            lang = parts[0];
+        }
+
+        // check for regional extensions
+        if(parts[1]) {
+            var testLang = parts[0] + '-' + parts[1].toUpperCase();
+            if(typeof OpenLayers.Lang[testLang] == "object") {
+                lang = testLang;
+            }
+        }
+        if(!lang) {
+            OpenLayers.Console.warn(
+                'Failed to find OpenLayers.Lang.' + parts.join("-") +
+                ' dictionary, falling back to default language'
+            );
+            lang = OpenLayers.Lang.defaultCode;
+        }
+        
+        OpenLayers.Lang.code = lang;
+    },
+
+    /**
+     * APIMethod: translate
+     * Looks up a key from a dictionary based on the current language string.
+     *     The value of <getCode> will be used to determine the appropriate
+     *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
+     *
+     * Parameters:
+     * key - {String} The key for an i18n string value in the dictionary.
+     * context - {Object} Optional context to be used with
+     *     <OpenLayers.String.format>.
+     * 
+     * Returns:
+     * {String} A internationalized string.
+     */
+    translate: function(key, context) {
+        var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
+        var message = dictionary[key];
+        if(!message) {
+            // Message not found, fall back to message key
+            message = key;
+        }
+        if(context) {
+            message = OpenLayers.String.format(message, context);
+        }
+        return message;
+    }
+    
+};
+
+
+/**
+ * APIMethod: OpenLayers.i18n
+ * Alias for <OpenLayers.Lang.translate>.  Looks up a key from a dictionary
+ *     based on the current language string. The value of
+ *     <OpenLayers.Lang.getCode> will be used to determine the appropriate
+ *     dictionary.  Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ *     <OpenLayers.String.format>.
+ * 
+ * Returns:
+ * {String} A internationalized string.
+ */
+OpenLayers.i18n = OpenLayers.Lang.translate;

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcGIS93Rest.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcGIS93Rest.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcGIS93Rest.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,252 @@
+/* Copyright (c) 2008 Avencia, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.ArcGIS93Rest
+ * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from
+ *     ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API.
+ *     Create a new ArcGIS93Rest layer with the <OpenLayers.Layer.ArcGIS93Rest>
+ *     constructor.  More detail on the REST API is available at
+ *     http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ;
+ *     specifically, the URL provided to this layer should be an export service
+ *     URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    DEFAULT_PARAMS: { 
+      format: "png"
+    },
+        
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} Default is true for ArcGIS93Rest layer
+     */
+    isBaseLayer: true,
+ 
+ 
+    /**
+     * Constructor: OpenLayers.Layer.ArcGIS93Rest
+     * Create a new ArcGIS93Rest layer object.
+     *
+     * Example:
+     * (code)
+     * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName",
+     *                                    "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer", 
+     *                                    {
+     *                                      layers: "0,1,2"
+     *                                    });
+     * (end)
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the ArcGIS server REST service
+     * options - {Object} An object with key/value pairs representing the
+     *                    options and option values.
+     * Valid Options:
+     *        format: {String} MIME type of desired image type.
+     *        layers: {String} Comma-separated list of layers to display.
+     *        srs: {String} Projection ID.
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = [];
+        //uppercase params
+        params = OpenLayers.Util.upperCaseObject(params);
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+        OpenLayers.Util.applyDefaults(
+                       this.params, 
+                       OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
+                       );
+                       
+        //layer is transparent        
+        if (this.params.TRANSPARENT && 
+            this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+            
+            // unless explicitly set in options, make layer an overlay
+            if ( (options == null) || (!options.isBaseLayer) ) {
+                this.isBaseLayer = false;
+            } 
+            
+            // jpegs can never be transparent, so intelligently switch the 
+            //  format, depending on the browser's capabilities
+            if (this.params.FORMAT == "jpg") {
+                this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif"
+                                                                 : "png";
+            }
+        }
+    },    
+
+    
+    /**
+     * Method: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
+    },   
+    
+    /**
+         * Method: clone
+         * Create a clone of this layer
+         *
+         * Returns:
+         * {<OpenLayers.Layer.ArcGIS93Rest>} An exact clone of this layer
+         */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.ArcGIS93Rest(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },
+    
+    
+    /**
+     * Method: getURL
+     * Return an image url this layer.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+     *                                request.
+     *
+     * Returns:
+     * {String} A string with the map image's url.
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+
+        // ArcGIS Server only wants the numeric portion of the projection ID.
+        var projWords = this.projection.getCode().split(":");
+        var srid = projWords[projWords.length - 1];
+
+        var imageSize = this.getImageSize(); 
+        var newParams = {
+            'BBOX': bounds.toBBOX(),
+            'SIZE': imageSize.w + "," + imageSize.h,
+            // We always want image, the other options were json, image with a whole lotta html around it, etc.
+            'F': "image",
+            'BBOXSR': srid,
+            'IMAGESR': srid
+        };
+
+        // Now add the filter parameters.
+        if (this.layerDefs) {
+            var layerDefStrList = [];
+            var layerID;
+            for(layerID in this.layerDefs) {
+                if (this.layerDefs.hasOwnProperty(layerID)) {
+                    if (this.layerDefs[layerID]) {
+                        layerDefStrList.push(layerID);
+                        layerDefStrList.push(":");
+                        layerDefStrList.push(this.layerDefs[layerID]);
+                        layerDefStrList.push(";");
+                    }
+                }
+            }
+            if (layerDefStrList.length > 0) {
+                newParams['LAYERDEFS'] = layerDefStrList.join("");
+            }
+        }
+        var requestString = this.getFullRequestString(newParams);
+        return requestString;
+    },
+    
+    /**
+     * Method: setLayerFilter
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * id - {String} The id of the layer to which the filter applies.
+     * queryDef - {String} A sql-ish query filter, for more detail see the ESRI
+     *                     documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html
+     */
+    setLayerFilter: function ( id, queryDef ) {
+        if (!this.layerDefs) {
+            this.layerDefs = {};
+        }
+        if (queryDef) {
+            this.layerDefs[id] = queryDef;
+        } else {
+            delete this.layerDefs[id];
+        }
+    },
+    
+    /**
+     * Method: clearLayerFilter
+     * Clears layer filters, either from a specific layer,
+     * or all of them.
+     *
+     * Parameters:
+     * id - {String} The id of the layer from which to remove any
+     *               filter.  If unspecified/blank, all filters
+     *               will be removed.
+     */
+    clearLayerFilter: function ( id ) {
+        if (id) {
+            delete this.layerDefs[id];
+        } else {
+            delete this.layerDefs;
+        }
+    },
+    
+    /**
+     * APIMethod: mergeNewParams
+     * Catch changeParams and uppercase the new params to be merged in
+     *     before calling changeParams on the super class.
+     * 
+     *     Once params have been changed, the tiles will be reloaded with
+     *     the new parameters.
+     * 
+     * Parameters:
+     * newParams - {Object} Hashtable of new params to use
+     */
+    mergeNewParams:function(newParams) {
+        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
+        var newArguments = [upperParams];
+        return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
+                                                             newArguments);
+    },
+
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+
+    
+    CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcIMS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcIMS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/ArcIMS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,442 @@
+/* Copyright (c) 2008 MetaCarta, Inc., published under the Clear BSD 
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the 
+ * full text of the license. */ 
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ * @requires OpenLayers/Format/ArcXML.js
+ * @requires OpenLayers/Request.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.ArcIMS
+ * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS
+ *     Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS>
+ *     constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Default query string parameters.
+     */
+    DEFAULT_PARAMS: { 
+        ClientVersion: "9.2",
+        ServiceName: ''
+    },
+    
+    /**
+     * APIProperty: tileSize
+     * {<OpenLayers.Size>} Size for tiles.  Default is 512x512.
+     */
+    tileSize: null,
+    
+    /**
+     * APIProperty: featureCoordSys
+     * {String} Code for feature coordinate system.  Default is "4326".
+     */
+    featureCoordSys: "4326",
+    
+    /**
+     * APIProperty: filterCoordSys
+     * {String} Code for filter coordinate system.  Default is "4326".
+     */
+    filterCoordSys: "4326",
+    
+    /**
+     * APIProperty: layers
+     * {Array} An array of objects with layer properties.
+     */
+    layers: null,
+    
+    /**
+     * APIProperty: async
+     * {Boolean} Request images asynchronously.  Default is true.
+     */
+    async: true,
+    
+    /**
+     * APIProperty: name
+     * {String} Layer name.  Default is "ArcIMS".
+     */
+    name: "ArcIMS",
+
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} The layer is a base layer.  Default is true.
+     */
+    isBaseLayer: true,
+
+    /**
+     * Constant: DEFAULT_OPTIONS
+     * {Object} Default layers properties.
+     */
+    DEFAULT_OPTIONS: {
+        tileSize: new OpenLayers.Size(512, 512),
+        featureCoordSys: "4326",
+        filterCoordSys: "4326",
+        layers: null,
+        isBaseLayer: true,
+        async: true,
+        name: "ArcIMS"
+    }, 
+ 
+    /**
+     * Constructor: OpenLayers.Layer.ArcIMS
+     * Create a new ArcIMS layer object.
+     *
+     * Example:
+     * (code)
+     * var arcims = new OpenLayers.Layer.ArcIMS(
+     *     "Global Sample",
+     *     "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", 
+     *     {
+     *         service: "OpenLayers_Sample", 
+     *         layers: [
+     *             // layers to manipulate
+     *             {id: "1", visible: true}
+     *         ]
+     *     }
+     * );
+     * (end)
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the ArcIMS server
+     * options - {Object} Optional object with properties to be set on the
+     *     layer.
+     */
+    initialize: function(name, url, options) {
+        
+        this.tileSize = new OpenLayers.Size(512, 512);
+
+        // parameters
+        this.params = OpenLayers.Util.applyDefaults(
+            {ServiceName: options.serviceName},
+            this.DEFAULT_PARAMS
+        );
+        this.options = OpenLayers.Util.applyDefaults(
+            options, this.DEFAULT_OPTIONS
+        );
+          
+        OpenLayers.Layer.Grid.prototype.initialize.apply(
+            this, [name, url, this.params, options]
+        );
+
+        //layer is transparent        
+        if (this.transparent) {
+            
+            // unless explicitly set in options, make layer an overlay
+            if (!this.isBaseLayer) {
+                this.isBaseLayer = false;
+            } 
+            
+            // jpegs can never be transparent, so intelligently switch the 
+            //  format, depending on the browser's capabilities
+            if (this.format == "image/jpeg") {
+                this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png";
+            }
+        }
+
+        // create an empty layer list if no layers specified in the options
+        if (this.options.layers === null) {
+            this.options.layers = [];
+        }
+    },    
+
+    
+    /**
+     * Method: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
+    },   
+    
+    
+    /**
+     * Method: getURL
+     * Return an image url this layer.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+     *     request.
+     *
+     * Returns:
+     * {String} A string with the map image's url.
+     */
+    getURL: function(bounds) {
+        var url = "";
+        bounds = this.adjustBounds(bounds);
+        
+        // create an arcxml request to generate the image
+        var axlReq = new OpenLayers.Format.ArcXML( 
+            OpenLayers.Util.extend(this.options, {
+                requesttype: "image",
+                envelope: bounds.toArray(),
+                tileSize: this.tileSize
+            })
+        );
+        
+        // create a synchronous ajax request to get an arcims image
+        var req = new OpenLayers.Request.POST({
+            url: this.getFullRequestString(),
+            data: axlReq.write(),
+            async: false
+        });
+        
+        // if the response exists
+        if (req != null) {
+            var doc = req.responseXML;
+
+            if (!doc || !doc.documentElement) {            
+                doc = req.responseText;
+            }
+
+            // create a new arcxml format to read the response
+            var axlResp = new OpenLayers.Format.ArcXML();
+            var arcxml = axlResp.read(doc);
+            url = this.getUrlOrImage(arcxml.image.output);
+        }
+        
+        return url;
+    },
+    
+    
+    /**
+     * Method: getURLasync
+     * Get an image url this layer asynchronously, and execute a callback
+     *     when the image url is generated.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+     *     request.
+     * scope - {Object} The scope of the callback method.
+     * prop - {String} The name of the property in the scoped object to 
+     *     recieve the image url.
+     * callback - {Function} Function to call when image url is retrieved.
+     */
+    getURLasync: function(bounds, scope, prop, callback) {
+        bounds = this.adjustBounds(bounds);
+        
+        // create an arcxml request to generate the image
+        var axlReq = new OpenLayers.Format.ArcXML(  
+            OpenLayers.Util.extend(this.options, { 
+                requesttype: "image",
+                envelope: bounds.toArray(),
+                tileSize: this.tileSize
+            })
+        );
+        
+        // create an asynchronous ajax request to get an arcims image
+        OpenLayers.Request.POST({
+            url: this.getFullRequestString(),
+            async: true,
+            data: axlReq.write(),
+            callback: function(req) {
+                // process the response from ArcIMS, and call the callback function
+                // to set the image URL
+                var doc = req.responseXML;
+                if (!doc || !doc.documentElement) {            
+                    doc = req.responseText;
+                }
+
+                // create a new arcxml format to read the response
+                var axlResp = new OpenLayers.Format.ArcXML();
+                var arcxml = axlResp.read(doc);
+                
+                scope[prop] = this.getUrlOrImage(arcxml.image.output);
+
+                // call the callback function to recieve the updated property on the
+                // scoped object
+                callback.apply(scope);
+            },
+            scope: this
+        });
+    },
+    
+    /**
+     * Method: getUrlOrImage
+     * Extract a url or image from the ArcXML image output.
+     *
+     * Parameters:
+     * output - {Object} The image.output property of the object returned from
+     *     the ArcXML format read method.
+     *
+     * Returns:
+     * {String} A URL for an image (potentially with the data protocol).
+     */
+    getUrlOrImage: function(output) {
+        var ret = "";
+        if(output.url) {
+            // If the image response output url is a string, then the image
+            // data is not inline.
+            ret = output.url;
+        } else if(output.data) {
+            // The image data is inline and base64 encoded, create a data
+            // url for the image.  This will only work for small images,
+            // due to browser url length limits.
+            ret = "data:image/" + output.type + 
+                  ";base64," + output.data;
+        }
+        return ret;
+    },
+    
+    /**
+     * Method: setLayerQuery
+     * Set the query definition on this layer. Query definitions are used to
+     *     render parts of the spatial data in an image, and can be used to
+     *     filter features or layers in the ArcIMS service.
+     *
+     * Parameters:
+     * id - {String} The ArcIMS layer ID.
+     * queryDef - {Object} The query definition to apply to this layer.
+     */
+    setLayerQuery: function(id, querydef) {
+        // find the matching layer, if it exists
+        for (var lyr = 0; lyr < this.options.layers.length; lyr++) {
+            if (id == this.options.layers[lyr].id) {
+                // replace this layer definition
+                this.options.layers[lyr].query = querydef;
+                return;
+            }
+        }
+      
+        // no layer found, create a new definition
+        this.options.layers.push({id: id, visible: true, query: querydef});
+    },
+    
+    /**
+     * Method: getFeatureInfo
+     * Get feature information from ArcIMS.  Using the applied geometry, apply
+     *     the options to the query (buffer, area/envelope intersection), and
+     *     query the ArcIMS service.
+     *
+     * A note about accuracy:
+     * ArcIMS interprets the accuracy attribute in feature requests to be
+     *     something like the 'modulus' operator on feature coordinates,
+     *     applied to the database geometry of the feature.  It doesn't round,
+     *     so your feature coordinates may be up to (1 x accuracy) offset from
+     *     the actual feature coordinates.  If the accuracy of the layer is not
+     *     specified, the accuracy will be computed to be approximately 1
+     *     feature coordinate per screen  pixel.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The
+     *     geometry to use when making the query. This should be a closed
+     *     polygon for behavior approximating a free selection.
+     * layer - {Object} The ArcIMS layer definition. This is an anonymous object
+     *     that looks like:
+     * (code)
+     * {
+     *     id: "ArcXML layer ID",  // the ArcXML layer ID
+     *     query: {
+     *         where: "STATE = 'PA'",  // the where clause of the query
+     *         accuracy: 100           // the accuracy of the returned feature
+     *     }
+     * }
+     * (end)
+     * options - {Object} Object with non-default properties to set on the layer.
+     *     Supported properties are buffer, callback, scope, and any other
+     *     properties applicable to the ArcXML format.  Set the 'callback' and
+     *     'scope' for an object and function to recieve the parsed features
+     *     from ArcIMS.
+     */
+    getFeatureInfo: function(geometry, layer, options) {
+        // set the buffer to 1 unit (dd/m/ft?) by default
+        var buffer = options.buffer || 1;
+        // empty callback by default
+        var callback = options.callback || function() {};
+        // default scope is window (global)
+        var scope = options.scope || window;
+
+        // apply these option to the request options
+        var requestOptions = {};
+        OpenLayers.Util.extend(requestOptions, this.options);
+
+        // this is a feature request
+        requestOptions.requesttype = "feature";
+
+        if (geometry instanceof OpenLayers.LonLat) {
+            // create an envelope if the geometry is really a lon/lat
+            requestOptions.polygon = null;
+            requestOptions.envelope = [ 
+                geometry.lon - buffer, 
+                geometry.lat - buffer,
+                geometry.lon + buffer,
+                geometry.lat + buffer
+            ];
+        } else if (geometry instanceof OpenLayers.Geometry.Polygon) {
+            // use the polygon assigned, and empty the envelope
+            requestOptions.envelope = null;
+            requestOptions.polygon = geometry;
+        }
+      
+        // create an arcxml request to get feature requests
+        var arcxml = new OpenLayers.Format.ArcXML(requestOptions);
+
+        // apply any get feature options to the arcxml request
+        OpenLayers.Util.extend(arcxml.request.get_feature, options);
+
+        arcxml.request.get_feature.layer = layer.id;
+        if (typeof layer.query.accuracy == "number") {
+            // set the accuracy if it was specified
+            arcxml.request.get_feature.query.accuracy = layer.query.accuracy;
+        } else {
+            // guess that the accuracy is 1 per screen pixel
+            var mapCenter = this.map.getCenter();
+            var viewPx = this.map.getViewPortPxFromLonLat(mapCenter);
+            viewPx.x++;
+            var mapOffCenter = this.map.getLonLatFromPixel(viewPx);
+            arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon;
+        }
+        
+        // set the get_feature query to be the same as the layer passed in
+        arcxml.request.get_feature.query.where = layer.query.where;
+        
+        // use area_intersection
+        arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection";
+      
+        // create a new asynchronous request to get the feature info
+        OpenLayers.Request.POST({
+            url: this.getFullRequestString({'CustomService': 'Query'}),
+            data: arcxml.write(),
+            callback: function(request) {
+                // parse the arcxml response
+                var response = arcxml.parseResponse(request.responseText);
+                
+                if (!arcxml.iserror()) {
+                    // if the arcxml is not an error, call the callback with the features parsed
+                    callback.call(scope, response.features);
+                } else {
+                    // if the arcxml is an error, return null features selected
+                    callback.call(scope, null);
+                }
+            }
+        });
+    },
+    
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added image tile.
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(
+            this, position, bounds, null, this.tileSize
+        );
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.ArcIMS"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/FixedZoomLevels.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/FixedZoomLevels.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/FixedZoomLevels.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,314 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.FixedZoomLevels
+ *   Some Layers will already have established zoom levels (like google 
+ *    or ve). Instead of trying to determine them and populate a resolutions[]
+ *    Array with those values, we will hijack the resolution functionality
+ *    here.
+ * 
+ *   When you subclass FixedZoomLevels: 
+ * 
+ *   The initResolutions() call gets nullified, meaning no resolutions[] array 
+ *    is set up. Which would be a big problem getResolution() in Layer, since 
+ *    it merely takes map.zoom and indexes into resolutions[]... but....
+ * 
+ *   The getResolution() call is also overridden. Instead of using the 
+ *    resolutions[] array, we simply calculate the current resolution based
+ *    on the current extent and the current map size. But how will we be able
+ *    to calculate the current extent without knowing the resolution...?
+ *  
+ *   The getExtent() function is also overridden. Instead of calculating extent
+ *    based on the center point and the current resolution, we instead 
+ *    calculate the extent by getting the lonlats at the top-left and 
+ *    bottom-right by using the getLonLatFromViewPortPx() translation function,
+ *    taken from the pixel locations (0,0) and the size of the map. But how 
+ *    will we be able to do lonlat-px translation without resolution....?
+ * 
+ *   The getZoomForResolution() method is overridden. Instead of indexing into
+ *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
+ *    the desired resolution. With this extent, we then call getZoomForExtent() 
+ * 
+ * 
+ *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, 
+ *    it is your responsibility to provide the following three functions:
+ * 
+ *   - getLonLatFromViewPortPx
+ *   - getViewPortPxFromLonLat
+ *   - getZoomForExtent
+ * 
+ *  ...those three functions should generally be provided by any reasonable 
+ *  API that you might be working from.
+ *
+ */
+OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
+      
+  /********************************************************/
+  /*                                                      */
+  /*                 Baselayer Functions                  */
+  /*                                                      */
+  /*    The following functions must all be implemented   */
+  /*                  by all base layers                  */
+  /*                                                      */
+  /********************************************************/
+    
+    /**
+     * Constructor: OpenLayers.Layer.FixedZoomLevels
+     * Create a new fixed zoom levels layer.
+     */
+    initialize: function() {
+        //this class is only just to add the following functions... 
+        // nothing to actually do here... but it is probably a good
+        // idea to have layers that use these functions call this 
+        // inititalize() anyways, in case at some point we decide we 
+        // do want to put some functionality or state in here. 
+    },
+    
+    /**
+     * Method: initResolutions
+     * Populate the resolutions array
+     */
+    initResolutions: function() {
+
+        var props = new Array('minZoomLevel', 'maxZoomLevel', 'numZoomLevels');
+          
+        for(var i=0, len=props.length; i<len; i++) {
+            var property = props[i];
+            this[property] = (this.options[property] != null)  
+                                     ? this.options[property] 
+                                     : this.map[property];
+        }
+
+        if ( (this.minZoomLevel == null) ||
+             (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
+            this.minZoomLevel = this.MIN_ZOOM_LEVEL;
+        }        
+
+        //
+        // At this point, we know what the minimum desired zoom level is, and
+        //  we must calculate the total number of zoom levels. 
+        //  
+        //  Because we allow for the setting of either the 'numZoomLevels'
+        //   or the 'maxZoomLevel' properties... on either the layer or the  
+        //   map, we have to define some rules to see which we take into
+        //   account first in this calculation. 
+        //
+        // The following is the precedence list for these properties:
+        // 
+        // (1) numZoomLevels set on layer
+        // (2) maxZoomLevel set on layer
+        // (3) numZoomLevels set on map
+        // (4) maxZoomLevel set on map*
+        // (5) none of the above*
+        //
+        // *Note that options (4) and (5) are only possible if the user 
+        //  _explicitly_ sets the 'numZoomLevels' property on the map to 
+        //  null, since it is set by default to 16. 
+        //
+
+        //
+        // Note to future: In 3.0, I think we should remove the default 
+        // value of 16 for map.numZoomLevels. Rather, I think that value 
+        // should be set as a default on the Layer.WMS class. If someone
+        // creates a 3rd party layer and does not specify any 'minZoomLevel', 
+        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly 
+        // specified any of those on the map object either.. then I think
+        // it is fair to say that s/he wants all the zoom levels available.
+        // 
+        // By making map.numZoomLevels *null* by default, that will be the 
+        // case. As it is, I don't feel comfortable changing that right now
+        // as it would be a glaring API change and actually would probably
+        // break many peoples' codes. 
+        //
+
+        //the number of zoom levels we'd like to have.
+        var desiredZoomLevels;
+
+        //this is the maximum number of zoom levels the layer will allow, 
+        // given the specified starting minimum zoom level.
+        var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
+
+        if ( ((this.options.numZoomLevels == null) && 
+              (this.options.maxZoomLevel != null)) // (2)
+              ||
+             ((this.numZoomLevels == null) &&
+              (this.maxZoomLevel != null)) // (4)
+           ) {
+            //calculate based on specified maxZoomLevel (on layer or map)
+            desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
+        } else {
+            //calculate based on specified numZoomLevels (on layer or map)
+            // this covers cases (1) and (3)
+            desiredZoomLevels = this.numZoomLevels;
+        }
+
+        if (desiredZoomLevels != null) {
+            //Now that we know what we would *like* the number of zoom levels
+            // to be, based on layer or map options, we have to make sure that
+            // it does not conflict with the actual limit, as specified by 
+            // the constants on the layer itself (and calculated into the
+            // 'limitZoomLevels' variable). 
+            this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
+        } else {
+            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was 
+            // set on either the layer or the map. So we just use the 
+            // maximum limit as calculated by the layer's constants.
+            this.numZoomLevels = limitZoomLevels;
+        }
+
+        //now that the 'numZoomLevels' is appropriately, safely set, 
+        // we go back and re-calculate the 'maxZoomLevel'.
+        this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
+
+        if (this.RESOLUTIONS != null) {
+            var resolutionsIndex = 0;
+            this.resolutions = [];
+            for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
+                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];            
+            }
+            this.maxResolution = this.resolutions[0];
+            this.minResolution = this.resolutions[this.resolutions.length - 1];
+        }       
+    },
+    
+    /**
+     * APIMethod: getResolution
+     * Get the current map resolution
+     * 
+     * Returns:
+     * {Float} Map units per Pixel
+     */
+    getResolution: function() {
+
+        if (this.resolutions != null) {
+            return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
+        } else {
+            var resolution = null;
+            
+            var viewSize = this.map.getSize();
+            var extent = this.getExtent();
+            
+            if ((viewSize != null) && (extent != null)) {
+                resolution = Math.max( extent.getWidth()  / viewSize.w,
+                                       extent.getHeight() / viewSize.h );
+            }
+            return resolution;
+        }
+     },
+
+    /**
+     * APIMethod: getExtent
+     * Calculates using px-> lonlat translation functions on tl and br 
+     *     corners of viewport
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *                       bounds of the current viewPort.
+     */
+    getExtent: function () {
+        var extent = null;
+        
+        
+        var size = this.map.getSize();
+        
+        var tlPx = new OpenLayers.Pixel(0,0);
+        var tlLL = this.getLonLatFromViewPortPx(tlPx);
+
+        var brPx = new OpenLayers.Pixel(size.w, size.h);
+        var brLL = this.getLonLatFromViewPortPx(brPx);
+        
+        if ((tlLL != null) && (brLL != null)) {
+            extent = new OpenLayers.Bounds(tlLL.lon, 
+                                       brLL.lat, 
+                                       brLL.lon, 
+                                       tlLL.lat);
+        }
+
+        return extent;
+    },
+
+    /**
+     * Method: getZoomForResolution
+     * Get the zoom level for a given resolution
+     *
+     * Parameters:
+     * resolution - {Float}
+     *
+     * Returns:
+     * {Integer} A suitable zoom level for the specified resolution.
+     *           If no baselayer is set, returns null.
+     */
+    getZoomForResolution: function(resolution) {
+      
+        if (this.resolutions != null) {
+            return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
+        } else {
+            var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
+            return this.getZoomForExtent(extent);
+        }
+    },
+
+
+
+    
+    /********************************************************/
+    /*                                                      */
+    /*             Translation Functions                    */
+    /*                                                      */
+    /*    The following functions translate GMaps and OL    */ 
+    /*     formats for Pixel, LonLat, Bounds, and Zoom      */
+    /*                                                      */
+    /********************************************************/
+    
+    
+    //
+    // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
+    //
+  
+    /**
+     * Method: getOLZoomFromMapObjectZoom
+     * Get the OL zoom index from the map object zoom level
+     *
+     * Parameters:
+     * moZoom - {Integer}
+     * 
+     * Returns:
+     * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
+     *           Returns null if null value is passed in
+     */
+    getOLZoomFromMapObjectZoom: function(moZoom) {
+        var zoom = null;
+        if (moZoom != null) {
+            zoom = moZoom - this.minZoomLevel;
+        }
+        return zoom;
+    },
+    
+    /**
+     * Method: getMapObjectZoomFromOLZoom
+     * Get the map object zoom level from the OL zoom level
+     *
+     * Parameters:
+     * olZoom - {Integer}
+     * 
+     * Returns:
+     * {Integer} A MapObject level, translated from the passed in olZoom
+     *           Returns null if null value is passed in
+     */
+    getMapObjectZoomFromOLZoom: function(olZoom) {
+        var zoom = null; 
+        if (olZoom != null) {
+            zoom = olZoom + this.minZoomLevel;
+        }
+        return zoom;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
+});
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/GeoRSS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/GeoRSS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/GeoRSS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,265 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Markers.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.GeoRSS
+ * Add GeoRSS Point features to your map. 
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Markers>
+ *  - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, {
+
+    /** 
+     * Property: location 
+     * {String} store url of text file 
+     */
+    location: null,
+
+    /** 
+     * Property: features 
+     * {Array(<OpenLayers.Feature>)} 
+     */
+    features: null,
+    
+    /**
+     * APIProperty: formatOptions
+     * {Object} Hash of options which should be passed to the format when it is
+     * created. Must be passed in the constructor.
+     */
+    formatOptions: null, 
+
+    /** 
+     * Property: selectedFeature 
+     * {<OpenLayers.Feature>} 
+     */
+    selectedFeature: null,
+
+    /** 
+     * APIProperty: icon 
+     * {<OpenLayers.Icon>}. This determines the Icon to be used on the map
+     * for this GeoRSS layer.
+     */
+    icon: null,
+
+    /**
+     * APIProperty: popupSize
+     * {<OpenLayers.Size>} This determines the size of GeoRSS popups. If 
+     * not provided, defaults to 250px by 120px. 
+     */
+    popupSize: null, 
+    
+    /** 
+     * APIProperty: useFeedTitle 
+     * {Boolean} Set layer.name to the first <title> element in the feed. Default is true. 
+     */
+    useFeedTitle: true,
+    
+    /**
+    * Constructor: OpenLayers.Layer.GeoRSS
+    * Create a GeoRSS Layer.
+    *
+    * Parameters:
+    * name - {String} 
+    * location - {String} 
+    * options - {Object}
+    */
+    initialize: function(name, location, options) {
+        OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]);
+        this.location = location;
+        this.features = [];
+    },
+
+    /**
+     * Method: destroy 
+     */
+    destroy: function() {
+        // Warning: Layer.Markers.destroy() must be called prior to calling
+        // clearFeatures() here, otherwise we leak memory. Indeed, if
+        // Layer.Markers.destroy() is called after clearFeatures(), it won't be
+        // able to remove the marker image elements from the layer's div since
+        // the markers will have been destroyed by clearFeatures().
+        OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
+        this.clearFeatures();
+        this.features = null;
+    },
+
+    /**
+     * Method: loadRSS
+     * Start the load of the RSS data. Don't do this when we first add the layer,
+     * since we may not be visible at any point, and it would therefore be a waste.
+     */
+    loadRSS: function() {
+        if (!this.loaded) {
+            this.events.triggerEvent("loadstart");
+            OpenLayers.Request.GET({
+                url: this.location,
+                success: this.parseData,
+                scope: this
+            });
+            this.loaded = true;
+        }    
+    },    
+    
+    /**
+     * Method: moveTo
+     * If layer is visible and RSS has not been loaded, load RSS. 
+     * 
+     * Parameters:
+     * bounds - {Object} 
+     * zoomChanged - {Object} 
+     * minor - {Object} 
+     */
+    moveTo:function(bounds, zoomChanged, minor) {
+        OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
+        if(this.visibility && !this.loaded){
+            this.loadRSS();
+        }
+    },
+        
+    /**
+     * Method: parseData
+     * Parse the data returned from the Events call.
+     *
+     * Parameters:
+     * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} 
+     */
+    parseData: function(ajaxRequest) {
+        var doc = ajaxRequest.responseXML;
+        if (!doc || !doc.documentElement) {
+            doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText);
+        }
+        
+        if (this.useFeedTitle) {
+            var name = null;
+            try {
+                name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue;
+            }
+            catch (e) {
+                name = doc.getElementsByTagName('title')[0].firstChild.nodeValue;
+            }
+            if (name) {
+                this.setName(name);
+            }    
+        }
+       
+        var options = {};
+        
+        OpenLayers.Util.extend(options, this.formatOptions);
+        
+        if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
+            options.externalProjection = this.projection;
+            options.internalProjection = this.map.getProjectionObject();
+        }    
+        
+        var format = new OpenLayers.Format.GeoRSS(options);
+        var features = format.read(doc);
+        
+        for (var i=0, len=features.length; i<len; i++) {
+            var data = {};
+            var feature = features[i];
+            
+            // we don't support features with no geometry in the GeoRSS
+            // layer at this time. 
+            if (!feature.geometry) {
+                continue;
+            }    
+            
+            var title = feature.attributes.title ? 
+                         feature.attributes.title : "Untitled";
+            
+            var description = feature.attributes.description ? 
+                         feature.attributes.description : "No description.";
+            
+            var link = feature.attributes.link ? feature.attributes.link : "";
+
+            var location = feature.geometry.getBounds().getCenterLonLat();
+            
+            
+            data.icon = this.icon == null ? 
+                                     OpenLayers.Marker.defaultIcon() : 
+                                     this.icon.clone();
+            
+            data.popupSize = this.popupSize ? 
+                             this.popupSize.clone() :
+                             new OpenLayers.Size(250, 120);
+            
+            if (title || description) {
+                // we have supplemental data, store them.
+                data.title = title;
+                data.description = description;
+            
+                var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; 
+                contentHTML += '<div class="olLayerGeoRSSTitle">';
+                if (link) {
+                    contentHTML += '<a class="link" href="'+link+'" target="_blank">';
+                }
+                contentHTML += title;
+                if (link) {
+                    contentHTML += '</a>';
+                }
+                contentHTML += '</div>';
+                contentHTML += '<div style="" class="olLayerGeoRSSDescription">';
+                contentHTML += description;
+                contentHTML += '</div>';
+                data['popupContentHTML'] = contentHTML;                
+            }
+            var feature = new OpenLayers.Feature(this, location, data);
+            this.features.push(feature);
+            var marker = feature.createMarker();
+            marker.events.register('click', feature, this.markerClick);
+            this.addMarker(marker);
+        }
+        this.events.triggerEvent("loadend");
+    },
+    
+    /**
+     * Method: markerClick
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    markerClick: function(evt) {
+        var sameMarkerClicked = (this == this.layer.selectedFeature);
+        this.layer.selectedFeature = (!sameMarkerClicked) ? this : null;
+        for(var i=0, len=this.layer.map.popups.length; i<len; i++) {
+            this.layer.map.removePopup(this.layer.map.popups[i]);
+        }
+        if (!sameMarkerClicked) {
+            var popup = this.createPopup();
+            OpenLayers.Event.observe(popup.div, "click",
+                OpenLayers.Function.bind(function() { 
+                    for(var i=0, len=this.layer.map.popups.length; i<len; i++) { 
+                        this.layer.map.removePopup(this.layer.map.popups[i]); 
+                    }
+                }, this)
+            );
+            this.layer.map.addPopup(popup); 
+        }
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: clearFeatures
+     * Destroy all features in this layer.
+     */
+    clearFeatures: function() {
+        if (this.features != null) {
+            while(this.features.length > 0) {
+                var feature = this.features[0];
+                OpenLayers.Util.removeItem(this.features, feature);
+                feature.destroy();
+            }
+        }        
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.GeoRSS"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Google.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Google.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Google.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,599 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/SphericalMercator.js
+ * @requires OpenLayers/Layer/EventPane.js
+ * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Google
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.SphericalMercator>
+ *  - <OpenLayers.Layer.EventPane>
+ *  - <OpenLayers.Layer.FixedZoomLevels>
+ */
+OpenLayers.Layer.Google = OpenLayers.Class(
+    OpenLayers.Layer.EventPane, 
+    OpenLayers.Layer.FixedZoomLevels, {
+    
+    /** 
+     * Constant: MIN_ZOOM_LEVEL
+     * {Integer} 0 
+     */
+    MIN_ZOOM_LEVEL: 0,
+    
+    /** 
+     * Constant: MAX_ZOOM_LEVEL
+     * {Integer} 19
+     */
+    MAX_ZOOM_LEVEL: 19,
+
+    /** 
+     * Constant: RESOLUTIONS
+     * {Array(Float)} Hardcode these resolutions so that they are more closely
+     *                tied with the standard wms projection
+     */
+    RESOLUTIONS: [
+        1.40625, 
+        0.703125, 
+        0.3515625, 
+        0.17578125, 
+        0.087890625, 
+        0.0439453125,
+        0.02197265625, 
+        0.010986328125, 
+        0.0054931640625, 
+        0.00274658203125,
+        0.001373291015625, 
+        0.0006866455078125, 
+        0.00034332275390625,
+        0.000171661376953125, 
+        0.0000858306884765625, 
+        0.00004291534423828125,
+        0.00002145767211914062, 
+        0.00001072883605957031,
+        0.00000536441802978515, 
+        0.00000268220901489257
+    ],
+
+    /**
+     * APIProperty: type
+     * {GMapType}
+     */
+    type: null,
+
+    /**
+     * APIProperty: sphericalMercator
+     * {Boolean} Should the map act as a mercator-projected map? This will
+     *     cause all interactions with the map to be in the actual map 
+     *     projection, which allows support for vector drawing, overlaying 
+     *     other maps, etc. 
+     */
+    sphericalMercator: false, 
+    
+    /**
+     * Property: dragObject
+     * {GDraggableObject} Since 2.93, Google has exposed the ability to get
+     *     the maps GDraggableObject. We can now use this for smooth panning
+     */
+    dragObject: null, 
+
+    /**
+     * Property: termsOfUse
+     * {DOMElement} Div for Google's copyright and terms of use link
+     */
+    termsOfUse: null, 
+
+    /**
+     * Property: poweredBy
+     * {DOMElement} Div for Google's powered by logo and link
+     */
+    poweredBy: null, 
+
+    /** 
+     * Constructor: OpenLayers.Layer.Google
+     * 
+     * Parameters:
+     * name - {String} A name for the layer.
+     * options - {Object} An optional object whose properties will be set
+     *     on the layer.
+     */
+    initialize: function(name, options) {
+        OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
+                                                                    arguments);
+        this.addContainerPxFunction();
+        if (this.sphericalMercator) {
+            OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
+            this.initMercatorParameters();
+        }    
+    },
+    
+    /** 
+     * Method: loadMapObject
+     * Load the GMap and register appropriate event listeners. If we can't 
+     *     load GMap2, then display a warning message.
+     */
+    loadMapObject:function() {
+        
+        //has gmaps library has been loaded?
+        try {
+            // create GMap, hide nav controls
+            this.mapObject = new GMap2( this.div );
+            
+            //since v 2.93 getDragObject is now available.
+            if(typeof this.mapObject.getDragObject == "function") {
+                this.dragObject = this.mapObject.getDragObject();
+            } else {
+                this.dragPanMapObject = null;
+            }
+
+            // move the ToS and branding stuff up to the container div
+            this.termsOfUse = this.div.lastChild;
+            this.div.removeChild(this.termsOfUse);
+            if (this.isFixed) {
+                this.map.viewPortDiv.appendChild(this.termsOfUse);
+            } else {
+                this.map.layerContainerDiv.appendChild(this.termsOfUse);
+            }
+            this.termsOfUse.style.zIndex = "1100";
+            this.termsOfUse.style.display = this.div.style.display;
+            this.termsOfUse.style.right = "";
+            this.termsOfUse.style.bottom = "";
+            this.termsOfUse.className = "olLayerGoogleCopyright";
+
+            this.poweredBy = this.div.lastChild;
+            this.div.removeChild(this.poweredBy);
+            if (this.isFixed) {
+                this.map.viewPortDiv.appendChild(this.poweredBy);
+            } else {
+                this.map.layerContainerDiv.appendChild(this.poweredBy);
+            }
+            this.poweredBy.style.zIndex = "1100";
+            this.poweredBy.style.display = this.div.style.display;
+            this.poweredBy.style.right = "";
+            this.poweredBy.style.bottom = "";
+            this.poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; 
+
+        } catch (e) {
+            OpenLayers.Console.error(e);
+        }
+               
+    },
+
+    /** 
+     * APIMethod: setMap
+     * Overridden from EventPane because if a map type has been specified, 
+     *     we need to attach a listener for the first moveend -- this is how 
+     *     we will know that the map has been centered. Only once the map has 
+     *     been centered is it safe to change the gmap object's map type. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
+
+        if (this.type != null) {
+            this.map.events.register("moveend", this, this.setMapType);
+        }
+    },
+    
+    /** 
+     * Method: setMapType
+     * The map has been centered, and a map type was specified, so we 
+     *     set the map type on the gmap object, then unregister the listener
+     *     so that we dont keep doing this every time the map moves.
+     */
+    setMapType: function() {
+        if (this.mapObject.getCenter() != null) {
+            
+            // Support for custom map types.
+            if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
+                                        this.type) == -1) {
+                this.mapObject.addMapType(this.type);
+            }    
+
+            this.mapObject.setMapType(this.type);
+            this.map.events.unregister("moveend", this, this.setMapType);
+        }
+    },
+
+    /**
+     * APIMethod: onMapResize
+     * 
+     * Parameters:
+     * evt - {Event}
+     */
+    onMapResize: function() {
+        // workaround for resizing of invisible or not yet fully loaded layers
+        // where GMap2.checkResize() does not work. We need to load the GMap
+        // for the old div size, then checkResize(), and then call
+        // layer.moveTo() to trigger GMap.setCenter() (which will finish
+        // the GMap initialization).
+        if(this.visibility && this.mapObject.isLoaded()) {
+            this.mapObject.checkResize();
+        } else {
+            if(!this._resized) {
+                var layer = this;
+                var handle = GEvent.addListener(this.mapObject, "load", function() {
+                    GEvent.removeListener(handle);
+                    delete layer._resized;
+                    layer.mapObject.checkResize();
+                    layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
+                })
+            }
+            this._resized = true;
+        }
+    },
+
+    /**
+     * Method: display
+     * Hide or show the layer
+     *
+     * Parameters:
+     * display - {Boolean}
+     */
+    display: function(display) {
+        OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
+        this.termsOfUse.style.display = this.div.style.display;
+        this.poweredBy.style.display = this.div.style.display;
+    },
+
+    /**
+     * APIMethod: removeMap
+     * On being removed from the map, also remove termsOfUse and poweredBy divs
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    removeMap: function(map) {
+        if (this.termsOfUse && this.termsOfUse.parentNode) {
+            this.termsOfUse.parentNode.removeChild(this.termsOfUse);
+            this.termsOfUse = null;
+        }
+        if (this.poweredBy && this.poweredBy.parentNode) {
+            this.poweredBy.parentNode.removeChild(this.poweredBy);
+            this.poweredBy = null;
+        }
+        OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
+    },
+    
+    /**
+     * APIMethod: getZoomForExtent
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     *  
+     * Returns:
+     * {Integer} Corresponding zoom level for a specified Bounds. 
+     *           If mapObject is not loaded or not centered, returns null
+     *
+    getZoomForExtent: function (bounds) {
+        var zoom = null;
+        if (this.mapObject != null) {
+            var moBounds = this.getMapObjectBoundsFromOLBounds(bounds);
+            var moZoom = this.getMapObjectZoomFromMapObjectBounds(moBounds);
+
+            //make sure zoom is within bounds    
+            var moZoom = Math.min(Math.max(moZoom, this.minZoomLevel), 
+                                 this.maxZoomLevel);
+
+            zoom = this.getOLZoomFromMapObjectZoom(moZoom);
+        }
+        return zoom;
+    },
+    
+    */
+    
+  //
+  // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
+  //
+
+    /**
+     * APIMethod: getOLBoundsFromMapObjectBounds
+     * 
+     * Parameters:
+     * moBounds - {Object}
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the 
+     *                       passed-in MapObject Bounds.
+     *                       Returns null if null value is passed in.
+     */
+    getOLBoundsFromMapObjectBounds: function(moBounds) {
+        var olBounds = null;
+        if (moBounds != null) {
+            var sw = moBounds.getSouthWest();
+            var ne = moBounds.getNorthEast();
+            if (this.sphericalMercator) {
+                sw = this.forwardMercator(sw.lng(), sw.lat());
+                ne = this.forwardMercator(ne.lng(), ne.lat());
+            } else {
+                sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); 
+                ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); 
+            }    
+            olBounds = new OpenLayers.Bounds(sw.lon, 
+                                             sw.lat, 
+                                             ne.lon, 
+                                             ne.lat );
+        }
+        return olBounds;
+    },
+
+    /**
+     * APIMethod: getMapObjectBoundsFromOLBounds
+     * 
+     * Parameters:
+     * olBounds - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {Object} A MapObject Bounds, translated from olBounds
+     *          Returns null if null value is passed in
+     */
+    getMapObjectBoundsFromOLBounds: function(olBounds) {
+        var moBounds = null;
+        if (olBounds != null) {
+            var sw = this.sphericalMercator ? 
+              this.inverseMercator(olBounds.bottom, olBounds.left) : 
+              new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
+            var ne = this.sphericalMercator ? 
+              this.inverseMercator(olBounds.top, olBounds.right) : 
+              new OpenLayers.LonLat(olBounds.top, olBounds.right);
+            moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
+                                         new GLatLng(ne.lat, ne.lon));
+        }
+        return moBounds;
+    },
+
+    /** 
+     * Method: addContainerPxFunction
+     * Hack-on function because GMAPS does not give it to us
+     * 
+     * Parameters: 
+     * gLatLng - {GLatLng}
+     * 
+     * Returns:
+     * {GPoint} A GPoint specifying gLatLng translated into "Container" coords
+     */
+    addContainerPxFunction: function() {
+        if ( (typeof GMap2 != "undefined") && 
+             !GMap2.prototype.fromLatLngToContainerPixel) {
+          
+            GMap2.prototype.fromLatLngToContainerPixel = function(gLatLng) {
+          
+                // first we translate into "DivPixel"
+                var gPoint = this.fromLatLngToDivPixel(gLatLng);
+      
+                // locate the sliding "Div" div
+                var div = this.getContainer().firstChild.firstChild;
+  
+                // adjust by the offset of "Div" and voila!
+                gPoint.x += div.offsetLeft;
+                gPoint.y += div.offsetTop;
+    
+                return gPoint;
+            };
+        }
+    },
+
+    /** 
+     * APIMethod: getWarningHTML
+     * 
+     * Returns: 
+     * {String} String with information on why layer is broken, how to get
+     *          it working.
+     */
+    getWarningHTML:function() {
+        return OpenLayers.i18n("googleWarning");
+    },
+
+
+    /************************************
+     *                                  *
+     *   MapObject Interface Controls   *
+     *                                  *
+     ************************************/
+
+
+  // Get&Set Center, Zoom
+
+    /** 
+     * APIMethod: setMapObjectCenter
+     * Set the mapObject to the specified center and zoom
+     * 
+     * Parameters:
+     * center - {Object} MapObject LonLat format
+     * zoom - {int} MapObject zoom format
+     */
+    setMapObjectCenter: function(center, zoom) {
+        this.mapObject.setCenter(center, zoom); 
+    },
+   
+    /**
+     * APIMethod: dragPanMapObject
+     * 
+     * Parameters:
+     * dX - {Integer}
+     * dY - {Integer}
+     */
+    dragPanMapObject: function(dX, dY) {
+        this.dragObject.moveBy(new GSize(-dX, dY));
+    },
+
+    /**
+     * APIMethod: getMapObjectCenter
+     * 
+     * Returns: 
+     * {Object} The mapObject's current center in Map Object format
+     */
+    getMapObjectCenter: function() {
+        return this.mapObject.getCenter();
+    },
+
+    /** 
+     * APIMethod: getMapObjectZoom
+     * 
+     * Returns:
+     * {Integer} The mapObject's current zoom, in Map Object format
+     */
+    getMapObjectZoom: function() {
+        return this.mapObject.getZoom();
+    },
+
+
+  // LonLat - Pixel Translation
+  
+    /**
+     * APIMethod: getMapObjectLonLatFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Object} MapObject LonLat translated from MapObject Pixel
+     */
+    getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+        return this.mapObject.fromContainerPixelToLatLng(moPixel);
+    },
+
+    /**
+     * APIMethod: getMapObjectPixelFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Object} MapObject Pixel transtlated from MapObject LonLat
+     */
+    getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+        return this.mapObject.fromLatLngToContainerPixel(moLonLat);
+    },
+
+  
+  // Bounds
+  
+    /** 
+     * APIMethod: getMapObjectZoomFromMapObjectBounds
+     * 
+     * Parameters:
+     * moBounds - {Object} MapObject Bounds format
+     * 
+     * Returns:
+     * {Object} MapObject Zoom for specified MapObject Bounds
+     */
+    getMapObjectZoomFromMapObjectBounds: function(moBounds) {
+        return this.mapObject.getBoundsZoomLevel(moBounds);
+    },
+
+    /************************************
+     *                                  *
+     *       MapObject Primitives       *
+     *                                  *
+     ************************************/
+
+
+  // LonLat
+    
+    /**
+     * APIMethod: getLongitudeFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Longitude of the given MapObject LonLat
+     */
+    getLongitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
+          moLonLat.lng();  
+    },
+
+    /**
+     * APIMethod: getLatitudeFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Latitude of the given MapObject LonLat
+     */
+    getLatitudeFromMapObjectLonLat: function(moLonLat) {
+        var lat = this.sphericalMercator ? 
+          this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
+          moLonLat.lat(); 
+        return lat;  
+    },
+    
+    /**
+     * APIMethod: getMapObjectLonLatFromLonLat
+     * 
+     * Parameters:
+     * lon - {Float}
+     * lat - {Float}
+     * 
+     * Returns:
+     * {Object} MapObject LonLat built from lon and lat params
+     */
+    getMapObjectLonLatFromLonLat: function(lon, lat) {
+        var gLatLng;
+        if(this.sphericalMercator) {
+            var lonlat = this.inverseMercator(lon, lat);
+            gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
+        } else {
+            gLatLng = new GLatLng(lat, lon);
+        }
+        return gLatLng;
+    },
+
+  // Pixel
+    
+    /**
+     * APIMethod: getXFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} X value of the MapObject Pixel
+     */
+    getXFromMapObjectPixel: function(moPixel) {
+        return moPixel.x;
+    },
+
+    /**
+     * APIMethod: getYFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} Y value of the MapObject Pixel
+     */
+    getYFromMapObjectPixel: function(moPixel) {
+        return moPixel.y;
+    },
+
+    /**
+     * APIMethod: getMapObjectPixelFromXY
+     * 
+     * Parameters:
+     * x - {Integer}
+     * y - {Integer}
+     * 
+     * Returns:
+     * {Object} MapObject Pixel from x and y parameters
+     */
+    getMapObjectPixelFromXY: function(x, y) {
+        return new GPoint(x, y);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.Google"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Grid.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Grid.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Grid.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,742 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/HTTPRequest.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Grid
+ * Base class for layers that use a lattice of tiles.  Create a new grid
+ * layer with the <OpenLayers.Layer.Grid> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.HTTPRequest>
+ */
+OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+    
+    /**
+     * APIProperty: tileSize
+     * {<OpenLayers.Size>}
+     */
+    tileSize: null,
+    
+    /**
+     * Property: grid
+     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is 
+     *     an array of tiles.
+     */
+    grid: null,
+
+    /**
+     * APIProperty: singleTile
+     * {Boolean} Moves the layer into single-tile mode, meaning that one tile 
+     *     will be loaded. The tile's size will be determined by the 'ratio'
+     *     property. When the tile is dragged such that it does not cover the 
+     *     entire viewport, it is reloaded.
+     */
+    singleTile: false,
+
+    /** APIProperty: ratio
+     *  {Float} Used only when in single-tile mode, this specifies the 
+     *          ratio of the size of the single tile to the size of the map.
+     */
+    ratio: 1.5,
+
+    /**
+     * APIProperty: buffer
+     * {Integer} Used only when in gridded mode, this specifies the number of 
+     *           extra rows and colums of tiles on each side which will
+     *           surround the minimum grid tiles to cover the map.
+     */
+    buffer: 2,
+
+    /**
+     * APIProperty: numLoadingTiles
+     * {Integer} How many tiles are still loading?
+     */
+    numLoadingTiles: 0,
+
+    /**
+     * Constructor: OpenLayers.Layer.Grid
+     * Create a new grid layer
+     *
+     * Parameters:
+     * name - {String}
+     * url - {String}
+     * params - {Object}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, 
+                                                                arguments);
+        
+        //grid layers will trigger 'tileloaded' when each new tile is 
+        // loaded, as a means of progress update to listeners.
+        // listeners can access 'numLoadingTiles' if they wish to keep track
+        // of the loading progress
+        //
+        this.events.addEventType("tileloaded");
+
+        this.grid = [];
+    },
+
+    /**
+     * APIMethod: destroy
+     * Deconstruct the layer and clear the grid.
+     */
+    destroy: function() {
+        this.clearGrid();
+        this.grid = null;
+        this.tileSize = null;
+        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); 
+    },
+
+    /**
+     * Method: clearGrid
+     * Go through and remove all tiles from the grid, calling
+     *    destroy() on each of them to kill circular references
+     */
+    clearGrid:function() {
+        if (this.grid) {
+            for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
+                var row = this.grid[iRow];
+                for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
+                    var tile = row[iCol];
+                    this.removeTileMonitoringHooks(tile);
+                    tile.destroy();
+                }
+            }
+            this.grid = [];
+        }
+    },
+
+    /**
+     * APIMethod: clone
+     * Create a clone of this layer
+     *
+     * Parameters:
+     * obj - {Object} Is this ever used?
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.Grid(this.name,
+                                            this.url,
+                                            this.params,
+                                            this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+        if (this.tileSize != null) {
+            obj.tileSize = this.tileSize.clone();
+        }
+        
+        // we do not want to copy reference to grid, so we make a new array
+        obj.grid = [];
+
+        return obj;
+    },    
+
+    /**
+     * Method: moveTo
+     * This function is called whenever the map is moved. All the moving
+     * of actual 'tiles' is done by the map, but moveTo's role is to accept
+     * a bounds and make sure the data that that bounds requires is pre-loaded.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean}
+     * dragging - {Boolean}
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
+        
+        bounds = bounds || this.map.getExtent();
+
+        if (bounds != null) {
+             
+            // if grid is empty or zoom has changed, we *must* re-tile
+            var forceReTile = !this.grid.length || zoomChanged;
+
+            // total bounds of the tiles
+            var tilesBounds = this.getTilesBounds();            
+      
+            if (this.singleTile) {
+                
+                // We want to redraw whenever even the slightest part of the 
+                //  current bounds is not contained by our tile.
+                //  (thus, we do not specify partial -- its default is false)
+                if ( forceReTile || 
+                     (!dragging && !tilesBounds.containsBounds(bounds))) {
+                    this.initSingleTile(bounds);
+                }
+            } else {
+             
+                // if the bounds have changed such that they are not even 
+                //  *partially* contained by our tiles (IE user has 
+                //  programmatically panned to the other side of the earth) 
+                //  then we want to reTile (thus, partial true).  
+                //
+                if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
+                    this.initGriddedTiles(bounds);
+                } else {
+                    //we might have to shift our buffer tiles
+                    this.moveGriddedTiles(bounds);
+                }
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: setTileSize
+     * Check if we are in singleTile mode and if so, set the size as a ratio
+     *     of the map size (as specified by the layer's 'ratio' property).
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setTileSize: function(size) { 
+        if (this.singleTile) {
+            size = this.map.getSize().clone();
+            size.h = parseInt(size.h * this.ratio);
+            size.w = parseInt(size.w * this.ratio);
+        } 
+        OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+    },
+        
+    /**
+     * Method: getGridBounds
+     * Deprecated. This function will be removed in 3.0. Please use 
+     *     getTilesBounds() instead.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+     * currently loaded tiles (including those partially or not at all seen 
+     * onscreen)
+     */
+    getGridBounds: function() {
+        var msg = "The getGridBounds() function is deprecated. It will be " +
+                  "removed in 3.0. Please use getTilesBounds() instead.";
+        OpenLayers.Console.warn(msg);
+        return this.getTilesBounds();
+    },
+
+    /**
+     * APIMethod: getTilesBounds
+     * Return the bounds of the tile grid.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+     *     currently loaded tiles (including those partially or not at all seen 
+     *     onscreen).
+     */
+    getTilesBounds: function() {    
+        var bounds = null; 
+        
+        if (this.grid.length) {
+            var bottom = this.grid.length - 1;
+            var bottomLeftTile = this.grid[bottom][0];
+    
+            var right = this.grid[0].length - 1; 
+            var topRightTile = this.grid[0][right];
+    
+            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left, 
+                                           bottomLeftTile.bounds.bottom,
+                                           topRightTile.bounds.right, 
+                                           topRightTile.bounds.top);
+            
+        }   
+        return bounds;
+    },
+
+    /**
+     * Method: initSingleTile
+     * 
+     * Parameters: 
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    initSingleTile: function(bounds) {
+
+        //determine new tile bounds
+        var center = bounds.getCenterLonLat();
+        var tileWidth = bounds.getWidth() * this.ratio;
+        var tileHeight = bounds.getHeight() * this.ratio;
+                                       
+        var tileBounds = 
+            new OpenLayers.Bounds(center.lon - (tileWidth/2),
+                                  center.lat - (tileHeight/2),
+                                  center.lon + (tileWidth/2),
+                                  center.lat + (tileHeight/2));
+  
+        var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+        var px = this.map.getLayerPxFromLonLat(ul);
+
+        if (!this.grid.length) {
+            this.grid[0] = [];
+        }
+
+        var tile = this.grid[0][0];
+        if (!tile) {
+            tile = this.addTile(tileBounds, px);
+            
+            this.addTileMonitoringHooks(tile);
+            tile.draw();
+            this.grid[0][0] = tile;
+        } else {
+            tile.moveTo(tileBounds, px);
+        }           
+        
+        //remove all but our single tile
+        this.removeExcessTiles(1,1);
+    },
+
+    /** 
+     * Method: calculateGridLayout
+     * Generate parameters for the grid layout. This  
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bound>}
+     * extent - {<OpenLayers.Bounds>}
+     * resolution - {Number}
+     *
+     * Returns:
+     * Object containing properties tilelon, tilelat, tileoffsetlat,
+     * tileoffsetlat, tileoffsetx, tileoffsety
+     */
+    calculateGridLayout: function(bounds, extent, resolution) {
+        var tilelon = resolution * this.tileSize.w;
+        var tilelat = resolution * this.tileSize.h;
+        
+        var offsetlon = bounds.left - extent.left;
+        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+        var tilecolremain = offsetlon/tilelon - tilecol;
+        var tileoffsetx = -tilecolremain * this.tileSize.w;
+        var tileoffsetlon = extent.left + tilecol * tilelon;
+        
+        var offsetlat = bounds.top - (extent.bottom + tilelat);  
+        var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+        var tilerowremain = tilerow - offsetlat/tilelat;
+        var tileoffsety = -tilerowremain * this.tileSize.h;
+        var tileoffsetlat = extent.bottom + tilerow * tilelat;
+        
+        return { 
+          tilelon: tilelon, tilelat: tilelat,
+          tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+          tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+        };
+
+    },
+
+    /**
+     * Method: initGriddedTiles
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    initGriddedTiles:function(bounds) {
+        
+        // work out mininum number of rows and columns; this is the number of
+        // tiles required to cover the viewport plus at least one for panning
+
+        var viewSize = this.map.getSize();
+        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 
+                      Math.max(1, 2 * this.buffer);
+        var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
+                      Math.max(1, 2 * this.buffer);
+        
+        var extent = this.maxExtent;
+        var resolution = this.map.getResolution();
+        
+        var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
+
+        var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
+        var tileoffsety = Math.round(tileLayout.tileoffsety);
+
+        var tileoffsetlon = tileLayout.tileoffsetlon;
+        var tileoffsetlat = tileLayout.tileoffsetlat;
+        
+        var tilelon = tileLayout.tilelon;
+        var tilelat = tileLayout.tilelat;
+
+        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+        var startX = tileoffsetx; 
+        var startLon = tileoffsetlon;
+
+        var rowidx = 0;
+        
+        var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
+        var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
+        
+    
+        do {
+            var row = this.grid[rowidx++];
+            if (!row) {
+                row = [];
+                this.grid.push(row);
+            }
+
+            tileoffsetlon = startLon;
+            tileoffsetx = startX;
+            var colidx = 0;
+ 
+            do {
+                var tileBounds = 
+                    new OpenLayers.Bounds(tileoffsetlon, 
+                                          tileoffsetlat, 
+                                          tileoffsetlon + tilelon,
+                                          tileoffsetlat + tilelat);
+
+                var x = tileoffsetx;
+                x -= layerContainerDivLeft;
+
+                var y = tileoffsety;
+                y -= layerContainerDivTop;
+
+                var px = new OpenLayers.Pixel(x, y);
+                var tile = row[colidx++];
+                if (!tile) {
+                    tile = this.addTile(tileBounds, px);
+                    this.addTileMonitoringHooks(tile);
+                    row.push(tile);
+                } else {
+                    tile.moveTo(tileBounds, px, false);
+                }
+     
+                tileoffsetlon += tilelon;       
+                tileoffsetx += this.tileSize.w;
+            } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+                     || colidx < minCols);
+             
+            tileoffsetlat -= tilelat;
+            tileoffsety += this.tileSize.h;
+        } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+                || rowidx < minRows);
+        
+        //shave off exceess rows and colums
+        this.removeExcessTiles(rowidx, colidx);
+
+        //now actually draw the tiles
+        this.spiralTileLoad();
+    },
+    
+    /**
+     * Method: spiralTileLoad
+     *   Starts at the top right corner of the grid and proceeds in a spiral 
+     *    towards the center, adding tiles one at a time to the beginning of a 
+     *    queue. 
+     * 
+     *   Once all the grid's tiles have been added to the queue, we go back 
+     *    and iterate through the queue (thus reversing the spiral order from 
+     *    outside-in to inside-out), calling draw() on each tile. 
+     */
+    spiralTileLoad: function() {
+        var tileQueue = [];
+ 
+        var directions = ["right", "down", "left", "up"];
+
+        var iRow = 0;
+        var iCell = -1;
+        var direction = OpenLayers.Util.indexOf(directions, "right");
+        var directionsTried = 0;
+        
+        while( directionsTried < directions.length) {
+
+            var testRow = iRow;
+            var testCell = iCell;
+
+            switch (directions[direction]) {
+                case "right":
+                    testCell++;
+                    break;
+                case "down":
+                    testRow++;
+                    break;
+                case "left":
+                    testCell--;
+                    break;
+                case "up":
+                    testRow--;
+                    break;
+            } 
+    
+            // if the test grid coordinates are within the bounds of the 
+            //  grid, get a reference to the tile.
+            var tile = null;
+            if ((testRow < this.grid.length) && (testRow >= 0) &&
+                (testCell < this.grid[0].length) && (testCell >= 0)) {
+                tile = this.grid[testRow][testCell];
+            }
+            
+            if ((tile != null) && (!tile.queued)) {
+                //add tile to beginning of queue, mark it as queued.
+                tileQueue.unshift(tile);
+                tile.queued = true;
+                
+                //restart the directions counter and take on the new coords
+                directionsTried = 0;
+                iRow = testRow;
+                iCell = testCell;
+            } else {
+                //need to try to load a tile in a different direction
+                direction = (direction + 1) % 4;
+                directionsTried++;
+            }
+        } 
+        
+        // now we go through and draw the tiles in forward order
+        for(var i=0, len=tileQueue.length; i<len; i++) {
+            var tile = tileQueue[i];
+            tile.draw();
+            //mark tile as unqueued for the next time (since tiles are reused)
+            tile.queued = false;       
+        }
+    },
+
+    /**
+     * APIMethod: addTile
+     * Gives subclasses of Grid the opportunity to create an 
+     * OpenLayer.Tile of their choosing. The implementer should initialize 
+     * the new tile and take whatever steps necessary to display it.
+     *
+     * Parameters
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.Tile>} The added OpenLayers.Tile
+     */
+    addTile:function(bounds, position) {
+        // Should be implemented by subclasses
+    },
+    
+    /** 
+     * Method: addTileMonitoringHooks
+     * This function takes a tile as input and adds the appropriate hooks to 
+     *     the tile so that the layer can keep track of the loading tiles.
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    addTileMonitoringHooks: function(tile) {
+        
+        tile.onLoadStart = function() {
+            //if that was first tile then trigger a 'loadstart' on the layer
+            if (this.numLoadingTiles == 0) {
+                this.events.triggerEvent("loadstart");
+            }
+            this.numLoadingTiles++;
+        };
+        tile.events.register("loadstart", this, tile.onLoadStart);
+      
+        tile.onLoadEnd = function() {
+            this.numLoadingTiles--;
+            this.events.triggerEvent("tileloaded");
+            //if that was the last tile, then trigger a 'loadend' on the layer
+            if (this.numLoadingTiles == 0) {
+                this.events.triggerEvent("loadend");
+            }
+        };
+        tile.events.register("loadend", this, tile.onLoadEnd);
+        tile.events.register("unload", this, tile.onLoadEnd);
+    },
+
+    /** 
+     * Method: removeTileMonitoringHooks
+     * This function takes a tile as input and removes the tile hooks 
+     *     that were added in addTileMonitoringHooks()
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    removeTileMonitoringHooks: function(tile) {
+        tile.unload();
+        tile.events.un({
+            "loadstart": tile.onLoadStart,
+            "loadend": tile.onLoadEnd,
+            "unload": tile.onLoadEnd,
+            scope: this
+        });
+    },
+    
+    /**
+     * Method: moveGriddedTiles
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    moveGriddedTiles: function(bounds) {
+        var buffer = this.buffer || 1;
+        while (true) {
+            var tlLayer = this.grid[0][0].position;
+            var tlViewPort = 
+                this.map.getViewPortPxFromLayerPx(tlLayer);
+            if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
+                this.shiftColumn(true);
+            } else if (tlViewPort.x < -this.tileSize.w * buffer) {
+                this.shiftColumn(false);
+            } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
+                this.shiftRow(true);
+            } else if (tlViewPort.y < -this.tileSize.h * buffer) {
+                this.shiftRow(false);
+            } else {
+                break;
+            }
+        };
+    },
+
+    /**
+     * Method: shiftRow
+     * Shifty grid work
+     *
+     * Parameters:
+     * prepend - {Boolean} if true, prepend to beginning.
+     *                          if false, then append to end
+     */
+    shiftRow:function(prepend) {
+        var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
+        var grid = this.grid;
+        var modelRow = grid[modelRowIndex];
+
+        var resolution = this.map.getResolution();
+        var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
+        var deltaLat = resolution * -deltaY;
+
+        var row = (prepend) ? grid.pop() : grid.shift();
+
+        for (var i=0, len=modelRow.length; i<len; i++) {
+            var modelTile = modelRow[i];
+            var bounds = modelTile.bounds.clone();
+            var position = modelTile.position.clone();
+            bounds.bottom = bounds.bottom + deltaLat;
+            bounds.top = bounds.top + deltaLat;
+            position.y = position.y + deltaY;
+            row[i].moveTo(bounds, position);
+        }
+
+        if (prepend) {
+            grid.unshift(row);
+        } else {
+            grid.push(row);
+        }
+    },
+
+    /**
+     * Method: shiftColumn
+     * Shift grid work in the other dimension
+     *
+     * Parameters:
+     * prepend - {Boolean} if true, prepend to beginning.
+     *                          if false, then append to end
+     */
+    shiftColumn: function(prepend) {
+        var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
+        var resolution = this.map.getResolution();
+        var deltaLon = resolution * deltaX;
+
+        for (var i=0, len=this.grid.length; i<len; i++) {
+            var row = this.grid[i];
+            var modelTileIndex = (prepend) ? 0 : (row.length - 1);
+            var modelTile = row[modelTileIndex];
+            
+            var bounds = modelTile.bounds.clone();
+            var position = modelTile.position.clone();
+            bounds.left = bounds.left + deltaLon;
+            bounds.right = bounds.right + deltaLon;
+            position.x = position.x + deltaX;
+
+            var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
+            tile.moveTo(bounds, position);
+            if (prepend) {
+                row.unshift(tile);
+            } else {
+                row.push(tile);
+            }
+        }
+    },
+    
+    /**
+     * Method: removeExcessTiles
+     * When the size of the map or the buffer changes, we may need to
+     *     remove some excess rows and columns.
+     * 
+     * Parameters:
+     * rows - {Integer} Maximum number of rows we want our grid to have.
+     * colums - {Integer} Maximum number of columns we want our grid to have.
+     */
+    removeExcessTiles: function(rows, columns) {
+        
+        // remove extra rows
+        while (this.grid.length > rows) {
+            var row = this.grid.pop();
+            for (var i=0, l=row.length; i<l; i++) {
+                var tile = row[i];
+                this.removeTileMonitoringHooks(tile);
+                tile.destroy();
+            }
+        }
+        
+        // remove extra columns
+        while (this.grid[0].length > columns) {
+            for (var i=0, l=this.grid.length; i<l; i++) {
+                var row = this.grid[i];
+                var tile = row.pop();
+                this.removeTileMonitoringHooks(tile);
+                tile.destroy();
+            }
+        }
+    },
+
+    /**
+     * Method: onMapResize
+     * For singleTile layers, this will set a new tile size according to the
+     * dimensions of the map pane.
+     */
+    onMapResize: function() {
+        if (this.singleTile) {
+            this.clearGrid();
+            this.setTileSize();
+        }
+    },
+    
+    /**
+     * APIMethod: getTileBounds
+     * Returns The tile bounds for a layer given a pixel location.
+     *
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+     */
+    getTileBounds: function(viewPortPx) {
+        var maxExtent = this.maxExtent;
+        var resolution = this.getResolution();
+        var tileMapWidth = resolution * this.tileSize.w;
+        var tileMapHeight = resolution * this.tileSize.h;
+        var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
+        var tileLeft = maxExtent.left + (tileMapWidth *
+                                         Math.floor((mapPoint.lon -
+                                                     maxExtent.left) /
+                                                    tileMapWidth));
+        var tileBottom = maxExtent.bottom + (tileMapHeight *
+                                             Math.floor((mapPoint.lat -
+                                                         maxExtent.bottom) /
+                                                        tileMapHeight));
+        return new OpenLayers.Bounds(tileLeft, tileBottom,
+                                     tileLeft + tileMapWidth,
+                                     tileBottom + tileMapHeight);
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.Grid"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/HTTPRequest.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/HTTPRequest.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/HTTPRequest.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,240 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.HTTPRequest
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
+
+    /** 
+     * Constant: URL_HASH_FACTOR
+     * {Float} Used to hash URL param strings for multi-WMS server selection.
+     *         Set to the Golden Ratio per Knuth's recommendation.
+     */
+    URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
+
+    /** 
+     * Property: url
+     * {Array(String) or String} This is either an array of url strings or 
+     *                           a single url string. 
+     */
+    url: null,
+
+    /** 
+     * Property: params
+     * {Object} Hashtable of key/value parameters
+     */
+    params: null,
+    
+    /** 
+     * APIProperty: reproject
+     * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+     * for information on the replacement for this functionality. 
+     * {Boolean} Whether layer should reproject itself based on base layer 
+     *           locations. This allows reprojection onto commercial layers. 
+     *           Default is false: Most layers can't reproject, but layers 
+     *           which can create non-square geographic pixels can, like WMS.
+     *           
+     */
+    reproject: false,
+
+    /**
+     * Constructor: OpenLayers.Layer.HTTPRequest
+     * 
+     * Parameters:
+     * name - {String}
+     * url - {Array(String) or String}
+     * params - {Object}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = arguments;
+        newArguments = [name, options];
+        OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
+        this.url = url;
+        this.params = OpenLayers.Util.extend( {}, params);
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        this.url = null;
+        this.params = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
+    },
+    
+    /**
+     * APIMethod: clone
+     * 
+     * Parameters:
+     * obj - {Object}
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this 
+     *                                  <OpenLayers.Layer.HTTPRequest>
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.HTTPRequest(this.name,
+                                                   this.url,
+                                                   this.params,
+                                                   this.options);
+        }
+        
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+        
+        return obj;
+    },
+
+    /** 
+     * APIMethod: setUrl
+     * 
+     * Parameters:
+     * newUrl - {String}
+     */
+    setUrl: function(newUrl) {
+        this.url = newUrl;
+    },
+
+    /**
+     * APIMethod: mergeNewParams
+     * 
+     * Parameters:
+     * newParams - {Object}
+     *
+     * Returns:
+     * redrawn: {Boolean} whether the layer was actually redrawn.
+     */
+    mergeNewParams:function(newParams) {
+        this.params = OpenLayers.Util.extend(this.params, newParams);
+        return this.redraw();
+    },
+
+    /**
+     * APIMethod: redraw
+     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
+     *
+     * Parameters:
+     * force - {Boolean} Force redraw by adding random parameter.
+     *
+     * Returns:
+     * {Boolean} The layer was redrawn.
+     */
+    redraw: function(force) { 
+        if (force) {
+            return this.mergeNewParams({"_olSalt": Math.random()});
+        } else {
+            return OpenLayers.Layer.prototype.redraw.apply(this, []);
+        }
+    },
+    
+    /**
+     * Method: selectUrl
+     * selectUrl() implements the standard floating-point multiplicative
+     *     hash function described by Knuth, and hashes the contents of the 
+     *     given param string into a float between 0 and 1. This float is then
+     *     scaled to the size of the provided urls array, and used to select
+     *     a URL.
+     *
+     * Parameters:
+     * paramString - {String}
+     * urls - {Array(String)}
+     * 
+     * Returns:
+     * {String} An entry from the urls array, deterministically selected based
+     *          on the paramString.
+     */
+    selectUrl: function(paramString, urls) {
+        var product = 1;
+        for (var i=0, len=paramString.length; i<len; i++) { 
+            product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR; 
+            product -= Math.floor(product); 
+        }
+        return urls[Math.floor(product * urls.length)];
+    },
+
+    /** 
+     * Method: getFullRequestString
+     * Combine url with layer's params and these newParams. 
+     *   
+     *    does checking on the serverPath variable, allowing for cases when it 
+     *     is supplied with trailing ? or &, as well as cases where not. 
+     *
+     *    return in formatted string like this:
+     *        "server?key1=value1&key2=value2&key3=value3"
+     * 
+     * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
+     *
+     * Parameters:
+     * newParams - {Object}
+     * altUrl - {String} Use this as the url instead of the layer's url
+     *   
+     * Returns: 
+     * {String}
+     */
+    getFullRequestString:function(newParams, altUrl) {
+
+        // if not altUrl passed in, use layer's url
+        var url = altUrl || this.url;
+        
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // if url is not a string, it should be an array of strings, 
+        // in which case we will deterministically select one of them in 
+        // order to evenly distribute requests to different urls.
+        //
+        if (url instanceof Array) {
+            url = this.selectUrl(paramsString, url);
+        }   
+ 
+        // ignore parameters that are already in the url search string
+        var urlParams = 
+            OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // requestString always starts with url
+        var requestString = url;        
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have 
+                    // paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Image.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Image.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Image.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,253 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+ 
+/**
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Image
+ * Instances of OpenLayers.Layer.Image are used to display data from a web
+ * accessible image as a map layer.  Create a new image layer with the
+ * <OpenLayers.Layer.Image> constructor.  Inherits from <OpenLayers.Layer>.
+ */
+OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, {
+
+    /**
+     * Property: isBaseLayer
+     * {Boolean} The layer is a base layer.  Default is true.  Set this property
+     * in the layer options
+     */
+    isBaseLayer: true,
+    
+    /**
+     * Property: url
+     * {String} URL of the image to use
+     */
+    url: null,
+
+    /**
+     * Property: extent
+     * {<OpenLayers.Bounds>} The image bounds in map units.  This extent will
+     *     also be used as the default maxExtent for the layer.  If you wish
+     *     to have a maxExtent that is different than the image extent, set the
+     *     maxExtent property of the options argument (as with any other layer).
+     */
+    extent: null,
+    
+    /**
+     * Property: size
+     * {<OpenLayers.Size>} The image size in pixels
+     */
+    size: null,
+
+    /**
+     * Property: tile
+     * {<OpenLayers.Tile.Image>}
+     */
+    tile: null,
+
+    /**
+     * Property: aspectRatio
+     * {Float} The ratio of height/width represented by a single pixel in the
+     * graphic
+     */
+    aspectRatio: null,
+
+    /**
+     * Constructor: OpenLayers.Layer.Image
+     * Create a new image layer
+     *
+     * Parameters:
+     * name - {String} A name for the layer.
+     * url - {String} Relative or absolute path to the image
+     * extent - {<OpenLayers.Bounds>} The extent represented by the image
+     * size - {<OpenLayers.Size>} The size (in pixels) of the image
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, extent, size, options) {
+        this.url = url;
+        this.extent = extent;
+        this.maxExtent = extent;
+        this.size = size;
+        OpenLayers.Layer.prototype.initialize.apply(this, [name, options]);
+
+        this.aspectRatio = (this.extent.getHeight() / this.size.h) /
+                           (this.extent.getWidth() / this.size.w);
+    },    
+
+    /**
+     * Method: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        if (this.tile) {
+            this.removeTileMonitoringHooks(this.tile);
+            this.tile.destroy();
+            this.tile = null;
+        }
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Paramters:
+     * obj - {Object} An optional layer (is this ever used?)
+     *
+     * Returns:
+     * {<OpenLayers.Layer.Image>} An exact copy of this layer
+     */
+    clone: function(obj) {
+        
+        if(obj == null) {
+            obj = new OpenLayers.Layer.Image(this.name,
+                                               this.url,
+                                               this.extent,
+                                               this.size,
+                                               this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },    
+    
+    /**
+     * APIMethod: setMap
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        /**
+         * If nothing to do with resolutions has been set, assume a single
+         * resolution determined by ratio*extent/size - if an image has a
+         * pixel aspect ratio different than one (as calculated above), the
+         * image will be stretched in one dimension only.
+         */
+        if( this.options.maxResolution == null ) {
+            this.options.maxResolution = this.aspectRatio *
+                                         this.extent.getWidth() /
+                                         this.size.w;
+        }
+        OpenLayers.Layer.prototype.setMap.apply(this, arguments);
+    },
+
+    /** 
+     * Method: moveTo
+     * Create the tile for the image or resize it for the new resolution
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean}
+     * dragging - {Boolean}
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+        var firstRendering = (this.tile == null);
+
+        if(zoomChanged || firstRendering) {
+
+            //determine new tile size
+            this.setTileSize();
+
+            //determine new position (upper left corner of new bounds)
+            var ul = new OpenLayers.LonLat(this.extent.left, this.extent.top);
+            var ulPx = this.map.getLayerPxFromLonLat(ul);
+
+            if(firstRendering) {
+                //create the new tile
+                this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, 
+                                                      null, this.tileSize);
+                this.addTileMonitoringHooks(this.tile);
+            } else {
+                //just resize the tile and set it's new position
+                this.tile.size = this.tileSize.clone();
+                this.tile.position = ulPx.clone();
+            }
+            this.tile.draw();
+        }
+    }, 
+
+    /**
+     * Set the tile size based on the map size.
+     */
+    setTileSize: function() {
+        var tileWidth = this.extent.getWidth() / this.map.getResolution();
+        var tileHeight = this.extent.getHeight() / this.map.getResolution();
+        this.tileSize = new OpenLayers.Size(tileWidth, tileHeight);
+    },
+
+    /** 
+     * Method: addTileMonitoringHooks
+     * This function takes a tile as input and adds the appropriate hooks to 
+     *     the tile so that the layer can keep track of the loading tiles.
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    addTileMonitoringHooks: function(tile) {
+        tile.onLoadStart = function() {
+            this.events.triggerEvent("loadstart");
+        };
+        tile.events.register("loadstart", this, tile.onLoadStart);
+      
+        tile.onLoadEnd = function() {
+            this.events.triggerEvent("loadend");
+        };
+        tile.events.register("loadend", this, tile.onLoadEnd);
+        tile.events.register("unload", this, tile.onLoadEnd);
+    },
+
+    /** 
+     * Method: removeTileMonitoringHooks
+     * This function takes a tile as input and removes the tile hooks 
+     *     that were added in <addTileMonitoringHooks>.
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    removeTileMonitoringHooks: function(tile) {
+        tile.unload();
+        tile.events.un({
+            "loadstart": tile.onLoadStart,
+            "loadend": tile.onLoadEnd,
+            "unload": tile.onLoadEnd,
+            scope: this
+        });
+    },
+    
+    /**
+     * APIMethod: setUrl
+     * 
+     * Parameters:
+     * newUrl - {String}
+     */
+    setUrl: function(newUrl) {
+        this.url = newUrl;
+        this.tile.draw();
+    },
+
+    /** 
+     * APIMethod: getURL
+     * The url we return is always the same (the image itself never changes)
+     *     so we can ignore the bounds parameter (it will always be the same, 
+     *     anyways) 
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    getURL: function(bounds) {
+        return this.url;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.Image"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/KaMapCache.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/KaMapCache.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/KaMapCache.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,147 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Layer/KaMap.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.KaMapCache
+ * 
+ * This class is designed to talk directly to a web-accessible ka-Map
+ * cache generated by the precache2.php script.
+ * 
+ * To create a a new KaMapCache layer, you must indicate also the "i" parameter
+ * (that will be used to calculate the file extension), and another special
+ * parameter, object names "metaTileSize", with "h" (height) and "w" (width)
+ * properties.
+ * 
+ *     // Create a new kaMapCache layer. 
+ *     var kamap_base = new OpenLayers.Layer.KaMapCache(
+ *         "Satellite",
+ *         "http://www.example.org/web/acessible/cache",
+ *         {g: "satellite", map: "world", i: 'png24', metaTileSize: {w: 5, h: 5} }
+ *       );
+ *    
+ *     // Create an kaMapCache overlay layer (using "isBaseLayer: false"). 
+ *     // Forces the output to be a "gif", using the "i" parameter.
+ *     var kamap_overlay = new OpenLayers.Layer.KaMapCache(
+ *         "Streets",
+ *         "http://www.example.org/web/acessible/cache",
+ *         {g: "streets", map: "world", i: "gif", metaTileSize: {w: 5, h: 5} },
+ *         {isBaseLayer: false}
+ *       );
+ *
+ * The cache URLs must look like: 
+ *   var/cache/World/50000/Group_Name/def/t-440320/l20480
+ * 
+ * This means that the cache generated via tile.php will *not* work with
+ *     this class, and should instead use the KaMap layer.
+ *
+ * More information is available in Ticket #1518.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.KaMap>
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, {
+
+    /**
+     * Constant: IMAGE_EXTENSIONS
+     * {Object} Simple hash map to convert format to extension.
+     */
+    IMAGE_EXTENSIONS: {
+        'jpeg': 'jpg',
+        'gif' : 'gif',
+        'png' : 'png',
+        'png8' : 'png',
+        'png24' : 'png',
+        'dithered' : 'png'
+    },
+    
+    /**
+     * Constant: DEFAULT_FORMAT
+     * {Object} Simple hash map to convert format to extension.
+     */
+    DEFAULT_FORMAT: 'jpeg',
+    
+    /**
+     * Constructor: OpenLayers.Layer.KaMapCache
+     * 
+     * Parameters:
+     * name - {String}
+     * url - {String}
+     * params - {Object} Parameters to be sent to the HTTP server in the
+     *    query string for the tile. The format can be set via the 'i'
+     *    parameter (defaults to jpg) , and the map should be set via 
+     *    the 'map' parameter. It has been reported that ka-Map may behave
+     *    inconsistently if your format parameter does not match the format
+     *    parameter configured in your config.php. (See ticket #327 for more
+     *    information.)
+     * options - {Object} Additional options for the layer. Any of the 
+     *     APIProperties listed on this layer, and any layer types it
+     *     extends, can be overridden through the options parameter. 
+     */
+    initialize: function(name, url, params, options) {
+        OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments);
+        this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || DEFAULT_FORMAT];
+    },
+
+    /**
+     * Method: getURL
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * 
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the 
+     *          passed-in bounds and appropriate tile size specified as 
+     *          parameters
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        var mapRes = this.map.getResolution();
+        var scale = Math.round((this.map.getScale() * 10000)) / 10000;
+        var pX = Math.round(bounds.left / mapRes);
+        var pY = -Math.round(bounds.top / mapRes);
+
+        var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w;
+        var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h;
+
+        // if url is not a string, it should be an array of strings,
+        // in which case we will deterministically select one of them in
+        // order to evenly distribute requests to different urls.
+        //
+        var url = this.url;
+        if (url instanceof Array) {
+            url = this.selectUrl(paramsString, url);
+        }  
+    
+        var components = [
+            url,
+            "/",
+            this.params.map,
+            "/",
+            scale,
+            "/",
+            this.params.g.replace(/\s/g, '_'),
+            "/def/t", 
+            metaY,
+            "/l",
+            metaX,
+            "/t",
+            pY,
+            "l",
+            pX,
+            ".",
+            this.extension
+          ];
+          
+        return components.join("");
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.KaMapCache"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapGuide.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapGuide.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapGuide.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,488 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * licence.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapGuide
+ * Instances of OpenLayers.Layer.MapGuide are used to display
+ * data from a MapGuide OS instance.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /** 
+     * APIProperty: isBaseLayer
+     * {Boolean} Treat this layer as a base layer.  Default is true.
+     **/
+    isBaseLayer: true,
+    
+    /**
+     * APIProperty: useHttpTile
+     * {Boolean} use a tile cache exposed directly via a webserver rather than the 
+	   *    via mapguide server. This does require extra configuration on the Mapguide Server,
+	   *    and will only work when singleTile is false. The url for the layer must be set to the
+	   *    webserver path rather than the Mapguide mapagent.	  
+	   *    See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp 
+     **/
+    useHttpTile: false,
+    
+    /** 
+     * APIProperty: singleTile
+     * {Boolean} use tile server or request single tile image. 
+     **/
+    singleTile: false,
+    
+    /** 
+     * APIProperty: useOverlay
+     * {Boolean} flag to indicate if the layer should be retrieved using
+     * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
+     **/
+    useOverlay: false,
+    
+    /** 
+     * APIProperty: useAsyncOverlay
+     * {Boolean} indicates if the MapGuide site supports the asynchronous 
+     * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
+     * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG 
+     * is called asynchronously, allows selections to be drawn separately from 
+     * the map and offers styling options.
+     * 
+     * With older versions of MapGuide, set useAsyncOverlay=false.  Note that in
+     * this case a synchronous AJAX call is issued and the mapname and session
+     * parameters must be used to initialize the layer, not the mapdefinition
+     * parameter. Also note that this will issue a synchronous AJAX request 
+     * before the image request can be issued so the users browser may lock
+     * up if the MG Web tier does not respond in a timely fashion.
+     **/
+    useAsyncOverlay: true,
+    
+    /**
+     * Constant: TILE_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs for tiled layer
+     */
+    TILE_PARAMS: {
+         operation: 'GETTILEIMAGE',
+         version: '1.2.0'
+    },
+
+    /**
+     * Constant: SINGLE_TILE_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs for untiled layer
+     */
+    SINGLE_TILE_PARAMS: {
+        operation: 'GETMAPIMAGE',
+        format: 'PNG',
+        locale: 'en',
+        clip: '1',
+        version: '1.0.0'
+    },
+    
+    /**
+     * Constant: OVERLAY_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs for untiled layer
+     */
+    OVERLAY_PARAMS: {
+        operation: 'GETDYNAMICMAPOVERLAYIMAGE',
+        format: 'PNG',
+        locale: 'en',
+        clip: '1',
+        version: '2.0.0'
+    },
+    
+    /** 
+     * Constant: FOLDER_PARAMS
+     * {Object} Hashtable of parameter key/value pairs which describe 
+     * the folder structure for tiles as configured in the mapguide 
+     * serverconfig.ini section [TileServiceProperties]
+     */
+    FOLDER_PARAMS: {
+        tileColumnsPerFolder: 30,
+        tileRowsPerFolder: 30,
+        format: 'png',
+        querystring: null
+    },	
+
+    /** 
+     * Property: defaultSize
+     * {<OpenLayers.Size>} Tile size as produced by MapGuide server
+     **/
+    defaultSize: new OpenLayers.Size(300,300),
+
+    /**
+     * Constructor: OpenLayers.Layer.MapGuide
+     * Create a new Mapguide layer, either tiled or untiled.  
+     *
+     * For tiled layers, the 'groupName' and 'mapDefinition' values 
+     * must be specified as parameters in the constructor.
+     *
+     * For untiled base layers, specify either combination of 'mapName' and
+     * 'session', or 'mapDefinition' and 'locale'.  
+     *
+     * For older versions of MapGuide and overlay layers, set useAsyncOverlay 
+     * to false and in this case mapName and session are required parameters 
+     * for the constructor.
+     *
+     * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion 
+     * factor that are different than the defaults used in OpenLayers, 
+     * so these must be adjusted accordingly in your application.  
+     * See the MapGuide example for how to set these values for MGOS.
+     *
+     * Parameters:
+     * name - {String} Name of the layer displayed in the interface
+     * url - {String} Location of the MapGuide mapagent executable
+     *            (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
+     * params - {Object} hashtable of additional parameters to use. Some
+     *     parameters may require additional code on the server. The ones that
+     *     you may want to use are: 
+     *   - mapDefinition - {String} The MapGuide resource definition
+     *            (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
+     *   - locale - Locale setting 
+     *            (for untiled overlays layers only)
+     *   - mapName - {String} Name of the map as stored in the MapGuide session.
+     *          (for untiled layers with a session parameter only)
+     *   - session - { String} MapGuide session ID 
+     *            (for untiled overlays layers only)
+     *   - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
+     *   - format - Image format to be returned (for untiled overlay layers only)
+     *   - showLayers - {String} A comma separated list of GUID's for the
+     *       layers to display eg: 'cvc-xcv34,453-345-345sdf'.
+     *   - hideLayers - {String} A comma separated list of GUID's for the
+     *       layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
+     *   - showGroups - {String} A comma separated list of GUID's for the
+     *       groups to display eg: 'cvc-xcv34,453-345-345sdf'.
+     *   - hideGroups - {String} A comma separated list of GUID's for the
+     *       groups to hide eg: 'cvc-xcv34,453-345-345sdf'
+     *   - selectionXml - {String} A selection xml string Some server plumbing
+     *       is required to read such a value.
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer; 
+     *          will vary depending if tiled or untiled maps are being requested
+     */
+    initialize: function(name, url, params, options) {
+        
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
+        
+        // unless explicitly set in options, if the layer is transparent, 
+        // it will be an overlay
+        if (options == null || options.isBaseLayer == null) {
+            this.isBaseLayer = ((this.transparent != "true") && 
+                                (this.transparent != true));
+        }
+
+        if (options && options.useOverlay!=null) {
+          this.useOverlay = options.useOverlay;
+        }
+        
+        //initialize for untiled layers
+        if (this.singleTile) {
+          if (this.useOverlay) {
+            OpenLayers.Util.applyDefaults(
+                           this.params,
+                           this.OVERLAY_PARAMS
+                           );
+            if (!this.useAsyncOverlay) {
+              this.params.version = "1.0.0";
+            }
+          } else {
+            OpenLayers.Util.applyDefaults(
+                           this.params,
+                           this.SINGLE_TILE_PARAMS
+                           );
+          }         
+        } else {
+            //initialize for tiled layers
+            if (this.useHttpTile) {
+                OpenLayers.Util.applyDefaults(
+                               this.params,
+                               this.FOLDER_PARAMS
+                               );
+            } else {
+                OpenLayers.Util.applyDefaults(
+                               this.params,
+                               this.TILE_PARAMS
+                               );
+            }
+            this.setTileSize(this.defaultSize); 
+        }
+    },
+
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
+     */
+    clone: function (obj) {
+      if (obj == null) {
+            obj = new OpenLayers.Layer.MapGuide(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+      }
+      //get all additions from superclasses
+      obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+      return obj;
+    },
+
+    /**
+     * Method: addTile
+     * Creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+
+    /**
+     * Method: getURL
+     * Return a query string for this layer
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
+     *                                for the request
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also 
+     *          the passed-in bounds and appropriate tile size specified 
+     *          as parameters.
+     */
+    getURL: function (bounds) {
+        var url;
+        var center = bounds.getCenterLonLat();
+        var mapSize = this.map.getCurrentSize();
+
+        if (this.singleTile) {
+          //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
+          //dynamic map parameters
+          var params = {
+            setdisplaydpi: OpenLayers.DOTS_PER_INCH,
+            setdisplayheight: mapSize.h*this.ratio,
+            setdisplaywidth: mapSize.w*this.ratio,
+            setviewcenterx: center.lon,
+            setviewcentery: center.lat,
+            setviewscale: this.map.getScale()
+          };
+          
+          if (this.useOverlay && !this.useAsyncOverlay) {
+            //first we need to call GETVISIBLEMAPEXTENT to set the extent
+            var getVisParams = {};
+            getVisParams = OpenLayers.Util.extend(getVisParams, params);
+            getVisParams.operation = "GETVISIBLEMAPEXTENT";
+            getVisParams.version = "1.0.0";
+            getVisParams.session = this.params.session;
+            getVisParams.mapName = this.params.mapName;
+            getVisParams.format = 'text/xml';
+            url = this.getFullRequestString( getVisParams );
+            
+            OpenLayers.Request.GET({url: url, async: false});
+          }
+          //construct the full URL
+          url = this.getFullRequestString( params );
+        } else {
+
+          //tiled version
+          var currentRes = this.map.getResolution();
+          var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
+          colidx = Math.round(colidx/this.tileSize.w);
+          var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
+          rowidx = Math.round(rowidx/this.tileSize.h);
+
+          if (this.useHttpTile){
+	          url = this.getImageFilePath(
+                   {
+                       tilecol: colidx,
+                       tilerow: rowidx,
+                       scaleindex: this.resolutions.length - this.map.zoom - 1
+                    });
+		  
+          } else {
+            url = this.getFullRequestString(
+                   {
+                       tilecol: colidx,
+                       tilerow: rowidx,
+                       scaleindex: this.resolutions.length - this.map.zoom - 1
+                    });
+          }
+       }
+       return url;
+    },
+
+    /**
+     * Method: getFullRequestString
+     * getFullRequestString on MapGuide layers is special, because we 
+     * do a regular expression replace on ',' in parameters to '+'.
+     * This is why it is subclassed here.
+     *
+     * Parameters:
+     * altUrl - {String} Alternative base URL to use.
+     *
+     * Returns:
+     * {String} A string with the layer's url appropriately encoded for MapGuide
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        // use layer's url unless altUrl passed in
+        var url = (altUrl == null) ? this.url : altUrl;
+        
+        // if url is not a string, it should be an array of strings, 
+        //  in which case we will randomly select one of them in order
+        //  to evenly distribute requests to different urls.
+        if (typeof url == "object") {
+            url = url[Math.floor(Math.random()*url.length)];
+        }   
+        // requestString always starts with url
+        var requestString = url;        
+
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        // ignore parameters that are already in the url search string
+        var urlParams = OpenLayers.Util.upperCaseObject(
+                            OpenLayers.Util.getArgs(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        /* MapGuide needs '+' seperating things like bounds/height/width.
+           Since typically this is URL encoded, we use a slight hack: we
+           depend on the list-like functionality of getParameterString to
+           leave ',' only in the case of list items (since otherwise it is
+           encoded) then do a regular expression replace on the , characters
+           to '+' */
+        paramsString = paramsString.replace(/,/g, "+");
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+     /** 
+     * Method: getImageFilePath
+     * special handler to request mapguide tiles from an http exposed tilecache 
+     *
+     * Parameters:
+     * altUrl - {String} Alternative base URL to use.
+     *
+     * Returns:
+     * {String} A string with the url for the tile image
+     */
+    getImageFilePath:function(newParams, altUrl) {
+        // use layer's url unless altUrl passed in
+        var url = (altUrl == null) ? this.url : altUrl;
+        
+        // if url is not a string, it should be an array of strings, 
+        //  in which case we will randomly select one of them in order
+        //  to evenly distribute requests to different urls.
+        if (typeof url == "object") {
+            url = url[Math.floor(Math.random()*url.length)];
+        }   
+        // requestString always starts with url
+        var requestString = url;        
+
+        var tileRowGroup = "";
+        var tileColGroup = "";
+        
+        if (newParams.tilerow < 0) {
+          tileRowGroup =  '-';
+        }
+          
+        if (newParams.tilerow == 0 ) {
+          tileRowGroup += '0';
+        } else {
+          tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
+        }
+          
+        if (newParams.tilecol < 0) {
+          tileColGroup =  '-';
+        }
+        
+        if (newParams.tilecol == 0) {
+          tileColGroup += '0';
+        } else {
+          tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
+        }					
+        
+        var tilePath = '/S' + Math.floor(newParams.scaleindex)
+                + '/' + this.params.basemaplayergroupname
+                + '/R' + tileRowGroup
+                + '/C' + tileColGroup
+                + '/' + (newParams.tilerow % this.params.tileRowsPerFolder) 
+                + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) 
+                + '.' + this.params.format;
+    
+        if (this.params.querystring) {
+               tilePath += "?" + this.params.querystring;
+        }
+        
+        requestString += tilePath;
+        return requestString;
+    },
+    
+    /** 
+     * Method: calculateGridLayout
+     * Generate parameters for the grid layout. This  
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bound>}
+     * extent - {<OpenLayers.Bounds>}
+     * resolution - {Number}
+     *
+     * Returns:
+     * Object containing properties tilelon, tilelat, tileoffsetlat,
+     * tileoffsetlat, tileoffsetx, tileoffsety
+     */
+    calculateGridLayout: function(bounds, extent, resolution) {
+        var tilelon = resolution * this.tileSize.w;
+        var tilelat = resolution * this.tileSize.h;
+        
+        var offsetlon = bounds.left - extent.left;
+        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+        var tilecolremain = offsetlon/tilelon - tilecol;
+        var tileoffsetx = -tilecolremain * this.tileSize.w;
+        var tileoffsetlon = extent.left + tilecol * tilelon;
+        
+        var offsetlat = extent.top - bounds.top + tilelat; 
+        var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
+        var tilerowremain = tilerow - offsetlat/tilelat;
+        var tileoffsety = tilerowremain * this.tileSize.h;
+        var tileoffsetlat = extent.top - tilelat*tilerow;
+        
+        return { 
+          tilelon: tilelon, tilelat: tilelat,
+          tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+          tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+        };
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.MapGuide"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapServer.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapServer.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MapServer.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,198 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapServer
+ * Instances of OpenLayers.Layer.MapServer are used to display
+ * data from a MapServer CGI instance.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    DEFAULT_PARAMS: {
+        mode: "map",
+        map_imagetype: "png"
+    },
+
+    /**
+     * Constructor: OpenLayers.Layer.MapServer
+     * Create a new MapServer layer object
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the MapServer CGI
+     *       (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
+     * params - {Object} An object with key/value pairs representing the
+     *          GetMap query string parameters and parameter values.
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = [];
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+        this.params = OpenLayers.Util.applyDefaults(
+            this.params, this.DEFAULT_PARAMS
+        );
+
+        // unless explicitly set in options, if the layer is transparent, 
+        // it will be an overlay
+        if (options == null || options.isBaseLayer == null) {
+            this.isBaseLayer = ((this.params.transparent != "true") && 
+                                (this.params.transparent != true));
+        }
+    },
+
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        if (obj == null) {
+            obj = new OpenLayers.Layer.MapServer(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },
+
+    /**
+     * Method: addTile
+     * Creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+    
+    /**
+     * Method: getURL
+     * Return a query string for this layer
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
+     *                                for the request
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also 
+     *          the passed-in bounds and appropriate tile size specified 
+     *          as parameters.
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        // Make a list, so that getFullRequestString uses literal "," 
+        var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
+
+        var imageSize = this.getImageSize(); 
+        
+        // make lists, so that literal ','s are used 
+        var url = this.getFullRequestString(
+                     {mapext:   extent,
+                      imgext:   extent,
+                      map_size: [imageSize.w, imageSize.h],
+                      imgx:     imageSize.w / 2,
+                      imgy:     imageSize.h / 2,
+                      imgxy:    [imageSize.w, imageSize.h]
+                      });
+        
+        return url;
+    },
+    
+    /** 
+     * Method: getFullRequestString
+     * combine the layer's url with its params and these newParams. 
+     *   
+     * Parameter:
+     * newParams - {Object} New parameters that should be added to the 
+     *                      request string.
+     * altUrl - {String} (optional) Replace the URL in the full request  
+     *                              string with the provided URL.
+     * 
+     * Returns: 
+     * {String} A string with the layer's url and parameters embedded in it.
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        // use layer's url unless altUrl passed in
+        var url = (altUrl == null) ? this.url : altUrl;
+        
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // if url is not a string, it should be an array of strings, 
+        // in which case we will deterministically select one of them in 
+        // order to evenly distribute requests to different urls.
+        if (url instanceof Array) {
+            url = this.selectUrl(paramsString, url);
+        }   
+        
+        // ignore parameters that are already in the url search string
+        var urlParams = OpenLayers.Util.upperCaseObject(
+                            OpenLayers.Util.getParameters(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // requestString always starts with url
+        var requestString = url;        
+
+        // MapServer needs '+' seperating things like bounds/height/width.
+        //   Since typically this is URL encoded, we use a slight hack: we
+        //  depend on the list-like functionality of getParameterString to
+        //  leave ',' only in the case of list items (since otherwise it is
+        //  encoded) then do a regular expression replace on the , characters
+        //  to '+'
+        //
+        paramsString = paramsString.replace(/,/g, "+");
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.MapServer"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Markers.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Markers.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Markers.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,186 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Markers
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer> 
+ */
+OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
+    
+    /** 
+     * APIProperty: isBaseLayer 
+     * {Boolean} Markers layer is never a base layer.  
+     */
+    isBaseLayer: false,
+    
+    /** 
+     * APIProperty: markers 
+     * {Array(<OpenLayers.Marker>)} internal marker list 
+     */
+    markers: null,
+
+
+    /** 
+     * Property: drawn 
+     * {Boolean} internal state of drawing. This is a workaround for the fact
+     * that the map does not call moveTo with a zoomChanged when the map is
+     * first starting up. This lets us catch the case where we have *never*
+     * drawn the layer, and draw it even if the zoom hasn't changed.
+     */
+    drawn: false,
+    
+    /**
+     * Constructor: OpenLayers.Layer.Markers 
+     * Create a Markers layer.
+     *
+     * Parameters:
+     * name - {String} 
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+        this.markers = [];
+    },
+    
+    /**
+     * APIMethod: destroy 
+     */
+    destroy: function() {
+        this.clearMarkers();
+        this.markers = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: setOpacity
+     * Sets the opacity for all the markers.
+     * 
+     * Parameter:
+     * opacity - {Float}
+     */
+    setOpacity: function(opacity) {
+        if (opacity != this.opacity) {
+            this.opacity = opacity;
+            for (var i=0, len=this.markers.length; i<len; i++) {
+                this.markers[i].setOpacity(this.opacity);
+            }
+        }
+    },
+
+    /** 
+     * Method: moveTo
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+        if (zoomChanged || !this.drawn) {
+            for(var i=0, len=this.markers.length; i<len; i++) {
+                this.drawMarker(this.markers[i]);
+            }
+            this.drawn = true;
+        }
+    },
+
+    /**
+     * APIMethod: addMarker
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    addMarker: function(marker) {
+        this.markers.push(marker);
+
+        if (this.opacity != null) {
+            marker.setOpacity(this.opacity);
+        }
+
+        if (this.map && this.map.getExtent()) {
+            marker.map = this.map;
+            this.drawMarker(marker);
+        }
+    },
+
+    /**
+     * APIMethod: removeMarker
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    removeMarker: function(marker) {
+        if (this.markers && this.markers.length) {
+            OpenLayers.Util.removeItem(this.markers, marker);
+            marker.erase();
+        }
+    },
+
+    /**
+     * Method: clearMarkers
+     * This method removes all markers from a layer. The markers are not
+     * destroyed by this function, but are removed from the list of markers.
+     */
+    clearMarkers: function() {
+        if (this.markers != null) {
+            while(this.markers.length > 0) {
+                this.removeMarker(this.markers[0]);
+            }
+        }
+    },
+
+    /** 
+     * Method: drawMarker
+     * Calculate the pixel location for the marker, create it, and 
+     *    add it to the layer's div
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    drawMarker: function(marker) {
+        var px = this.map.getLayerPxFromLonLat(marker.lonlat);
+        if (px == null) {
+            marker.display(false);
+        } else {
+            if (!marker.isDrawn()) {
+                var markerImg = marker.draw(px);
+                this.div.appendChild(markerImg);
+            } else if(marker.icon) {
+                marker.icon.moveTo(px);
+            }
+        }
+    },
+    
+    /** 
+     * APIMethod: getDataExtent
+     * Calculates the max extent which includes all of the markers.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        var maxExtent = null;
+        
+        if ( this.markers && (this.markers.length > 0)) {
+            var maxExtent = new OpenLayers.Bounds();
+            for(var i=0, len=this.markers.length; i<len; i++) {
+                var marker = this.markers[i];
+                maxExtent.extend(marker.lonlat);
+            }
+        }
+
+        return maxExtent;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.Markers"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MultiMap.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MultiMap.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/MultiMap.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,283 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/EventPane.js
+ * @requires OpenLayers/Layer/FixedZoomLevels.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MultiMap
+ * Note that MultiMap does not fully support the sphericalMercator
+ * option. See Ticket #953 for more details.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.EventPane>
+ *  - <OpenLayers.Layer.FixedZoomLevels>
+ */
+OpenLayers.Layer.MultiMap = OpenLayers.Class(
+  OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, {
+    
+    /** 
+     * Constant: MIN_ZOOM_LEVEL
+     * {Integer} 1 
+     */
+    MIN_ZOOM_LEVEL: 1,
+    
+    /** 
+     * Constant: MAX_ZOOM_LEVEL
+     * {Integer} 17
+     */
+    MAX_ZOOM_LEVEL: 17,
+
+    /** 
+     * Constant: RESOLUTIONS
+     * {Array(Float)} Hardcode these resolutions so that they are more closely
+     *                tied with the standard wms projection
+     */
+    RESOLUTIONS: [
+        9, 
+        1.40625,
+        0.703125,
+        0.3515625,
+        0.17578125,
+        0.087890625,
+        0.0439453125,
+        0.02197265625,
+        0.010986328125,
+        0.0054931640625,
+        0.00274658203125,
+        0.001373291015625,
+        0.0006866455078125,
+        0.00034332275390625,
+        0.000171661376953125,
+        0.0000858306884765625,
+        0.00004291534423828125
+    ],
+
+    /**
+     * APIProperty: type
+     * {?}
+     */
+    type: null,
+
+    /** 
+     * Constructor: OpenLayers.Layer.MultiMap
+     * 
+     * Parameters:
+     * name - {String}
+     * options - {Object}
+     */
+    initialize: function(name, options) {
+        OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
+        OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
+                                                                    arguments);
+        if (this.sphericalMercator) {
+            OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
+            this.initMercatorParameters();
+            this.RESOLUTIONS.unshift(10); 
+        }    
+    },
+    
+    /**
+     * Method: loadMapObject
+     */
+    loadMapObject:function() {
+        try { //crash proofing
+            this.mapObject = new MultimapViewer(this.div);
+        } catch (e) { }
+    },
+
+    /** 
+     * APIMethod: getWarningHTML
+     * 
+     * Returns: 
+     * {String} String with information on why layer is broken, how to get
+     *          it working.
+     */
+    getWarningHTML:function() {
+        return OpenLayers.i18n(
+            "getLayerWarning", {'layerType':"MM", 'layerLib':"MultiMap"}
+        );
+    },
+
+
+
+    /************************************
+     *                                  *
+     *   MapObject Interface Controls   *
+     *                                  *
+     ************************************/
+
+
+  // Get&Set Center, Zoom
+
+    /** 
+     * APIMethod: setMapObjectCenter
+     * Set the mapObject to the specified center and zoom
+     * 
+     * Parameters:
+     * center - {Object} MapObject LonLat format
+     * zoom - {int} MapObject zoom format
+     */
+    setMapObjectCenter: function(center, zoom) {
+        this.mapObject.goToPosition(center, zoom); 
+    },
+   
+    /**
+     * APIMethod: getMapObjectCenter
+     * 
+     * Returns: 
+     * {Object} The mapObject's current center in Map Object format
+     */
+    getMapObjectCenter: function() {
+        return this.mapObject.getCurrentPosition();
+    },
+
+    /** 
+     * APIMethod: getMapObjectZoom
+     * 
+     * Returns:
+     * {Integer} The mapObject's current zoom, in Map Object format
+     */
+    getMapObjectZoom: function() {
+        return this.mapObject.getZoomFactor();
+    },
+
+
+  // LonLat - Pixel Translation
+  
+    /**
+     * APIMethod: getMapObjectLonLatFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Object} MapObject LonLat translated from MapObject Pixel
+     */
+    getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+        moPixel.x = moPixel.x - (this.map.getSize().w/2);
+        moPixel.y = moPixel.y - (this.map.getSize().h/2);
+        return this.mapObject.getMapPositionAt(moPixel);
+    },
+
+    /**
+     * APIMethod: getMapObjectPixelFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Object} MapObject Pixel transtlated from MapObject LonLat
+     */
+    getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+        return this.mapObject.geoPosToContainerPixels(moLonLat);
+    },
+
+
+    /************************************
+     *                                  *
+     *       MapObject Primitives       *
+     *                                  *
+     ************************************/
+
+
+  // LonLat
+    
+    /**
+     * APIMethod: getLongitudeFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Longitude of the given MapObject LonLat
+     */
+    getLongitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+            this.forwardMercator(moLonLat.lon, moLonLat.lat).lon :
+            moLonLat.lon;
+    },
+
+    /**
+     * APIMethod: getLatitudeFromMapObjectLonLat
+     * 
+     * Parameters:
+     * moLonLat - {Object} MapObject LonLat format
+     * 
+     * Returns:
+     * {Float} Latitude of the given MapObject LonLat
+     */
+    getLatitudeFromMapObjectLonLat: function(moLonLat) {
+        return this.sphericalMercator ? 
+            this.forwardMercator(moLonLat.lon, moLonLat.lat).lat :
+            moLonLat.lat;
+    },
+
+    /**
+     * APIMethod: getMapObjectLonLatFromLonLat
+     * 
+     * Parameters:
+     * lon - {Float}
+     * lat - {Float}
+     * 
+     * Returns:
+     * {Object} MapObject LonLat built from lon and lat params
+     */
+    getMapObjectLonLatFromLonLat: function(lon, lat) {
+        var mmLatLon;
+        if(this.sphericalMercator) {
+            var lonlat = this.inverseMercator(lon, lat);
+            mmLatLon = new MMLatLon(lonlat.lat, lonlat.lon);
+        } else {
+            mmLatLon = new MMLatLon(lat, lon);
+        }
+        return mmLatLon;
+    },
+
+  // Pixel
+    
+    /**
+     * APIMethod: getXFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} X value of the MapObject Pixel
+     */
+    getXFromMapObjectPixel: function(moPixel) {
+        return moPixel.x;
+    },
+
+    /**
+     * APIMethod: getYFromMapObjectPixel
+     * 
+     * Parameters:
+     * moPixel - {Object} MapObject Pixel format
+     * 
+     * Returns:
+     * {Integer} Y value of the MapObject Pixel
+     */
+    getYFromMapObjectPixel: function(moPixel) {
+        return moPixel.y;
+    },
+
+    /**
+     * APIMethod: getMapObjectPixelFromXY
+     * 
+     * Parameters:
+     * x - {Integer}
+     * y - {Integer}
+     * 
+     * Returns:
+     * {Object} MapObject Pixel from x and y parameters
+     */
+    getMapObjectPixelFromXY: function(x, y) {
+        return new MMPoint(x, y);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.MultiMap"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/PointTrack.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/PointTrack.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/PointTrack.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,102 @@
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Vector.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.PointTrack
+ * Vector layer to display ordered point features as a line, creating one
+ * LineString feature for each pair of two points.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Vector> 
+ */
+OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, {
+  
+    /**
+     * APIProperty:
+     * dataFrom  - {<OpenLayers.Layer.PointTrack.dataFrom>} optional. If the
+     *             lines should get the data/attributes from one of the two
+     *             points, creating it, which one should it be?
+     */
+    dataFrom: null,
+    
+    /**
+     * Constructor: OpenLayers.PointTrack
+     * Constructor for a new OpenLayers.PointTrack instance.
+     *
+     * Parameters:
+     * name     - {String} name of the layer
+     * options  - {Object} Optional object with properties to tag onto the
+     *            instance.
+     */    
+    initialize: function(name, options) {
+        OpenLayers.Layer.Vector.prototype.initialize.apply(this, arguments);
+    },
+        
+    /**
+     * APIMethod: addNodes
+     * Adds point features that will be used to create lines from, using point
+     * pairs. The first point of a pair will be the source node, the second
+     * will be the target node.
+     * 
+     * Parameters:
+     * pointFeatures - {Array(<OpenLayers.Feature>)}
+     * 
+     */
+    addNodes: function(pointFeatures) {
+        if (pointFeatures.length < 2) {
+            OpenLayers.Console.error(
+                    "At least two point features have to be added to create" +
+                    "a line from");
+            return;
+        }
+        
+        var lines = new Array(pointFeatures.length-1);
+        
+        var pointFeature, startPoint, endPoint;
+        for(var i=0, len=pointFeatures.length; i<len; i++) {
+            pointFeature = pointFeatures[i];
+            endPoint = pointFeature.geometry;
+            
+            if (!endPoint) {
+              var lonlat = pointFeature.lonlat;
+              endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
+            } else if(endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") {
+                OpenLayers.Console.error(
+                        "Only features with point geometries are supported.");
+                return;
+            }
+            
+            if(i > 0) {
+                var attributes = (this.dataFrom != null) ?
+                        (pointFeatures[i+this.dataFrom].data ||
+                                pointFeatures[i+this.dataFrom].attributes) :
+                        null;
+                var line = new OpenLayers.Geometry.LineString([startPoint,
+                        endPoint]);
+                        
+                lines[i-1] = new OpenLayers.Feature.Vector(line, attributes);
+            }
+            
+            startPoint = endPoint;
+        }
+
+        this.addFeatures(lines);
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.PointTrack"
+});
+
+/**
+ * Constant: OpenLayers.Layer.PointTrack.dataFrom
+ * {Object} with the following keys
+ * - SOURCE_NODE: take data/attributes from the source node of the line
+ * - TARGET_NODE: take data/attributes from the target node of the line
+ */
+OpenLayers.Layer.PointTrack.dataFrom = {'SOURCE_NODE': -1, 'TARGET_NODE': 0};
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/SphericalMercator.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/SphericalMercator.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/SphericalMercator.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,159 @@
+/**
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Projection.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.SphericalMercator
+ * A mixin for layers that wraps up the pieces neccesary to have a coordinate
+ *     conversion for working with commercial APIs which use a spherical
+ *     mercator projection.  Using this layer as a base layer, additional
+ *     layers can be used as overlays if they are in the same projection.
+ *
+ * A layer is given properties of this object by setting the sphericalMercator
+ *     property to true.
+ *
+ * More projection information:
+ *  - http://spatialreference.org/ref/user/google-projection/
+ *
+ * Proj4 Text:
+ *     +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
+ *     +k=1.0 +units=m +nadgrids=@null +no_defs
+ *
+ * WKT:
+ *     900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
+ *     DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], 
+ *     PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295], 
+ *     AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
+ *     PROJECTION["Mercator_1SP_Google"], 
+ *     PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], 
+ *     PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], 
+ *     PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
+ *     AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
+ */
+OpenLayers.Layer.SphericalMercator = {
+
+    /**
+     * Method: getExtent
+     * Get the map's extent.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} The map extent.
+     */
+    getExtent: function() {
+        var extent = null;
+        if (this.sphericalMercator) {
+            extent = this.map.calculateBounds();
+        } else {
+            extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
+        }
+        return extent;
+    },
+
+    /** 
+     * Method: initMercatorParameters 
+     * Set up the mercator parameters on the layer: resolutions,
+     *     projection, units.
+     */
+    initMercatorParameters: function() {
+        // set up properties for Mercator - assume EPSG:900913
+        this.RESOLUTIONS = [];
+        var maxResolution = 156543.0339;
+        for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
+            this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
+        }
+        this.units = "m";
+        this.projection = "EPSG:900913";
+    },
+
+    /**
+     * APIMethod: forwardMercator
+     * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
+     *
+     * Parameters:
+     * lon - {float} 
+     * lat - {float}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
+     */
+    forwardMercator: function(lon, lat) {
+        var x = lon * 20037508.34 / 180;
+        var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
+
+        y = y * 20037508.34 / 180;
+        
+        return new OpenLayers.LonLat(x, y);
+    },
+
+    /**
+     * APIMethod: inverseMercator
+     * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
+     *
+     * Parameters:
+     * x - {float} A map x in Spherical Mercator.
+     * y - {float} A map y in Spherical Mercator.
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
+     */
+    inverseMercator: function(x, y) {
+
+        var lon = (x / 20037508.34) * 180;
+        var lat = (y / 20037508.34) * 180;
+
+        lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
+        
+        return new OpenLayers.LonLat(lon, lat);
+    },
+
+    /**
+     * Method: projectForward 
+     * Given an object with x and y properties in EPSG:4326, modify the x,y
+     * properties on the object to be the Spherical Mercator projected
+     * coordinates.
+     *
+     * Parameters:
+     * point - {Object} An object with x and y properties. 
+     * 
+     * Returns:
+     * {Object} The point, with the x and y properties transformed to spherical
+     * mercator.
+     */
+    projectForward: function(point) {
+        var lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(point.x, point.y);
+        point.x = lonlat.lon;
+        point.y = lonlat.lat;
+        return point;
+    },
+    
+    /**
+     * Method: projectInverse
+     * Given an object with x and y properties in Spherical Mercator, modify
+     * the x,y properties on the object to be the unprojected coordinates.
+     *
+     * Parameters:
+     * point - {Object} An object with x and y properties. 
+     * 
+     * Returns:
+     * {Object} The point, with the x and y properties transformed from
+     * spherical mercator to unprojected coordinates..
+     */
+    projectInverse: function(point) {
+        var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y);
+        point.x = lonlat.lon;
+        point.y = lonlat.lat;
+        return point;
+    }
+
+};
+
+/**
+ * Note: Two transforms declared
+ * Transforms from EPSG:4326 to EPSG:900913 and from EPSG:900913 to EPSG:4326
+ *     are set by this class.
+ */
+OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:900913",
+    OpenLayers.Layer.SphericalMercator.projectForward);
+OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:4326",
+    OpenLayers.Layer.SphericalMercator.projectInverse);

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TMS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TMS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TMS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,152 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * licence.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.TMS
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * APIProperty: serviceVersion
+     * {String}
+     */
+    serviceVersion: "1.0.0",
+
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean}
+     */
+    isBaseLayer: true,
+
+    /**
+     * APIProperty: tileOrigin
+     * {<OpenLayers.Pixel>}
+     */
+    tileOrigin: null,
+
+    /**
+     * APIProperty: serverResolutions
+     * {Array} A list of all resolutions available on the server.  Only set this 
+     *     property if the map resolutions differs from the server.
+     */
+    serverResolutions: null,
+
+    /**
+     * Constructor: OpenLayers.Layer.TMS
+     * 
+     * Parameters:
+     * name - {String}
+     * url - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, options) {
+        var newArguments = [];
+        newArguments.push(name, url, {}, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+    },    
+
+    /**
+     * APIMethod:destroy
+     */
+    destroy: function() {
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
+    },
+
+    
+    /**
+     * APIMethod: clone
+     * 
+     * Parameters:
+     * obj - {Object}
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.TMS>} An exact clone of this <OpenLayers.Layer.TMS>
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.TMS(this.name,
+                                           this.url,
+                                           this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },    
+    
+    /**
+     * Method: getURL
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the 
+     *          passed-in bounds and appropriate tile size specified as 
+     *          parameters
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        var res = this.map.getResolution();
+        var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
+        var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h));
+        var z = this.serverResolutions != null ?
+            OpenLayers.Util.indexOf(this.serverResolutions, res) :
+            this.map.getZoom();
+        var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; 
+        var url = this.url;
+        if (url instanceof Array) {
+            url = this.selectUrl(path, url);
+        }
+        return url + path;
+    },
+
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+
+    /** 
+     * APIMethod: setMap
+     * When the layer is added to a map, then we can fetch our origin 
+     *    (if we don't have one.) 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
+        if (!this.tileOrigin) { 
+            this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left,
+                                                this.map.maxExtent.bottom);
+        }                                       
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.TMS"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TileCache.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TileCache.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/TileCache.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,164 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * licence.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.TileCache
+ * A read only TileCache layer.  Used to requests tiles cached by TileCache in
+ *     a web accessible cache.  This means that you have to pre-populate your
+ *     cache before this layer can be used.  It is meant only to read tiles
+ *     created by TileCache, and not to make calls to TileCache for tile
+ *     creation.  Create a new instance with the
+ *     <OpenLayers.Layer.TileCache> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /** 
+     * APIProperty: isBaseLayer
+     * {Boolean} Treat this layer as a base layer.  Default is true.
+     */
+    isBaseLayer: true,
+    
+    /** 
+     * APIProperty: format
+     * {String} Mime type of the images returned.  Default is image/png.
+     */
+    format: 'image/png',
+
+    /**
+     * APIProperty: serverResolutions
+     * {Array} A list of all resolutions available on the server.  Only set this 
+     *     property if the map resolutions differs from the server.
+     */
+    serverResolutions: null,
+
+    /**
+     * Constructor: OpenLayers.Layer.TileCache
+     * Create a new read only TileCache layer.
+     *
+     * Parameters:
+     * name - {String} Name of the layer displayed in the interface
+     * url - {String} Location of the web accessible cache (not the location of
+     *     your tilecache script!)
+     * layername - {String} Layer name as defined in the TileCache 
+     *     configuration
+     * options - {Object} Optional object with properties to be set on the
+     *     layer.  Note that you should speficy your resolutions to match
+     *     your TileCache configuration.  This can be done by setting
+     *     the resolutions array directly (here or on the map), by setting
+     *     maxResolution and numZoomLevels, or by using scale based properties.
+     */
+    initialize: function(name, url, layername, options) {
+        this.layername = layername;
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this,
+                                                         [name, url, {}, options]);
+        this.extension = this.format.split('/')[1].toLowerCase();
+        this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension;
+    },    
+
+    /**
+     * APIMethod: clone
+     * obj - {Object} 
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.TileCache>} An exact clone of this 
+     *     <OpenLayers.Layer.TileCache>
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.TileCache(this.name,
+                                                 this.url,
+                                                 this.layername,
+                                                 this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },    
+    
+    /**
+     * Method: getURL
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * 
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the 
+     *     passed-in bounds and appropriate tile size specified as parameters.
+     */
+    getURL: function(bounds) {
+        var res = this.map.getResolution();
+        var bbox = this.maxExtent;
+        var size = this.tileSize;
+        var tileX = Math.round((bounds.left - bbox.left) / (res * size.w));
+        var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h));
+        var tileZ = this.serverResolutions != null ?
+            OpenLayers.Util.indexOf(this.serverResolutions, res) :
+            this.map.getZoom();
+        /**
+         * Zero-pad a positive integer.
+         * number - {Int} 
+         * length - {Int} 
+         *
+         * Returns:
+         * {String} A zero-padded string
+         */
+        function zeroPad(number, length) {
+            number = String(number);
+            var zeros = [];
+            for(var i=0; i<length; ++i) {
+                zeros.push('0');
+            }
+            return zeros.join('').substring(0, length - number.length) + number;
+        }
+        var components = [
+            this.layername,
+            zeroPad(tileZ, 2),
+            zeroPad(parseInt(tileX / 1000000), 3),
+            zeroPad((parseInt(tileX / 1000) % 1000), 3),
+            zeroPad((parseInt(tileX) % 1000), 3),
+            zeroPad(parseInt(tileY / 1000000), 3),
+            zeroPad((parseInt(tileY / 1000) % 1000), 3),
+            zeroPad((parseInt(tileY) % 1000), 3) + '.' + this.extension
+        ];
+        var path = components.join('/'); 
+        var url = this.url;
+        if (url instanceof Array) {
+            url = this.selectUrl(path, url);
+        }
+        url = (url.charAt(url.length - 1) == '/') ? url : url + '/';
+        return url + path;
+    },
+
+    /**
+     * Method: addTile
+     * Create a tile, initialize it, and add it to the layer div. 
+     *
+     * Parameters: 
+     * bounds - {<OpenLayers.Bounds>} 
+     * position - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added <OpenLayers.Tile.Image>
+     */
+    addTile:function(bounds, position) {
+        var url = this.getURL(bounds);
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                             url, this.tileSize);
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.TileCache"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Vector.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Vector.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/Vector.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,814 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Renderer.js
+ * @requires OpenLayers/StyleMap.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Vector
+ * Instances of OpenLayers.Layer.Vector are used to render vector data from
+ *     a variety of sources. Create a new vector layer with the
+ *     <OpenLayers.Layer.Vector> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * layer.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * All event objects have at least the following properties:
+     * object - {Object} A reference to layer.events.object.
+     * element - {DOMElement} A reference to layer.events.element.
+     *
+     * Supported map event types (in addition to those from <OpenLayers.Layer>):
+     * beforefeatureadded - Triggered before a feature is added.  Listeners
+     *      will receive an object with a *feature* property referencing the
+     *      feature to be added.  To stop the feature from being added, a
+     *      listener should return false.
+     * beforefeaturesadded - Triggered before an array of features is added.
+     *      Listeners will receive an object with a *features* property
+     *      referencing the feature to be added. To stop the features from
+     *      being added, a listener should return false.
+     * featureadded - Triggered after a feature is added.  The event
+     *      object passed to listeners will have a *feature* property with a
+     *      reference to the added feature.
+     * featuresadded - Triggered after features are added.  The event
+     *      object passed to listeners will have a *features* property with a
+     *      reference to an array of added features.
+     * beforefeatureremoved - Triggered before a feature is removed. Listeners
+     *      will receive an object with a *feature* property referencing the
+     *      feature to be removed.
+     * featureremoved - Triggerd after a feature is removed. The event
+     *      object passed to listeners will have a *feature* property with a
+     *      reference to the removed feature.
+     * featuresremoved - Triggered after features are removed. The event
+     *      object passed to listeners will have a *features* property with a
+     *      reference to an array of removed features.
+     * featureselected - Triggered after a feature is selected.  Listeners
+     *      will receive an object with a *feature* property referencing the
+     *      selected feature.
+     * featureunselected - Triggered after a feature is unselected.
+     *      Listeners will receive an object with a *feature* property
+     *      referencing the unselected feature.
+     * beforefeaturemodified - Triggered when a feature is selected to 
+     *      be modified.  Listeners will receive an object with a *feature* 
+     *      property referencing the selected feature.
+     * featuremodified - Triggered when a feature has been modified.
+     *      Listeners will receive an object with a *feature* property referencing 
+     *      the modified feature.
+     * afterfeaturemodified - Triggered when a feature is finished being modified.
+     *      Listeners will receive an object with a *feature* property referencing 
+     *      the modified feature.
+     * vertexmodified - Triggered when a vertex within any feature geometry
+     *      has been modified.  Listeners will receive an object with a
+     *      *feature* property referencing the modified feature, a *vertex*
+     *      property referencing the vertex modified (always a point geometry),
+     *      and a *pixel* property referencing the pixel location of the
+     *      modification.
+     * sketchstarted - Triggered when a feature sketch bound for this layer
+     *      is started.  Listeners will receive an object with a *feature*
+     *      property referencing the new sketch feature and a *vertex* property
+     *      referencing the creation point.
+     * sketchmodified - Triggered when a feature sketch bound for this layer
+     *      is modified.  Listeners will receive an object with a *vertex*
+     *      property referencing the modified vertex and a *feature* property
+     *      referencing the sketch feature.
+     * sketchcomplete - Triggered when a feature sketch bound for this layer
+     *      is complete.  Listeners will receive an object with a *feature*
+     *      property referencing the sketch feature.  By returning false, a
+     *      listener can stop the sketch feature from being added to the layer.
+     * refresh - Triggered when something wants a strategy to ask the protocol
+     *      for a new set of features.
+     */
+    EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
+                  "featureadded", "featuresadded",
+                  "beforefeatureremoved", "featureremoved", "featuresremoved",
+                  "beforefeatureselected", "featureselected", "featureunselected", 
+                  "beforefeaturemodified", "featuremodified", "afterfeaturemodified",
+                  "vertexmodified", "sketchstarted", "sketchmodified",
+                  "sketchcomplete", "refresh"],
+
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} The layer is a base layer.  Default is true.  Set this property
+     * in the layer options
+     */
+    isBaseLayer: false,
+
+    /** 
+     * APIProperty: isFixed
+     * {Boolean} Whether the layer remains in one place while dragging the
+     * map.
+     */
+    isFixed: false,
+
+    /** 
+     * APIProperty: isVector
+     * {Boolean} Whether the layer is a vector layer.
+     */
+    isVector: true,
+    
+    /** 
+     * APIProperty: features
+     * {Array(<OpenLayers.Feature.Vector>)} 
+     */
+    features: null,
+    
+    /** 
+     * Property: selectedFeatures
+     * {Array(<OpenLayers.Feature.Vector>)} 
+     */
+    selectedFeatures: null,
+    
+    /**
+     * Property: unrenderedFeatures
+     * {Object} hash of features, keyed by feature.id, that the renderer
+     *     failed to draw
+     */
+    unrenderedFeatures: null,
+
+    /**
+     * APIProperty: reportError
+     * {Boolean} report friendly error message when loading of renderer
+     * fails.
+     */
+    reportError: true, 
+
+    /** 
+     * APIProperty: style
+     * {Object} Default style for the layer
+     */
+    style: null,
+    
+    /**
+     * Property: styleMap
+     * {<OpenLayers.StyleMap>}
+     */
+    styleMap: null,
+    
+    /**
+     * Property: strategies
+     * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
+     */
+    strategies: null,
+    
+    /**
+     * Property: protocol
+     * {<OpenLayers.Protocol>} Optional protocol for the layer.
+     */
+    protocol: null,
+    
+    /**
+     * Property: renderers
+     * {Array(String)} List of supported Renderer classes. Add to this list to
+     * add support for additional renderers. This list is ordered:
+     * the first renderer which returns true for the  'supported()'
+     * method will be used, if not defined in the 'renderer' option.
+     */
+    renderers: ['SVG', 'VML', 'Canvas'],
+    
+    /** 
+     * Property: renderer
+     * {<OpenLayers.Renderer>}
+     */
+    renderer: null,
+    
+    /**
+     * APIProperty: rendererOptions
+     * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
+     *     supported options.
+     */
+    rendererOptions: null,
+    
+    /** 
+     * APIProperty: geometryType
+     * {String} geometryType allows you to limit the types of geometries this
+     * layer supports. This should be set to something like
+     * "OpenLayers.Geometry.Point" to limit types.
+     */
+    geometryType: null,
+
+    /** 
+     * Property: drawn
+     * {Boolean} Whether the Vector Layer features have been drawn yet.
+     */
+    drawn: false,
+
+    /**
+     * Constructor: OpenLayers.Layer.Vector
+     * Create a new vector layer
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * options - {Object} Optional object with non-default properties to set on
+     *           the layer.
+     *
+     * Returns:
+     * {<OpenLayers.Layer.Vector>} A new vector layer
+     */
+    initialize: function(name, options) {
+        
+        // concatenate events specific to vector with those from the base
+        this.EVENT_TYPES =
+            OpenLayers.Layer.Vector.prototype.EVENT_TYPES.concat(
+            OpenLayers.Layer.prototype.EVENT_TYPES
+        );
+
+        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+
+        // allow user-set renderer, otherwise assign one
+        if (!this.renderer || !this.renderer.supported()) {  
+            this.assignRenderer();
+        }
+
+        // if no valid renderer found, display error
+        if (!this.renderer || !this.renderer.supported()) {
+            this.renderer = null;
+            this.displayError();
+        } 
+
+        if (!this.styleMap) {
+            this.styleMap = new OpenLayers.StyleMap();
+        }
+
+        this.features = [];
+        this.selectedFeatures = [];
+        this.unrenderedFeatures = {};
+        
+        // Allow for custom layer behavior
+        if(this.strategies){
+            for(var i=0, len=this.strategies.length; i<len; i++) {
+                this.strategies[i].setLayer(this);
+            }
+        }
+
+    },
+
+    /**
+     * APIMethod: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        if (this.strategies) {
+            var strategy, i, len;
+            for(i=0, len=this.strategies.length; i<len; i++) {
+                strategy = this.strategies[i];
+                if(strategy.autoDestroy) {
+                    strategy.destroy();
+                }
+            }
+            this.strategies = null;
+        }
+        if (this.protocol) {
+            if(this.protocol.autoDestroy) {
+                this.protocol.destroy();
+            }
+            this.protocol = null;
+        }
+        this.destroyFeatures();
+        this.features = null;
+        this.selectedFeatures = null;
+        this.unrenderedFeatures = null;
+        if (this.renderer) {
+            this.renderer.destroy();
+        }
+        this.renderer = null;
+        this.geometryType = null;
+        this.drawn = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments);  
+    },
+
+    /**
+     * Method: refresh
+     * Ask the layer to request features again and redraw them.  Triggers
+     *     the refresh event if the layer is in range and visible.
+     *
+     * Parameters:
+     * obj - {Object} Optional object with properties for any listener of
+     *     the refresh event.
+     */
+    refresh: function(obj) {
+        if(this.calculateInRange() && this.visibility) {
+            this.events.triggerEvent("refresh", obj);
+        }
+    },
+
+    /** 
+     * Method: assignRenderer
+     * Iterates through the available renderer implementations and selects 
+     * and assigns the first one whose "supported()" function returns true.
+     */    
+    assignRenderer: function()  {
+        for (var i=0, len=this.renderers.length; i<len; i++) {
+            var rendererClass = OpenLayers.Renderer[this.renderers[i]];
+            if (rendererClass && rendererClass.prototype.supported()) {
+                this.renderer = new rendererClass(this.div,
+                    this.rendererOptions);
+                break;
+            }  
+        }  
+    },
+
+    /** 
+     * Method: displayError 
+     * Let the user know their browser isn't supported.
+     */
+    displayError: function() {
+        if (this.reportError) {
+            OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported", 
+                                     {'renderers':this.renderers.join("\n")}));
+        }    
+    },
+
+    /** 
+     * Method: setMap
+     * The layer has been added to the map. 
+     * 
+     * If there is no renderer set, the layer can't be used. Remove it.
+     * Otherwise, give the renderer a reference to the map and set its size.
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {        
+        OpenLayers.Layer.prototype.setMap.apply(this, arguments);
+
+        if (!this.renderer) {
+            this.map.removeLayer(this);
+        } else {
+            this.renderer.map = this.map;
+            this.renderer.setSize(this.map.getSize());
+        }
+    },
+
+    /**
+     * Method: afterAdd
+     * Called at the end of the map.addLayer sequence.  At this point, the map
+     *     will have a base layer.  Any autoActivate strategies will be
+     *     activated here.
+     */
+    afterAdd: function() {
+        if(this.strategies) {
+            var strategy, i, len;
+            for(i=0, len=this.strategies.length; i<len; i++) {
+                strategy = this.strategies[i];
+                if(strategy.autoActivate) {
+                    strategy.activate();
+                }
+            }
+        }
+    },
+
+    /**
+     * Method: removeMap
+     * The layer has been removed from the map.
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    removeMap: function(map) {
+        if(this.strategies) {
+            var strategy, i, len;
+            for(i=0, len=this.strategies.length; i<len; i++) {
+                strategy = this.strategies[i];
+                if(strategy.autoActivate) {
+                    strategy.deactivate();
+                }
+            }
+        }
+    },
+    
+    /**
+     * Method: onMapResize
+     * Notify the renderer of the change in size. 
+     * 
+     */
+    onMapResize: function() {
+        OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
+        this.renderer.setSize(this.map.getSize());
+    },
+
+    /**
+     * Method: moveTo
+     *  Reset the vector layer's div so that it once again is lined up with 
+     *   the map. Notify the renderer of the change of extent, and in the
+     *   case of a change of zoom level (resolution), have the 
+     *   renderer redraw features.
+     * 
+     *  If the layer has not yet been drawn, cycle through the layer's 
+     *   features and draw each one.
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
+     */
+    moveTo: function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+        
+        var coordSysUnchanged = true;
+
+        if (!dragging) {
+            this.renderer.root.style.visibility = "hidden";
+            
+            this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
+            this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
+            var extent = this.map.getExtent();
+            coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
+            
+            this.renderer.root.style.visibility = "visible";
+
+            // Force a reflow on gecko based browsers to prevent jump/flicker.
+            // This seems to happen on only certain configurations; it was originally
+            // noticed in FF 2.0 and Linux.
+            if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
+                this.div.scrollLeft = this.div.scrollLeft;
+            }
+            
+            if(!zoomChanged && coordSysUnchanged) {
+                for(var i in this.unrenderedFeatures) {
+                    var feature = this.unrenderedFeatures[i];
+                    this.drawFeature(feature);
+                }
+            }
+        }
+        
+        if (!this.drawn || zoomChanged || !coordSysUnchanged) {
+            this.drawn = true;
+            var feature;
+            for(var i=0, len=this.features.length; i<len; i++) {
+                this.renderer.locked = (i !== (len - 1));
+                feature = this.features[i];
+                this.drawFeature(feature);
+            }
+        }    
+    },
+    
+    /** 
+     * APIMethod: display
+     * Hide or show the Layer
+     * 
+     * Parameters:
+     * display - {Boolean}
+     */
+    display: function(display) {
+        OpenLayers.Layer.prototype.display.apply(this, arguments);
+        // we need to set the display style of the root in case it is attached
+        // to a foreign layer
+        var currentDisplay = this.div.style.display;
+        if(currentDisplay != this.renderer.root.style.display) {
+            this.renderer.root.style.display = currentDisplay;
+        }
+    },
+
+    /**
+     * APIMethod: addFeatures
+     * Add Features to the layer.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
+     * options - {Object}
+     */
+    addFeatures: function(features, options) {
+        if (!(features instanceof Array)) {
+            features = [features];
+        }
+        
+        var notify = !options || !options.silent;
+        if(notify) {
+            var event = {features: features};
+            var ret = this.events.triggerEvent("beforefeaturesadded", event);
+            if(ret === false) {
+                return;
+            }
+            features = event.features;
+        }
+        
+
+        for (var i=0, len=features.length; i<len; i++) {
+            if (i != (features.length - 1)) {
+                this.renderer.locked = true;
+            } else {
+                this.renderer.locked = false;
+            }    
+            var feature = features[i];
+            
+            if (this.geometryType &&
+              !(feature.geometry instanceof this.geometryType)) {
+                var throwStr = OpenLayers.i18n('componentShouldBe',
+                          {'geomType':this.geometryType.prototype.CLASS_NAME});
+                throw throwStr;
+              }
+
+            this.features.push(feature);
+            
+            //give feature reference to its layer
+            feature.layer = this;
+
+            if (!feature.style && this.style) {
+                feature.style = OpenLayers.Util.extend({}, this.style);
+            }
+
+            if (notify) {
+                if(this.events.triggerEvent("beforefeatureadded",
+                                            {feature: feature}) === false) {
+                    continue;
+                };
+                this.preFeatureInsert(feature);
+            }
+
+            this.drawFeature(feature);
+            
+            if (notify) {
+                this.events.triggerEvent("featureadded", {
+                    feature: feature
+                });
+                this.onFeatureInsert(feature);
+            }
+        }
+        
+        if(notify) {
+            this.events.triggerEvent("featuresadded", {features: features});
+        }
+    },
+
+
+    /**
+     * APIMethod: removeFeatures
+     * Remove features from the layer.  This erases any drawn features and
+     *     removes them from the layer's control.  The beforefeatureremoved
+     *     and featureremoved events will be triggered for each feature.  The
+     *     featuresremoved event will be triggered after all features have
+     *     been removed.  To supress event triggering, use the silent option.
+     * 
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
+     *     removed.
+     * options - {Object} Optional properties for changing behavior of the
+     *     removal.
+     *
+     * Valid options:
+     * silent - {Boolean} Supress event triggering.  Default is false.
+     */
+    removeFeatures: function(features, options) {
+        if(!features || features.length === 0) {
+            return;
+        }
+        if (!(features instanceof Array)) {
+            features = [features];
+        }
+        if (features === this.features) {
+            features = features.slice();
+        }
+
+        var notify = !options || !options.silent;
+
+        for (var i = features.length - 1; i >= 0; i--) {
+            // We remain locked so long as we're not at 0
+            // and the 'next' feature has a geometry. We do the geometry check
+            // because if all the features after the current one are 'null', we
+            // won't call eraseGeometry, so we break the 'renderer functions
+            // will always be called with locked=false *last*' rule. The end result
+            // is a possible gratiutious unlocking to save a loop through the rest 
+            // of the list checking the remaining features every time. So long as
+            // null geoms are rare, this is probably okay.    
+            if (i != 0 && features[i-1].geometry) {
+                this.renderer.locked = true;
+            } else {
+                this.renderer.locked = false;
+            }
+    
+            var feature = features[i];
+            delete this.unrenderedFeatures[feature.id];
+
+            if (notify) {
+                this.events.triggerEvent("beforefeatureremoved", {
+                    feature: feature
+                });
+            }
+
+            this.features = OpenLayers.Util.removeItem(this.features, feature);
+            // feature has no layer at this point
+            feature.layer = null;
+
+            if (feature.geometry) {
+                this.renderer.eraseFeatures(feature);
+            }
+                    
+            //in the case that this feature is one of the selected features, 
+            // remove it from that array as well.
+            if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
+                OpenLayers.Util.removeItem(this.selectedFeatures, feature);
+            }
+
+            if (notify) {
+                this.events.triggerEvent("featureremoved", {
+                    feature: feature
+                });
+            }
+        }
+
+        if (notify) {
+            this.events.triggerEvent("featuresremoved", {features: features});
+        }
+    },
+
+    /**
+     * APIMethod: destroyFeatures
+     * Erase and destroy features on the layer.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of
+     *     features to destroy.  If not supplied, all features on the layer
+     *     will be destroyed.
+     * options - {Object}
+     */
+    destroyFeatures: function(features, options) {
+        var all = (features == undefined); // evaluates to true if
+                                           // features is null
+        if(all) {
+            features = this.features;
+        }
+        if(features) {
+            this.removeFeatures(features, options);
+            for(var i=features.length-1; i>=0; i--) {
+                features[i].destroy();
+            }
+        }
+    },
+
+    /**
+     * APIMethod: drawFeature
+     * Draw (or redraw) a feature on the layer.  If the optional style argument
+     * is included, this style will be used.  If no style is included, the
+     * feature's style will be used.  If the feature doesn't have a style,
+     * the layer's style will be used.
+     * 
+     * This function is not designed to be used when adding features to 
+     * the layer (use addFeatures instead). It is meant to be used when
+     * the style of a feature has changed, or in some other way needs to 
+     * visually updated *after* it has already been added to a layer. You
+     * must add the feature to the layer for most layer-related events to 
+     * happen.
+     *
+     * Parameters: 
+     * feature - {<OpenLayers.Feature.Vector>} 
+     * style - {Object} Symbolizer hash or {String} renderIntent
+     */
+    drawFeature: function(feature, style) {
+        // don't try to draw the feature with the renderer if the layer is not 
+        // drawn itself
+        if (!this.drawn) {
+            return
+        }
+        if (typeof style != "object") {
+            if(!style && feature.state === OpenLayers.State.DELETE) {
+                style = "delete";
+            }
+            var renderIntent = style || feature.renderIntent;
+            style = feature.style || this.style;
+            if (!style) {
+                style = this.styleMap.createSymbolizer(feature, renderIntent);
+            }
+        }
+        
+        if (!this.renderer.drawFeature(feature, style)) {
+            this.unrenderedFeatures[feature.id] = feature;
+        } else {
+            delete this.unrenderedFeatures[feature.id];
+        };
+    },
+    
+    /**
+     * Method: eraseFeatures
+     * Erase features from the layer.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>)} 
+     */
+    eraseFeatures: function(features) {
+        this.renderer.eraseFeatures(features);
+    },
+
+    /**
+     * Method: getFeatureFromEvent
+     * Given an event, return a feature if the event occurred over one.
+     * Otherwise, return null.
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
+     */
+    getFeatureFromEvent: function(evt) {
+        if (!this.renderer) {
+            OpenLayers.Console.error(OpenLayers.i18n("getFeatureError")); 
+            return null;
+        }    
+        var featureId = this.renderer.getFeatureIdFromEvent(evt);
+        return this.getFeatureById(featureId);
+    },
+    
+    /**
+     * APIMethod: getFeatureById
+     * Given a feature id, return the feature if it exists in the features array
+     *
+     * Parameters:
+     * featureId - {String} 
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+     * featureId
+     */
+    getFeatureById: function(featureId) {
+        //TBD - would it be more efficient to use a hash for this.features?
+        var feature = null;
+        for(var i=0, len=this.features.length; i<len; ++i) {
+            if(this.features[i].id == featureId) {
+                feature = this.features[i];
+                break;
+            }
+        }
+        return feature;
+    },
+    
+    /**
+     * Unselect the selected features
+     * i.e. clears the featureSelection array
+     * change the style back
+    clearSelection: function() {
+
+       var vectorLayer = this.map.vectorLayer;
+        for (var i = 0; i < this.map.featureSelection.length; i++) {
+            var featureSelection = this.map.featureSelection[i];
+            vectorLayer.drawFeature(featureSelection, vectorLayer.style);
+        }
+        this.map.featureSelection = [];
+    },
+     */
+
+
+    /**
+     * APIMethod: onFeatureInsert
+     * method called after a feature is inserted.
+     * Does nothing by default. Override this if you
+     * need to do something on feature updates.
+     *
+     * Paarameters: 
+     * feature - {<OpenLayers.Feature.Vector>} 
+     */
+    onFeatureInsert: function(feature) {
+    },
+    
+    /**
+     * APIMethod: preFeatureInsert
+     * method called before a feature is inserted.
+     * Does nothing by default. Override this if you
+     * need to do something when features are first added to the
+     * layer, but before they are drawn, such as adjust the style.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} 
+     */
+    preFeatureInsert: function(feature) {
+    },
+
+    /** 
+     * APIMethod: getDataExtent
+     * Calculates the max extent which includes all of the features.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        var maxExtent = null;
+
+        if(this.features && (this.features.length > 0)) {
+            maxExtent = new OpenLayers.Bounds();
+            for(var i=0, len=this.features.length; i<len; i++) {
+                maxExtent.extend(this.features[i].geometry.getBounds());
+            }
+        }
+
+        return maxExtent;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.Vector"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WFS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WFS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WFS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,598 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile/WFS.js
+ * @requires OpenLayers/Layer/Vector.js
+ * @requires OpenLayers/Layer/Markers.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WFS
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Vector>
+ *  - <OpenLayers.Layer.Markers>
+ */
+OpenLayers.Layer.WFS = OpenLayers.Class(
+  OpenLayers.Layer.Vector, OpenLayers.Layer.Markers, {
+
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} WFS layer is not a base layer by default. 
+     */
+    isBaseLayer: false,
+    
+    /**
+     * Property: tile
+     * {<OpenLayers.Tile.WFS>}
+     */
+    tile: null,    
+    
+    /**
+     * APIProperty: ratio
+     * {Float} the ratio of image/tile size to map size (this is the untiled
+     *     buffer)
+     */
+    ratio: 2,
+
+    /**  
+     * Property: DEFAULT_PARAMS
+     * {Object} Hashtable of default key/value parameters
+     */
+    DEFAULT_PARAMS: { service: "WFS",
+                      version: "1.0.0",
+                      request: "GetFeature"
+                    },
+    
+    /** 
+     * APIProperty: featureClass
+     * {<OpenLayers.Feature>} If featureClass is defined, an old-style markers
+     *     based WFS layer is created instead of a new-style vector layer. If
+     *     sent, this should be a subclass of OpenLayers.Feature
+     */
+    featureClass: null,
+    
+    /**
+      * APIProperty: format
+      * {<OpenLayers.Format>} The format you want the data to be parsed with.
+      * Must be passed in the constructor. Should be a class, not an instance.
+      * This option can only be used if no featureClass is passed / vectorMode
+      * is false: if a featureClass is passed, then this parameter is ignored.
+      */
+    format: null,
+
+    /** 
+     * Property: formatObject
+     * {<OpenLayers.Format>} Internally created/managed format object, used by
+     * the Tile to parse data.
+     */
+    formatObject: null,
+
+    /**
+     * APIProperty: formatOptions
+     * {Object} Hash of options which should be passed to the format when it is
+     * created. Must be passed in the constructor.
+     */
+    formatOptions: null, 
+
+    /**
+     * Property: vectorMode
+     * {Boolean} Should be calculated automatically. Determines whether the
+     *     layer is in vector mode or marker mode.
+     */
+    vectorMode: true, 
+    
+    /**
+     * APIProperty: encodeBBOX
+     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', 
+     *     but some services want it that way. Default false.
+     */
+    encodeBBOX: false,
+    
+    /**
+     * APIProperty: extractAttributes 
+     * {Boolean} Should the WFS layer parse attributes from the retrieved
+     *     GML? Defaults to false. If enabled, parsing is slower, but 
+     *     attributes are available in the attributes property of 
+     *     layer features.
+     */
+    extractAttributes: false,
+
+    /**
+     * Constructor: OpenLayers.Layer.WFS
+     *
+     * Parameters:
+     * name - {String} 
+     * url - {String} 
+     * params - {Object} 
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        if (options == undefined) { options = {}; } 
+        
+        if (options.featureClass || 
+            !OpenLayers.Layer.Vector || 
+            !OpenLayers.Feature.Vector) {
+            this.vectorMode = false;
+        }    
+        
+        // Turn off error reporting, browsers like Safari may work
+        // depending on the setup, and we don't want an unneccesary alert.
+        OpenLayers.Util.extend(options, {'reportError': false});
+        var newArguments = [];
+        newArguments.push(name, options);
+        OpenLayers.Layer.Vector.prototype.initialize.apply(this, newArguments);
+        if (!this.renderer || !this.vectorMode) {
+            this.vectorMode = false; 
+            if (!options.featureClass) {
+                options.featureClass = OpenLayers.Feature.WFS;
+            }   
+            OpenLayers.Layer.Markers.prototype.initialize.apply(this, 
+                                                                newArguments);
+        }
+        
+        if (this.params && this.params.typename && !this.options.typename) {
+            this.options.typename = this.params.typename;
+        }
+        
+        if (!this.options.geometry_column) {
+            this.options.geometry_column = "the_geom";
+        }    
+        
+        this.params = OpenLayers.Util.applyDefaults(
+            params, 
+            OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
+        );
+        this.url = url;
+    },    
+    
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        if (this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.destroy.apply(this, arguments);
+        } else {    
+            OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
+        }    
+        if (this.tile) {
+            this.tile.destroy();
+        }
+        this.tile = null;
+
+        this.ratio = null;
+        this.featureClass = null;
+        this.format = null;
+
+        if (this.formatObject && this.formatObject.destroy) {
+            this.formatObject.destroy();
+        }
+        this.formatObject = null;
+        
+        this.formatOptions = null;
+        this.vectorMode = null;
+        this.encodeBBOX = null;
+        this.extractAttributes = null;
+    },
+    
+    /**
+     * Method: setMap
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        if (this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments);
+            
+            var options = {
+              'extractAttributes': this.extractAttributes
+            };
+            
+            OpenLayers.Util.extend(options, this.formatOptions);
+            if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
+                options.externalProjection = this.projection;
+                options.internalProjection = this.map.getProjectionObject();
+            }    
+            
+            this.formatObject = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
+        } else {    
+            OpenLayers.Layer.Markers.prototype.setMap.apply(this, arguments);
+        }    
+    },
+    
+    /** 
+     * Method: moveTo
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        if (this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments);
+        } else {
+            OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
+        }    
+
+        // don't load wfs features while dragging, wait for drag end
+        if (dragging) {
+            // TBD try to hide the vector layer while dragging
+            // this.setVisibility(false);
+            // this will probably help for panning performances
+            return false;
+        }
+        
+        if ( zoomChanged ) {
+            if (this.vectorMode) {
+                this.renderer.clear();
+            }
+        }
+        
+    //DEPRECATED - REMOVE IN 3.0
+        // don't load data if current zoom level doesn't match
+        if (this.options.minZoomLevel) {
+            OpenLayers.Console.warn(OpenLayers.i18n('minZoomLevelError'));
+            
+            if (this.map.getZoom() < this.options.minZoomLevel) {
+                return null;
+            }
+        }
+        
+        if (bounds == null) {
+            bounds = this.map.getExtent();
+        }
+
+        var firstRendering = (this.tile == null);
+
+        //does the new bounds to which we need to move fall outside of the 
+        // current tile's bounds?
+        var outOfBounds = (!firstRendering &&
+                           !this.tile.bounds.containsBounds(bounds));
+
+        if (zoomChanged || firstRendering || (!dragging && outOfBounds)) {
+            //determine new tile bounds
+            var center = bounds.getCenterLonLat();
+            var tileWidth = bounds.getWidth() * this.ratio;
+            var tileHeight = bounds.getHeight() * this.ratio;
+            var tileBounds = 
+                new OpenLayers.Bounds(center.lon - (tileWidth / 2),
+                                      center.lat - (tileHeight / 2),
+                                      center.lon + (tileWidth / 2),
+                                      center.lat + (tileHeight / 2));
+
+            //determine new tile size
+            var tileSize = this.map.getSize();
+            tileSize.w = tileSize.w * this.ratio;
+            tileSize.h = tileSize.h * this.ratio;
+
+            //determine new position (upper left corner of new bounds)
+            var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+            var pos = this.map.getLayerPxFromLonLat(ul);
+
+            //formulate request url string
+            var url = this.getFullRequestString();
+        
+            var params = null;
+
+            // Cant combine "filter" and "BBOX". This is a cheap hack to help
+            // people out who can't migrate to the WFS protocol immediately.
+            var filter = this.params.filter || this.params.FILTER;
+            if (filter) {
+                params = {FILTER: filter};
+            }
+            else {
+                params = {BBOX: this.encodeBBOX ? tileBounds.toBBOX() 
+                                                    : tileBounds.toArray()};
+            }
+            
+            if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
+                var projectedBounds = tileBounds.clone();
+                projectedBounds.transform(this.map.getProjectionObject(), 
+                                          this.projection);
+                if (!filter){
+                    params.BBOX = this.encodeBBOX ? projectedBounds.toBBOX() 
+                                                : projectedBounds.toArray();
+                }
+            }                                  
+
+            url += "&" + OpenLayers.Util.getParameterString(params);
+
+            if (!this.tile) {
+                this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, 
+                                                     url, tileSize);
+                this.addTileMonitoringHooks(this.tile);
+                this.tile.draw();
+            } else {
+                if (this.vectorMode) {
+                    this.destroyFeatures();
+                    this.renderer.clear();
+                } else {
+                    this.clearMarkers();
+                }    
+                this.removeTileMonitoringHooks(this.tile);
+                this.tile.destroy();
+                
+                this.tile = null;
+                this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, 
+                                                     url, tileSize);
+                this.addTileMonitoringHooks(this.tile);
+                this.tile.draw();
+            } 
+        }
+    },
+
+    /** 
+     * Method: addTileMonitoringHooks
+     * This function takes a tile as input and adds the appropriate hooks to 
+     *     the tile so that the layer can keep track of the loading tile
+     *     (making sure to check that the tile is always the layer's current
+     *     tile before taking any action).
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    addTileMonitoringHooks: function(tile) {
+        tile.onLoadStart = function() {
+            //if this is the the layer's current tile, then trigger 
+            // a 'loadstart'
+            if (this == this.layer.tile) {
+                this.layer.events.triggerEvent("loadstart");
+            }
+        };
+        tile.events.register("loadstart", tile, tile.onLoadStart);
+      
+        tile.onLoadEnd = function() {
+            //if this is the the layer's current tile, then trigger 
+            // a 'tileloaded' and 'loadend'
+            if (this == this.layer.tile) {
+                this.layer.events.triggerEvent("tileloaded");
+                this.layer.events.triggerEvent("loadend");
+            }
+        };
+        tile.events.register("loadend", tile, tile.onLoadEnd);
+        tile.events.register("unload", tile, tile.onLoadEnd);
+    },
+    
+    /** 
+     * Method: removeTileMonitoringHooks
+     * This function takes a tile as input and removes the tile hooks 
+     *     that were added in addTileMonitoringHooks()
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    removeTileMonitoringHooks: function(tile) {
+        tile.unload();
+        tile.events.un({
+            "loadstart": tile.onLoadStart,
+            "loadend": tile.onLoadEnd,
+            "unload": tile.onLoadEnd,
+            scope: tile
+        });
+    },
+
+    /**
+     * Method: onMapResize
+     * Call the onMapResize method of the appropriate parent class. 
+     */
+    onMapResize: function() {
+        if(this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.onMapResize.apply(this, 
+                                                                arguments);
+        } else {
+            OpenLayers.Layer.Markers.prototype.onMapResize.apply(this, 
+                                                                 arguments);
+        }
+    },
+    
+    /**
+     * Method: display
+     * Call the display method of the appropriate parent class. 
+     */
+    display: function() {
+        if(this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.display.apply(this, 
+                                                                arguments);
+        } else {
+            OpenLayers.Layer.Markers.prototype.display.apply(this, 
+                                                                 arguments);
+        }
+    },
+    
+    /**
+     * APIMethod: mergeNewParams
+     * Modify parameters for the layer and redraw.
+     * 
+     * Parameters:
+     * newParams - {Object}
+     */
+    mergeNewParams:function(newParams) {
+        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
+        var newArguments = [upperParams];
+        return OpenLayers.Layer.HTTPRequest.prototype.mergeNewParams.apply(this, 
+                                                                 newArguments);
+    },
+
+    /**
+     * APIMethod: clone
+     *
+     * Parameters:
+     * obj - {Object} 
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.WFS>} An exact clone of this OpenLayers.Layer.WFS
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.WFS(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+
+        //get all additions from superclasses
+        if (this.vectorMode) {
+            obj = OpenLayers.Layer.Vector.prototype.clone.apply(this, [obj]);
+        } else {
+            obj = OpenLayers.Layer.Markers.prototype.clone.apply(this, [obj]);
+        }    
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },
+
+    /** 
+     * APIMethod: getFullRequestString
+     * combine the layer's url with its params and these newParams. 
+     *   
+     *    Add the SRS parameter from 'projection' -- this is probably
+     *     more eloquently done via a setProjection() method, but this 
+     *     works for now and always.
+     *
+     * Parameters:
+     * newParams - {Object} 
+     * altUrl - {String} Use this as the url instead of the layer's url
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        var projectionCode = this.projection.getCode() || this.map.getProjection();
+        this.params.SRS = (projectionCode == "none") ? null : projectionCode;
+
+        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+                                                    this, arguments);
+    },
+   
+    /**
+     * APIMethod: commit
+     * Write out the data to a WFS server.
+     */
+    commit: function() {
+        if (!this.writer) {
+            var options = {};
+            if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
+                options.externalProjection = this.projection;
+                options.internalProjection = this.map.getProjectionObject();
+            }    
+            
+            this.writer = new OpenLayers.Format.WFS(options,this);
+        }
+
+        var data = this.writer.write(this.features);
+
+        OpenLayers.Request.POST({
+            url: this.url,
+            data: data,
+            success: this.commitSuccess,
+            failure: this.commitFailure,
+            scope: this
+        });
+    },
+
+    /**
+     * Method: commitSuccess
+     * Called when the Ajax request returns a response
+     *
+     * Parameters:
+     * response - {XmlNode} from server
+     */
+    commitSuccess: function(request) {
+        var response = request.responseText;
+        if (response.indexOf('SUCCESS') != -1) {
+            this.commitReport(OpenLayers.i18n("commitSuccess", {'response':response}));
+            
+            for(var i = 0; i < this.features.length; i++) {
+                this.features[i].state = null;
+            }    
+            // TBD redraw the layer or reset the state of features
+            // foreach features: set state to null
+        } else if (response.indexOf('FAILED') != -1 ||
+            response.indexOf('Exception') != -1) {
+            this.commitReport(OpenLayers.i18n("commitFailed", {'response':response}));
+        }
+    },
+    
+    /**
+     * Method: commitFailure
+     * Called when the Ajax request fails
+     *
+     * Parameters:
+     * response - {XmlNode} from server
+     */
+    commitFailure: function(request) {},
+    
+    /**
+     * APIMethod: commitReport 
+     * Called with a 'success' message if the commit succeeded, otherwise
+     *     a failure message, and the full request text as a second parameter.
+     *     Override this function to provide custom transaction reporting.
+     *
+     * string - {String} reporting string
+     * response - {String} full XML response
+     */
+    commitReport: function(string, response) {
+        OpenLayers.Console.userError(string);
+    },
+
+    
+    /**
+     * APIMethod: refresh
+     * Refreshes all the features of the layer
+     */
+    refresh: function() {
+        if (this.tile) {
+            if (this.vectorMode) {
+                this.renderer.clear();
+                this.features.length = 0;
+            } else {   
+                this.clearMarkers();
+                this.markers.length = 0;
+            }    
+            this.tile.draw();
+        }
+    },
+    
+    /** 
+     * APIMethod: getDataExtent
+     * Calculates the max extent which includes all of the layer data.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        var extent; 
+        //get all additions from superclasses
+        if (this.vectorMode) {
+            extent = OpenLayers.Layer.Vector.prototype.getDataExtent.apply(this);
+        } else {
+            extent = OpenLayers.Layer.Markers.prototype.getDataExtent.apply(this);
+        }    
+
+        return extent;
+    },
+    
+    /** 
+     * APIMethod: setOpacity 
+     * Call the setOpacity method of the appropriate parent class to set the
+     *     opacity.  
+     * 
+     * Parameter: 
+     * opacity - {Float} 
+     */
+    setOpacity: function (opacity) {
+        if (this.vectorMode) {
+            OpenLayers.Layer.Vector.prototype.setOpacity.apply(this, [opacity]);
+        } else {
+            OpenLayers.Layer.Markers.prototype.setOpacity.apply(this, [opacity]);
+        }    
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.WFS"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS/Untiled.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS/Untiled.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS/Untiled.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,71 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+ 
+/**
+ * @requires OpenLayers/Layer/WMS.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WMS.Untiled
+ * *Deprecated*.  To be removed in 3.0.  Instead use OpenLayers.Layer.WMS and 
+ *     pass the option 'singleTile' as true.
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Layer.WMS>
+ */
+OpenLayers.Layer.WMS.Untiled = OpenLayers.Class(OpenLayers.Layer.WMS, {
+
+    /**
+     * APIProperty: singleTile
+     * {singleTile} Always true for untiled.
+     */
+    singleTile: true,
+
+    /**
+     * Constructor: OpenLayers.Layer.WMS.Untiled
+     *
+     * Parameters:
+     * name - {String} 
+     * url - {String} 
+     * params - {Object} 
+     * options - {Object} 
+     */
+    initialize: function(name, url, params, options) {
+        OpenLayers.Layer.WMS.prototype.initialize.apply(this, arguments);
+        
+        var msg = "The OpenLayers.Layer.WMS.Untiled class is deprecated and " +
+                  "will be removed in 3.0. Instead, you should use the " +
+                  "normal OpenLayers.Layer.WMS class, passing it the option " +
+                  "'singleTile' as true.";
+        OpenLayers.Console.warn(msg);
+    },    
+
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.WMS.Untiled>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.WMS.Untiled(this.name,
+                                                   this.url,
+                                                   this.params,
+                                                   this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.WMS.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    }, 
+
+    CLASS_NAME: "OpenLayers.Layer.WMS.Untiled"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WMS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,235 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WMS
+ * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
+ *     Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
+ *     constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    DEFAULT_PARAMS: { service: "WMS",
+                      version: "1.1.1",
+                      request: "GetMap",
+                      styles: "",
+                      exceptions: "application/vnd.ogc.se_inimage",
+                      format: "image/jpeg"
+                     },
+    
+    /**
+     * Property: reproject
+     * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
+     * for information on the replacement for this functionality. 
+     * {Boolean} Try to reproject this layer if its coordinate reference system
+     *           is different than that of the base layer.  Default is true.  
+     *           Set this in the layer options.  Should be set to false in 
+     *           most cases.
+     */
+    reproject: false,
+ 
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} Default is true for WMS layer
+     */
+    isBaseLayer: true,
+    
+    /**
+     * APIProperty: encodeBBOX
+     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', 
+     * but some services want it that way. Default false.
+     */
+    encodeBBOX: false,
+    
+    /** 
+     * APIProperty: noMagic 
+     * {Boolean} If true, the image format will not be automagicaly switched 
+     *     from image/jpeg to image/png or image/gif when using 
+     *     TRANSPARENT=TRUE. Also isBaseLayer will not changed by the  
+     *     constructor. Default false. 
+     */ 
+    noMagic: false,  
+    
+    /**
+     * Constructor: OpenLayers.Layer.WMS
+     * Create a new WMS layer object
+     *
+     * Example:
+     * (code)
+     * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
+     *                                    "http://wms.jpl.nasa.gov/wms.cgi", 
+     *                                    {layers: "modis,global_mosaic"});
+     * (end)
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the WMS
+     *                (e.g. http://wms.jpl.nasa.gov/wms.cgi)
+     * params - {Object} An object with key/value pairs representing the
+     *                   GetMap query string parameters and parameter values.
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = [];
+        //uppercase params
+        params = OpenLayers.Util.upperCaseObject(params);
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+        OpenLayers.Util.applyDefaults(
+                       this.params, 
+                       OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
+                       );
+
+
+        //layer is transparent        
+        if (!this.noMagic && this.params.TRANSPARENT && 
+            this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+            
+            // unless explicitly set in options, make layer an overlay
+            if ( (options == null) || (!options.isBaseLayer) ) {
+                this.isBaseLayer = false;
+            } 
+            
+            // jpegs can never be transparent, so intelligently switch the 
+            //  format, depending on teh browser's capabilities
+            if (this.params.FORMAT == "image/jpeg") {
+                this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
+                                                                 : "image/png";
+            }
+        }
+
+    },    
+
+    /**
+     * Method: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
+    },
+
+    
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.WMS(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },    
+    
+    /**
+     * Method: getURL
+     * Return a GetMap query string for this layer
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+     *                                request.
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the
+     *          passed-in bounds and appropriate tile size specified as 
+     *          parameters.
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        
+        var imageSize = this.getImageSize(); 
+        var newParams = {
+            'BBOX': this.encodeBBOX ?  bounds.toBBOX() : bounds.toArray(),
+            'WIDTH': imageSize.w,
+            'HEIGHT': imageSize.h
+        };
+        var requestString = this.getFullRequestString(newParams);
+        return requestString;
+    },
+
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+
+    /**
+     * APIMethod: mergeNewParams
+     * Catch changeParams and uppercase the new params to be merged in
+     *     before calling changeParams on the super class.
+     * 
+     *     Once params have been changed, the tiles will be reloaded with
+     *     the new parameters.
+     * 
+     * Parameters:
+     * newParams - {Object} Hashtable of new params to use
+     */
+    mergeNewParams:function(newParams) {
+        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
+        var newArguments = [upperParams];
+        return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
+                                                             newArguments);
+    },
+
+    /** 
+     * APIMethod: getFullRequestString
+     * Combine the layer's url with its params and these newParams. 
+     *   
+     *     Add the SRS parameter from projection -- this is probably
+     *     more eloquently done via a setProjection() method, but this 
+     *     works for now and always.
+     *
+     * Parameters:
+     * newParams - {Object}
+     * altUrl - {String} Use this as the url instead of the layer's url
+     * 
+     * Returns:
+     * {String} 
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        var projectionCode = this.map.getProjection();
+        this.params.SRS = (projectionCode == "none") ? null : projectionCode;
+
+        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+                                                    this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.WMS"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WorldWind.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WorldWind.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer/WorldWind.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,119 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WorldWind
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, {
+    
+    DEFAULT_PARAMS: {
+    },
+
+    /**
+     * APIProperty: isBaseLayer
+     * WorldWind layer is a base layer by default.
+     */
+    isBaseLayer: true,    
+
+    
+    /** 
+     * APIProperty: lzd
+     * LevelZeroTileSizeDegrees
+     */
+    lzd: null,
+
+    /**
+     * APIProperty: zoomLevels
+     * Number of zoom levels.
+     */
+    zoomLevels: null,
+    
+    /**
+     * Constructor: OpenLayers.Layer.WorldWind
+     * 
+     * Parameters:
+     * name - {String} Name of Layer
+     * url - {String} Base URL  
+     * lzd - {Float} Level zero tile size degrees 
+     * zoomLevels - {Int} number of zoom levels
+     * params - {Object} additional parameters
+     * options - {Object} additional options
+     */
+    initialize: function(name, url, lzd, zoomLevels, params, options) {
+        this.lzd = lzd;
+        this.zoomLevels = zoomLevels;
+        var newArguments = [];
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+        this.params = OpenLayers.Util.applyDefaults(
+            this.params, this.DEFAULT_PARAMS
+        );
+    },
+    /**
+     * Method: addTile
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                             null, this.tileSize);
+    },
+
+    /**
+     * Method: getZoom
+     * Convert map zoom to WW zoom.
+     */
+    getZoom: function () {
+        var zoom = this.map.getZoom();
+        var extent = this.map.getMaxExtent();
+        zoom = zoom - Math.log(this.maxResolution / (this.lzd/512))/Math.log(2);
+        return zoom;
+    },
+
+    /**
+     * Method: getURL
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the 
+     *           passed-in bounds and appropriate tile size specified as 
+     *           parameters
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        var zoom = this.getZoom();
+        var extent = this.map.getMaxExtent();
+        var deg = this.lzd/Math.pow(2,this.getZoom());
+        var x = Math.floor((bounds.left - extent.left)/deg);
+        var y = Math.floor((bounds.bottom - extent.bottom)/deg);
+        if (this.map.getResolution() <= (this.lzd/512)
+            && this.getZoom() <= this.zoomLevels) {
+            return this.getFullRequestString(
+              { L: zoom, 
+                X: x,
+                Y: y
+              });
+        } else {
+            return OpenLayers.Util.getImagesLocation() + "blank.gif";
+        }
+
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.WorldWind"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Layer.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,1170 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Map.js
+ * @requires OpenLayers/Projection.js
+ */
+
+/**
+ * Class: OpenLayers.Layer
+ */
+OpenLayers.Layer = OpenLayers.Class({
+
+    /**
+     * APIProperty: id
+     * {String}
+     */
+    id: null,
+
+    /** 
+     * APIProperty: name
+     * {String}
+     */
+    name: null,
+
+    /** 
+     * APIProperty: div
+     * {DOMElement}
+     */
+    div: null,
+
+    /**
+     * Property: opacity
+     * {Float} The layer's opacity. Float number between 0.0 and 1.0.
+     */
+    opacity: null,
+
+    /**
+     * APIProperty: alwaysInRange
+     * {Boolean} If a layer's display should not be scale-based, this should 
+     *     be set to true. This will cause the layer, as an overlay, to always 
+     *     be 'active', by always returning true from the calculateInRange() 
+     *     function. 
+     * 
+     *     If not explicitly specified for a layer, its value will be 
+     *     determined on startup in initResolutions() based on whether or not 
+     *     any scale-specific properties have been set as options on the 
+     *     layer. If no scale-specific options have been set on the layer, we 
+     *     assume that it should always be in range.
+     * 
+     *     See #987 for more info.
+     */
+    alwaysInRange: null,   
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * layer.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * All event objects have at least the following properties:
+     * object - {Object} A reference to layer.events.object.
+     * element - {DOMElement} A reference to layer.events.element.
+     *
+     * Supported map event types:
+     * loadstart - Triggered when layer loading starts.
+     * loadend - Triggered when layer loading ends.
+     * loadcancel - Triggered when layer loading is canceled.
+     * visibilitychanged - Triggered when layer visibility is changed.
+     * move - Triggered when layer moves (triggered with every mousemove
+     *     during a drag).
+     * moveend - Triggered when layer is done moving, object passed as
+     *     argument has a zoomChanged boolean property which tells that the
+     *     zoom has changed.
+     */
+    EVENT_TYPES: ["loadstart", "loadend", "loadcancel", "visibilitychanged",
+                  "move", "moveend"],
+        
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>}
+     */
+    events: null,
+
+    /**
+     * APIProperty: map
+     * {<OpenLayers.Map>} This variable is set when the layer is added to 
+     *     the map, via the accessor function setMap().
+     */
+    map: null,
+    
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} Whether or not the layer is a base layer. This should be set 
+     *     individually by all subclasses. Default is false
+     */
+    isBaseLayer: false,
+ 
+    /**
+     * Property: alpha
+     * {Boolean} The layer's images have an alpha channel.  Default is false. 
+     */
+    alpha: false,
+
+    /** 
+     * APIProperty: displayInLayerSwitcher
+     * {Boolean} Display the layer's name in the layer switcher.  Default is
+     *     true.
+     */
+    displayInLayerSwitcher: true,
+
+    /**
+     * APIProperty: visibility
+     * {Boolean} The layer should be displayed in the map.  Default is true.
+     */
+    visibility: true,
+
+    /**
+     * APIProperty: attribution
+     * {String} Attribution string, displayed when an 
+     *     <OpenLayers.Control.Attribution> has been added to the map.
+     */
+    attribution: null, 
+
+    /** 
+     * Property: inRange
+     * {Boolean} The current map resolution is within the layer's min/max 
+     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom 
+     *     changes.
+     */
+    inRange: false,
+    
+    /**
+     * Propery: imageSize
+     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than 
+     *     the tile by twice the gutter in each dimension.
+     */
+    imageSize: null,
+    
+    /**
+     * Property: imageOffset
+     * {<OpenLayers.Pixel>} For layers with a gutter, the image offset 
+     *     represents displacement due to the gutter.
+     */
+    imageOffset: null,
+
+  // OPTIONS
+
+    /** 
+     * Property: options
+     * {Object} An optional object whose properties will be set on the layer.
+     *     Any of the layer properties can be set as a property of the options
+     *     object and sent to the constructor when the layer is created.
+     */
+    options: null,
+
+    /**
+     * APIProperty: eventListeners
+     * {Object} If set as an option at construction, the eventListeners
+     *     object will be registered with <OpenLayers.Events.on>.  Object
+     *     structure must be a listeners object as shown in the example for
+     *     the events.on method.
+     */
+    eventListeners: null,
+
+    /**
+     * APIProperty: gutter
+     * {Integer} Determines the width (in pixels) of the gutter around image
+     *     tiles to ignore.  By setting this property to a non-zero value,
+     *     images will be requested that are wider and taller than the tile
+     *     size by a value of 2 x gutter.  This allows artifacts of rendering
+     *     at tile edges to be ignored.  Set a gutter value that is equal to
+     *     half the size of the widest symbol that needs to be displayed.
+     *     Defaults to zero.  Non-tiled layers always have zero gutter.
+     */ 
+    gutter: 0, 
+
+    /**
+     * APIProperty: projection
+     * {<OpenLayers.Projection>} or {<String>} Set in the layer options to
+     *     override the default projection string this layer - also set maxExtent,
+     *     maxResolution, and units if appropriate. Can be either a string or
+     *     an <OpenLayers.Projection> object when created -- will be converted
+     *     to an object when setMap is called if a string is passed.  
+     */
+    projection: null,    
+    
+    /**
+     * APIProperty: units
+     * {String} The layer map units.  Defaults to 'degrees'.  Possible values
+     *     are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+     */
+    units: null,
+
+    /**
+     * APIProperty: scales
+     * {Array}  An array of map scales in descending order.  The values in the
+     *     array correspond to the map scale denominator.  Note that these
+     *     values only make sense if the display (monitor) resolution of the
+     *     client is correctly guessed by whomever is configuring the
+     *     application.  In addition, the units property must also be set.
+     *     Use <resolutions> instead wherever possible.
+     */
+    scales: null,
+
+    /**
+     * APIProperty: resolutions
+     * {Array} A list of map resolutions (map units per pixel) in descending
+     *     order.  If this is not set in the layer constructor, it will be set
+     *     based on other resolution related properties (maxExtent,
+     *     maxResolution, maxScale, etc.).
+     */
+    resolutions: null,
+    
+    /**
+     * APIProperty: maxExtent
+     * {<OpenLayers.Bounds>}  The center of these bounds will not stray outside
+     *     of the viewport extent during panning.  In addition, if
+     *     <displayOutsideMaxExtent> is set to false, data will not be
+     *     requested that falls completely outside of these bounds.
+     */
+    maxExtent: null,
+    
+    /**
+     * APIProperty: minExtent
+     * {<OpenLayers.Bounds>}
+     */
+    minExtent: null,
+    
+    /**
+     * APIProperty: maxResolution
+     * {Float} Default max is 360 deg / 256 px, which corresponds to
+     *     zoom level 0 on gmaps.  Specify a different value in the layer 
+     *     options if you are not using a geographic projection and 
+     *     displaying the whole world.
+     */
+    maxResolution: null,
+
+    /**
+     * APIProperty: minResolution
+     * {Float}
+     */
+    minResolution: null,
+
+    /**
+     * APIProperty: numZoomLevels
+     * {Integer}
+     */
+    numZoomLevels: null,
+   
+    /**
+     * APIProperty: minScale
+     * {Float}
+     */
+    minScale: null,
+    
+    /**
+     * APIProperty: maxScale
+     * {Float}
+     */
+    maxScale: null,
+
+    /**
+     * APIProperty: displayOutsideMaxExtent
+     * {Boolean} Request map tiles that are completely outside of the max 
+     *     extent for this layer. Defaults to false.
+     */
+    displayOutsideMaxExtent: false,
+
+    /**
+     * APIProperty: wrapDateLine
+     * {Boolean} #487 for more info.   
+     */
+    wrapDateLine: false,
+    
+    /**
+     * APIProperty: transitionEffect
+     * {String} The transition effect to use when the map is panned or
+     *     zoomed.  
+     *
+     * There are currently two supported values:
+     *  - *null* No transition effect (the default).
+     *  - *resize*  Existing tiles are resized on zoom to provide a visual
+     *    effect of the zoom having taken place immediately.  As the
+     *    new tiles become available, they are drawn over top of the
+     *    resized tiles.
+     */
+    transitionEffect: null,
+    
+    /**
+     * Property: SUPPORTED_TRANSITIONS
+     * {Array} An immutable (that means don't change it!) list of supported 
+     *     transitionEffect values.
+     */
+    SUPPORTED_TRANSITIONS: ['resize'],
+    
+    /**
+     * Constructor: OpenLayers.Layer
+     *
+     * Parameters:
+     * name - {String} The layer name
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+
+        this.addOptions(options);
+
+        this.name = name;
+        
+        if (this.id == null) {
+
+            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+
+            this.div = OpenLayers.Util.createDiv(this.id);
+            this.div.style.width = "100%";
+            this.div.style.height = "100%";
+            this.div.dir = "ltr";
+
+            this.events = new OpenLayers.Events(this, this.div, 
+                                                this.EVENT_TYPES);
+            if(this.eventListeners instanceof Object) {
+                this.events.on(this.eventListeners);
+            }
+
+        }
+
+        if (this.wrapDateLine) {
+            this.displayOutsideMaxExtent = true;
+        }
+    },
+    
+    /**
+     * Method: destroy
+     * Destroy is a destructor: this is to alleviate cyclic references which
+     *     the Javascript garbage cleaner can not take care of on its own.
+     *
+     * Parameters:
+     * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
+     *     been destroyed.  Default is true.
+     */
+    destroy: function(setNewBaseLayer) {
+        if (setNewBaseLayer == null) {
+            setNewBaseLayer = true;
+        }
+        if (this.map != null) {
+            this.map.removeLayer(this, setNewBaseLayer);
+        }
+        this.projection = null;
+        this.map = null;
+        this.name = null;
+        this.div = null;
+        this.options = null;
+
+        if (this.events) {
+            if(this.eventListeners) {
+                this.events.un(this.eventListeners);
+            }
+            this.events.destroy();
+        }
+        this.eventListeners = null;
+        this.events = null;
+    },
+    
+   /**
+    * Method: clone
+    *
+    * Parameters:
+    * obj - {<OpenLayers.Layer>} The layer to be cloned
+    *
+    * Returns:
+    * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
+    */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer(this.name, this.options);
+        } 
+        
+        // catch any randomly tagged-on properties
+        OpenLayers.Util.applyDefaults(obj, this);
+        
+        // a cloned layer should never have its map property set
+        //  because it has not been added to a map yet. 
+        obj.map = null;
+        
+        return obj;
+    },
+    
+    /** 
+     * APIMethod: setName
+     * Sets the new layer name for this layer.  Can trigger a changelayer event
+     *     on the map.
+     *
+     * Parameters:
+     * newName - {String} The new name.
+     */
+    setName: function(newName) {
+        if (newName != this.name) {
+            this.name = newName;
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer", {
+                    layer: this,
+                    property: "name"
+                });
+            }
+        }
+    },    
+    
+   /**
+    * APIMethod: addOptions
+    * 
+    * Parameters:
+    * newOptions - {Object}
+    */
+    addOptions: function (newOptions) {
+        
+        if (this.options == null) {
+            this.options = {};
+        }
+        
+        // update our copy for clone
+        OpenLayers.Util.extend(this.options, newOptions);
+
+        // add new options to this
+        OpenLayers.Util.extend(this, newOptions);
+    },
+    
+    /**
+     * APIMethod: onMapResize
+     * This function can be implemented by subclasses
+     */
+    onMapResize: function() {
+        //this function can be implemented by subclasses  
+    },
+
+    /**
+     * APIMethod: redraw
+     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
+     *
+     * Returns:
+     * {Boolean} The layer was redrawn.
+     */
+    redraw: function() {
+        var redrawn = false;
+        if (this.map) {
+
+            // min/max Range may have changed
+            this.inRange = this.calculateInRange();
+
+            // map's center might not yet be set
+            var extent = this.getExtent();
+
+            if (extent && this.inRange && this.visibility) {
+                var zoomChanged = true;
+                this.moveTo(extent, zoomChanged, false);
+                this.events.triggerEvent("moveend",
+                    {"zoomChanged": zoomChanged});
+                redrawn = true;
+            }
+        }
+        return redrawn;
+    },
+
+    /**
+     * Method: moveTo
+     * 
+     * Parameters:
+     * bound - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
+     *     do some init work in that case.
+     * dragging - {Boolean}
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        var display = this.visibility;
+        if (!this.isBaseLayer) {
+            display = display && this.inRange;
+        }
+        this.display(display);
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the layer. This is done through an accessor
+     *     so that subclasses can override this and take special action once 
+     *     they have their map variable set. 
+     * 
+     *     Here we take care to bring over any of the necessary default 
+     *     properties from the map. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        if (this.map == null) {
+        
+            this.map = map;
+            
+            // grab some essential layer data from the map if it hasn't already
+            //  been set
+            this.maxExtent = this.maxExtent || this.map.maxExtent;
+            this.projection = this.projection || this.map.projection;
+            
+            if (this.projection && typeof this.projection == "string") {
+                this.projection = new OpenLayers.Projection(this.projection);
+            }
+            
+            // Check the projection to see if we can get units -- if not, refer
+            // to properties.
+            this.units = this.projection.getUnits() ||
+                         this.units || this.map.units;
+            
+            this.initResolutions();
+            
+            if (!this.isBaseLayer) {
+                this.inRange = this.calculateInRange();
+                var show = ((this.visibility) && (this.inRange));
+                this.div.style.display = show ? "" : "none";
+            }
+            
+            // deal with gutters
+            this.setTileSize();
+        }
+    },
+    
+    /**
+     * Method: afterAdd
+     * Called at the end of the map.addLayer sequence.  At this point, the map
+     *     will have a base layer.  To be overridden by subclasses.
+     */
+    afterAdd: function() {
+    },
+    
+    /**
+     * APIMethod: removeMap
+     * Just as setMap() allows each layer the possibility to take a 
+     *     personalized action on being added to the map, removeMap() allows
+     *     each layer to take a personalized action on being removed from it. 
+     *     For now, this will be mostly unused, except for the EventPane layer,
+     *     which needs this hook so that it can remove the special invisible
+     *     pane. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    removeMap: function(map) {
+        //to be overridden by subclasses
+    },
+    
+    /**
+     * APIMethod: getImageSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} The size that the image should be, taking into 
+     *     account gutters.
+     */ 
+    getImageSize: function() { 
+        return (this.imageSize || this.tileSize); 
+    },    
+  
+    /**
+     * APIMethod: setTileSize
+     * Set the tile size based on the map size.  This also sets layer.imageSize
+     *     and layer.imageOffset for use by Tile.Image.
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setTileSize: function(size) {
+        var tileSize = (size) ? size :
+                                ((this.tileSize) ? this.tileSize :
+                                                   this.map.getTileSize());
+        this.tileSize = tileSize;
+        if(this.gutter) {
+          // layers with gutters need non-null tile sizes
+          //if(tileSize == null) {
+          //    OpenLayers.console.error("Error in layer.setMap() for " +
+          //                              this.name + ": layers with " +
+          //                              "gutters need non-null tile sizes");
+          //}
+            this.imageOffset = new OpenLayers.Pixel(-this.gutter, 
+                                                    -this.gutter); 
+            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), 
+                                                 tileSize.h + (2*this.gutter)); 
+        }
+    },
+
+    /**
+     * APIMethod: getVisibility
+     * 
+     * Returns:
+     * {Boolean} The layer should be displayed (if in range).
+     */
+    getVisibility: function() {
+        return this.visibility;
+    },
+
+    /** 
+     * APIMethod: setVisibility
+     * Set the visibility flag for the layer and hide/show & redraw 
+     *     accordingly. Fire event unless otherwise specified
+     * 
+     * Note that visibility is no longer simply whether or not the layer's
+     *     style.display is set to "block". Now we store a 'visibility' state 
+     *     property on the layer class, this allows us to remember whether or 
+     *     not we *desire* for a layer to be visible. In the case where the 
+     *     map's resolution is out of the layer's range, this desire may be 
+     *     subverted.
+     * 
+     * Parameters:
+     * visible - {Boolean} Whether or not to display the layer (if in range)
+     */
+    setVisibility: function(visibility) {
+        if (visibility != this.visibility) {
+            this.visibility = visibility;
+            this.display(visibility);
+            this.redraw();
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer", {
+                    layer: this,
+                    property: "visibility"
+                });
+            }
+            this.events.triggerEvent("visibilitychanged");
+        }
+    },
+
+    /** 
+     * APIMethod: display
+     * Hide or show the Layer
+     * 
+     * Parameters:
+     * display - {Boolean}
+     */
+    display: function(display) {
+        var inRange = this.calculateInRange();
+        if (display != (this.div.style.display != "none")) {
+            this.div.style.display = (display && inRange) ? "block" : "none";
+        }
+    },
+
+    /**
+     * APIMethod: calculateInRange
+     * 
+     * Returns:
+     * {Boolean} The layer is displayable at the current map's current
+     *     resolution. Note that if 'alwaysInRange' is true for the layer, 
+     *     this function will always return true.
+     */
+    calculateInRange: function() {
+        var inRange = false;
+
+        if (this.alwaysInRange) {
+            inRange = true;
+        } else {
+            if (this.map) {
+                var resolution = this.map.getResolution();
+                inRange = ( (resolution >= this.minResolution) &&
+                            (resolution <= this.maxResolution) );
+            }
+        }
+        return inRange;
+    },
+
+    /** 
+     * APIMethod: setIsBaseLayer
+     * 
+     * Parameters:
+     * isBaseLayer - {Boolean}
+     */
+    setIsBaseLayer: function(isBaseLayer) {
+        if (isBaseLayer != this.isBaseLayer) {
+            this.isBaseLayer = isBaseLayer;
+            if (this.map != null) {
+                this.map.events.triggerEvent("changebaselayer", {
+                    layer: this
+                });
+            }
+        }
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Baselayer Functions                  */
+  /*                                                      */
+  /********************************************************/
+  
+    /** 
+     * Method: initResolutions
+     * This method's responsibility is to set up the 'resolutions' array 
+     *     for the layer -- this array is what the layer will use to interface
+     *     between the zoom levels of the map and the resolution display 
+     *     of the layer.
+     * 
+     * The user has several options that determine how the array is set up.
+     *  
+     * For a detailed explanation, see the following wiki from the 
+     *     openlayers.org homepage:
+     *     http://trac.openlayers.org/wiki/SettingZoomLevels
+     */
+    initResolutions: function() {
+
+        // These are the relevant options which are used for calculating 
+        //  resolutions information.
+        //
+        var props = new Array(
+          'projection', 'units',
+          'scales', 'resolutions',
+          'maxScale', 'minScale', 
+          'maxResolution', 'minResolution', 
+          'minExtent', 'maxExtent',
+          'numZoomLevels', 'maxZoomLevel'
+        );
+
+        //these are the properties which do *not* imply that user wishes 
+        // this layer to be scale-dependant
+        var notScaleProps = ['projection', 'units'];    
+
+        //should the layer be scale-dependant? default is false -- this will 
+        // only be set true if we find that the user has specified a property
+        // from the 'props' array that is not in 'notScaleProps'
+        var useInRange = false;
+
+        // First we create a new object where we will store all of the 
+        //  resolution-related properties that we find in either the layer's
+        //  'options' array or from the map.
+        //
+        var confProps = {};        
+        for(var i=0, len=props.length; i<len; i++) {
+            var property = props[i];
+            
+            // If the layer had one of these properties set *and* it is 
+            // a scale property (is not a non-scale property), then we assume
+            // the user did intend to use scale-dependant display (useInRange).
+            if (this.options[property] && 
+                OpenLayers.Util.indexOf(notScaleProps, property) == -1) {
+                useInRange = true;
+            }
+                   
+            confProps[property] = this.options[property] || this.map[property];
+        }
+
+        //only automatically set 'alwaysInRange' if the user hasn't already 
+        // set it (to true or false, since the default is null). If user did
+        // not intend to use scale-dependant display then we set they layer
+        // as alwaysInRange. This means calculateInRange() will always return 
+        // true and the layer will never be turned off due to scale changes.
+        //
+        if (this.alwaysInRange == null) {
+            this.alwaysInRange = !useInRange;
+        }
+
+        // Do not use the scales array set at the map level if 
+        // either minScale or maxScale or both are set at the
+        // layer level
+        if ((this.options.minScale != null ||
+             this.options.maxScale != null) &&
+            this.options.scales == null) {
+
+            confProps.scales = null;
+        }
+        // Do not use the resolutions array set at the map level if 
+        // either minResolution or maxResolution or both are set at the
+        // layer level
+        if ((this.options.minResolution != null ||
+             this.options.maxResolution != null) &&
+            this.options.resolutions == null) {
+
+            confProps.resolutions = null;
+        }
+
+        // If numZoomLevels hasn't been set and the maxZoomLevel *has*, 
+        //  then use maxZoomLevel to calculate numZoomLevels
+        //
+        if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
+            confProps.numZoomLevels = confProps.maxZoomLevel + 1;
+        }
+
+        // First off, we take whatever hodge-podge of values we have and 
+        //  calculate/distill them down into a resolutions[] array
+        //
+        if ((confProps.scales != null) || (confProps.resolutions != null)) {
+          //preset levels
+            if (confProps.scales != null) {
+                confProps.resolutions = [];
+                for(var i=0, len=confProps.scales.length; i<len; i++) {
+                    var scale = confProps.scales[i];
+                    confProps.resolutions[i] = 
+                       OpenLayers.Util.getResolutionFromScale(scale, 
+                                                              confProps.units);
+                }
+            }
+            confProps.numZoomLevels = confProps.resolutions.length;
+
+        } else {
+          //maxResolution and numZoomLevels based calculation
+
+            // determine maxResolution
+            if (confProps.minScale) {
+                confProps.maxResolution = 
+                    OpenLayers.Util.getResolutionFromScale(confProps.minScale, 
+                                                           confProps.units);
+            } else if (confProps.maxResolution == "auto") {
+                var viewSize = this.map.getSize();
+                var wRes = confProps.maxExtent.getWidth() / viewSize.w;
+                var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
+                confProps.maxResolution = Math.max(wRes, hRes);
+            } 
+
+            // determine minResolution
+            if (confProps.maxScale != null) {           
+                confProps.minResolution = 
+                    OpenLayers.Util.getResolutionFromScale(confProps.maxScale, 
+                                                           confProps.units);
+            } else if ( (confProps.minResolution == "auto") && 
+                        (confProps.minExtent != null) ) {
+                var viewSize = this.map.getSize();
+                var wRes = confProps.minExtent.getWidth() / viewSize.w;
+                var hRes = confProps.minExtent.getHeight()/ viewSize.h;
+                confProps.minResolution = Math.max(wRes, hRes);
+            } 
+
+            // determine numZoomLevels if not already set on the layer
+            // this gives numZoomLevels assuming approximately base 2 scaling
+            if (confProps.minResolution != null &&
+                this.options.numZoomLevels == undefined) {
+                var ratio = confProps.maxResolution / confProps.minResolution;
+                confProps.numZoomLevels = 
+                    Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+            }
+            
+            // now we have numZoomLevels and maxResolution, 
+            //  we can populate the resolutions array
+            confProps.resolutions = new Array(confProps.numZoomLevels);
+            var base = 2;
+            if(typeof confProps.minResolution == "number" &&
+               confProps.numZoomLevels > 1) {
+                /**
+                 * If maxResolution and minResolution are set (or related
+                 * scale properties), we calculate the base for exponential
+                 * scaling that starts at maxResolution and ends at
+                 * minResolution in numZoomLevels steps.
+                 */
+                base = Math.pow(
+                    (confProps.maxResolution / confProps.minResolution),
+                    (1 / (confProps.numZoomLevels - 1))
+                );
+            }
+            for (var i=0; i < confProps.numZoomLevels; i++) {
+                var res = confProps.maxResolution / Math.pow(base, i);
+                confProps.resolutions[i] = res;
+            }
+        }
+        
+        //sort resolutions array ascendingly
+        //
+        confProps.resolutions.sort( function(a, b) { return(b-a); } );
+
+        // now set our newly calculated values back to the layer 
+        //  Note: We specifically do *not* set them to layer.options, which we 
+        //        will preserve as it was when we added this layer to the map. 
+        //        this way cloned layers reset themselves to new map div 
+        //        dimensions)
+        //
+
+        this.resolutions = confProps.resolutions;
+        this.maxResolution = confProps.resolutions[0];
+        var lastIndex = confProps.resolutions.length - 1;
+        this.minResolution = confProps.resolutions[lastIndex];
+        
+        this.scales = [];
+        for(var i=0, len=confProps.resolutions.length; i<len; i++) {
+            this.scales[i] = 
+               OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i], 
+                                                      confProps.units);
+        }
+        this.minScale = this.scales[0];
+        this.maxScale = this.scales[this.scales.length - 1];
+        
+        this.numZoomLevels = confProps.numZoomLevels;
+    },
+
+    /**
+     * APIMethod: getResolution
+     * 
+     * Returns:
+     * {Float} The currently selected resolution of the map, taken from the
+     *     resolutions array, indexed by current zoom level.
+     */
+    getResolution: function() {
+        var zoom = this.map.getZoom();
+        return this.getResolutionForZoom(zoom);
+    },
+
+    /** 
+     * APIMethod: getExtent
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *     bounds of the current viewPort.
+     */
+    getExtent: function() {
+        // just use stock map calculateBounds function -- passing no arguments
+        //  means it will user map's current center & resolution
+        //
+        return this.map.calculateBounds();
+    },
+
+    /**
+     * APIMethod: getZoomForExtent
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
+     *     not exactly contain the entire extent.
+     *     Default is false.
+     *
+     * Returns:
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     for the passed-in extent. We do this by calculating the ideal 
+     *     resolution for the given extent (based on the map size) and then 
+     *     calling getZoomForResolution(), passing along the 'closest'
+     *     parameter.
+     */
+    getZoomForExtent: function(extent, closest) {
+        var viewSize = this.map.getSize();
+        var idealResolution = Math.max( extent.getWidth()  / viewSize.w,
+                                        extent.getHeight() / viewSize.h );
+
+        return this.getZoomForResolution(idealResolution, closest);
+    },
+    
+    /** 
+     * Method: getDataExtent
+     * Calculates the max extent which includes all of the data for the layer.
+     *     This function is to be implemented by subclasses.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        //to be implemented by subclasses
+    },
+
+    /**
+     * APIMethod: getResolutionForZoom
+     * 
+     * Parameter:
+     * zoom - {Float}
+     * 
+     * Returns:
+     * {Float} A suitable resolution for the specified zoom.
+     */
+    getResolutionForZoom: function(zoom) {
+        zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
+        var resolution;
+        if(this.map.fractionalZoom) {
+            var low = Math.floor(zoom);
+            var high = Math.ceil(zoom);
+            resolution = this.resolutions[low] -
+                ((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
+        } else {
+            resolution = this.resolutions[Math.round(zoom)];
+        }
+        return resolution;
+    },
+
+    /**
+     * APIMethod: getZoomForResolution
+     * 
+     * Parameters:
+     * resolution - {Float}
+     * closest - {Boolean} Find the zoom level that corresponds to the absolute 
+     *     closest resolution, which may result in a zoom whose corresponding
+     *     resolution is actually smaller than we would have desired (if this
+     *     is being called from a getZoomForExtent() call, then this means that
+     *     the returned zoom index might not actually contain the entire 
+     *     extent specified... but it'll be close).
+     *     Default is false.
+     * 
+     * Returns:
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     that corresponds to the best fit resolution given the passed in 
+     *     value and the 'closest' specification.
+     */
+    getZoomForResolution: function(resolution, closest) {
+        var zoom;
+        if(this.map.fractionalZoom) {
+            var lowZoom = 0;
+            var highZoom = this.resolutions.length - 1;
+            var highRes = this.resolutions[lowZoom];
+            var lowRes = this.resolutions[highZoom];
+            var res;
+            for(var i=0, len=this.resolutions.length; i<len; ++i) {
+                res = this.resolutions[i];
+                if(res >= resolution) {
+                    highRes = res;
+                    lowZoom = i;
+                }
+                if(res <= resolution) {
+                    lowRes = res;
+                    highZoom = i;
+                    break;
+                }
+            }
+            var dRes = highRes - lowRes;
+            if(dRes > 0) {
+                zoom = lowZoom + ((highRes - resolution) / dRes);
+            } else {
+                zoom = lowZoom;
+            }
+        } else {
+            var diff;
+            var minDiff = Number.POSITIVE_INFINITY;
+            for(var i=0, len=this.resolutions.length; i<len; i++) {            
+                if (closest) {
+                    diff = Math.abs(this.resolutions[i] - resolution);
+                    if (diff > minDiff) {
+                        break;
+                    }
+                    minDiff = diff;
+                } else {
+                    if (this.resolutions[i] < resolution) {
+                        break;
+                    }
+                }
+            }
+            zoom = Math.max(0, i-1);
+        }
+        return zoom;
+    },
+    
+    /**
+     * APIMethod: getLonLatFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in 
+     *     view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
+     */
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        var lonlat = null;
+        if (viewPortPx != null) {
+            var size = this.map.getSize();
+            var center = this.map.getCenter();
+            if (center) {
+                var res  = this.map.getResolution();
+        
+                var delta_x = viewPortPx.x - (size.w / 2);
+                var delta_y = viewPortPx.y - (size.h / 2);
+            
+                lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
+                                             center.lat - delta_y * res); 
+
+                if (this.wrapDateLine) {
+                    lonlat = lonlat.wrapDateLine(this.maxExtent);
+                }
+            } // else { DEBUG STATEMENT }
+        }
+        return lonlat;
+    },
+
+    /**
+     * APIMethod: getViewPortPxFromLonLat
+     * Returns a pixel location given a map location.  This method will return
+     *     fractional pixel values.
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     *
+     * Returns: 
+     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in 
+     *     <OpenLayers.LonLat>,translated into view port pixels.
+     */
+    getViewPortPxFromLonLat: function (lonlat) {
+        var px = null; 
+        if (lonlat != null) {
+            var resolution = this.map.getResolution();
+            var extent = this.map.getExtent();
+            px = new OpenLayers.Pixel(
+                (1/resolution * (lonlat.lon - extent.left)),
+                (1/resolution * (extent.top - lonlat.lat))
+            );    
+        }
+        return px;
+    },
+    
+    /**
+     * APIMethod: setOpacity
+     * Sets the opacity for the entire layer (all images)
+     * 
+     * Parameter:
+     * opacity - {Float}
+     */
+    setOpacity: function(opacity) {
+        if (opacity != this.opacity) {
+            this.opacity = opacity;
+            for(var i=0, len=this.div.childNodes.length; i<len; ++i) {
+                var element = this.div.childNodes[i].firstChild;
+                OpenLayers.Util.modifyDOMElement(element, null, null, null, 
+                                                 null, null, null, opacity);
+            }
+        }
+    },
+
+    /**
+     * Method: getZIndex
+     * 
+     * Returns: 
+     * {Integer} the z-index of this layer
+     */    
+    getZIndex: function () {
+        return this.div.style.zIndex;
+    },
+
+    /**
+     * Method: setZIndex
+     * 
+     * Parameters: 
+     * zIndex - {Integer}
+     */    
+    setZIndex: function (zIndex) {
+        this.div.style.zIndex = zIndex;
+    },
+
+    /**
+     * Method: adjustBounds
+     * This function will take a bounds, and if wrapDateLine option is set
+     *     on the layer, it will return a bounds which is wrapped around the 
+     *     world. We do not wrap for bounds which *cross* the 
+     *     maxExtent.left/right, only bounds which are entirely to the left 
+     *     or entirely to the right.
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    adjustBounds: function (bounds) {
+
+        if (this.gutter) {
+            // Adjust the extent of a bounds in map units by the 
+            // layer's gutter in pixels.
+            var mapGutter = this.gutter * this.map.getResolution();
+            bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
+                                           bounds.bottom - mapGutter,
+                                           bounds.right + mapGutter,
+                                           bounds.top + mapGutter);
+        }
+
+        if (this.wrapDateLine) {
+            // wrap around the date line, within the limits of rounding error
+            var wrappingOptions = { 
+                'rightTolerance':this.getResolution()
+            };    
+            bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
+                              
+        }
+        return bounds;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Map.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Map.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Map.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,2338 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Tween.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Map
+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.
+ * Create a new map with the <OpenLayers.Map> constructor.
+ * 
+ * On their own maps do not provide much functionality.  To extend a map
+ * it's necessary to add controls (<OpenLayers.Control>) and 
+ * layers (<OpenLayers.Layer>) to the map. 
+ */
+OpenLayers.Map = OpenLayers.Class({
+    
+    /**
+     * Constant: Z_INDEX_BASE
+     * {Object} Base z-indexes for different classes of thing 
+     */
+    Z_INDEX_BASE: {
+        BaseLayer: 100,
+        Overlay: 325,
+        Feature: 725,
+        Popup: 750,
+        Control: 1000
+    },
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types.  Register a listener
+     *     for a particular event with the following syntax:
+     * (code)
+     * map.events.register(type, obj, listener);
+     * (end)
+     *
+     * Listeners will be called with a reference to an event object.  The
+     *     properties of this event depends on exactly what happened.
+     *
+     * All event objects have at least the following properties:
+     *  - *object* {Object} A reference to map.events.object.
+     *  - *element* {DOMElement} A reference to map.events.element.
+     *
+     * Browser events have the following additional properties:
+     *  - *xy* {<OpenLayers.Pixel>} The pixel location of the event (relative
+     *      to the the map viewport).
+     *  - other properties that come with browser events
+     *
+     * Supported map event types:
+     *  - *preaddlayer* triggered before a layer has been added.  The event
+     *      object will include a *layer* property that references the layer  
+     *      to be added.
+     *  - *addlayer* triggered after a layer has been added.  The event object
+     *      will include a *layer* property that references the added layer.
+     *  - *removelayer* triggered after a layer has been removed.  The event
+     *      object will include a *layer* property that references the removed
+     *      layer.
+     *  - *changelayer* triggered after a layer name change, order change, or
+     *      visibility change (due to resolution thresholds).  Listeners will
+     *      receive an event object with *layer* and *property* properties.  The
+     *      *layer* property will be a reference to the changed layer.  The
+     *      *property* property will be a key to the changed property (name,
+     *      visibility, or order).
+     *  - *movestart* triggered after the start of a drag, pan, or zoom
+     *  - *move* triggered after each drag, pan, or zoom
+     *  - *moveend* triggered after a drag, pan, or zoom completes
+     *  - *zoomend* triggered after a zoom completes
+     *  - *addmarker* triggered after a marker has been added
+     *  - *removemarker* triggered after a marker has been removed
+     *  - *clearmarkers* triggered after markers have been cleared
+     *  - *mouseover* triggered after mouseover the map
+     *  - *mouseout* triggered after mouseout the map
+     *  - *mousemove* triggered after mousemove the map
+     *  - *dragstart* Does not work.  Register for movestart instead.
+     *  - *drag* Does not work.  Register for move instead.
+     *  - *dragend* Does not work.  Register for moveend instead.
+     *  - *changebaselayer* triggered after the base layer changes
+     */
+    EVENT_TYPES: [ 
+        "preaddlayer", "addlayer", "removelayer", "changelayer", "movestart",
+        "move", "moveend", "zoomend", "popupopen", "popupclose",
+        "addmarker", "removemarker", "clearmarkers", "mouseover",
+        "mouseout", "mousemove", "dragstart", "drag", "dragend",
+        "changebaselayer"],
+
+    /**
+     * Property: id
+     * {String} Unique identifier for the map
+     */
+    id: null,
+    
+    /**
+     * Property: fractionalZoom
+     * {Boolean} For a base layer that supports it, allow the map resolution
+     *     to be set to a value between one of the values in the resolutions
+     *     array.  Default is false.
+     *
+     * When fractionalZoom is set to true, it is possible to zoom to
+     *     an arbitrary extent.  This requires a base layer from a source
+     *     that supports requests for arbitrary extents (i.e. not cached
+     *     tiles on a regular lattice).  This means that fractionalZoom
+     *     will not work with commercial layers (Google, Yahoo, VE), layers
+     *     using TileCache, or any other pre-cached data sources.
+     *
+     * If you are using fractionalZoom, then you should also use
+     *     <getResolutionForZoom> instead of layer.resolutions[zoom] as the
+     *     former works for non-integer zoom levels.
+     */
+    fractionalZoom: false,
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *                       events on the map
+     */
+    events: null,
+    
+    /**
+     * APIProperty: allOverlays
+     * {Boolean} Allow the map to function with "overlays" only.  Defaults to
+     *     false.  If true, the lowest layer in the draw order will act as
+     *     the base layer.  In addition, if set to true, all layers will
+     *     have isBaseLayer set to false when they are added to the map.
+     *
+     * Note:
+     * If you set map.allOverlays to true, then you *cannot* use
+     *     map.setBaseLayer or layer.setIsBaseLayer.  With allOverlays true,
+     *     the lowest layer in the draw layer is the base layer.  So, to change
+     *     the base layer, use <setLayerIndex> or <raiseLayer> to set the layer
+     *     index to 0.
+     */
+    allOverlays: false,
+
+    /**
+     * APIProperty: div
+     * {DOMElement|String} The element that contains the map (or an id for
+     *     that element).  If the <OpenLayers.Map> constructor is called
+     *     with two arguments, this should be provided as the first argument.
+     *     Alternatively, the map constructor can be called with the options
+     *     object as the only argument.  In this case (one argument), a
+     *     div property may or may not be provided.  If the div property
+     *     is not provided, the map can be rendered to a container later
+     *     using the <render> method.
+     *     
+     * Note: If you calling <render> after map construction, do not use
+     *     <maxResolution>  auto.  Instead, divide your <maxExtent> by your
+     *     maximum expected dimension.
+     */
+    div: null,
+    
+    /**
+     * Property: dragging
+     * {Boolean} The map is currently being dragged.
+     */
+    dragging: false,
+
+    /**
+     * Property: size
+     * {<OpenLayers.Size>} Size of the main div (this.div)
+     */
+    size: null,
+    
+    /**
+     * Property: viewPortDiv
+     * {HTMLDivElement} The element that represents the map viewport
+     */
+    viewPortDiv: null,
+
+    /**
+     * Property: layerContainerOrigin
+     * {<OpenLayers.LonLat>} The lonlat at which the later container was
+     *                       re-initialized (on-zoom)
+     */
+    layerContainerOrigin: null,
+
+    /**
+     * Property: layerContainerDiv
+     * {HTMLDivElement} The element that contains the layers.
+     */
+    layerContainerDiv: null,
+
+    /**
+     * APIProperty: layers
+     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
+     */
+    layers: null,
+
+    /**
+     * Property: controls
+     * {Array(<OpenLayers.Control>)} List of controls associated with the map.
+     *
+     * If not provided in the map options at construction, the map will
+     *     be given the following controls by default:
+     *  - <OpenLayers.Control.Navigation>
+     *  - <OpenLayers.Control.PanZoom>
+     *  - <OpenLayers.Control.ArgParser>
+     *  - <OpenLayers.Control.Attribution>
+     */
+    controls: null,
+
+    /**
+     * Property: popups
+     * {Array(<OpenLayers.Popup>)} List of popups associated with the map
+     */
+    popups: null,
+
+    /**
+     * APIProperty: baseLayer
+     * {<OpenLayers.Layer>} The currently selected base layer.  This determines
+     * min/max zoom level, projection, etc.
+     */
+    baseLayer: null,
+    
+    /**
+     * Property: center
+     * {<OpenLayers.LonLat>} The current center of the map
+     */
+    center: null,
+
+    /**
+     * Property: resolution
+     * {Float} The resolution of the map.
+     */
+    resolution: null,
+
+    /**
+     * Property: zoom
+     * {Integer} The current zoom level of the map
+     */
+    zoom: 0,    
+
+    /**
+     * Property: panRatio
+     * {Float} The ratio of the current extent within
+     *         which panning will tween.
+     */
+    panRatio: 1.5,    
+
+    /**
+     * Property: viewRequestID
+     * {String} Used to store a unique identifier that changes when the map 
+     *          view changes. viewRequestID should be used when adding data 
+     *          asynchronously to the map: viewRequestID is incremented when 
+     *          you initiate your request (right now during changing of 
+     *          baselayers and changing of zooms). It is stored here in the 
+     *          map and also in the data that will be coming back 
+     *          asynchronously. Before displaying this data on request 
+     *          completion, we check that the viewRequestID of the data is 
+     *          still the same as that of the map. Fix for #480
+     */
+    viewRequestID: 0,
+
+  // Options
+
+    /**
+     * APIProperty: tileSize
+     * {<OpenLayers.Size>} Set in the map options to override the default tile
+     *                     size for this map.
+     */
+    tileSize: null,
+
+    /**
+     * APIProperty: projection
+     * {String} Set in the map options to override the default projection 
+     *          string this map - also set maxExtent, maxResolution, and 
+     *          units if appropriate.  Default is "EPSG:4326".
+     */
+    projection: "EPSG:4326",    
+        
+    /**
+     * APIProperty: units
+     * {String} The map units.  Defaults to 'degrees'.  Possible values are
+     *          'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+     */
+    units: 'degrees',
+
+    /**
+     * APIProperty: resolutions
+     * {Array(Float)} A list of map resolutions (map units per pixel) in 
+     *     descending order.  If this is not set in the layer constructor, it 
+     *     will be set based on other resolution related properties 
+     *     (maxExtent, maxResolution, maxScale, etc.).
+     */
+    resolutions: null,
+
+    /**
+     * APIProperty: maxResolution
+     * {Float} Default max is 360 deg / 256 px, which corresponds to
+     *          zoom level 0 on gmaps.  Specify a different value in the map 
+     *          options if you are not using a geographic projection and 
+     *          displaying the whole world.
+     */
+    maxResolution: 1.40625,
+
+    /**
+     * APIProperty: minResolution
+     * {Float}
+     */
+    minResolution: null,
+
+    /**
+     * APIProperty: maxScale
+     * {Float}
+     */
+    maxScale: null,
+
+    /**
+     * APIProperty: minScale
+     * {Float}
+     */
+    minScale: null,
+
+    /**
+     * APIProperty: maxExtent
+     * {<OpenLayers.Bounds>} The maximum extent for the map.  Defaults to the
+     *                       whole world in decimal degrees 
+     *                       (-180, -90, 180, 90).  Specify a different
+     *                        extent in the map options if you are not using a 
+     *                        geographic projection and displaying the whole 
+     *                        world.
+     */
+    maxExtent: null,
+    
+    /**
+     * APIProperty: minExtent
+     * {<OpenLayers.Bounds>}
+     */
+    minExtent: null,
+    
+    /**
+     * APIProperty: restrictedExtent
+     * {<OpenLayers.Bounds>} Limit map navigation to this extent where possible.
+     *     If a non-null restrictedExtent is set, panning will be restricted
+     *     to the given bounds.  In addition, zooming to a resolution that
+     *     displays more than the restricted extent will center the map
+     *     on the restricted extent.  If you wish to limit the zoom level
+     *     or resolution, use maxResolution.
+     */
+    restrictedExtent: null,
+
+    /**
+     * APIProperty: numZoomLevels
+     * {Integer} Number of zoom levels for the map.  Defaults to 16.  Set a
+     *           different value in the map options if needed.
+     */
+    numZoomLevels: 16,
+
+    /**
+     * APIProperty: theme
+     * {String} Relative path to a CSS file from which to load theme styles.
+     *          Specify null in the map options (e.g. {theme: null}) if you 
+     *          want to get cascading style declarations - by putting links to 
+     *          stylesheets or style declarations directly in your page.
+     */
+    theme: null,
+    
+    /** 
+     * APIProperty: displayProjection
+     * {<OpenLayers.Projection>} Requires proj4js support.Projection used by
+     *     several controls to display data to user. If this property is set,
+     *     it will be set on any control which has a null displayProjection
+     *     property at the time the control is added to the map. 
+     */
+    displayProjection: null,
+
+    /**
+     * APIProperty: fallThrough
+     * {Boolean} Should OpenLayers allow events on the map to fall through to
+     *           other elements on the page, or should it swallow them? (#457)
+     *           Default is to fall through.
+     */
+    fallThrough: true,
+    
+    /**
+     * Property: panTween
+     * {OpenLayers.Tween} Animated panning tween object, see panTo()
+     */
+    panTween: null,
+
+    /**
+     * APIProperty: eventListeners
+     * {Object} If set as an option at construction, the eventListeners
+     *     object will be registered with <OpenLayers.Events.on>.  Object
+     *     structure must be a listeners object as shown in the example for
+     *     the events.on method.
+     */
+    eventListeners: null,
+
+    /**
+     * APIProperty: panMethod
+     * {Function} The Easing function to be used for tweening.  Default is
+     * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off
+     * animated panning.
+     */
+    panMethod: OpenLayers.Easing.Expo.easeOut,
+    
+    /**
+     * Property: panDuration
+     * {Integer} The number of steps to be passed to the
+     * OpenLayers.Tween.start() method when the map is
+     * panned.
+     * Default is 50.
+     */
+    panDuration: 50,
+    
+    /**
+     * Property: paddingForPopups
+     * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent 
+     *     the popup from getting too close to the map border.
+     */
+    paddingForPopups : null,
+    
+    /**
+     * Constructor: OpenLayers.Map
+     * Constructor for a new OpenLayers.Map instance.  There are two possible
+     *     ways to call the map constructor.  See the examples below.
+     *
+     * Parameters:
+     * div - {String} Id of an element in your page that will contain the map.
+     *     May be omitted if the <div> option is provided or if you intend
+     *     to use <render> later.
+     * options - {Object} Optional object with properties to tag onto the map.
+     *
+     * Examples (method one):
+     * (code)
+     * // create a map with default options in an element with the id "map1"
+     * var map = new OpenLayers.Map("map1");
+     *
+     * // create a map with non-default options in an element with id "map2"
+     * var options = {
+     *     maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+     *     maxResolution: 156543,
+     *     units: 'm',
+     *     projection: "EPSG:41001"
+     * };
+     * var map = new OpenLayers.Map("map2", options);
+     * (end)
+     *
+     * Examples (method two - single argument):
+     * (code)
+     * // create a map with non-default options
+     * var map = new OpenLayers.Map({
+     *     div: "map_id",
+     *     maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+     *     maxResolution: 156543,
+     *     units: 'm',
+     *     projection: "EPSG:41001"
+     * });
+     *
+     * // create a map without a reference to a container - call render later
+     * var map = new OpenLayers.Map({
+     *     maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+     *     maxResolution: 156543,
+     *     units: 'm',
+     *     projection: "EPSG:41001"
+     * });
+     */    
+    initialize: function (div, options) {
+        
+        // If only one argument is provided, check if it is an object.
+        if(arguments.length === 1 && typeof div === "object") {
+            options = div;
+            div = options && options.div;
+        }
+
+        // Simple-type defaults are set in class definition. 
+        //  Now set complex-type defaults 
+        this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
+                                            OpenLayers.Map.TILE_HEIGHT);
+        
+        this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+        
+        this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
+
+        this.theme = OpenLayers._getScriptLocation() + 
+                             'theme/default/style.css'; 
+
+        // now override default options 
+        OpenLayers.Util.extend(this, options);
+
+        this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
+
+        this.div = OpenLayers.Util.getElement(div);
+        if(!this.div) {
+            this.div = document.createElement("div");
+            this.div.style.height = "1px";
+            this.div.style.width = "1px";
+        }
+        
+        OpenLayers.Element.addClass(this.div, 'olMap');
+
+        // the viewPortDiv is the outermost div we modify
+        var id = this.div.id + "_OpenLayers_ViewPort";
+        this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
+                                                     "relative", null,
+                                                     "hidden");
+        this.viewPortDiv.style.width = "100%";
+        this.viewPortDiv.style.height = "100%";
+        this.viewPortDiv.className = "olMapViewport";
+        this.div.appendChild(this.viewPortDiv);
+
+        // the layerContainerDiv is the one that holds all the layers
+        id = this.div.id + "_OpenLayers_Container";
+        this.layerContainerDiv = OpenLayers.Util.createDiv(id);
+        this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
+        
+        this.viewPortDiv.appendChild(this.layerContainerDiv);
+
+        this.events = new OpenLayers.Events(this, 
+                                            this.div, 
+                                            this.EVENT_TYPES, 
+                                            this.fallThrough, 
+                                            {includeXY: true});
+        this.updateSize();
+        if(this.eventListeners instanceof Object) {
+            this.events.on(this.eventListeners);
+        }
+ 
+        // update the map size and location before the map moves
+        this.events.register("movestart", this, this.updateSize);
+
+        // Because Mozilla does not support the "resize" event for elements 
+        // other than "window", we need to put a hack here. 
+        if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
+            // If IE, register the resize on the div
+            this.events.register("resize", this, this.updateSize);
+        } else {
+            // Else updateSize on catching the window's resize
+            //  Note that this is ok, as updateSize() does nothing if the 
+            //  map's size has not actually changed.
+            this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, 
+                this);
+            OpenLayers.Event.observe(window, 'resize',
+                            this.updateSizeDestroy);
+        }
+        
+        // only append link stylesheet if the theme property is set
+        if(this.theme) {
+            // check existing links for equivalent url
+            var addNode = true;
+            var nodes = document.getElementsByTagName('link');
+            for(var i=0, len=nodes.length; i<len; ++i) {
+                if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
+                                                   this.theme)) {
+                    addNode = false;
+                    break;
+                }
+            }
+            // only add a new node if one with an equivalent url hasn't already
+            // been added
+            if(addNode) {
+                var cssNode = document.createElement('link');
+                cssNode.setAttribute('rel', 'stylesheet');
+                cssNode.setAttribute('type', 'text/css');
+                cssNode.setAttribute('href', this.theme);
+                document.getElementsByTagName('head')[0].appendChild(cssNode);
+            }
+        }
+
+        this.layers = [];
+        
+        if (this.controls == null) {
+            if (OpenLayers.Control != null) { // running full or lite?
+                this.controls = [ new OpenLayers.Control.Navigation(),
+                                  new OpenLayers.Control.PanZoom(),
+                                  new OpenLayers.Control.ArgParser(),
+                                  new OpenLayers.Control.Attribution()
+                                ];
+            } else {
+                this.controls = [];
+            }
+        }
+
+        for(var i=0, len=this.controls.length; i<len; i++) {
+            this.addControlToMap(this.controls[i]);
+        }
+
+        this.popups = [];
+
+        this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
+        
+
+        // always call map.destroy()
+        OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
+    },
+    
+    /**
+     * APIMethod: render
+     * Render the map to a specified container.
+     * 
+     * Parameters:
+     * div - {String|DOMElement} The container that the map should be rendered
+     *     to. If different than the current container, the map viewport
+     *     will be moved from the current to the new container.
+     */
+    render: function(div) {
+        this.div = OpenLayers.Util.getElement(div);
+        OpenLayers.Element.addClass(this.div, 'olMap');
+        this.events.attachToElement(this.div);
+        this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
+        this.div.appendChild(this.viewPortDiv);
+        this.updateSize();
+    },
+
+    /**
+     * Method: unloadDestroy
+     * Function that is called to destroy the map on page unload. stored here
+     *     so that if map is manually destroyed, we can unregister this.
+     */
+    unloadDestroy: null,
+    
+    /**
+     * Method: updateSizeDestroy
+     * When the map is destroyed, we need to stop listening to updateSize
+     *    events: this method stores the function we need to unregister in 
+     *    non-IE browsers.
+     */
+    updateSizeDestroy: null,
+
+    /**
+     * APIMethod: destroy
+     * Destroy this map
+     */
+    destroy:function() {
+        // if unloadDestroy is null, we've already been destroyed
+        if (!this.unloadDestroy) {
+            return false;
+        }
+
+        // map has been destroyed. dont do it again!
+        OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
+        this.unloadDestroy = null;
+
+        if (this.updateSizeDestroy) {
+            OpenLayers.Event.stopObserving(window, 'resize', 
+                                           this.updateSizeDestroy);
+        } else {
+            this.events.unregister("resize", this, this.updateSize);
+        }    
+        
+        this.paddingForPopups = null;    
+
+        if (this.controls != null) {
+            for (var i = this.controls.length - 1; i>=0; --i) {
+                this.controls[i].destroy();
+            } 
+            this.controls = null;
+        }
+        if (this.layers != null) {
+            for (var i = this.layers.length - 1; i>=0; --i) {
+                //pass 'false' to destroy so that map wont try to set a new 
+                // baselayer after each baselayer is removed
+                this.layers[i].destroy(false);
+            } 
+            this.layers = null;
+        }
+        if (this.viewPortDiv) {
+            this.div.removeChild(this.viewPortDiv);
+        }
+        this.viewPortDiv = null;
+
+        if(this.eventListeners) {
+            this.events.un(this.eventListeners);
+            this.eventListeners = null;
+        }
+        this.events.destroy();
+        this.events = null;
+
+    },
+
+    /**
+     * APIMethod: setOptions
+     * Change the map options
+     *
+     * Parameters:
+     * options - {Object} Hashtable of options to tag to the map
+     */
+    setOptions: function(options) {
+        OpenLayers.Util.extend(this, options);
+    },
+
+    /**
+     * APIMethod: getTileSize
+     * Get the tile size for the map
+     *
+     * Returns:
+     * {<OpenLayers.Size>}
+     */
+     getTileSize: function() {
+         return this.tileSize;
+     },
+
+
+    /**
+     * APIMethod: getBy
+     * Get a list of objects given a property and a match item.
+     *
+     * Parameters:
+     * array - {String} A property on the map whose value is an array.
+     * property - {String} A property on each item of the given array.
+     * match - {String | Object} A string to match.  Can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     match.test(map[array][i][property]) evaluates to true, the item will
+     *     be included in the array returned.  If no items are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array} An array of items where the given property matches the given
+     *     criteria.
+     */
+    getBy: function(array, property, match) {
+        var test = (typeof match.test == "function");
+        var found = OpenLayers.Array.filter(this[array], function(item) {
+            return item[property] == match || (test && match.test(item[property]));
+        });
+        return found;
+    },
+
+    /**
+     * APIMethod: getLayersBy
+     * Get a list of layers with properties matching the given criteria.
+     *
+     * Parameter:
+     * property - {String} A layer property to be matched.
+     * match - {String | Object} A string to match.  Can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     match.test(layer[property]) evaluates to true, the layer will be
+     *     included in the array returned.  If no layers are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Layer>)} A list of layers matching the given criteria.
+     *     An empty array is returned if no matches are found.
+     */
+    getLayersBy: function(property, match) {
+        return this.getBy("layers", property, match);
+    },
+
+    /**
+     * APIMethod: getLayersByName
+     * Get a list of layers with names matching the given name.
+     *
+     * Parameter:
+     * match - {String | Object} A layer name.  The name can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     name.test(layer.name) evaluates to true, the layer will be included
+     *     in the list of layers returned.  If no layers are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Layer>)} A list of layers matching the given name.
+     *     An empty array is returned if no matches are found.
+     */
+    getLayersByName: function(match) {
+        return this.getLayersBy("name", match);
+    },
+
+    /**
+     * APIMethod: getLayersByClass
+     * Get a list of layers of a given class (CLASS_NAME).
+     *
+     * Parameter:
+     * match - {String | Object} A layer class name.  The match can also be a
+     *     regular expression literal or object.  In addition, it can be any
+     *     object with a method named test.  For reqular expressions or other,
+     *     if type.test(layer.CLASS_NAME) evaluates to true, the layer will
+     *     be included in the list of layers returned.  If no layers are
+     *     found, an empty array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Layer>)} A list of layers matching the given class.
+     *     An empty array is returned if no matches are found.
+     */
+    getLayersByClass: function(match) {
+        return this.getLayersBy("CLASS_NAME", match);
+    },
+
+    /**
+     * APIMethod: getControlsBy
+     * Get a list of controls with properties matching the given criteria.
+     *
+     * Parameter:
+     * property - {String} A control property to be matched.
+     * match - {String | Object} A string to match.  Can also be a regular
+     *     expression literal or object.  In addition, it can be any object
+     *     with a method named test.  For reqular expressions or other, if
+     *     match.test(layer[property]) evaluates to true, the layer will be
+     *     included in the array returned.  If no layers are found, an empty
+     *     array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Control>)} A list of controls matching the given
+     *     criteria.  An empty array is returned if no matches are found.
+     */
+    getControlsBy: function(property, match) {
+        return this.getBy("controls", property, match);
+    },
+
+    /**
+     * APIMethod: getControlsByClass
+     * Get a list of controls of a given class (CLASS_NAME).
+     *
+     * Parameter:
+     * match - {String | Object} A control class name.  The match can also be a
+     *     regular expression literal or object.  In addition, it can be any
+     *     object with a method named test.  For reqular expressions or other,
+     *     if type.test(control.CLASS_NAME) evaluates to true, the control will
+     *     be included in the list of controls returned.  If no controls are
+     *     found, an empty array is returned.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Control>)} A list of controls matching the given class.
+     *     An empty array is returned if no matches are found.
+     */
+    getControlsByClass: function(match) {
+        return this.getControlsBy("CLASS_NAME", match);
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Layer Functions                     */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Layers to and from the Map           */
+  /*                                                      */
+  /********************************************************/         
+
+    /**
+     * APIMethod: getLayer
+     * Get a layer based on its id
+     *
+     * Parameter:
+     * id - {String} A layer id
+     *
+     * Returns:
+     * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's 
+     *                      layer collection, or null if not found.
+     */
+    getLayer: function(id) {
+        var foundLayer = null;
+        for (var i=0, len=this.layers.length; i<len; i++) {
+            var layer = this.layers[i];
+            if (layer.id == id) {
+                foundLayer = layer;
+                break;
+            }
+        }
+        return foundLayer;
+    },
+
+    /**
+    * Method: setLayerZIndex
+    * 
+    * Parameters:
+    * layer - {<OpenLayers.Layer>} 
+    * zIdx - {int} 
+    */    
+    setLayerZIndex: function (layer, zIdx) {
+        layer.setZIndex(
+            this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
+            + zIdx * 5 );
+    },
+
+    /**
+     * Method: resetLayersZIndex
+     * Reset each layer's z-index based on layer's array index
+     */
+    resetLayersZIndex: function() {
+        for (var i=0, len=this.layers.length; i<len; i++) {
+            var layer = this.layers[i];
+            this.setLayerZIndex(layer, i);
+        }
+    },
+
+    /**
+    * APIMethod: addLayer
+    *
+    * Parameters:
+    * layer - {<OpenLayers.Layer>} 
+    */    
+    addLayer: function (layer) {
+        for(var i=0, len=this.layers.length; i <len; i++) {
+            if (this.layers[i] == layer) {
+                var msg = OpenLayers.i18n('layerAlreadyAdded', 
+                                                      {'layerName':layer.name});
+                OpenLayers.Console.warn(msg);
+                return false;
+            }
+        }
+        if(this.allOverlays) {
+            layer.isBaseLayer = false;
+        }
+
+        this.events.triggerEvent("preaddlayer", {layer: layer});
+        
+        layer.div.className = "olLayerDiv";
+        layer.div.style.overflow = "";
+        this.setLayerZIndex(layer, this.layers.length);
+
+        if (layer.isFixed) {
+            this.viewPortDiv.appendChild(layer.div);
+        } else {
+            this.layerContainerDiv.appendChild(layer.div);
+        }
+        this.layers.push(layer);
+        layer.setMap(this);
+
+        if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer))  {
+            if (this.baseLayer == null) {
+                // set the first baselaye we add as the baselayer
+                this.setBaseLayer(layer);
+            } else {
+                layer.setVisibility(false);
+            }
+        } else {
+            layer.redraw();
+        }
+
+        this.events.triggerEvent("addlayer", {layer: layer});
+        layer.afterAdd();
+    },
+
+    /**
+    * APIMethod: addLayers 
+    *
+    * Parameters:
+    * layers - {Array(<OpenLayers.Layer>)} 
+    */    
+    addLayers: function (layers) {
+        for (var i=0, len=layers.length; i<len; i++) {
+            this.addLayer(layers[i]);
+        }
+    },
+
+    /** 
+     * APIMethod: removeLayer
+     * Removes a layer from the map by removing its visual element (the 
+     *   layer.div property), then removing it from the map's internal list 
+     *   of layers, setting the layer's map property to null. 
+     * 
+     *   a "removelayer" event is triggered.
+     * 
+     *   very worthy of mention is that simply removing a layer from a map
+     *   will not cause the removal of any popups which may have been created
+     *   by the layer. this is due to the fact that it was decided at some
+     *   point that popups would not belong to layers. thus there is no way 
+     *   for us to know here to which layer the popup belongs.
+     *    
+     *     A simple solution to this is simply to call destroy() on the layer.
+     *     the default OpenLayers.Layer class's destroy() function
+     *     automatically takes care to remove itself from whatever map it has
+     *     been attached to. 
+     * 
+     *     The correct solution is for the layer itself to register an 
+     *     event-handler on "removelayer" and when it is called, if it 
+     *     recognizes itself as the layer being removed, then it cycles through
+     *     its own personal list of popups, removing them from the map.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * setNewBaseLayer - {Boolean} Default is true
+     */
+    removeLayer: function(layer, setNewBaseLayer) {
+        if (setNewBaseLayer == null) {
+            setNewBaseLayer = true;
+        }
+
+        if (layer.isFixed) {
+            this.viewPortDiv.removeChild(layer.div);
+        } else {
+            this.layerContainerDiv.removeChild(layer.div);
+        }
+        OpenLayers.Util.removeItem(this.layers, layer);
+        layer.removeMap(this);
+        layer.map = null;
+
+        // if we removed the base layer, need to set a new one
+        if(this.baseLayer == layer) {
+            this.baseLayer = null;
+            if(setNewBaseLayer) {
+                for(var i=0, len=this.layers.length; i<len; i++) {
+                    var iLayer = this.layers[i];
+                    if (iLayer.isBaseLayer || this.allOverlays) {
+                        this.setBaseLayer(iLayer);
+                        break;
+                    }
+                }
+            }
+        }
+
+        this.resetLayersZIndex();
+
+        this.events.triggerEvent("removelayer", {layer: layer});
+    },
+
+    /**
+     * APIMethod: getNumLayers
+     * 
+     * Returns:
+     * {Int} The number of layers attached to the map.
+     */
+    getNumLayers: function () {
+        return this.layers.length;
+    },
+
+    /** 
+     * APIMethod: getLayerIndex
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>}
+     *
+     * Returns:
+     * {Integer} The current (zero-based) index of the given layer in the map's
+     *           layer stack. Returns -1 if the layer isn't on the map.
+     */
+    getLayerIndex: function (layer) {
+        return OpenLayers.Util.indexOf(this.layers, layer);
+    },
+    
+    /** 
+     * APIMethod: setLayerIndex
+     * Move the given layer to the specified (zero-based) index in the layer
+     *     list, changing its z-index in the map display. Use
+     *     map.getLayerIndex() to find out the current index of a layer. Note
+     *     that this cannot (or at least should not) be effectively used to
+     *     raise base layers above overlays.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * idx - {int} 
+     */
+    setLayerIndex: function (layer, idx) {
+        var base = this.getLayerIndex(layer);
+        if (idx < 0) {
+            idx = 0;
+        } else if (idx > this.layers.length) {
+            idx = this.layers.length;
+        }
+        if (base != idx) {
+            this.layers.splice(base, 1);
+            this.layers.splice(idx, 0, layer);
+            for (var i=0, len=this.layers.length; i<len; i++) {
+                this.setLayerZIndex(this.layers[i], i);
+            }
+            this.events.triggerEvent("changelayer", {
+                layer: layer, property: "order"
+            });
+            if(this.allOverlays) {
+                if(idx === 0) {
+                    this.setBaseLayer(layer);
+                } else if(this.baseLayer !== this.layers[0]) {
+                    this.setBaseLayer(this.layers[0]);
+                }
+            }
+        }
+    },
+
+    /** 
+     * APIMethod: raiseLayer
+     * Change the index of the given layer by delta. If delta is positive, 
+     *     the layer is moved up the map's layer stack; if delta is negative,
+     *     the layer is moved down.  Again, note that this cannot (or at least
+     *     should not) be effectively used to raise base layers above overlays.
+     *
+     * Paremeters:
+     * layer - {<OpenLayers.Layer>} 
+     * delta - {int} 
+     */
+    raiseLayer: function (layer, delta) {
+        var idx = this.getLayerIndex(layer) + delta;
+        this.setLayerIndex(layer, idx);
+    },
+    
+    /** 
+     * APIMethod: setBaseLayer
+     * Allows user to specify one of the currently-loaded layers as the Map's
+     *     new base layer.
+     * 
+     * Parameters:
+     * newBaseLayer - {<OpenLayers.Layer>}
+     */
+    setBaseLayer: function(newBaseLayer) {
+        var oldExtent = null;
+        if (this.baseLayer) {
+            oldExtent = this.baseLayer.getExtent();
+        }
+
+        if (newBaseLayer != this.baseLayer) {
+          
+            // is newBaseLayer an already loaded layer?m
+            if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
+
+                // make the old base layer invisible 
+                if (this.baseLayer != null && !this.allOverlays) {
+                    this.baseLayer.setVisibility(false);
+                }
+
+                // set new baselayer
+                this.baseLayer = newBaseLayer;
+                
+                // Increment viewRequestID since the baseLayer is 
+                // changing. This is used by tiles to check if they should 
+                // draw themselves.
+                this.viewRequestID++;
+                if(!this.allOverlays) {
+                    this.baseLayer.visibility = true;
+                }
+
+                //redraw all layers
+                var center = this.getCenter();
+                if (center != null) {
+
+                    //either get the center from the old Extent or just from
+                    // the current center of the map. 
+                    var newCenter = (oldExtent) 
+                        ? oldExtent.getCenterLonLat()
+                        : center;
+
+                    //the new zoom will either come from the old Extent or 
+                    // from the current resolution of the map                                                
+                    var newZoom = (oldExtent) 
+                        ? this.getZoomForExtent(oldExtent, true)
+                        : this.getZoomForResolution(this.resolution, true);
+
+                    // zoom and force zoom change
+                    this.setCenter(newCenter, newZoom, false, true);
+                }
+
+                this.events.triggerEvent("changebaselayer", {
+                    layer: this.baseLayer
+                });
+            }        
+        }
+    },
+
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Control Functions                    */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Controls to and from the Map         */
+  /*                                                      */
+  /********************************************************/         
+
+    /**
+     * APIMethod: addControl
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>}
+     * px - {<OpenLayers.Pixel>}
+     */    
+    addControl: function (control, px) {
+        this.controls.push(control);
+        this.addControlToMap(control, px);
+    },
+
+    /**
+     * Method: addControlToMap
+     * 
+     * Parameters:
+     * 
+     * control - {<OpenLayers.Control>}
+     * px - {<OpenLayers.Pixel>}
+     */    
+    addControlToMap: function (control, px) {
+        // If a control doesn't have a div at this point, it belongs in the
+        // viewport.
+        control.outsideViewport = (control.div != null);
+        
+        // If the map has a displayProjection, and the control doesn't, set 
+        // the display projection.
+        if (this.displayProjection && !control.displayProjection) {
+            control.displayProjection = this.displayProjection;
+        }    
+        
+        control.setMap(this);
+        var div = control.draw(px);
+        if (div) {
+            if(!control.outsideViewport) {
+                div.style.zIndex = this.Z_INDEX_BASE['Control'] +
+                                    this.controls.length;
+                this.viewPortDiv.appendChild( div );
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: getControl
+     * 
+     * Parameters:
+     * id - {String} ID of the control to return.
+     * 
+     * Returns:
+     * {<OpenLayers.Control>} The control from the map's list of controls 
+     *                        which has a matching 'id'. If none found, 
+     *                        returns null.
+     */    
+    getControl: function (id) {
+        var returnControl = null;
+        for(var i=0, len=this.controls.length; i<len; i++) {
+            var control = this.controls[i];
+            if (control.id == id) {
+                returnControl = control;
+                break;
+            }
+        }
+        return returnControl;
+    },
+    
+    /** 
+     * APIMethod: removeControl
+     * Remove a control from the map. Removes the control both from the map 
+     *     object's internal array of controls, as well as from the map's 
+     *     viewPort (assuming the control was not added outsideViewport)
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control to remove.
+     */    
+    removeControl: function (control) {
+        //make sure control is non-null and actually part of our map
+        if ( (control) && (control == this.getControl(control.id)) ) {
+            if (control.div && (control.div.parentNode == this.viewPortDiv)) {
+                this.viewPortDiv.removeChild(control.div);
+            }
+            OpenLayers.Util.removeItem(this.controls, control);
+        }
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Popup Functions                     */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Popups to and from the Map           */
+  /*                                                      */
+  /********************************************************/         
+
+    /** 
+     * APIMethod: addPopup
+     * 
+     * Parameters:
+     * popup - {<OpenLayers.Popup>}
+     * exclusive - {Boolean} If true, closes all other popups first
+     */
+    addPopup: function(popup, exclusive) {
+
+        if (exclusive) {
+            //remove all other popups from screen
+            for (var i = this.popups.length - 1; i >= 0; --i) {
+                this.removePopup(this.popups[i]);
+            }
+        }
+
+        popup.map = this;
+        this.popups.push(popup);
+        var popupDiv = popup.draw();
+        if (popupDiv) {
+            popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +
+                                    this.popups.length;
+            this.layerContainerDiv.appendChild(popupDiv);
+        }
+    },
+    
+    /** 
+    * APIMethod: removePopup
+    * 
+    * Parameters:
+    * popup - {<OpenLayers.Popup>}
+    */
+    removePopup: function(popup) {
+        OpenLayers.Util.removeItem(this.popups, popup);
+        if (popup.div) {
+            try { this.layerContainerDiv.removeChild(popup.div); }
+            catch (e) { } // Popups sometimes apparently get disconnected
+                      // from the layerContainerDiv, and cause complaints.
+        }
+        popup.map = null;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*              Container Div Functions                 */
+  /*                                                      */
+  /*   The following functions deal with the access to    */
+  /*    and maintenance of the size of the container div  */
+  /*                                                      */
+  /********************************************************/     
+
+    /**
+     * APIMethod: getSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the 
+     *                     size, in pixels, of the div into which OpenLayers 
+     *                     has been loaded. 
+     *                     Note - A clone() of this locally cached variable is
+     *                     returned, so as not to allow users to modify it.
+     */
+    getSize: function () {
+        var size = null;
+        if (this.size != null) {
+            size = this.size.clone();
+        }
+        return size;
+    },
+
+    /**
+     * APIMethod: updateSize
+     * This function should be called by any external code which dynamically
+     *     changes the size of the map div (because mozilla wont let us catch 
+     *     the "onresize" for an element)
+     */
+    updateSize: function() {
+        // the div might have moved on the page, also
+        this.events.clearMouseCache();
+        var newSize = this.getCurrentSize();
+        var oldSize = this.getSize();
+        if (oldSize == null) {
+            this.size = oldSize = newSize;
+        }
+        if (!newSize.equals(oldSize)) {
+            
+            // store the new size
+            this.size = newSize;
+
+            //notify layers of mapresize
+            for(var i=0, len=this.layers.length; i<len; i++) {
+                this.layers[i].onMapResize();                
+            }
+
+            if (this.baseLayer != null) {
+                var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
+                var centerLL = this.getLonLatFromViewPortPx(center);
+                var zoom = this.getZoom();
+                this.zoom = null;
+                this.setCenter(this.getCenter(), zoom);
+            }
+
+        }
+    },
+    
+    /**
+     * Method: getCurrentSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions 
+     *                     of the map div
+     */
+    getCurrentSize: function() {
+
+        var size = new OpenLayers.Size(this.div.clientWidth, 
+                                       this.div.clientHeight);
+
+        // Workaround for the fact that hidden elements return 0 for size.
+        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+            var dim = OpenLayers.Element.getDimensions(this.div);
+            size.w = dim.width;
+            size.h = dim.height;
+        }
+        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+            size.w = parseInt(this.div.style.width);
+            size.h = parseInt(this.div.style.height);
+        }
+        return size;
+    },
+
+    /** 
+     * Method: calculateBounds
+     * 
+     * Parameters:
+     * center - {<OpenLayers.LonLat>} Default is this.getCenter()
+     * resolution - {float} Default is this.getResolution() 
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A bounds based on resolution, center, and 
+     *                       current mapsize.
+     */
+    calculateBounds: function(center, resolution) {
+
+        var extent = null;
+        
+        if (center == null) {
+            center = this.getCenter();
+        }                
+        if (resolution == null) {
+            resolution = this.getResolution();
+        }
+    
+        if ((center != null) && (resolution != null)) {
+
+            var size = this.getSize();
+            var w_deg = size.w * resolution;
+            var h_deg = size.h * resolution;
+        
+            extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+                                           center.lat - h_deg / 2,
+                                           center.lon + w_deg / 2,
+                                           center.lat + h_deg / 2);
+        
+        }
+
+        return extent;
+    },
+
+
+  /********************************************************/
+  /*                                                      */
+  /*            Zoom, Center, Pan Functions               */
+  /*                                                      */
+  /*    The following functions handle the validation,    */
+  /*   getting and setting of the Zoom Level and Center   */
+  /*       as well as the panning of the Map              */
+  /*                                                      */
+  /********************************************************/
+    /**
+     * APIMethod: getCenter
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>}
+     */
+    getCenter: function () {
+        var center = null;
+        if (this.center) {
+            center = this.center.clone();
+        }
+        return center;
+    },
+
+
+    /**
+     * APIMethod: getZoom
+     * 
+     * Returns:
+     * {Integer}
+     */
+    getZoom: function () {
+        return this.zoom;
+    },
+    
+    /** 
+     * APIMethod: pan
+     * Allows user to pan by a value of screen pixels
+     * 
+     * Parameters:
+     * dx - {Integer}
+     * dy - {Integer}
+     * options - {Object} Options to configure panning:
+     *  - *animate* {Boolean} Use panTo instead of setCenter. Default is true.
+     *  - *dragging* {Boolean} Call setCenter with dragging true.  Default is
+     *    false.
+     */
+    pan: function(dx, dy, options) {
+        options = OpenLayers.Util.applyDefaults(options, {
+            animate: true,
+            dragging: false
+        });
+        // getCenter
+        var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
+
+        // adjust
+        var newCenterPx = centerPx.add(dx, dy);
+        
+        // only call setCenter if not dragging or there has been a change
+        if (!options.dragging || !newCenterPx.equals(centerPx)) {
+            var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
+            if (options.animate) {
+                this.panTo(newCenterLonLat);
+            } else {
+                this.setCenter(newCenterLonLat, null, options.dragging);
+            }    
+        }
+
+   },
+   
+   /** 
+     * APIMethod: panTo
+     * Allows user to pan to a new lonlat
+     * If the new lonlat is in the current extent the map will slide smoothly
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.Lonlat>}
+     */
+    panTo: function(lonlat) {
+        if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) {
+            if (!this.panTween) {
+                this.panTween = new OpenLayers.Tween(this.panMethod);
+            }
+            var center = this.getCenter();
+
+            // center will not change, don't do nothing
+            if (lonlat.lon == center.lon &&
+                lonlat.lat == center.lat) {
+                return;
+            }
+
+            var from = {
+                lon: center.lon,
+                lat: center.lat
+            };
+            var to = {
+                lon: lonlat.lon,
+                lat: lonlat.lat
+            };
+            this.panTween.start(from, to, this.panDuration, {
+                callbacks: {
+                    start: OpenLayers.Function.bind(function(lonlat) {
+                        this.events.triggerEvent("movestart");
+                    }, this),
+                    eachStep: OpenLayers.Function.bind(function(lonlat) {
+                        lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+                        this.moveTo(lonlat, this.zoom, {
+                            'dragging': true,
+                            'noEvent': true
+                        });
+                    }, this),
+                    done: OpenLayers.Function.bind(function(lonlat) {
+                        lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+                        this.moveTo(lonlat, this.zoom, {
+                            'noEvent': true
+                        });
+                        this.events.triggerEvent("moveend");
+                    }, this)
+                }
+            });
+        } else {
+            this.setCenter(lonlat);
+        }
+    },
+
+    /**
+     * APIMethod: setCenter
+     * Set the map center (and optionally, the zoom level).
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>} The new center location.
+     * zoom - {Integer} Optional zoom level.
+     * dragging - {Boolean} Specifies whether or not to trigger 
+     *                      movestart/end events
+     * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom 
+     *                             change events (needed on baseLayer change)
+     *
+     * TBD: reconsider forceZoomChange in 3.0
+     */
+    setCenter: function(lonlat, zoom, dragging, forceZoomChange) {
+        this.moveTo(lonlat, zoom, {
+            'dragging': dragging,
+            'forceZoomChange': forceZoomChange,
+            'caller': 'setCenter'
+        });
+    },
+
+    /**
+     * Method: moveTo
+     *
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * zoom - {Integer}
+     * options - {Object}
+     */
+    moveTo: function(lonlat, zoom, options) {
+        if (!options) { 
+            options = {};
+        }    
+        // dragging is false by default
+        var dragging = options.dragging;
+        // forceZoomChange is false by default
+        var forceZoomChange = options.forceZoomChange;
+        // noEvent is false by default
+        var noEvent = options.noEvent;
+
+        if (this.panTween && options.caller == "setCenter") {
+            this.panTween.stop();
+        }    
+             
+        if (!this.center && !this.isValidLonLat(lonlat)) {
+            lonlat = this.maxExtent.getCenterLonLat();
+        }
+
+        if(this.restrictedExtent != null) {
+            // In 3.0, decide if we want to change interpretation of maxExtent.
+            if(lonlat == null) { 
+                lonlat = this.getCenter(); 
+            }
+            if(zoom == null) { 
+                zoom = this.getZoom(); 
+            }
+            var resolution = this.getResolutionForZoom(zoom);
+            var extent = this.calculateBounds(lonlat, resolution); 
+            if(!this.restrictedExtent.containsBounds(extent)) {
+                var maxCenter = this.restrictedExtent.getCenterLonLat(); 
+                if(extent.getWidth() > this.restrictedExtent.getWidth()) { 
+                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); 
+                } else if(extent.left < this.restrictedExtent.left) {
+                    lonlat = lonlat.add(this.restrictedExtent.left -
+                                        extent.left, 0); 
+                } else if(extent.right > this.restrictedExtent.right) { 
+                    lonlat = lonlat.add(this.restrictedExtent.right -
+                                        extent.right, 0); 
+                } 
+                if(extent.getHeight() > this.restrictedExtent.getHeight()) { 
+                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); 
+                } else if(extent.bottom < this.restrictedExtent.bottom) { 
+                    lonlat = lonlat.add(0, this.restrictedExtent.bottom -
+                                        extent.bottom); 
+                } 
+                else if(extent.top > this.restrictedExtent.top) { 
+                    lonlat = lonlat.add(0, this.restrictedExtent.top -
+                                        extent.top); 
+                } 
+            }
+        }
+        
+        var zoomChanged = forceZoomChange || (
+                            (this.isValidZoomLevel(zoom)) && 
+                            (zoom != this.getZoom()) );
+
+        var centerChanged = (this.isValidLonLat(lonlat)) && 
+                            (!lonlat.equals(this.center));
+
+
+        // if neither center nor zoom will change, no need to do anything
+        if (zoomChanged || centerChanged || !dragging) {
+
+            if (!this.dragging && !noEvent) {
+                this.events.triggerEvent("movestart");
+            }
+
+            if (centerChanged) {
+                if ((!zoomChanged) && (this.center)) { 
+                    // if zoom hasnt changed, just slide layerContainer
+                    //  (must be done before setting this.center to new value)
+                    this.centerLayerContainer(lonlat);
+                }
+                this.center = lonlat.clone();
+            }
+
+            // (re)set the layerContainerDiv's location
+            if ((zoomChanged) || (this.layerContainerOrigin == null)) {
+                this.layerContainerOrigin = this.center.clone();
+                this.layerContainerDiv.style.left = "0px";
+                this.layerContainerDiv.style.top  = "0px";
+            }
+
+            if (zoomChanged) {
+                this.zoom = zoom;
+                this.resolution = this.getResolutionForZoom(zoom);
+                // zoom level has changed, increment viewRequestID.
+                this.viewRequestID++;
+            }    
+            
+            var bounds = this.getExtent();
+            
+            //send the move call to the baselayer and all the overlays    
+
+            if(this.baseLayer.visibility) {
+                this.baseLayer.moveTo(bounds, zoomChanged, dragging);
+                if(dragging) {
+                    this.baseLayer.events.triggerEvent("move");
+                } else {
+                    this.baseLayer.events.triggerEvent("moveend",
+                        {"zoomChanged": zoomChanged}
+                    );
+                }
+            }
+            
+            bounds = this.baseLayer.getExtent();
+            
+            for (var i=0, len=this.layers.length; i<len; i++) {
+                var layer = this.layers[i];
+                if (layer !== this.baseLayer && !layer.isBaseLayer) {
+                    var inRange = layer.calculateInRange();
+                    if (layer.inRange != inRange) {
+                        // the inRange property has changed. If the layer is
+                        // no longer in range, we turn it off right away. If
+                        // the layer is no longer out of range, the moveTo
+                        // call below will turn on the layer.
+                        layer.inRange = inRange;
+                        if (!inRange) {
+                            layer.display(false);
+                        }
+                        this.events.triggerEvent("changelayer", {
+                            layer: layer, property: "visibility"
+                        });
+                    }
+                    if (inRange && layer.visibility) {
+                        layer.moveTo(bounds, zoomChanged, dragging);
+                        if(dragging) {
+                            layer.events.triggerEvent("move");
+                        } else {
+                            layer.events.triggerEvent("moveend",
+                                {"zoomChanged": zoomChanged}
+                            );
+                        }
+                    }
+                }                
+            }
+            
+            if (zoomChanged) {
+                //redraw popups
+                for (var i=0, len=this.popups.length; i<len; i++) {
+                    this.popups[i].updatePosition();
+                }
+            }    
+            
+            this.events.triggerEvent("move");
+    
+            if (zoomChanged) { this.events.triggerEvent("zoomend"); }
+        }
+
+        // even if nothing was done, we want to notify of this
+        if (!dragging && !noEvent) {
+            this.events.triggerEvent("moveend");
+        }
+        
+        // Store the map dragging state for later use
+        this.dragging = !!dragging; 
+
+    },
+
+    /** 
+     * Method: centerLayerContainer
+     * This function takes care to recenter the layerContainerDiv.
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     */
+    centerLayerContainer: function (lonlat) {
+
+        var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
+        var newPx = this.getViewPortPxFromLonLat(lonlat);
+
+        if ((originPx != null) && (newPx != null)) {
+            this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px";
+            this.layerContainerDiv.style.top  = Math.round(originPx.y - newPx.y) + "px";
+        }
+    },
+
+    /**
+     * Method: isValidZoomLevel
+     * 
+     * Parameters:
+     * zoomLevel - {Integer}
+     * 
+     * Returns:
+     * {Boolean} Whether or not the zoom level passed in is non-null and 
+     *           within the min/max range of zoom levels.
+     */
+    isValidZoomLevel: function(zoomLevel) {
+       return ( (zoomLevel != null) &&
+                (zoomLevel >= 0) && 
+                (zoomLevel < this.getNumZoomLevels()) );
+    },
+    
+    /**
+     * Method: isValidLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {Boolean} Whether or not the lonlat passed in is non-null and within
+     *           the maxExtent bounds
+     */
+    isValidLonLat: function(lonlat) {
+        var valid = false;
+        if (lonlat != null) {
+            var maxExtent = this.getMaxExtent();
+            valid = maxExtent.containsLonLat(lonlat);        
+        }
+        return valid;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Layer Options                        */
+  /*                                                      */
+  /*    Accessor functions to Layer Options parameters    */
+  /*                                                      */
+  /********************************************************/
+    
+    /**
+     * APIMethod: getProjection
+     * This method returns a string representing the projection. In 
+     *     the case of projection support, this will be the srsCode which
+     *     is loaded -- otherwise it will simply be the string value that
+     *     was passed to the projection at startup.
+     *
+     * FIXME: In 3.0, we will remove getProjectionObject, and instead
+     *     return a Projection object from this function. 
+     * 
+     * Returns:
+     * {String} The Projection string from the base layer or null. 
+     */
+    getProjection: function() {
+        var projection = this.getProjectionObject();
+        return projection ? projection.getCode() : null;
+    },
+    
+    /**
+     * APIMethod: getProjectionObject
+     * Returns the projection obect from the baselayer.
+     *
+     * Returns:
+     * {<OpenLayers.Projection>} The Projection of the base layer.
+     */
+    getProjectionObject: function() {
+        var projection = null;
+        if (this.baseLayer != null) {
+            projection = this.baseLayer.projection;
+        }
+        return projection;
+    },
+    
+    /**
+     * APIMethod: getMaxResolution
+     * 
+     * Returns:
+     * {String} The Map's Maximum Resolution
+     */
+    getMaxResolution: function() {
+        var maxResolution = null;
+        if (this.baseLayer != null) {
+            maxResolution = this.baseLayer.maxResolution;
+        }
+        return maxResolution;
+    },
+        
+    /**
+     * APIMethod: getMaxExtent
+     *
+     * Parameters:
+     * options - {Object} 
+     * 
+     * Allowed Options:
+     * restricted - {Boolean} If true, returns restricted extent (if it is 
+     *     available.)
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} The maxExtent property as set on the current 
+     *     baselayer, unless the 'restricted' option is set, in which case
+     *     the 'restrictedExtent' option from the map is returned (if it
+     *     is set).
+     */
+    getMaxExtent: function (options) {
+        var maxExtent = null;
+        if(options && options.restricted && this.restrictedExtent){
+            maxExtent = this.restrictedExtent;
+        } else if (this.baseLayer != null) {
+            maxExtent = this.baseLayer.maxExtent;
+        }        
+        return maxExtent;
+    },
+    
+    /**
+     * APIMethod: getNumZoomLevels
+     * 
+     * Returns:
+     * {Integer} The total number of zoom levels that can be displayed by the 
+     *           current baseLayer.
+     */
+    getNumZoomLevels: function() {
+        var numZoomLevels = null;
+        if (this.baseLayer != null) {
+            numZoomLevels = this.baseLayer.numZoomLevels;
+        }
+        return numZoomLevels;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Baselayer Functions                  */
+  /*                                                      */
+  /*    The following functions, all publicly exposed     */
+  /*       in the API?, are all merely wrappers to the    */
+  /*       the same calls on whatever layer is set as     */
+  /*                the current base layer                */
+  /*                                                      */
+  /********************************************************/
+
+    /**
+     * APIMethod: getExtent
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *                       bounds of the current viewPort. 
+     *                       If no baselayer is set, returns null.
+     */
+    getExtent: function () {
+        var extent = null;
+        if (this.baseLayer != null) {
+            extent = this.baseLayer.getExtent();
+        }
+        return extent;
+    },
+
+    /**
+     * APIMethod: getResolution
+     * 
+     * Returns:
+     * {Float} The current resolution of the map. 
+     *         If no baselayer is set, returns null.
+     */
+    getResolution: function () {
+        var resolution = null;
+        if (this.baseLayer != null) {
+            resolution = this.baseLayer.getResolution();
+        }
+        return resolution;
+    },
+
+    /**
+     * APIMethod: getUnits
+     * 
+     * Returns:
+     * {Float} The current units of the map. 
+     *         If no baselayer is set, returns null.
+     */
+    getUnits: function () {
+        var units = null;
+        if (this.baseLayer != null) {
+            units = this.baseLayer.units;
+        }
+        return units;
+    },
+
+     /**
+      * APIMethod: getScale
+      * 
+      * Returns:
+      * {Float} The current scale denominator of the map. 
+      *         If no baselayer is set, returns null.
+      */
+    getScale: function () {
+        var scale = null;
+        if (this.baseLayer != null) {
+            var res = this.getResolution();
+            var units = this.baseLayer.units;
+            scale = OpenLayers.Util.getScaleFromResolution(res, units);
+        }
+        return scale;
+    },
+
+
+    /**
+     * APIMethod: getZoomForExtent
+     * 
+     * Parameters: 
+     * bounds - {<OpenLayers.Bounds>}
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
+     *     not exactly contain the entire extent.
+     *     Default is false.
+     * 
+     * Returns:
+     * {Integer} A suitable zoom level for the specified bounds.
+     *           If no baselayer is set, returns null.
+     */
+    getZoomForExtent: function (bounds, closest) {
+        var zoom = null;
+        if (this.baseLayer != null) {
+            zoom = this.baseLayer.getZoomForExtent(bounds, closest);
+        }
+        return zoom;
+    },
+
+    /**
+     * APIMethod: getResolutionForZoom
+     * 
+     * Parameter:
+     * zoom - {Float}
+     * 
+     * Returns:
+     * {Float} A suitable resolution for the specified zoom.  If no baselayer
+     *     is set, returns null.
+     */
+    getResolutionForZoom: function(zoom) {
+        var resolution = null;
+        if(this.baseLayer) {
+            resolution = this.baseLayer.getResolutionForZoom(zoom);
+        }
+        return resolution;
+    },
+
+    /**
+     * APIMethod: getZoomForResolution
+     * 
+     * Parameter:
+     * resolution - {Float}
+     * closest - {Boolean} Find the zoom level that corresponds to the absolute 
+     *     closest resolution, which may result in a zoom whose corresponding
+     *     resolution is actually smaller than we would have desired (if this
+     *     is being called from a getZoomForExtent() call, then this means that
+     *     the returned zoom index might not actually contain the entire 
+     *     extent specified... but it'll be close).
+     *     Default is false.
+     * 
+     * Returns:
+     * {Integer} A suitable zoom level for the specified resolution.
+     *           If no baselayer is set, returns null.
+     */
+    getZoomForResolution: function(resolution, closest) {
+        var zoom = null;
+        if (this.baseLayer != null) {
+            zoom = this.baseLayer.getZoomForResolution(resolution, closest);
+        }
+        return zoom;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Zooming Functions                   */
+  /*                                                      */
+  /*    The following functions, all publicly exposed     */
+  /*       in the API, are all merely wrappers to the     */
+  /*               the setCenter() function               */
+  /*                                                      */
+  /********************************************************/
+  
+    /** 
+     * APIMethod: zoomTo
+     * Zoom to a specific zoom level
+     * 
+     * Parameters:
+     * zoom - {Integer}
+     */
+    zoomTo: function(zoom) {
+        if (this.isValidZoomLevel(zoom)) {
+            this.setCenter(null, zoom);
+        }
+    },
+    
+    /**
+     * APIMethod: zoomIn
+     * 
+     * Parameters:
+     * zoom - {int}
+     */
+    zoomIn: function() {
+        this.zoomTo(this.getZoom() + 1);
+    },
+    
+    /**
+     * APIMethod: zoomOut
+     * 
+     * Parameters:
+     * zoom - {int}
+     */
+    zoomOut: function() {
+        this.zoomTo(this.getZoom() - 1);
+    },
+
+    /**
+     * APIMethod: zoomToExtent
+     * Zoom to the passed in bounds, recenter
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified bounds. Note that this may result in a zoom that does 
+     *     not exactly contain the entire extent.
+     *     Default is false.
+     * 
+     */
+    zoomToExtent: function(bounds, closest) {
+        var center = bounds.getCenterLonLat();
+        if (this.baseLayer.wrapDateLine) {
+            var maxExtent = this.getMaxExtent();
+
+            //fix straddling bounds (in the case of a bbox that straddles the 
+            // dateline, it's left and right boundaries will appear backwards. 
+            // we fix this by allowing a right value that is greater than the
+            // max value at the dateline -- this allows us to pass a valid 
+            // bounds to calculate zoom)
+            //
+            bounds = bounds.clone();
+            while (bounds.right < bounds.left) {
+                bounds.right += maxExtent.getWidth();
+            }
+            //if the bounds was straddling (see above), then the center point 
+            // we got from it was wrong. So we take our new bounds and ask it
+            // for the center. Because our new bounds is at least partially 
+            // outside the bounds of maxExtent, the new calculated center 
+            // might also be. We don't want to pass a bad center value to 
+            // setCenter, so we have it wrap itself across the date line.
+            //
+            center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
+        }
+        this.setCenter(center, this.getZoomForExtent(bounds, closest));
+    },
+
+    /** 
+     * APIMethod: zoomToMaxExtent
+     * Zoom to the full extent and recenter.
+     *
+     * Parameters:
+     * options - 
+     * 
+     * Allowed Options:
+     * restricted - {Boolean} True to zoom to restricted extent if it is 
+     *     set. Defaults to true.
+     */
+    zoomToMaxExtent: function(options) {
+        //restricted is true by default
+        var restricted = (options) ? options.restricted : true;
+
+        var maxExtent = this.getMaxExtent({
+            'restricted': restricted 
+        });
+        this.zoomToExtent(maxExtent);
+    },
+
+    /** 
+     * APIMethod: zoomToScale
+     * Zoom to a specified scale 
+     * 
+     * Parameters:
+     * scale - {float}
+     * closest - {Boolean} Find the zoom level that most closely fits the 
+     *     specified scale. Note that this may result in a zoom that does 
+     *     not exactly contain the entire extent.
+     *     Default is false.
+     * 
+     */
+    zoomToScale: function(scale, closest) {
+        var res = OpenLayers.Util.getResolutionFromScale(scale, 
+                                                         this.baseLayer.units);
+        var size = this.getSize();
+        var w_deg = size.w * res;
+        var h_deg = size.h * res;
+        var center = this.getCenter();
+
+        var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+                                           center.lat - h_deg / 2,
+                                           center.lon + w_deg / 2,
+                                           center.lat + h_deg / 2);
+        this.zoomToExtent(extent, closest);
+    },
+    
+  /********************************************************/
+  /*                                                      */
+  /*             Translation Functions                    */
+  /*                                                      */
+  /*      The following functions translate between       */
+  /*           LonLat, LayerPx, and ViewPortPx            */
+  /*                                                      */
+  /********************************************************/
+      
+  //
+  // TRANSLATION: LonLat <-> ViewPortPx
+  //
+
+    /**
+     * Method: getLonLatFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view 
+     *                       port <OpenLayers.Pixel>, translated into lon/lat
+     *                       by the current base layer.
+     */
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        var lonlat = null; 
+        if (this.baseLayer != null) {
+            lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
+        }
+        return lonlat;
+    },
+
+    /**
+     * APIMethod: getViewPortPxFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into view port 
+     *                      pixels by the current base layer.
+     */
+    getViewPortPxFromLonLat: function (lonlat) {
+        var px = null; 
+        if (this.baseLayer != null) {
+            px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
+        }
+        return px;
+    },
+
+    
+  //
+  // CONVENIENCE TRANSLATION FUNCTIONS FOR API
+  //
+
+    /**
+     * APIMethod: getLonLatFromPixel
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
+     *                       OpenLayers.Pixel, translated into lon/lat by the 
+     *                       current base layer
+     */
+    getLonLatFromPixel: function (px) {
+        return this.getLonLatFromViewPortPx(px);
+    },
+
+    /**
+     * APIMethod: getPixelFromLonLat
+     * Returns a pixel location given a map location.  The map location is
+     *     translated to an integer pixel location (in viewport pixel
+     *     coordinates) by the current base layer.
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>} A map location.
+     * 
+     * Returns: 
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the 
+     *     <OpenLayers.LonLat> translated into view port pixels by the current
+     *     base layer.
+     */
+    getPixelFromLonLat: function (lonlat) {
+        var px = this.getViewPortPxFromLonLat(lonlat);
+        px.x = Math.round(px.x);
+        px.y = Math.round(px.y);
+        return px;
+    },
+
+
+
+  //
+  // TRANSLATION: ViewPortPx <-> LayerPx
+  //
+
+    /**
+     * APIMethod: getViewPortPxFromLayerPx
+     * 
+     * Parameters:
+     * layerPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel 
+     *                      coordinates
+     */
+    getViewPortPxFromLayerPx:function(layerPx) {
+        var viewPortPx = null;
+        if (layerPx != null) {
+            var dX = parseInt(this.layerContainerDiv.style.left);
+            var dY = parseInt(this.layerContainerDiv.style.top);
+            viewPortPx = layerPx.add(dX, dY);            
+        }
+        return viewPortPx;
+    },
+    
+    /**
+     * APIMethod: getLayerPxFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel 
+     *                      coordinates
+     */
+    getLayerPxFromViewPortPx:function(viewPortPx) {
+        var layerPx = null;
+        if (viewPortPx != null) {
+            var dX = -parseInt(this.layerContainerDiv.style.left);
+            var dY = -parseInt(this.layerContainerDiv.style.top);
+            layerPx = viewPortPx.add(dX, dY);
+            if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
+                layerPx = null;
+            }
+        }
+        return layerPx;
+    },
+    
+  //
+  // TRANSLATION: LonLat <-> LayerPx
+  //
+
+    /**
+     * Method: getLonLatFromLayerPx
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>}
+     */
+    getLonLatFromLayerPx: function (px) {
+       //adjust for displacement of layerContainerDiv
+       px = this.getViewPortPxFromLayerPx(px);
+       return this.getLonLatFromViewPortPx(px);         
+    },
+    
+    /**
+     * APIMethod: getLayerPxFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>} lonlat
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into layer pixels 
+     *                      by the current base layer
+     */
+    getLayerPxFromLonLat: function (lonlat) {
+       //adjust for displacement of layerContainerDiv
+       var px = this.getPixelFromLonLat(lonlat);
+       return this.getLayerPxFromViewPortPx(px);         
+    },
+
+    CLASS_NAME: "OpenLayers.Map"
+});
+
+/**
+ * Constant: TILE_WIDTH
+ * {Integer} 256 Default tile width (unless otherwise specified)
+ */
+OpenLayers.Map.TILE_WIDTH = 256;
+/**
+ * Constant: TILE_HEIGHT
+ * {Integer} 256 Default tile height (unless otherwise specified)
+ */
+OpenLayers.Map.TILE_HEIGHT = 256;

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/Framed.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/Framed.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/Framed.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,342 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Anchored.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.Framed
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Popup.Anchored>
+ */
+OpenLayers.Popup.Framed =
+  OpenLayers.Class(OpenLayers.Popup.Anchored, {
+
+    /**
+     * Property: imageSrc
+     * {String} location of the image to be used as the popup frame
+     */
+    imageSrc: null,
+
+    /**
+     * Property: imageSize
+     * {<OpenLayers.Size>} Size (measured in pixels) of the image located
+     *     by the 'imageSrc' property.
+     */
+    imageSize: null,
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The image has some alpha and thus needs to use the alpha 
+     *     image hack. Note that setting this to true will have no noticeable
+     *     effect in FF or IE7 browsers, but will all but crush the ie6 
+     *     browser. 
+     *     Default is false.
+     */
+    isAlphaImage: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of different position blocks (Object/Hashs). Each block 
+     *     will be keyed by a two-character 'relativePosition' 
+     *     code string (ie "tl", "tr", "bl", "br"). Block properties are 
+     *     'offset', 'padding' (self-explanatory), and finally the 'blocks'
+     *     parameter, which is an array of the block objects. 
+     * 
+     *     Each block object must have 'size', 'anchor', and 'position' 
+     *     properties.
+     * 
+     *     Note that positionBlocks should never be modified at runtime.
+     */
+    positionBlocks: null,
+
+    /**
+     * Property: blocks
+     * {Array[Object]} Array of objects, each of which is one "block" of the 
+     *     popup. Each block has a 'div' and an 'image' property, both of 
+     *     which are DOMElements, and the latter of which is appended to the 
+     *     former. These are reused as the popup goes changing positions for
+     *     great economy and elegance.
+     */
+    blocks: null,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} We want the framed popup to work dynamically placed relative
+     *     to its anchor but also in just one fixed position. A well designed
+     *     framed popup will have the pixels and logic to display itself in 
+     *     any of the four relative positions, but (understandably), this will
+     *     not be the case for all of them. By setting this property to 'true', 
+     *     framed popup will not recalculate for the best placement each time
+     *     it's open, but will always open the same way. 
+     *     Note that if this is set to true, it is generally advisable to also
+     *     set the 'panIntoView' property to true so that the popup can be 
+     *     scrolled into view (since it will often be offscreen on open)
+     *     Default is false.
+     */
+    fixedRelativePosition: false,
+
+    /** 
+     * Constructor: OpenLayers.Popup.Framed
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * contentSize - {<OpenLayers.Size>}
+     * contentHTML - {String}
+     * anchor - {Object} Object to which we'll anchor the popup. Must expose 
+     *     a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>) 
+     *     (Note that this is generally an <OpenLayers.Icon>).
+     * closeBox - {Boolean}
+     * closeBoxCallback - {Function} Function to be called on closeBox click.
+     */
+    initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
+
+        if (this.fixedRelativePosition) {
+            //based on our decided relativePostion, set the current padding
+            // this keeps us from getting into trouble 
+            this.updateRelativePosition();
+            
+            //make calculateRelativePosition always return the specified
+            // fixed position.
+            this.calculateRelativePosition = function(px) {
+                return this.relativePosition;
+            };
+        }
+
+        this.contentDiv.style.position = "absolute";
+        this.contentDiv.style.zIndex = 1;
+
+        if (closeBox) {
+            this.closeDiv.style.zIndex = 1;
+        }
+
+        this.groupDiv.style.position = "absolute";
+        this.groupDiv.style.top = "0px";
+        this.groupDiv.style.left = "0px";
+        this.groupDiv.style.height = "100%";
+        this.groupDiv.style.width = "100%";
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        this.imageSrc = null;
+        this.imageSize = null;
+        this.isAlphaImage = null;
+
+        this.fixedRelativePosition = false;
+        this.positionBlocks = null;
+
+        //remove our blocks
+        for(var i = 0; i < this.blocks.length; i++) {
+            var block = this.blocks[i];
+
+            if (block.image) {
+                block.div.removeChild(block.image);
+            }
+            block.image = null;
+
+            if (block.div) {
+                this.groupDiv.removeChild(block.div);
+            }
+            block.div = null;
+        }
+        this.blocks = null;
+
+        OpenLayers.Popup.Anchored.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: setBackgroundColor
+     */
+    setBackgroundColor:function(color) {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the background color makes no sense. 
+    },
+
+    /**
+     * APIMethod: setBorder
+     */
+    setBorder:function() {
+        //does nothing since the framed popup's entire scheme is based on a 
+        // an image -- changing the popup's border makes no sense. 
+    },
+
+    /**
+     * Method: setOpacity
+     * Sets the opacity of the popup.
+     * 
+     * Parameters:
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
+     */
+    setOpacity:function(opacity) {
+        //does nothing since we suppose that we'll never apply an opacity
+        // to a framed popup
+    },
+
+    /**
+     * APIMethod: setSize
+     * Overridden here, because we need to update the blocks whenever the size
+     *     of the popup has changed.
+     * 
+     * Parameters:
+     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
+     *     contents div (in pixels).
+     */
+    setSize:function(contentSize) { 
+        OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
+
+        this.updateBlocks();
+    },
+
+    /**
+     * Method: updateRelativePosition
+     * When the relative position changes, we need to set the new padding 
+     *     BBOX on the popup, reposition the close div, and update the blocks.
+     */
+    updateRelativePosition: function() {
+
+        //update the padding
+        this.padding = this.positionBlocks[this.relativePosition].padding;
+
+        //update the position of our close box to new padding
+        if (this.closeDiv) {
+            // use the content div's css padding to determine if we should
+            //  padd the close div
+            var contentDivPadding = this.getContentDivPadding();
+
+            this.closeDiv.style.right = contentDivPadding.right + 
+                                        this.padding.right + "px";
+            this.closeDiv.style.top = contentDivPadding.top + 
+                                      this.padding.top + "px";
+        }
+
+        this.updateBlocks();
+    },
+
+    /** 
+     * Method: calculateNewPx
+     * Besides the standard offset as determined by the Anchored class, our 
+     *     Framed popups have a special 'offset' property for each of their 
+     *     positions, which is used to offset the popup relative to its anchor.
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} The the new px position of the popup on the screen
+     *     relative to the passed-in px.
+     */
+    calculateNewPx:function(px) {
+        var newPx = OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(
+            this, arguments
+        );
+
+        newPx = newPx.offset(this.positionBlocks[this.relativePosition].offset);
+
+        return newPx;
+    },
+
+    /**
+     * Method: createBlocks
+     */
+    createBlocks: function() {
+        this.blocks = [];
+
+        //since all positions contain the same number of blocks, we can 
+        // just pick the first position and use its blocks array to create
+        // our blocks array
+        var firstPosition = null;
+        for(var key in this.positionBlocks) {
+            firstPosition = key;
+            break;
+        }
+        
+        var position = this.positionBlocks[firstPosition];
+        for (var i = 0; i < position.blocks.length; i++) {
+
+            var block = {};
+            this.blocks.push(block);
+
+            var divId = this.id + '_FrameDecorationDiv_' + i;
+            block.div = OpenLayers.Util.createDiv(divId, 
+                null, null, null, "absolute", null, "hidden", null
+            );
+
+            var imgId = this.id + '_FrameDecorationImg_' + i;
+            var imageCreator = 
+                (this.isAlphaImage) ? OpenLayers.Util.createAlphaImageDiv
+                                    : OpenLayers.Util.createImage;
+
+            block.image = imageCreator(imgId, 
+                null, this.imageSize, this.imageSrc, 
+                "absolute", null, null, null
+            );
+
+            block.div.appendChild(block.image);
+            this.groupDiv.appendChild(block.div);
+        }
+    },
+
+    /**
+     * Method: updateBlocks
+     * Internal method, called on initialize and when the popup's relative
+     *     position has changed. This function takes care of re-positioning
+     *     the popup's blocks in their appropropriate places.
+     */
+    updateBlocks: function() {
+        if (!this.blocks) {
+            this.createBlocks();
+        }
+        
+        if (this.size && this.relativePosition) {
+            var position = this.positionBlocks[this.relativePosition];
+            for (var i = 0; i < position.blocks.length; i++) {
+    
+                var positionBlock = position.blocks[i];
+                var block = this.blocks[i];
+    
+                // adjust sizes
+                var l = positionBlock.anchor.left;
+                var b = positionBlock.anchor.bottom;
+                var r = positionBlock.anchor.right;
+                var t = positionBlock.anchor.top;
+    
+                //note that we use the isNaN() test here because if the 
+                // size object is initialized with a "auto" parameter, the 
+                // size constructor calls parseFloat() on the string, 
+                // which will turn it into NaN
+                //
+                var w = (isNaN(positionBlock.size.w)) ? this.size.w - (r + l) 
+                                                      : positionBlock.size.w;
+    
+                var h = (isNaN(positionBlock.size.h)) ? this.size.h - (b + t) 
+                                                      : positionBlock.size.h;
+    
+                block.div.style.width = (w < 0 ? 0 : w) + 'px';
+                block.div.style.height = (h < 0 ? 0 : h) + 'px';
+    
+                block.div.style.left = (l != null) ? l + 'px' : '';
+                block.div.style.bottom = (b != null) ? b + 'px' : '';
+                block.div.style.right = (r != null) ? r + 'px' : '';            
+                block.div.style.top = (t != null) ? t + 'px' : '';
+    
+                block.image.style.left = positionBlock.position.x + 'px';
+                block.image.style.top = positionBlock.position.y + 'px';
+            }
+    
+            this.contentDiv.style.left = this.padding.left + "px";
+            this.contentDiv.style.top = this.padding.top + "px";
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.Framed"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/FramedCloud.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/FramedCloud.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup/FramedCloud.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,230 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Popup/Framed.js
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.FramedCloud
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Popup.Framed>
+ */
+OpenLayers.Popup.FramedCloud = 
+  OpenLayers.Class(OpenLayers.Popup.Framed, {
+
+    /** 
+     * Property: contentDisplayClass
+     * {String} The CSS class of the popup content div.
+     */
+    contentDisplayClass: "olFramedCloudPopupContent",
+
+    /**
+     * APIProperty: autoSize
+     * {Boolean} Framed Cloud is autosizing by default.
+     */
+    autoSize: true,
+
+    /**
+     * APIProperty: panMapIfOutOfView
+     * {Boolean} Framed Cloud does pan into view by default.
+     */
+    panMapIfOutOfView: true,
+
+    /**
+     * APIProperty: imageSize
+     * {<OpenLayers.Size>}
+     */
+    imageSize: new OpenLayers.Size(676, 736),
+
+    /**
+     * APIProperty: isAlphaImage
+     * {Boolean} The FramedCloud does not use an alpha image (in honor of the 
+     *     good ie6 folk out there)
+     */
+    isAlphaImage: false,
+
+    /** 
+     * APIProperty: fixedRelativePosition
+     * {Boolean} The Framed Cloud popup works in just one fixed position.
+     */
+    fixedRelativePosition: false,
+
+    /**
+     * Property: positionBlocks
+     * {Object} Hash of differen position blocks, keyed by relativePosition
+     *     two-character code string (ie "tl", "tr", "bl", "br")
+     */
+    positionBlocks: {
+        "tl": {
+            'offset': new OpenLayers.Pixel(44, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 19),
+                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
+                    position: new OpenLayers.Pixel(0, -631)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 18),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -632)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 35),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(0, -688)
+                }
+            ]
+        },
+        "tr": {
+            'offset': new OpenLayers.Pixel(-45, 0),
+            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 19),
+                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
+                    position: new OpenLayers.Pixel(0, -631)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 19),
+                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
+                    position: new OpenLayers.Pixel(-638, -631)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 35),
+                    anchor: new OpenLayers.Bounds(0, 0, null, null),
+                    position: new OpenLayers.Pixel(-215, -687)
+                }
+            ]
+        },
+        "bl": {
+            'offset': new OpenLayers.Pixel(45, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 33),
+                    anchor: new OpenLayers.Bounds(null, null, 0, 0),
+                    position: new OpenLayers.Pixel(-101, -674)
+                }
+            ]
+        },
+        "br": {
+            'offset': new OpenLayers.Pixel(-44, 0),
+            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
+            'blocks': [
+                { // top-left
+                    size: new OpenLayers.Size('auto', 'auto'),
+                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
+                    position: new OpenLayers.Pixel(0, 0)
+                },
+                { //top-right
+                    size: new OpenLayers.Size(22, 'auto'),
+                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
+                    position: new OpenLayers.Pixel(-638, 0)
+                },
+                { //bottom-left
+                    size: new OpenLayers.Size('auto', 21),
+                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
+                    position: new OpenLayers.Pixel(0, -629)
+                },
+                { //bottom-right
+                    size: new OpenLayers.Size(22, 21),
+                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
+                    position: new OpenLayers.Pixel(-638, -629)
+                },
+                { // stem
+                    size: new OpenLayers.Size(81, 33),
+                    anchor: new OpenLayers.Bounds(0, null, null, 0),
+                    position: new OpenLayers.Pixel(-311, -674)
+                }
+            ]
+        }
+    },
+
+    /**
+     * APIProperty: minSize
+     * {<OpenLayers.Size>}
+     */
+    minSize: new OpenLayers.Size(105, 10),
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>}
+     */
+    maxSize: new OpenLayers.Size(600, 660),
+
+    /** 
+     * Constructor: OpenLayers.Popup.FramedCloud
+     * 
+     * Parameters:
+     * id - {String}
+     * lonlat - {<OpenLayers.LonLat>}
+     * contentSize - {<OpenLayers.Size>}
+     * contentHTML - {String}
+     * anchor - {Object} Object to which we'll anchor the popup. Must expose 
+     *     a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>) 
+     *     (Note that this is generally an <OpenLayers.Icon>).
+     * closeBox - {Boolean}
+     * closeBoxCallback - {Function} Function to be called on closeBox click.
+     */
+    initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox, 
+                        closeBoxCallback) {
+
+        this.imageSrc = OpenLayers.Util.getImagesLocation() + 'cloud-popup-relative.png';
+        OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments);
+        this.contentDiv.className = this.contentDisplayClass;
+    },
+
+    /** 
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Popup.Framed.prototype.destroy.apply(this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Popup.FramedCloud"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Popup.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,1051 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Class: OpenLayers.Popup
+ * A popup is a small div that can opened and closed on the map.
+ * Typically opened in response to clicking on a marker.  
+ * See <OpenLayers.Marker>.  Popup's don't require their own
+ * layer and are added the the map using the <OpenLayers.Map.addPopup>
+ * method.
+ *
+ * Example:
+ * (code)
+ * popup = new OpenLayers.Popup("chicken", 
+ *                    new OpenLayers.LonLat(5,40),
+ *                    new OpenLayers.Size(200,200),
+ *                    "example popup",
+ *                    true);
+ *       
+ * map.addPopup(popup);
+ * (end)
+ */
+OpenLayers.Popup = OpenLayers.Class({
+
+    /** 
+     * Property: events  
+     * {<OpenLayers.Events>} custom event manager 
+     */
+    events: null,
+    
+    /** Property: id
+     * {String} the unique identifier assigned to this popup.
+     */
+    id: "",
+
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} the position of this popup on the map
+     */
+    lonlat: null,
+
+    /** 
+     * Property: div 
+     * {DOMElement} the div that contains this popup.
+     */
+    div: null,
+
+    /** 
+     * Property: contentSize 
+     * {<OpenLayers.Size>} the width and height of the content.
+     */
+    contentSize: null,    
+
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} the width and height of the popup.
+     */
+    size: null,    
+
+    /** 
+     * Property: contentHTML 
+     * {String} An HTML string for this popup to display.
+     */
+    contentHTML: null,
+    
+    /** 
+     * Property: backgroundColor 
+     * {String} the background color used by the popup.
+     */
+    backgroundColor: "",
+    
+    /** 
+     * Property: opacity 
+     * {float} the opacity of this popup (between 0.0 and 1.0)
+     */
+    opacity: "",
+
+    /** 
+     * Property: border 
+     * {String} the border size of the popup.  (eg 2px)
+     */
+    border: "",
+    
+    /** 
+     * Property: contentDiv 
+     * {DOMElement} a reference to the element that holds the content of
+     *              the div.
+     */
+    contentDiv: null,
+    
+    /** 
+     * Property: groupDiv 
+     * {DOMElement} First and only child of 'div'. The group Div contains the
+     *     'contentDiv' and the 'closeDiv'.
+     */
+    groupDiv: null,
+
+    /** 
+     * Property: closeDiv
+     * {DOMElement} the optional closer image
+     */
+    closeDiv: null,
+
+    /** 
+     * APIProperty: autoSize
+     * {Boolean} Resize the popup to auto-fit the contents.
+     *     Default is false.
+     */
+    autoSize: false,
+
+    /**
+     * APIProperty: minSize
+     * {<OpenLayers.Size>} Minimum size allowed for the popup's contents.
+     */
+    minSize: null,
+
+    /**
+     * APIProperty: maxSize
+     * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
+     */
+    maxSize: null,
+
+    /** 
+     * Property: displayClass
+     * {String} The CSS class of the popup.
+     */
+    displayClass: "olPopup",
+
+    /** 
+     * Property: contentDisplayClass
+     * {String} The CSS class of the popup content div.
+     */
+    contentDisplayClass: "olPopupContent",
+
+    /** 
+     * Property: padding 
+     * {int or <OpenLayers.Bounds>} An extra opportunity to specify internal 
+     *     padding of the content div inside the popup. This was originally
+     *     confused with the css padding as specified in style.css's 
+     *     'olPopupContent' class. We would like to get rid of this altogether,
+     *     except that it does come in handy for the framed and anchoredbubble
+     *     popups, who need to maintain yet another barrier between their 
+     *     content and the outer border of the popup itself. 
+     * 
+     *     Note that in order to not break API, we must continue to support 
+     *     this property being set as an integer. Really, though, we'd like to 
+     *     have this specified as a Bounds object so that user can specify
+     *     distinct left, top, right, bottom paddings. With the 3.0 release
+     *     we can make this only a bounds.
+     */
+    padding: 0,
+
+    /** 
+     * Property: disableFirefoxOverflowHack
+     * {Boolean} The hack for overflow in Firefox causes all elements 
+     *     to be re-drawn, which causes Flash elements to be 
+     *     re-initialized, which is troublesome.
+     *     With this property the hack can be disabled.
+     */
+    disableFirefoxOverflowHack: false,
+
+    /**
+     * Method: fixPadding
+     * To be removed in 3.0, this function merely helps us to deal with the 
+     *     case where the user may have set an integer value for padding, 
+     *     instead of an <OpenLayers.Bounds> object.
+     */
+    fixPadding: function() {
+        if (typeof this.padding == "number") {
+            this.padding = new OpenLayers.Bounds(
+                this.padding, this.padding, this.padding, this.padding
+            );
+        }
+    },
+
+    /**
+     * APIProperty: panMapIfOutOfView
+     * {Boolean} When drawn, pan map such that the entire popup is visible in
+     *     the current viewport (if necessary).
+     *     Default is false.
+     */
+    panMapIfOutOfView: false,
+    
+    /**
+     * APIProperty: keepInMap 
+     * {Boolean} If panMapIfOutOfView is false, and this property is true, 
+     *     contrain the popup such that it always fits in the available map
+     *     space. By default, this is not set on the base class. If you are
+     *     creating popups that are near map edges and not allowing pannning,
+     *     and especially if you have a popup which has a
+     *     fixedRelativePosition, setting this to false may be a smart thing to
+     *     do. Subclasses may want to override this setting.
+     *   
+     *     Default is false.
+     */
+    keepInMap: false,
+
+    /**
+     * APIProperty: closeOnMove
+     * {Boolean} When map pans, close the popup.
+     *     Default is false.
+     */
+    closeOnMove: false,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
+     */
+    map: null,
+
+    /** 
+    * Constructor: OpenLayers.Popup
+    * Create a popup.
+    * 
+    * Parameters: 
+    * id - {String} a unqiue identifier for this popup.  If null is passed
+    *               an identifier will be automatically generated. 
+    * lonlat - {<OpenLayers.LonLat>}  The position on the map the popup will
+    *                                 be shown.
+    * contentSize - {<OpenLayers.Size>} The size of the content.
+    * contentHTML - {String}          An HTML string to display inside the   
+    *                                 popup.
+    * closeBox - {Boolean}            Whether to display a close box inside
+    *                                 the popup.
+    * closeBoxCallback - {Function}   Function to be called on closeBox click.
+    */
+    initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {
+        if (id == null) {
+            id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+        }
+
+        this.id = id;
+        this.lonlat = lonlat;
+
+        this.contentSize = (contentSize != null) ? contentSize 
+                                  : new OpenLayers.Size(
+                                                   OpenLayers.Popup.WIDTH,
+                                                   OpenLayers.Popup.HEIGHT);
+        if (contentHTML != null) { 
+             this.contentHTML = contentHTML;
+        }
+        this.backgroundColor = OpenLayers.Popup.COLOR;
+        this.opacity = OpenLayers.Popup.OPACITY;
+        this.border = OpenLayers.Popup.BORDER;
+
+        this.div = OpenLayers.Util.createDiv(this.id, null, null, 
+                                             null, null, null, "hidden");
+        this.div.className = this.displayClass;
+        
+        var groupDivId = this.id + "_GroupDiv";
+        this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, 
+                                                    null, "relative", null,
+                                                    "hidden");
+
+        var id = this.div.id + "_contentDiv";
+        this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), 
+                                                    null, "relative");
+        this.contentDiv.className = this.contentDisplayClass;
+        this.groupDiv.appendChild(this.contentDiv);
+        this.div.appendChild(this.groupDiv);
+
+        if (closeBox) {
+            this.addCloseBox(closeBoxCallback);
+        } 
+
+        this.registerEvents();
+    },
+
+    /** 
+     * Method: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+
+        this.id = null;
+        this.lonlat = null;
+        this.size = null;
+        this.contentHTML = null;
+        
+        this.backgroundColor = null;
+        this.opacity = null;
+        this.border = null;
+        
+        if (this.closeOnMove && this.map) {
+            this.map.events.unregister("movestart", this, this.hide);
+        }
+
+        this.events.destroy();
+        this.events = null;
+        
+        if (this.closeDiv) {
+            OpenLayers.Event.stopObservingElement(this.closeDiv); 
+            this.groupDiv.removeChild(this.closeDiv);
+        }
+        this.closeDiv = null;
+        
+        this.div.removeChild(this.groupDiv);
+        this.groupDiv = null;
+
+        if (this.map != null) {
+            this.map.removePopup(this);
+        }
+        this.map = null;
+        this.div = null;
+        
+        this.autoSize = null;
+        this.minSize = null;
+        this.maxSize = null;
+        this.padding = null;
+        this.panMapIfOutOfView = null;
+    },
+
+    /** 
+    * Method: draw
+    * Constructs the elements that make up the popup.
+    *
+    * Parameters:
+    * px - {<OpenLayers.Pixel>} the position the popup in pixels.
+    * 
+    * Returns:
+    * {DOMElement} Reference to a div that contains the drawn popup
+    */
+    draw: function(px) {
+        if (px == null) {
+            if ((this.lonlat != null) && (this.map != null)) {
+                px = this.map.getLayerPxFromLonLat(this.lonlat);
+            }
+        }
+
+        // this assumes that this.map already exists, which is okay because 
+        // this.draw is only called once the popup has been added to the map.
+        if (this.closeOnMove) {
+            this.map.events.register("movestart", this, this.hide);
+        }
+        
+        //listen to movestart, moveend to disable overflow (FF bug)
+        if (!this.disableFirefoxOverflowHack && OpenLayers.Util.getBrowserName() == 'firefox') {
+            this.map.events.register("movestart", this, function() {
+                var style = document.defaultView.getComputedStyle(
+                    this.contentDiv, null
+                );
+                var currentOverflow = style.getPropertyValue("overflow");
+                if (currentOverflow != "hidden") {
+                    this.contentDiv._oldOverflow = currentOverflow;
+                    this.contentDiv.style.overflow = "hidden";
+                }
+            });
+            this.map.events.register("moveend", this, function() {
+                var oldOverflow = this.contentDiv._oldOverflow;
+                if (oldOverflow) {
+                    this.contentDiv.style.overflow = oldOverflow;
+                    this.contentDiv._oldOverflow = null;
+                }
+            });
+        }
+
+        this.moveTo(px);
+        if (!this.autoSize && !this.size) {
+            this.setSize(this.contentSize);
+        }
+        this.setBackgroundColor();
+        this.setOpacity();
+        this.setBorder();
+        this.setContentHTML();
+        
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
+
+        return this.div;
+    },
+
+    /** 
+     * Method: updatePosition
+     * if the popup has a lonlat and its map members set, 
+     * then have it move itself to its proper position
+     */
+    updatePosition: function() {
+        if ((this.lonlat) && (this.map)) {
+            var px = this.map.getLayerPxFromLonLat(this.lonlat);
+            if (px) {
+                this.moveTo(px);           
+            }    
+        }
+    },
+
+    /**
+     * Method: moveTo
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} the top and left position of the popup div. 
+     */
+    moveTo: function(px) {
+        if ((px != null) && (this.div != null)) {
+            this.div.style.left = px.x + "px";
+            this.div.style.top = px.y + "px";
+        }
+    },
+
+    /**
+     * Method: visible
+     *
+     * Returns:      
+     * {Boolean} Boolean indicating whether or not the popup is visible
+     */
+    visible: function() {
+        return OpenLayers.Element.visible(this.div);
+    },
+
+    /**
+     * Method: toggle
+     * Toggles visibility of the popup.
+     */
+    toggle: function() {
+        if (this.visible()) {
+            this.hide();
+        } else {
+            this.show();
+        }
+    },
+
+    /**
+     * Method: show
+     * Makes the popup visible.
+     */
+    show: function() {
+        OpenLayers.Element.show(this.div);
+
+        if (this.panMapIfOutOfView) {
+            this.panIntoView();
+        }    
+    },
+
+    /**
+     * Method: hide
+     * Makes the popup invisible.
+     */
+    hide: function() {
+        OpenLayers.Element.hide(this.div);
+    },
+
+    /**
+     * Method: setSize
+     * Used to adjust the size of the popup. 
+     *
+     * Parameters:
+     * contentSize - {<OpenLayers.Size>} the new size for the popup's 
+     *     contents div (in pixels).
+     */
+    setSize:function(contentSize) { 
+        this.size = contentSize.clone(); 
+        
+        // if our contentDiv has a css 'padding' set on it by a stylesheet, we 
+        //  must add that to the desired "size". 
+        var contentDivPadding = this.getContentDivPadding();
+        var wPadding = contentDivPadding.left + contentDivPadding.right;
+        var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+
+        // take into account the popup's 'padding' property
+        this.fixPadding();
+        wPadding += this.padding.left + this.padding.right;
+        hPadding += this.padding.top + this.padding.bottom;
+
+        // make extra space for the close div
+        if (this.closeDiv) {
+            var closeDivWidth = parseInt(this.closeDiv.style.width);
+            wPadding += closeDivWidth + contentDivPadding.right;
+        }
+
+        //increase size of the main popup div to take into account the 
+        // users's desired padding and close div.        
+        this.size.w += wPadding;
+        this.size.h += hPadding;
+
+        //now if our browser is IE, we need to actually make the contents 
+        // div itself bigger to take its own padding into effect. this makes 
+        // me want to shoot someone, but so it goes.
+        if (OpenLayers.Util.getBrowserName() == "msie") {
+            this.contentSize.w += 
+                contentDivPadding.left + contentDivPadding.right;
+            this.contentSize.h += 
+                contentDivPadding.bottom + contentDivPadding.top;
+        }
+
+        if (this.div != null) {
+            this.div.style.width = this.size.w + "px";
+            this.div.style.height = this.size.h + "px";
+        }
+        if (this.contentDiv != null){
+            this.contentDiv.style.width = contentSize.w + "px";
+            this.contentDiv.style.height = contentSize.h + "px";
+        }
+    },  
+
+    /**
+     * APIMethod: updateSize
+     * Auto size the popup so that it precisely fits its contents (as 
+     *     determined by this.contentDiv.innerHTML). Popup size will, of
+     *     course, be limited by the available space on the current map
+     */
+    updateSize: function() {
+        
+        // determine actual render dimensions of the contents by putting its
+        // contents into a fake contentDiv (for the CSS) and then measuring it
+        var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" + 
+            this.contentDiv.innerHTML + 
+            "</div>";
+ 
+        var containerElement = (this.map) ? this.map.layerContainerDiv
+        								  : document.body;
+        var realSize = OpenLayers.Util.getRenderedDimensions(
+            preparedHTML, null,	{
+                displayClass: this.displayClass,
+                containerElement: containerElement
+            }
+        );
+
+        // is the "real" size of the div is safe to display in our map?
+        var safeSize = this.getSafeContentSize(realSize);
+
+        var newSize = null;
+        if (safeSize.equals(realSize)) {
+            //real size of content is small enough to fit on the map, 
+            // so we use real size.
+            newSize = realSize;
+
+        } else {
+
+            //make a new OL.Size object with the clipped dimensions 
+            // set or null if not clipped.
+            var fixedSize = new OpenLayers.Size();
+            fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
+            fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
+        
+            if (fixedSize.w && fixedSize.h) {
+                //content is too big in both directions, so we will use 
+                // max popup size (safeSize), knowing well that it will 
+                // overflow both ways.                
+                newSize = safeSize;
+            } else {
+                //content is clipped in only one direction, so we need to 
+                // run getRenderedDimensions() again with a fixed dimension
+                var clippedSize = OpenLayers.Util.getRenderedDimensions(
+                    preparedHTML, fixedSize, {
+                        displayClass: this.contentDisplayClass,
+                        containerElement: containerElement
+                    }
+                );
+                
+                //if the clipped size is still the same as the safeSize, 
+                // that means that our content must be fixed in the 
+                // offending direction. If overflow is 'auto', this means 
+                // we are going to have a scrollbar for sure, so we must 
+                // adjust for that.
+                //
+                var currentOverflow = OpenLayers.Element.getStyle(
+                    this.contentDiv, "overflow"
+                );
+                if ( (currentOverflow != "hidden") && 
+                     (clippedSize.equals(safeSize)) ) {
+                    var scrollBar = OpenLayers.Util.getScrollbarWidth();
+                    if (fixedSize.w) {
+                        clippedSize.h += scrollBar;
+                    } else {
+                        clippedSize.w += scrollBar;
+                    }
+                }
+                
+                newSize = this.getSafeContentSize(clippedSize);
+            }
+        }                        
+        this.setSize(newSize);     
+    },    
+
+    /**
+     * Method: setBackgroundColor
+     * Sets the background color of the popup.
+     *
+     * Parameters:
+     * color - {String} the background color.  eg "#FFBBBB"
+     */
+    setBackgroundColor:function(color) { 
+        if (color != undefined) {
+            this.backgroundColor = color; 
+        }
+        
+        if (this.div != null) {
+            this.div.style.backgroundColor = this.backgroundColor;
+        }
+    },  
+    
+    /**
+     * Method: setOpacity
+     * Sets the opacity of the popup.
+     * 
+     * Parameters:
+     * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).   
+     */
+    setOpacity:function(opacity) { 
+        if (opacity != undefined) {
+            this.opacity = opacity; 
+        }
+        
+        if (this.div != null) {
+            // for Mozilla and Safari
+            this.div.style.opacity = this.opacity;
+
+            // for IE
+            this.div.style.filter = 'alpha(opacity=' + this.opacity*100 + ')';
+        }
+    },  
+    
+    /**
+     * Method: setBorder
+     * Sets the border style of the popup.
+     *
+     * Parameters:
+     * border - {String} The border style value. eg 2px 
+     */
+    setBorder:function(border) { 
+        if (border != undefined) {
+            this.border = border;
+        }
+        
+        if (this.div != null) {
+            this.div.style.border = this.border;
+        }
+    },      
+    
+    /**
+     * Method: setContentHTML
+     * Allows the user to set the HTML content of the popup.
+     *
+     * Parameters:
+     * contentHTML - {String} HTML for the div.
+     */
+    setContentHTML:function(contentHTML) {
+
+        if (contentHTML != null) {
+            this.contentHTML = contentHTML;
+        }
+       
+        if ((this.contentDiv != null) && 
+            (this.contentHTML != null) &&
+            (this.contentHTML != this.contentDiv.innerHTML)) {
+       
+            this.contentDiv.innerHTML = this.contentHTML;
+       
+            if (this.autoSize) {
+                
+                //if popup has images, listen for when they finish
+                // loading and resize accordingly
+                this.registerImageListeners();
+
+                //auto size the popup to its current contents
+                this.updateSize();
+            }
+        }    
+
+    },
+    
+    /**
+     * Method: registerImageListeners
+     * Called when an image contained by the popup loaded. this function
+     *     updates the popup size, then unregisters the image load listener.
+     */   
+    registerImageListeners: function() { 
+
+        // As the images load, this function will call updateSize() to 
+        // resize the popup to fit the content div (which presumably is now
+        // bigger than when the image was not loaded).
+        // 
+        // If the 'panMapIfOutOfView' property is set, we will pan the newly
+        // resized popup back into view.
+        // 
+        // Note that this function, when called, will have 'popup' and 
+        // 'img' properties in the context.
+        //
+        var onImgLoad = function() {
+            
+            this.popup.updateSize();
+     
+            if ( this.popup.visible() && this.popup.panMapIfOutOfView ) {
+                this.popup.panIntoView();
+            }
+
+            OpenLayers.Event.stopObserving(
+                this.img, "load", this.img._onImageLoad
+            );
+    
+        };
+
+        //cycle through the images and if their size is 0x0, that means that 
+        // they haven't been loaded yet, so we attach the listener, which 
+        // will fire when the images finish loading and will resize the 
+        // popup accordingly to its new size.
+        var images = this.contentDiv.getElementsByTagName("img");
+        for (var i = 0, len = images.length; i < len; i++) {
+            var img = images[i];
+            if (img.width == 0 || img.height == 0) {
+
+                var context = {
+                    'popup': this,
+                    'img': img
+                };
+
+                //expando this function to the image itself before registering
+                // it. This way we can easily and properly unregister it.
+                img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);
+
+                OpenLayers.Event.observe(img, 'load', img._onImgLoad);
+            }    
+        } 
+    },
+
+    /**
+     * APIMethod: getSafeContentSize
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>} Desired size to make the popup.
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} A size to make the popup which is neither smaller
+     *     than the specified minimum size, nor bigger than the maximum 
+     *     size (which is calculated relative to the size of the viewport).
+     */
+    getSafeContentSize: function(size) {
+
+        var safeContentSize = size.clone();
+
+        // if our contentDiv has a css 'padding' set on it by a stylesheet, we 
+        //  must add that to the desired "size". 
+        var contentDivPadding = this.getContentDivPadding();
+        var wPadding = contentDivPadding.left + contentDivPadding.right;
+        var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+
+        // take into account the popup's 'padding' property
+        this.fixPadding();
+        wPadding += this.padding.left + this.padding.right;
+        hPadding += this.padding.top + this.padding.bottom;
+
+        if (this.closeDiv) {
+            var closeDivWidth = parseInt(this.closeDiv.style.width);
+            wPadding += closeDivWidth + contentDivPadding.right;
+        }
+
+        // prevent the popup from being smaller than a specified minimal size
+        if (this.minSize) {
+            safeContentSize.w = Math.max(safeContentSize.w, 
+                (this.minSize.w - wPadding));
+            safeContentSize.h = Math.max(safeContentSize.h, 
+                (this.minSize.h - hPadding));
+        }
+
+        // prevent the popup from being bigger than a specified maximum size
+        if (this.maxSize) {
+            safeContentSize.w = Math.min(safeContentSize.w, 
+                (this.maxSize.w - wPadding));
+            safeContentSize.h = Math.min(safeContentSize.h, 
+                (this.maxSize.h - hPadding));
+        }
+        
+        //make sure the desired size to set doesn't result in a popup that 
+        // is bigger than the map's viewport.
+        //
+        if (this.map && this.map.size) {
+            
+            var extraX = 0, extraY = 0;
+            if (this.keepInMap && !this.panMapIfOutOfView) {
+                var px = this.map.getPixelFromLonLat(this.lonlat);
+                switch (this.relativePosition) {
+                    case "tr":
+                        extraX = px.x;
+                        extraY = this.map.size.h - px.y;
+                        break;
+                    case "tl":
+                        extraX = this.map.size.w - px.x;
+                        extraY = this.map.size.h - px.y;
+                        break;
+                    case "bl":
+                        extraX = this.map.size.w - px.x;
+                        extraY = px.y;
+                        break;
+                    case "br":
+                        extraX = px.x;
+                        extraY = px.y;
+                        break;
+                    default:    
+                        extraX = px.x;
+                        extraY = this.map.size.h - px.y;
+                        break;
+                }
+            }    
+          
+            var maxY = this.map.size.h - 
+                this.map.paddingForPopups.top - 
+                this.map.paddingForPopups.bottom - 
+                hPadding - extraY;
+            
+            var maxX = this.map.size.w - 
+                this.map.paddingForPopups.left - 
+                this.map.paddingForPopups.right - 
+                wPadding - extraX;
+            
+            safeContentSize.w = Math.min(safeContentSize.w, maxX);
+            safeContentSize.h = Math.min(safeContentSize.h, maxY);
+        }
+        
+        return safeContentSize;
+    },
+    
+    /**
+     * Method: getContentDivPadding
+     * Glorious, oh glorious hack in order to determine the css 'padding' of 
+     *     the contentDiv. IE/Opera return null here unless we actually add the 
+     *     popup's main 'div' element (which contains contentDiv) to the DOM. 
+     *     So we make it invisible and then add it to the document temporarily. 
+     *
+     *     Once we've taken the padding readings we need, we then remove it 
+     *     from the DOM (it will actually get added to the DOM in 
+     *     Map.js's addPopup)
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getContentDivPadding: function() {
+
+        //use cached value if we have it
+        var contentDivPadding = this._contentDivPadding;
+        if (!contentDivPadding) {
+
+        	if (this.div.parentNode == null) {
+	        	//make the div invisible and add it to the page        
+	            this.div.style.display = "none";
+	            document.body.appendChild(this.div);
+	    	}
+	            
+            //read the padding settings from css, put them in an OL.Bounds        
+            contentDivPadding = new OpenLayers.Bounds(
+                OpenLayers.Element.getStyle(this.contentDiv, "padding-left"),
+                OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"),
+                OpenLayers.Element.getStyle(this.contentDiv, "padding-right"),
+                OpenLayers.Element.getStyle(this.contentDiv, "padding-top")
+            );
+    
+            //cache the value
+            this._contentDivPadding = contentDivPadding;
+
+            if (this.div.parentNode == document.body) {
+	            //remove the div from the page and make it visible again
+	            document.body.removeChild(this.div);
+	            this.div.style.display = "";
+            }
+        }
+        return contentDivPadding;
+    },
+
+    /**
+     * Method: addCloseBox
+     * 
+     * Parameters:
+     * callback - {Function} The callback to be called when the close button
+     *     is clicked.
+     */
+    addCloseBox: function(callback) {
+
+        this.closeDiv = OpenLayers.Util.createDiv(
+            this.id + "_close", null, new OpenLayers.Size(17, 17)
+        );
+        this.closeDiv.className = "olPopupCloseBox"; 
+        
+        // use the content div's css padding to determine if we should
+        //  padd the close div
+        var contentDivPadding = this.getContentDivPadding();
+         
+        this.closeDiv.style.right = contentDivPadding.right + "px";
+        this.closeDiv.style.top = contentDivPadding.top + "px";
+        this.groupDiv.appendChild(this.closeDiv);
+
+        var closePopup = callback || function(e) {
+            this.hide();
+            OpenLayers.Event.stop(e);
+        };
+        OpenLayers.Event.observe(this.closeDiv, "click", 
+                OpenLayers.Function.bindAsEventListener(closePopup, this));
+    },
+
+    /**
+     * Method: panIntoView
+     * Pans the map such that the popup is totaly viewable (if necessary)
+     */
+    panIntoView: function() {
+        
+        var mapSize = this.map.getSize();
+    
+        //start with the top left corner of the popup, in px, 
+        // relative to the viewport
+        var origTL = this.map.getViewPortPxFromLayerPx( new OpenLayers.Pixel(
+            parseInt(this.div.style.left),
+            parseInt(this.div.style.top)
+        ));
+        var newTL = origTL.clone();
+    
+        //new left (compare to margins, using this.size to calculate right)
+        if (origTL.x < this.map.paddingForPopups.left) {
+            newTL.x = this.map.paddingForPopups.left;
+        } else 
+        if ( (origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {
+            newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;
+        }
+        
+        //new top (compare to margins, using this.size to calculate bottom)
+        if (origTL.y < this.map.paddingForPopups.top) {
+            newTL.y = this.map.paddingForPopups.top;
+        } else 
+        if ( (origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {
+            newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;
+        }
+        
+        var dx = origTL.x - newTL.x;
+        var dy = origTL.y - newTL.y;
+        
+        this.map.pan(dx, dy);
+    },
+
+    /** 
+     * Method: registerEvents
+     * Registers events on the popup.
+     *
+     * Do this in a separate function so that subclasses can 
+     *   choose to override it if they wish to deal differently
+     *   with mouse events
+     * 
+     *   Note in the following handler functions that some special
+     *    care is needed to deal correctly with mousing and popups. 
+     *   
+     *   Because the user might select the zoom-rectangle option and
+     *    then drag it over a popup, we need a safe way to allow the
+     *    mousemove and mouseup events to pass through the popup when
+     *    they are initiated from outside.
+     * 
+     *   Otherwise, we want to essentially kill the event propagation
+     *    for all other events, though we have to do so carefully, 
+     *    without disabling basic html functionality, like clicking on 
+     *    hyperlinks or drag-selecting text.
+     */
+     registerEvents:function() {
+        this.events = new OpenLayers.Events(this, this.div, null, true);
+
+        this.events.on({
+            "mousedown": this.onmousedown,
+            "mousemove": this.onmousemove,
+            "mouseup": this.onmouseup,
+            "click": this.onclick,
+            "mouseout": this.onmouseout,
+            "dblclick": this.ondblclick,
+            scope: this
+        });
+        
+     },
+
+    /** 
+     * Method: onmousedown 
+     * When mouse goes down within the popup, make a note of
+     *   it locally, and then do not propagate the mousedown 
+     *   (but do so safely so that user can select text inside)
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    onmousedown: function (evt) {
+        this.mousedown = true;
+        OpenLayers.Event.stop(evt, true);
+    },
+
+    /** 
+     * Method: onmousemove
+     * If the drag was started within the popup, then 
+     *   do not propagate the mousemove (but do so safely
+     *   so that user can select text inside)
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    onmousemove: function (evt) {
+        if (this.mousedown) {
+            OpenLayers.Event.stop(evt, true);
+        }
+    },
+
+    /** 
+     * Method: onmouseup
+     * When mouse comes up within the popup, after going down 
+     *   in it, reset the flag, and then (once again) do not 
+     *   propagate the event, but do so safely so that user can 
+     *   select text inside
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    onmouseup: function (evt) {
+        if (this.mousedown) {
+            this.mousedown = false;
+            OpenLayers.Event.stop(evt, true);
+        }
+    },
+
+    /**
+     * Method: onclick
+     * Ignore clicks, but allowing default browser handling
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    onclick: function (evt) {
+        OpenLayers.Event.stop(evt, true);
+    },
+
+    /** 
+     * Method: onmouseout
+     * When mouse goes out of the popup set the flag to false so that
+     *   if they let go and then drag back in, we won't be confused.
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    onmouseout: function (evt) {
+        this.mousedown = false;
+    },
+    
+    /** 
+     * Method: ondblclick
+     * Ignore double-clicks, but allowing default browser handling
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    ondblclick: function (evt) {
+        OpenLayers.Event.stop(evt, true);
+    },
+
+    CLASS_NAME: "OpenLayers.Popup"
+});
+
+OpenLayers.Popup.WIDTH = 200;
+OpenLayers.Popup.HEIGHT = 200;
+OpenLayers.Popup.COLOR = "white";
+OpenLayers.Popup.OPACITY = 1;
+OpenLayers.Popup.BORDER = "0px";

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Projection.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Projection.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Projection.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,177 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Projection
+ * Class for coordinate transforms between coordinate systems.
+ *     Depends on the proj4js library. If proj4js is not available, 
+ *     then this is just an empty stub.
+ */
+OpenLayers.Projection = OpenLayers.Class({
+
+    /**
+     * Property: proj
+     * {Object} Proj4js.Proj instance.
+     */
+    proj: null,
+    
+    /**
+     * Property: projCode
+     * {String}
+     */
+    projCode: null,
+
+    /**
+     * Constructor: OpenLayers.Projection
+     * This class offers several methods for interacting with a wrapped 
+     *     pro4js projection object. 
+     *
+     * Parameters:
+     * projCode - {String} A string identifying the Well Known Identifier for
+     *    the projection.
+     * options - {Object} An optional object to set additional properties
+     *     on the layer.
+     *
+     * Returns:
+     * {<OpenLayers.Projection>} A projection object.
+     */
+    initialize: function(projCode, options) {
+        OpenLayers.Util.extend(this, options);
+        this.projCode = projCode;
+        if (window.Proj4js) {
+            this.proj = new Proj4js.Proj(projCode);
+        }
+    },
+    
+    /**
+     * APIMethod: getCode
+     * Get the string SRS code.
+     *
+     * Returns:
+     * {String} The SRS code.
+     */
+    getCode: function() {
+        return this.proj ? this.proj.srsCode : this.projCode;
+    },
+   
+    /**
+     * APIMethod: getUnits
+     * Get the units string for the projection -- returns null if 
+     *     proj4js is not available.
+     *
+     * Returns:
+     * {String} The units abbreviation.
+     */
+    getUnits: function() {
+        return this.proj ? this.proj.units : null;
+    },
+
+    /**
+     * Method: toString
+     * Convert projection to string (getCode wrapper).
+     *
+     * Returns:
+     * {String} The projection code.
+     */
+    toString: function() {
+        return this.getCode();
+    },
+
+    /**
+     * Method: equals
+     * Test equality of two projection instances.  Determines equality based
+     *     soley on the projection code.
+     *
+     * Returns:
+     * {Boolean} The two projections are equivalent.
+     */
+    equals: function(projection) {
+        if (projection && projection.getCode) {
+            return this.getCode() == projection.getCode();
+        } else {
+            return false;
+        }    
+    },
+
+    /* Method: destroy
+     * Destroy projection object.
+     */
+    destroy: function() {
+        delete this.proj;
+        delete this.projCode;
+    },
+    
+    CLASS_NAME: "OpenLayers.Projection" 
+});     
+
+/**
+ * Property: transforms
+ * Transforms is an object, with from properties, each of which may
+ * have a to property. This allows you to define projections without 
+ * requiring support for proj4js to be included.
+ *
+ * This object has keys which correspond to a 'source' projection object.  The
+ * keys should be strings, corresponding to the projection.getCode() value.
+ * Each source projection object should have a set of destination projection
+ * keys included in the object. 
+ * 
+ * Each value in the destination object should be a transformation function,
+ * where the function is expected to be passed an object with a .x and a .y
+ * property.  The function should return the object, with the .x and .y
+ * transformed according to the transformation function.
+ *
+ * Note - Properties on this object should not be set directly.  To add a
+ *     transform method to this object, use the <addTransform> method.  For an
+ *     example of usage, see the OpenLayers.Layer.SphericalMercator file.
+ */
+OpenLayers.Projection.transforms = {};
+
+/**
+ * APIMethod: addTransform
+ * Set a custom transform method between two projections.  Use this method in
+ *     cases where the proj4js lib is not available or where custom projections
+ *     need to be handled.
+ *
+ * Parameters:
+ * from - {String} The code for the source projection
+ * to - {String} the code for the destination projection
+ * method - {Function} A function that takes a point as an argument and
+ *     transforms that point from the source to the destination projection
+ *     in place.  The original point should be modified.
+ */
+OpenLayers.Projection.addTransform = function(from, to, method) {
+    if(!OpenLayers.Projection.transforms[from]) {
+        OpenLayers.Projection.transforms[from] = {};
+    }
+    OpenLayers.Projection.transforms[from][to] = method;
+};
+
+/**
+ * APIMethod: transform
+ * Transform a point coordinate from one projection to another.  Note that
+ *     the input point is transformed in place.
+ * 
+ * Parameters:
+ * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
+ *     properties representing coordinates in those dimensions.
+ * sourceProj - {OpenLayers.Projection} Source map coordinate system
+ * destProj - {OpenLayers.Projection} Destination map coordinate system
+ *
+ * Returns:
+ * point - {object} A transformed coordinate.  The original point is modified.
+ */
+OpenLayers.Projection.transform = function(point, source, dest) {
+    if (source.proj && dest.proj) {
+        point = Proj4js.transform(source.proj, dest.proj, point);
+    } else if (source && dest && 
+               OpenLayers.Projection.transforms[source.getCode()] && 
+               OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
+        OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point); 
+    }
+    return point;
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/HTTP.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/HTTP.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/HTTP.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,521 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.HTTP
+ * A basic HTTP protocol for vector layers.  Create a new instance with the
+ *     <OpenLayers.Protocol.HTTP> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
+
+    /**
+     * Property: url
+     * {String} Service URL, read-only, set through the options
+     *     passed to constructor.
+     */
+    url: null,
+
+    /**
+     * Property: headers
+     * {Object} HTTP request headers, read-only, set through the options
+     *     passed to the constructor,
+     *     Example: {'Content-Type': 'plain/text'}
+     */
+    headers: null,
+
+    /**
+     * Property: params
+     * {Object} Parameters of GET requests, read-only, set through the options
+     *     passed to the constructor,
+     *     Example: {'bbox': '5,5,5,5'}
+     */
+    params: null,
+    
+    /**
+     * Property: callback
+     * {Object} Function to be called when the <read>, <create>,
+     *     <update>, <delete> or <commit> operation completes, read-only,
+     *     set through the options passed to the constructor.
+     */
+    callback: null,
+
+    /**
+     * Property: scope
+     * {Object} Callback execution scope, read-only, set through the
+     *     options passed to the constructor.
+     */
+    scope: null,
+
+    /**
+     * Property: readWithPOST
+     * {Boolean} true if read operations are done with POST requests
+     *     instead of GET, defaults to false.
+     */
+    readWithPOST: false,
+
+    /**
+     * Constructor: OpenLayers.Protocol.HTTP
+     * A class for giving layers generic HTTP protocol.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options include:
+     * url - {String}
+     * headers - {Object} 
+     * params - {Object}
+     * format - {<OpenLayers.Format>}
+     * callback - {Function}
+     * scope - {Object}
+     */
+    initialize: function(options) {
+        this.params = {};
+        this.headers = {};
+        OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        this.params = null;
+        this.headers = null;
+        OpenLayers.Protocol.prototype.destroy.apply(this);
+    },
+   
+    /**
+     * Method: createCallback
+     * Returns a function that applies the given public method with resp and
+     *     options arguments.
+     *
+     * Parameters:
+     * method - {Function} The method to be applied by the callback.
+     * response - {<OpenLayers.Protocol.Response>} The protocol response object.
+     * options - {Object} Options sent to the protocol method (read, create,
+     *     update, or delete).
+     */
+    createCallback: function(method, response, options) {
+        return OpenLayers.Function.bind(function() {
+            method.apply(this, [response, options]);
+        }, this);
+    },
+
+    /**
+     * APIMethod: read
+     * Construct a request for reading new features.
+     *
+     * Parameters:
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Valid options:
+     * url - {String} Url for the request.
+     * params - {Object} Parameters to get serialized as a query string.
+     * headers - {Object} Headers to be set on the request.
+     * filter - {<OpenLayers.Filter.BBOX>} If a bbox filter is sent, it will be
+     *     serialized according to the OpenSearch Geo extension
+     *     (bbox=minx,miny,maxx,maxy).  Note that a BBOX filter as the child
+     *     of a logical filter will not be serialized.
+     * readWithPOST - {Boolean} If the request should be done with POST.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
+     *     references the HTTP request, this object is also passed to the
+     *     callback function when the request completes, its "features" property
+     *     is then populated with the the features received from the server.
+     */
+    read: function(options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+        var readWithPOST = (options.readWithPOST !== undefined) ?
+                           options.readWithPOST : this.readWithPOST;
+        var resp = new OpenLayers.Protocol.Response({requestType: "read"});
+
+        if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
+            if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
+                options.params = OpenLayers.Util.extend(options.params, {
+                    bbox: options.filter.value.toArray()
+                });
+            }
+        }
+
+        if(readWithPOST) {
+            resp.priv = OpenLayers.Request.POST({
+                url: options.url,
+                callback: this.createCallback(this.handleRead, resp, options),
+                data: OpenLayers.Util.getParameterString(options.params),
+                headers: {
+                    "Content-Type": "application/x-www-form-urlencoded"
+                }
+            });
+        } else {
+            resp.priv = OpenLayers.Request.GET({
+                url: options.url,
+                callback: this.createCallback(this.handleRead, resp, options),
+                params: options.params,
+                headers: options.headers
+            });
+        }
+
+        return resp;
+    },
+
+    /**
+     * Method: handleRead
+     * Individual callbacks are created for read, create and update, should
+     *     a subclass need to override each one separately.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     the user callback.
+     * options - {Object} The user options passed to the read call.
+     */
+    handleRead: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+    
+    /**
+     * APIMethod: create
+     * Construct a request for writing newly created features.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes, its "features" property is then populated with the
+     *     the features received from the server.
+     */
+    create: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: features,
+            requestType: "create"
+        });
+
+        resp.priv = OpenLayers.Request.POST({
+            url: options.url,
+            callback: this.createCallback(this.handleCreate, resp, options),
+            headers: options.headers,
+            data: this.format.write(features)
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleCreate
+     * Called the the request issued by <create> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the create call.
+     */
+    handleCreate: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * APIMethod: update
+     * Construct a request updating modified feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes, its "features" property is then populated with the
+     *     the feature received from the server.
+     */
+    update: function(feature, options) {
+        var url = options.url || feature.url || this.options.url;
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: feature,
+            requestType: "update"
+        });
+
+        resp.priv = OpenLayers.Request.PUT({
+            url: url,
+            callback: this.createCallback(this.handleUpdate, resp, options),
+            headers: options.headers,
+            data: this.format.write(feature)
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleUpdate
+     * Called the the request issued by <update> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the update call.
+     */
+    handleUpdate: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * APIMethod: delete
+     * Construct a request deleting a removed feature.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *     This object is modified and should not be reused.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *     object, whose "priv" property references the HTTP request, this 
+     *     object is also passed to the callback function when the request
+     *     completes.
+     */
+    "delete": function(feature, options) {
+        var url = options.url || feature.url || this.options.url;
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = new OpenLayers.Protocol.Response({
+            reqFeatures: feature,
+            requestType: "delete"
+        });
+
+        resp.priv = OpenLayers.Request.DELETE({
+            url: url,
+            callback: this.createCallback(this.handleDelete, resp, options),
+            headers: options.headers
+        });
+
+        return resp;
+    },
+
+    /**
+     * Method: handleDelete
+     * Called the the request issued by <delete> is complete.  May be overridden
+     *     by subclasses.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the delete call.
+     */
+    handleDelete: function(resp, options) {
+        this.handleResponse(resp, options);
+    },
+
+    /**
+     * Method: handleResponse
+     * Called by CRUD specific handlers.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+     *     any user callback.
+     * options - {Object} The user options passed to the create, read, update,
+     *     or delete call.
+     */
+    handleResponse: function(resp, options) {
+        var request = resp.priv;
+        if(options.callback) {
+            if(request.status >= 200 && request.status < 300) {
+                // success
+                if(resp.requestType != "delete") {
+                    resp.features = this.parseFeatures(request);
+                }
+                resp.code = OpenLayers.Protocol.Response.SUCCESS;
+            } else {
+                // failure
+                resp.code = OpenLayers.Protocol.Response.FAILURE;
+            }
+            options.callback.call(options.scope, resp);
+        }
+    },
+
+    /**
+     * Method: parseFeatures
+     * Read HTTP response body and return features.
+     *
+     * Parameters:
+     * request - {XMLHttpRequest} The request object
+     *
+     * Returns:
+     * {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>} Array of features or a single feature.
+     */
+    parseFeatures: function(request) {
+        var doc = request.responseXML;
+        if (!doc || !doc.documentElement) {
+            doc = request.responseText;
+        }
+        if (!doc || doc.length <= 0) {
+            return null;
+        }
+        return this.format.read(doc);
+    },
+
+    /**
+     * APIMethod: commit
+     * Iterate over each feature and take action based on the feature state.
+     *     Possible actions are create, update and delete.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})}
+     * options - {Object} Optional object for setting up intermediate commit
+     *     callbacks.
+     *
+     * Valid options:
+     * create - {Object} Optional object to be passed to the <create> method.
+     * update - {Object} Optional object to be passed to the <update> method.
+     * delete - {Object} Optional object to be passed to the <delete> method.
+     * callback - {Function} Optional function to be called when the commit
+     *     is complete.
+     * scope - {Object} Optional object to be set as the scope of the callback.
+     *
+     * Returns:
+     * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
+     *     one per request made to the server, each object's "priv" property
+     *     references the corresponding HTTP request.
+     */
+    commit: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+        var resp = [], nResponses = 0;
+        
+        // Divide up features before issuing any requests.  This properly
+        // counts requests in the event that any responses come in before
+        // all requests have been issued.
+        var types = {};
+        types[OpenLayers.State.INSERT] = [];
+        types[OpenLayers.State.UPDATE] = [];
+        types[OpenLayers.State.DELETE] = [];
+        var feature, list, requestFeatures = [];
+        for(var i=0, len=features.length; i<len; ++i) {
+            feature = features[i];
+            list = types[feature.state];
+            if(list) {
+                list.push(feature);
+                requestFeatures.push(feature); 
+            }
+        }
+        // tally up number of requests
+        var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
+            types[OpenLayers.State.UPDATE].length +
+            types[OpenLayers.State.DELETE].length;
+        
+        // This response will be sent to the final callback after all the others
+        // have been fired.
+        var success = true;
+        var finalResponse = new OpenLayers.Protocol.Response({
+            reqFeatures: requestFeatures        
+        });
+        
+        function insertCallback(response) {
+            var len = response.features ? response.features.length : 0;
+            var fids = new Array(len);
+            for(var i=0; i<len; ++i) {
+                fids[i] = response.features[i].fid;
+            }   
+            finalResponse.insertIds = fids;
+            callback.apply(this, [response]);
+        }
+ 
+        function callback(response) {
+            this.callUserCallback(response, options);
+            success = success && response.success();
+            nResponses++;
+            if (nResponses >= nRequests) {
+                if (options.callback) {
+                    finalResponse.code = success ? 
+                        OpenLayers.Protocol.Response.SUCCESS :
+                        OpenLayers.Protocol.Response.FAILURE;
+                    options.callback.apply(options.scope, [finalResponse]);
+                }    
+            }
+        }
+
+        // start issuing requests
+        var queue = types[OpenLayers.State.INSERT];
+        if(queue.length > 0) {
+            resp.push(this.create(
+                queue, OpenLayers.Util.applyDefaults(
+                    {callback: insertCallback, scope: this}, options.create
+                )
+            ));
+        }
+        queue = types[OpenLayers.State.UPDATE];
+        for(var i=queue.length-1; i>=0; --i) {
+            resp.push(this.update(
+                queue[i], OpenLayers.Util.applyDefaults(
+                    {callback: callback, scope: this}, options.update
+                ))
+            );
+        }
+        queue = types[OpenLayers.State.DELETE];
+        for(var i=queue.length-1; i>=0; --i) {
+            resp.push(this["delete"](
+                queue[i], OpenLayers.Util.applyDefaults(
+                    {callback: callback, scope: this}, options["delete"]
+                ))
+            );
+        }
+        return resp;
+    },
+
+    /**
+     * APIMethod: abort
+     * Abort an ongoing request, the response object passed to
+     * this method must come from this HTTP protocol (as a result
+     * of a create, read, update, delete or commit operation).
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>}
+     */
+    abort: function(response) {
+        if (response) {
+            response.priv.abort();
+        }
+    },
+
+    /**
+     * Method: callUserCallback
+     * This method is used from within the commit method each time an
+     *     an HTTP response is received from the server, it is responsible
+     *     for calling the user-supplied callbacks.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>}
+     * options - {Object} The map of options passed to the commit call.
+     */
+    callUserCallback: function(resp, options) {
+        var opt = options[resp.requestType];
+        if(opt && opt.callback) {
+            opt.callback.call(opt.scope, resp);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Protocol.HTTP" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL/Gears.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL/Gears.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL/Gears.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,559 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires Gears/gears_init.js
+ * @requires OpenLayers/Protocol/SQL.js
+ * @requires OpenLayers/Format/JSON.js
+ * @requires OpenLayers/Format/WKT.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.SQL.Gears
+ * This Protocol stores feature in the browser via the Gears Database module 
+ * <http://code.google.com/apis/gears/api_database.html>.
+ *
+ * The main advantage is that all the read, create, update and delete operations 
+ * can be done offline.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol.SQL>
+ */
+OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, {
+
+    /**
+     * Property: FID_PREFIX
+     * {String}
+     */
+    FID_PREFIX: '__gears_fid__',
+
+    /**
+     * Property: NULL_GEOMETRY
+     * {String}
+     */
+    NULL_GEOMETRY: '__gears_null_geometry__',
+
+    /**
+     * Property: NULL_FEATURE_STATE
+     * {String}
+     */
+    NULL_FEATURE_STATE: '__gears_null_feature_state__',
+
+    /**
+     * Property: jsonParser
+     * {<OpenLayers.Format.JSON>}
+     */
+    jsonParser: null,
+
+    /**
+     * Property: wktParser
+     * {<OpenLayers.Format.WKT>}
+     */
+    wktParser: null,
+
+    /**
+     * Property: fidRegExp
+     * {RegExp} Regular expression to know whether a feature was
+     *      created in offline mode.
+     */
+    fidRegExp: null,
+
+    /**
+     * Property: saveFeatureState
+     * {Boolean} Whether to save the feature state (<OpenLayers.State>)
+     *      into the database, defaults to true.
+     */    
+    saveFeatureState: true,
+
+    /**
+     * Property: typeOfFid
+     * {String} The type of the feature identifier, either "number" or
+     *      "string", defaults to "string".
+     */
+    typeOfFid: "string",
+
+    /**
+     * Property: db
+     * {GearsDatabase}
+     */
+    db: null,
+
+    /**
+     * Constructor: OpenLayers.Protocol.SQL.Gears
+     */
+    initialize: function(options) {
+        if (!this.supported()) {
+            return;
+        }
+        OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]);
+        this.jsonParser = new OpenLayers.Format.JSON();
+        this.wktParser = new OpenLayers.Format.WKT();
+
+        this.fidRegExp = new RegExp('^' + this.FID_PREFIX);
+        this.initializeDatabase();
+
+        
+    },
+
+    /**
+     * Method: initializeDatabase
+     */
+    initializeDatabase: function() {
+        this.db = google.gears.factory.create('beta.database');
+        this.db.open(this.databaseName);
+        this.db.execute(
+            "CREATE TABLE IF NOT EXISTS " + this.tableName +
+            " (fid TEXT UNIQUE, geometry TEXT, properties TEXT," +
+            "  state TEXT)");
+   },
+
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        this.db.close();
+        this.db = null;
+
+        this.jsonParser = null;
+        this.wktParser = null;
+
+        OpenLayers.Protocol.SQL.prototype.destroy.apply(this);
+    },
+
+    /**
+     * APIMethod: supported
+     * Determine whether a browser supports Gears
+     *
+     * Returns:
+     * {Boolean} The browser supports Gears
+     */
+    supported: function() {
+        return !!(window.google && google.gears);
+    },
+
+    /**
+     * APIMethod: read
+     * Read all features from the database and return a
+     * <OpenLayers.Protocol.Response> instance. If the options parameter
+     * contains a callback attribute, the function is called with the response
+     * as a parameter.
+     *
+     * Parameters:
+     * options - {Object} Optional object for configuring the request; it
+     *      can have the {Boolean} property "noFeatureStateReset" which
+     *      specifies if the state of features read from the Gears
+     *      database must be reset to null, if "noFeatureStateReset"
+     *      is undefined or false then each feature's state is reset
+     *      to null, if "noFeatureStateReset" is true the feature state
+     *      is preserved.
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *      object.
+     */
+    read: function(options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var feature, features = [];
+        var rs = this.db.execute("SELECT * FROM " + this.tableName);
+        while (rs.isValidRow()) {
+            feature = this.unfreezeFeature(rs);
+            if (this.evaluateFilter(feature, options.filter)) {
+                if (!options.noFeatureStateReset) {
+                    feature.state = null;
+                }
+                features.push(feature);
+            }
+            rs.next();
+        }
+        rs.close();
+
+        var resp = new OpenLayers.Protocol.Response({
+            code: OpenLayers.Protocol.Response.SUCCESS,
+            requestType: "read",
+            features: features
+        });
+
+        if (options && options.callback) {
+            options.callback.call(options.scope, resp);
+        }
+
+        return resp;
+    },
+
+    /**
+     * Method: unfreezeFeature
+     *
+     * Parameters:
+     * row - {ResultSet}
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>}
+     */
+    unfreezeFeature: function(row) {
+        var feature;
+        var wkt = row.fieldByName('geometry');
+        if (wkt == this.NULL_GEOMETRY) {
+            feature = new OpenLayers.Feature.Vector();
+        } else {
+            feature = this.wktParser.read(wkt);
+        }
+
+        feature.attributes = this.jsonParser.read(
+            row.fieldByName('properties'));
+
+        feature.fid = this.extractFidFromField(row.fieldByName('fid'));
+
+        var state = row.fieldByName('state');
+        if (state == this.NULL_FEATURE_STATE) {
+            state = null;
+        }
+        feature.state = state;
+
+        return feature;
+    },
+
+    /**
+     * Method: extractFidFromField
+     *
+     * Parameters:
+     * field - {String}
+     *
+     * Returns
+     * {String} or {Number} The fid.
+     */
+    extractFidFromField: function(field) {
+        if (!field.match(this.fidRegExp) && this.typeOfFid == "number") {
+            field = parseFloat(field);
+        }
+        return field;
+    },
+
+    /**
+     * APIMethod: create
+     * Create new features into the database.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *            {<OpenLayers.Feature.Vector>} The features to create in
+     *            the database.
+     * options - {Object} Optional object for configuring the request.
+     *
+     * Returns:
+     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *          object.
+     */
+    create: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = this.createOrUpdate(features);
+        resp.requestType = "create";
+
+        if (options && options.callback) {
+            options.callback.call(options.scope, resp);
+        }
+
+        return resp;
+    },
+
+    /**
+     * APIMethod: update
+     * Construct a request updating modified feature.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *            {<OpenLayers.Feature.Vector>} The features to update in
+     *            the database.
+     * options - {Object} Optional object for configuring the request.
+     *
+     * Returns:
+     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *          object.
+     */
+    update: function(features, options) {
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var resp = this.createOrUpdate(features);
+        resp.requestType = "update";
+
+        if (options && options.callback) {
+            options.callback.call(options.scope, resp);
+        }
+
+        return resp;
+    },
+
+    /**
+     * Method: createOrUpdate
+     * Construct a request for updating or creating features in the
+     * database.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *      {<OpenLayers.Feature.Vector>} The feature to create or update
+     *      in the database.
+     *
+     * Returns:
+     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *          object.
+     */
+    createOrUpdate: function(features) {
+        if (!(features instanceof Array)) {
+            features = [features];
+        }
+
+        var i, len = features.length, feature;
+        var insertedFeatures = new Array(len);
+ 
+        for (i = 0; i < len; i++) {
+            feature = features[i];
+            var params = this.freezeFeature(feature);
+            this.db.execute(
+                "REPLACE INTO " + this.tableName + 
+                " (fid, geometry, properties, state)" + 
+                " VALUES (?, ?, ?, ?)",
+                params);
+
+            var clone = feature.clone();
+            clone.fid = this.extractFidFromField(params[0]);
+            insertedFeatures[i] = clone;
+        }
+
+        return new OpenLayers.Protocol.Response({
+            code: OpenLayers.Protocol.Response.SUCCESS,
+            features: insertedFeatures,
+            reqFeatures: features
+        });
+    },
+
+    /**
+     * Method: freezeFeature
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     * state - {String} The feature state to store in the database.
+     *
+     * Returns:
+     * {Array}
+     */
+    freezeFeature: function(feature) {
+        // 2 notes:
+        // - fid might not be a string
+        // - getFeatureStateForFreeze needs the feature fid to it's stored
+        //   in the feature here
+        feature.fid = feature.fid != null ?
+            "" + feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX);
+
+        var geometry = feature.geometry != null ?
+            feature.geometry.toString() : this.NULL_GEOMETRY;
+
+        var properties = this.jsonParser.write(feature.attributes);
+
+        var state = this.getFeatureStateForFreeze(feature);
+
+        return [feature.fid, geometry, properties, state];
+    },
+
+    /**
+     * Method: getFeatureStateForFreeze
+     * Get the state of the feature to store into the database.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>} The feature.
+     *
+     * Returns
+     * {String} The state
+     */
+    getFeatureStateForFreeze: function(feature) {
+        var state;
+        if (!this.saveFeatureState) {
+            state = this.NULL_FEATURE_STATE;
+        } else if (this.createdOffline(feature)) {
+            // if the feature was created in offline mode, its
+            // state must remain INSERT
+            state = OpenLayers.State.INSERT;
+        } else {
+            state = feature.state;
+        }
+        return state;
+    },
+
+    /**
+     * APIMethod: delete
+     * Delete features from the database.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})} or
+     *            {<OpenLayers.Feature.Vector>}
+     * options - {Object} Optional object for configuring the request.
+     *       This object is modified and should not be reused.
+     *
+     * Returns:
+     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+     *          object.
+     */
+    "delete": function(features, options) {
+        if (!(features instanceof Array)) {
+            features = [features];
+        }
+
+        options = OpenLayers.Util.applyDefaults(options, this.options);
+
+        var i, len, feature;
+        for (i = 0, len = features.length; i < len; i++) {
+            feature = features[i];
+
+            // if saveFeatureState is set to true and if the feature wasn't created
+            // in offline mode we don't delete it in the database but just update 
+            // it state column
+            if (this.saveFeatureState && !this.createdOffline(feature)) {
+                var toDelete = feature.clone();
+                toDelete.fid = feature.fid;
+                if (toDelete.geometry) {
+                    toDelete.geometry.destroy();
+                    toDelete.geometry = null;
+                }
+                toDelete.state = feature.state;
+                this.createOrUpdate(toDelete);
+            } else {
+                this.db.execute(
+                    "DELETE FROM " + this.tableName +
+                    " WHERE fid = ?", [feature.fid]);
+            }
+        }
+
+        var resp = new OpenLayers.Protocol.Response({
+            code: OpenLayers.Protocol.Response.SUCCESS,
+            requestType: "delete",
+            reqFeatures: features
+        });
+
+        if (options && options.callback) {
+            options.callback.call(options.scope, resp);
+        }
+
+        return resp;
+    },
+
+    /**
+     * Method: createdOffline
+     * Returns true if the feature had a feature id when it was created in
+     *      the Gears database, false otherwise; this is determined by
+     *      checking the form of the feature's fid value.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     *
+     * Returns:
+     * {Boolean}
+     */
+    createdOffline: function(feature) {
+        return (typeof feature.fid == "string" &&
+                !!(feature.fid.match(this.fidRegExp)));
+    },
+
+    /**
+     * APIMethod: commit
+     * Go over the features and for each take action
+     * based on the feature state. Possible actions are create,
+     * update and delete.
+     *
+     * Parameters:
+     * features - {Array({<OpenLayers.Feature.Vector>})}
+     * options - {Object} Object whose possible keys are "create", "update",
+     *      "delete", "callback" and "scope", the values referenced by the
+     *      first three are objects as passed to the "create", "update", and
+     *      "delete" methods, the value referenced by the "callback" key is
+     *      a function which is called when the commit operation is complete
+     *      using the scope referenced by the "scope" key.
+     *
+     * Returns:
+     * {Array({<OpenLayers.Protocol.Response>})} An array of
+     *       <OpenLayers.Protocol.Response> objects, one per request made
+     *       to the database.
+     */
+    commit: function(features, options) {
+        var opt, resp = [], nRequests = 0, nResponses = 0;
+
+        function callback(resp) {
+            if (++nResponses < nRequests) {
+                resp.last = false;
+            }
+            this.callUserCallback(options, resp);
+        }
+
+        var feature, toCreate = [], toUpdate = [], toDelete = [];
+        for (var i = features.length - 1; i >= 0; i--) {
+            feature = features[i];
+            switch (feature.state) {
+            case OpenLayers.State.INSERT:
+                toCreate.push(feature);
+                break;
+            case OpenLayers.State.UPDATE:
+                toUpdate.push(feature);
+                break;
+            case OpenLayers.State.DELETE:
+                toDelete.push(feature);
+                break;
+            }
+        }
+        if (toCreate.length > 0) {
+            nRequests++;
+            opt = OpenLayers.Util.applyDefaults(
+                {"callback": callback, "scope": this},
+                options.create
+            );
+            resp.push(this.create(toCreate, opt));
+        }
+        if (toUpdate.length > 0) {
+            nRequests++;
+            opt = OpenLayers.Util.applyDefaults(
+                {"callback": callback, "scope": this},
+                options.update
+            );
+            resp.push(this.update(toUpdate, opt));
+        }
+        if (toDelete.length > 0) {
+            nRequests++;
+            opt = OpenLayers.Util.applyDefaults(
+                {"callback": callback, "scope": this},
+                options["delete"]
+            );
+            resp.push(this["delete"](toDelete, opt));
+        }
+
+        return resp;
+    },
+
+    /**
+     * Method: clear
+     * Removes all rows of the table.
+     */
+    clear: function() {
+        this.db.execute("DELETE FROM " + this.tableName);
+    },
+
+    /**
+     * Method: callUserCallback
+     * This method is called from within commit each time a request is made
+     * to the database, it is responsible for calling the user-supplied
+     * callbacks.
+     *
+     * Parameters:
+     * options - {Object} The map of options passed to the commit call.
+     * resp - {<OpenLayers.Protocol.Response>}
+     */
+    callUserCallback: function(options, resp) {
+        var opt = options[resp.requestType];
+        if (opt && opt.callback) {
+            opt.callback.call(opt.scope, resp);
+        }
+        if (resp.last && options.callback) {
+            options.callback.call(options.scope);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Protocol.SQL.Gears"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/SQL.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,87 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.SQL
+ * Abstract SQL protocol class.  Not to be instantiated directly.  Use
+ *     one of the SQL protocol subclasses instead.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.SQL = OpenLayers.Class(OpenLayers.Protocol, {
+
+    /**
+     * APIProperty: databaseName
+     * {String}
+     */
+    databaseName: 'ol',
+
+    /**
+     * APIProperty: tableName
+     * Name of the database table into which Features should be saved.
+     */
+    tableName: "ol_vector_features",
+
+    /**
+     * Property: postReadFiltering
+     * {Boolean} Whether the filter (if there's one) must be applied after
+     *      the features have been read from the database; for example the
+     *      BBOX strategy passes the read method a BBOX spatial filter, if
+     *      postReadFiltering is true every feature read from the database
+     *      will go through the BBOX spatial filter, which can be costly;
+     *      defaults to true.
+     */
+    postReadFiltering: true,
+
+    /**
+     * Constructor: OpenLayers.Protocol.SQL
+     */
+    initialize: function(options) {
+        OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        OpenLayers.Protocol.prototype.destroy.apply(this);
+    },
+
+    /**
+     * APIMethod: supported
+     * This should be overridden by specific subclasses
+     *
+     * Returns:
+     * {Boolean} Whether or not the browser supports the SQL backend
+     */
+    supported: function() {
+        return false;
+    },
+
+    /**
+     * Method: evaluateFilter
+     * If postReadFiltering is true evaluate the filter against the feature
+     * and return the result of the evaluation, otherwise return true.
+     *
+     * Parameters:
+     * {<OpenLayers.Feature.Vector>} The feature.
+     * {<OpenLayers.Filter>} The filter.
+     *
+     * Returns:
+     * {Boolean} true if postReadFiltering if false, the result of the
+     * filter evaluation otherwise.
+     */
+    evaluateFilter: function(feature, filter) {
+        return filter && this.postReadFiltering ?
+            filter.evaluate(feature) : true;
+    },
+
+    CLASS_NAME: "OpenLayers.Protocol.SQL"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,343 @@
+/**
+ * @requires OpenLayers/Protocol/WFS.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1
+ * Abstract class for for v1.0.0 and v1.1.0 protocol.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, {
+    
+    /**
+     * Property: version
+     * {String} WFS version number.
+     */
+    version: null,
+    
+    /**
+     * Property: srsName
+     * {String} Name of spatial reference system.  Default is "EPSG:4326".
+     */
+    srsName: "EPSG:4326",
+    
+    /**
+     * Property: featureType
+     * {String} Local feature typeName.
+     */
+    featureType: null,
+    
+    /**
+     * Property: featureNS
+     * {String} Feature namespace.
+     */
+    featureNS: null,
+    
+    /**
+     * Property: geometryName
+     * {String} Name of the geometry attribute for features.  Default is
+     *     "the_geom".
+     */
+    geometryName: "the_geom",
+    
+    /**
+     * Property: schema
+     * {String} Optional schema location that will be included in the
+     *     schemaLocation attribute value.  Note that the feature type schema
+     *     is required for a strict XML validator (on transactions with an
+     *     insert for example), but is *not* required by the WFS specification
+     *     (since the server is supposed to know about feature type schemas).
+     */
+    schema: null,
+
+    /**
+     * Property: featurePrefix
+     * {String} Namespace alias for feature type.  Default is "feature".
+     */
+    featurePrefix: "feature",
+    
+    /**
+     * Property: formatOptions
+     * {Object} Optional options for the format.  If a format is not provided,
+     *     this property can be used to extend the default format options.
+     */
+    formatOptions: null,
+    
+    /**
+     * Constructor: OpenLayers.Protocol.WFS
+     * A class for giving layers WFS protocol.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options properties:
+     * url - {String} URL to send requests to (required).
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (required, but can be autodetected
+     *     for reading if featurePrefix is provided and identical to the prefix
+     *     in the server response).
+     * featurePrefix - {String} Feature namespace alias (optional - only used
+     *     for writing if featureNS is provided).  Default is 'feature'.
+     * geometryName - {String} Name of geometry attribute.  Default is 'the_geom'.
+     */
+    initialize: function(options) {
+        OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
+        if(!options.format) {
+            this.format = OpenLayers.Format.WFST(OpenLayers.Util.extend({
+                version: this.version,
+                featureType: this.featureType,
+                featureNS: this.featureNS,
+                featurePrefix: this.featurePrefix,
+                geometryName: this.geometryName,
+                srsName: this.srsName,
+                schema: this.schema
+            }, this.formatOptions));
+        }
+        if(!this.featureNS) {
+            // featureNS autodetection
+            var readNode = this.format.readNode;
+            this.format.readNode = function(node, obj) {
+                if(!this.featureNS && node.prefix == this.featurePrefix) {
+                    this.featureNS = node.namespaceURI;
+                    this.setNamespace("feature", this.featureNS);
+                }
+                return readNode.apply(this, arguments);
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        if(this.options && !this.options.format) {
+            this.format.destroy();
+        }
+        this.format = null;
+        OpenLayers.Protocol.prototype.destroy.apply(this);
+    },
+
+    /**
+     * Method: createCallback
+     * Returns a function that applies the given public method with resp and
+     *     options arguments.
+     *
+     * Parameters:
+     * method - {Function} The method to be applied by the callback.
+     * response - {<OpenLayers.Protocol.Response>} The protocol response object.
+     * options - {Object} Options sent to the protocol method (read, create,
+     *     update, or delete).
+     */
+    createCallback: function(method, response, options) {
+        return OpenLayers.Function.bind(function() {
+            method.apply(this, [response, options]);
+        }, this);
+    },
+
+    /**
+     * Method: read
+     * Construct a request for reading new features.  Since WFS splits the
+     *     basic CRUD operations into GetFeature requests (for read) and
+     *     Transactions (for all others), this method does not make use of the
+     *     format's read method (that is only about reading transaction
+     *     responses).
+     */
+    read: function(options) {
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options || {});
+        var response = new OpenLayers.Protocol.Response({requestType: "read"});
+        
+        var data = OpenLayers.Format.XML.prototype.write.apply(
+            this.format, [this.format.writeNode("wfs:GetFeature", options)]
+        );
+
+        response.priv = OpenLayers.Request.POST({
+            url: options.url,
+            callback: this.createCallback(this.handleRead, response, options),
+            params: options.params,
+            headers: options.headers,
+            data: data
+        });        
+
+        return response;
+    },
+    
+    /**
+     * Method: handleRead
+     * Deal with response from the read request.
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>} The response object to pass
+     *     to the user callback.
+     * options - {Object} The user options passed to the read call.
+     */
+    handleRead: function(response, options) {
+        if(options.callback) {
+            var request = response.priv;
+            if(request.status >= 200 && request.status < 300) {
+                // success
+                response.features = this.parseFeatures(request);
+                response.code = OpenLayers.Protocol.Response.SUCCESS;
+            } else {
+                // failure
+                response.code = OpenLayers.Protocol.Response.FAILURE;
+            }
+            options.callback.call(options.scope, response);
+        }; 
+    },
+
+    /**
+     * Method: parseFeatures
+     * Read HTTP response body and return features
+     *
+     * Parameters:
+     * request - {XMLHttpRequest} The request object
+     *
+     * Returns:
+     * {Array({<OpenLayers.Feature.Vector>})} or
+     *     {<OpenLayers.Feature.Vector>} Array of features or a single feature.
+     */
+    parseFeatures: function(request) {
+        var doc = request.responseXML;
+        if(!doc || !doc.documentElement) {
+            doc = request.responseText;
+        }
+        if(!doc || doc.length <= 0) {
+            return null;
+        }
+        return this.format.read(doc);
+    },
+
+    /**
+     * Method: commit
+     * Given a list of feature, assemble a batch request for update, create,
+     *     and delete transactions.  A commit call on the prototype amounts
+     *     to writing a WFS transaction - so the write method on the format
+     *     is used.
+     *
+     * Parameters:
+     * features - {Array(<OpenLayers.Feature.Vector>}
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} A response object with a features
+     *     property containing any insertIds and a priv property referencing
+     *     the XMLHttpRequest object.
+     */
+    commit: function(features, options) {
+
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options);
+        
+        var response = new OpenLayers.Protocol.Response({
+            requestType: "commit",
+            reqFeatures: features
+        });
+        response.priv = OpenLayers.Request.POST({
+            url: options.url,
+            data: this.format.write(features, options),
+            callback: this.createCallback(this.handleCommit, response, options)
+        });
+        
+        return response;
+    },
+    
+    /**
+     * Method: handleCommit
+     * Called when the commit request returns.
+     * 
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>} The response object to pass
+     *     to the user callback.
+     * options - {Object} The user options passed to the commit call.
+     */
+    handleCommit: function(response, options) {
+        if(options.callback) {
+            var request = response.priv;
+
+            // ensure that we have an xml doc
+            var data = request.responseXML;
+            if(!data || !data.documentElement) {
+                data = request.responseText;
+            }
+            
+            var obj = this.format.read(data) || {};
+            
+            response.insertIds = obj.insertIds || [];
+            response.code = (obj.success) ?
+                OpenLayers.Protocol.Response.SUCCESS :
+                OpenLayers.Protocol.Response.FAILURE;
+            options.callback.call(options.scope, response);
+        }
+    },
+    
+    /**
+     * Method: filterDelete
+     * Send a request that deletes all features by their filter.
+     * 
+     * Parameters:
+     * filter - {OpenLayers.Filter} filter
+     */
+    filterDelete: function(filter, options) {
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options);    
+        
+        var response = new OpenLayers.Protocol.Response({
+            requestType: "commit"
+        });    
+        
+        var root = this.format.createElementNSPlus("wfs:Transaction", {
+        	attributes: {
+       	        service: "WFS",
+        	    version: this.version
+            }
+        });
+        
+        var deleteNode = this.format.createElementNSPlus("wfs:Delete", {
+            attributes: {
+                typeName: (options.featureNS ? this.featurePrefix + ":" : "") +
+                    options.featureType
+            }
+        });       
+        
+        if(options.featureNS) {
+            deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS);
+        }
+        var filterNode = this.format.writeNode("ogc:Filter", filter);
+        
+        deleteNode.appendChild(filterNode);
+        
+        root.appendChild(deleteNode);
+        
+        var data = OpenLayers.Format.XML.prototype.write.apply(
+            this.format, [root]
+        );
+        
+        return OpenLayers.Request.POST({
+            url: this.url,
+            callback : options.callback || function(){},
+            data: data
+        });   
+        
+    },
+
+    /**
+     * Method: abort
+     * Abort an ongoing request, the response object passed to
+     * this method must come from this protocol (as a result
+     * of a read, or commit operation).
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>}
+     */
+    abort: function(response) {
+        if (response) {
+            response.priv.abort();
+        }
+    },
+  
+    CLASS_NAME: "OpenLayers.Protocol.WFS.v1" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1_1_0.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1_1_0.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS/v1_1_0.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,43 @@
+/**
+ * @requires OpenLayers/Protocol/WFS/v1.js
+ * @requires OpenLayers/Format/WFST/v1_1_0.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1_1_0
+ * A WFS v1.1.0 protocol for vector layers.  Create a new instance with the
+ *     <OpenLayers.Protocol.WFS.v1_1_0> constructor.
+ *
+ * Differences from the v1.0.0 protocol:
+ *  - uses Filter Encoding 1.1.0 instead of 1.0.0
+ *  - uses GML 3 instead of 2 if no format is provided
+ *  
+ * Inherits from:
+ *  - <OpenLayers.Protocol.WFS.v1>
+ */
+OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, {
+    
+    /**
+     * Property: version
+     * {String} WFS version number.
+     */
+    version: "1.1.0",
+    
+    /**
+     * Constructor: OpenLayers.Protocol.WFS.v1_1_0
+     * A class for giving layers WFS v1.1.0 protocol.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options properties:
+     * featureType - {String} Local (without prefix) feature typeName (required).
+     * featureNS - {String} Feature namespace (optional).
+     * featurePrefix - {String} Feature namespace alias (optional - only used
+     *     if featureNS is provided).  Default is 'feature'.
+     * geometryName - {String} Name of geometry attribute.  Default is 'the_geom'.
+     */
+   
+    CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Protocol/WFS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,70 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ */
+
+/**
+ * Function: OpenLayers.Protocol.WFS
+ * Used to create a versioned WFS protocol.  Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol>} A WFS protocol of the given version.
+ */
+OpenLayers.Protocol.WFS = function(options) {
+    options = OpenLayers.Util.applyDefaults(
+        options, OpenLayers.Protocol.WFS.DEFAULTS
+    );
+    var cls = OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g, "_")];
+    if(!cls) {
+        throw "Unsupported WFS version: " + options.version;
+    }
+    return new cls(options);
+};
+
+/**
+ * Function: OpenLayers.Protocol.WFS.fromWMSLayer
+ * Convenience function to create a WFS protocol from a WMS layer.  This makes
+ *     the assumption that a WFS requests can be issued at the same URL as
+ *     WMS requests and that a WFS featureType exists with the same name as the
+ *     WMS layer.
+ *     
+ * This function is designed to auto-configure <url>, <featureType>,
+ *     <featurePrefix> and <srsName> for WFS <version> 1.1.0. Note that
+ *     srsName matching with the WMS layer will not work with WFS 1.0.0..
+ * 
+ * Parameters:
+ * layer - {<OpenLayers.Layer.WMS>} WMS layer that has a matching WFS
+ *     FeatureType at the same server url with the same typename.
+ * options - {Object} Default properties to be set on the protocol.
+ *
+ */
+OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) {
+    var typeName, featurePrefix;
+    var param = layer.params["LAYERS"];
+    var parts = (param instanceof Array ? param[0] : param).split(":");
+    if(parts.length > 1) {
+        featurePrefix = parts[0];
+    }
+    typeName = parts.pop();
+    var protocolOptions = {
+        url: layer.url,
+        featureType: typeName,
+        featurePrefix: featurePrefix,
+        srsName: layer.projection && layer.projection.getCode() ||
+                 layer.map && layer.map.getProjectionObject().getCode(),
+        version: "1.1.0"
+    };
+    return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(
+        options, protocolOptions
+    ));
+};
+
+/**
+ * Constant: OpenLayers.Protocol.WFS.DEFAULTS
+ */
+OpenLayers.Protocol.WFS.DEFAULTS = {
+    "version": "1.0.0"
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/Elements.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/Elements.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/Elements.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,1021 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer.js
+ */
+
+/**
+ * Class: OpenLayers.ElementsIndexer
+ * This class takes care of figuring out which order elements should be
+ *     placed in the DOM based on given indexing methods. 
+ */
+OpenLayers.ElementsIndexer = OpenLayers.Class({
+   
+    /**
+     * Property: maxZIndex
+     * {Integer} This is the largest-most z-index value for a node
+     *     contained within the indexer.
+     */
+    maxZIndex: null,
+    
+    /**
+     * Property: order
+     * {Array<String>} This is an array of node id's stored in the
+     *     order that they should show up on screen. Id's higher up in the
+     *     array (higher array index) represent nodes with higher z-indeces.
+     */
+    order: null, 
+    
+    /**
+     * Property: indices
+     * {Object} This is a hash that maps node ids to their z-index value
+     *     stored in the indexer. This is done to make finding a nodes z-index 
+     *     value O(1).
+     */
+    indices: null,
+    
+    /**
+     * Property: compare
+     * {Function} This is the function used to determine placement of
+     *     of a new node within the indexer. If null, this defaults to to
+     *     the Z_ORDER_DRAWING_ORDER comparison method.
+     */
+    compare: null,
+    
+    /**
+     * APIMethod: initialize
+     * Create a new indexer with 
+     * 
+     * Parameters:
+     * yOrdering - {Boolean} Whether to use y-ordering.
+     */
+    initialize: function(yOrdering) {
+
+        this.compare = yOrdering ? 
+            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER :
+            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;
+            
+        this.order = [];
+        this.indices = {};
+        this.maxZIndex = 0;
+    },
+    
+    /**
+     * APIMethod: insert
+     * Insert a new node into the indexer. In order to find the correct 
+     *     positioning for the node to be inserted, this method uses a binary 
+     *     search. This makes inserting O(log(n)). 
+     * 
+     * Parameters:
+     * newNode - {DOMElement} The new node to be inserted.
+     * 
+     * Returns
+     * {DOMElement} the node before which we should insert our newNode, or
+     *     null if newNode can just be appended.
+     */
+    insert: function(newNode) {
+        // If the node is known to the indexer, remove it so we can
+        // recalculate where it should go.
+        if (this.exists(newNode)) {
+            this.remove(newNode);
+        }
+        
+        var nodeId = newNode.id;
+        
+        this.determineZIndex(newNode);       
+
+        var leftIndex = -1;
+        var rightIndex = this.order.length;
+        var middle;
+
+        while (rightIndex - leftIndex > 1) {
+            middle = parseInt((leftIndex + rightIndex) / 2);
+            
+            var placement = this.compare(this, newNode,
+                OpenLayers.Util.getElement(this.order[middle]));
+            
+            if (placement > 0) {
+                leftIndex = middle;
+            } else {
+                rightIndex = middle;
+            } 
+        }
+        
+        this.order.splice(rightIndex, 0, nodeId);
+        this.indices[nodeId] = this.getZIndex(newNode);
+        
+        // If the new node should be before another in the index
+        // order, return the node before which we have to insert the new one;
+        // else, return null to indicate that the new node can be appended.
+	return this.getNextElement(rightIndex);
+    },
+    
+    /**
+     * APIMethod: remove
+     * 
+     * Parameters:
+     * node - {DOMElement} The node to be removed.
+     */
+    remove: function(node) {
+        var nodeId = node.id;
+        var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId);
+        if (arrayIndex >= 0) {
+            // Remove it from the order array, as well as deleting the node
+            // from the indeces hash.
+            this.order.splice(arrayIndex, 1);
+            delete this.indices[nodeId];
+            
+            // Reset the maxium z-index based on the last item in the 
+            // order array.
+            if (this.order.length > 0) {
+                var lastId = this.order[this.order.length - 1];
+                this.maxZIndex = this.indices[lastId];
+            } else {
+                this.maxZIndex = 0;
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: clear
+     */
+    clear: function() {
+        this.order = [];
+        this.indices = {};
+        this.maxZIndex = 0;
+    },
+    
+    /**
+     * APIMethod: exists
+     *
+     * Parameters:
+     * node- {DOMElement} The node to test for existence.
+     *
+     * Returns:
+     * {Boolean} Whether or not the node exists in the indexer?
+     */
+    exists: function(node) {
+        return (this.indices[node.id] != null);
+    },
+
+    /**
+     * APIMethod: getZIndex
+     * Get the z-index value for the current node from the node data itself.
+     * 
+     * Parameters:
+     * node - {DOMElement} The node whose z-index to get.
+     * 
+     * Returns:
+     * {Integer} The z-index value for the specified node (from the node 
+     *     data itself).
+     */
+    getZIndex: function(node) {
+        return node._style.graphicZIndex;  
+    },
+    
+    /**
+     * Method: determineZIndex
+     * Determine the z-index for the current node if there isn't one, 
+     *     and set the maximum value if we've found a new maximum.
+     * 
+     * Parameters:
+     * node - {DOMElement} 
+     */
+    determineZIndex: function(node) {
+        var zIndex = node._style.graphicZIndex;
+        
+        // Everything must have a zIndex. If none is specified,
+        // this means the user *must* (hint: assumption) want this
+        // node to succomb to drawing order. To enforce drawing order
+        // over all indexing methods, we'll create a new z-index that's
+        // greater than any currently in the indexer.
+        if (zIndex == null) {
+            zIndex = this.maxZIndex;
+            node._style.graphicZIndex = zIndex; 
+        } else if (zIndex > this.maxZIndex) {
+            this.maxZIndex = zIndex;
+        }
+    },
+	
+    /**
+     * APIMethod: getNextElement
+     * Get the next element in the order stack.
+     * 
+     * Parameters:
+     * index - {Integer} The index of the current node in this.order.
+     * 
+     * Returns:
+     * {DOMElement} the node following the index passed in, or
+     *     null.
+     */
+    getNextElement: function(index) {
+		var nextIndex = index + 1;
+        if (nextIndex < this.order.length){
+			var nextElement = OpenLayers.Util.getElement(this.order[nextIndex]);
+			if (nextElement == undefined){
+			  nextElement = this.getNextElement(nextIndex);
+			}
+			return nextElement;
+		} else {
+			return null;
+		} 
+    },	
+    
+    CLASS_NAME: "OpenLayers.ElementsIndexer"
+});
+
+/**
+ * Namespace: OpenLayers.ElementsIndexer.IndexingMethods
+ * These are the compare methods for figuring out where a new node should be 
+ *     placed within the indexer. These methods are very similar to general 
+ *     sorting methods in that they return -1, 0, and 1 to specify the 
+ *     direction in which new nodes fall in the ordering.
+ */
+OpenLayers.ElementsIndexer.IndexingMethods = {
+    
+    /**
+     * Method: Z_ORDER
+     * This compare method is used by other comparison methods.
+     *     It can be used individually for ordering, but is not recommended,
+     *     because it doesn't subscribe to drawing order.
+     * 
+     * Parameters:
+     * indexer - {<OpenLayers.ElementsIndexer>}
+     * newNode - {DOMElement}
+     * nextNode - {DOMElement}
+     * 
+     * Returns:
+     * {Integer}
+     */
+    Z_ORDER: function(indexer, newNode, nextNode) {
+        var newZIndex = indexer.getZIndex(newNode);
+
+        var returnVal = 0;
+        if (nextNode) {
+            var nextZIndex = indexer.getZIndex(nextNode);
+            returnVal = newZIndex - nextZIndex; 
+        }
+        
+        return returnVal;
+    },
+
+    /**
+     * APIMethod: Z_ORDER_DRAWING_ORDER
+     * This method orders nodes by their z-index, but does so in a way
+     *     that, if there are other nodes with the same z-index, the newest 
+     *     drawn will be the front most within that z-index. This is the 
+     *     default indexing method.
+     * 
+     * Parameters:
+     * indexer - {<OpenLayers.ElementsIndexer>}
+     * newNode - {DOMElement}
+     * nextNode - {DOMElement}
+     * 
+     * Returns:
+     * {Integer}
+     */
+    Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) {
+        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
+            indexer, 
+            newNode, 
+            nextNode
+        );
+        
+        // Make Z_ORDER subscribe to drawing order by pushing it above
+        // all of the other nodes with the same z-index.
+        if (nextNode && returnVal == 0) {
+            returnVal = 1;
+        }
+        
+        return returnVal;
+    },
+
+    /**
+     * APIMethod: Z_ORDER_Y_ORDER
+     * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it
+     *     best describes which ordering methods have precedence (though, the 
+     *     name would be too long). This method orders nodes by their z-index, 
+     *     but does so in a way that, if there are other nodes with the same 
+     *     z-index, the nodes with the lower y position will be "closer" than 
+     *     those with a higher y position. If two nodes have the exact same y 
+     *     position, however, then this method will revert to using drawing  
+     *     order to decide placement.
+     * 
+     * Parameters:
+     * indexer - {<OpenLayers.ElementsIndexer>}
+     * newNode - {DOMElement}
+     * nextNode - {DOMElement}
+     * 
+     * Returns:
+     * {Integer}
+     */
+    Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) {
+        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
+            indexer, 
+            newNode, 
+            nextNode
+        );
+        
+        if (nextNode && returnVal == 0) {
+            var newLat = newNode._geometry.getBounds().bottom;
+            var nextLat = nextNode._geometry.getBounds().bottom;
+            
+            var result = nextLat - newLat;
+            returnVal = (result ==0) ? 1 : result;
+        }
+        
+        return returnVal;       
+    }
+};
+
+/**
+ * Class: OpenLayers.Renderer.Elements
+ * This is another virtual class in that it should never be instantiated by 
+ *  itself as a Renderer. It exists because there is *tons* of shared 
+ *  functionality between different vector libraries which use nodes/elements
+ *  as a base for rendering vectors. 
+ * 
+ * The highlevel bits of code that are implemented here are the adding and 
+ *  removing of geometries, which is essentially the same for any 
+ *  element-based renderer. The details of creating each node and drawing the
+ *  paths are of course different, but the machinery is the same. 
+ * 
+ * Inherits:
+ *  - <OpenLayers.Renderer>
+ */
+OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
+
+    /**
+     * Property: rendererRoot
+     * {DOMElement}
+     */
+    rendererRoot: null,
+    
+    /**
+     * Property: root
+     * {DOMElement}
+     */
+    root: null,
+    
+    /**
+     * Property: vectorRoot
+     * {DOMElement}
+     */
+    vectorRoot: null,
+
+    /**
+     * Property: textRoot
+     * {DOMElement}
+     */
+    textRoot: null,
+
+    /**
+     * Property: xmlns
+     * {String}
+     */    
+    xmlns: null,
+    
+    /**
+     * Property: Indexer
+     * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer 
+     *     created upon initialization if the zIndexing or yOrdering options
+     *     passed to this renderer's constructor are set to true.
+     */
+    indexer: null, 
+    
+    /**
+     * Constant: BACKGROUND_ID_SUFFIX
+     * {String}
+     */
+    BACKGROUND_ID_SUFFIX: "_background",
+    
+    /**
+     * Constant: BACKGROUND_ID_SUFFIX
+     * {String}
+     */
+    LABEL_ID_SUFFIX: "_label",
+    
+    /**
+     * Property: minimumSymbolizer
+     * {Object}
+     */
+    minimumSymbolizer: {
+        strokeLinecap: "round",
+        strokeOpacity: 1,
+        strokeDashstyle: "solid",
+        fillOpacity: 1,
+        pointRadius: 0
+    },
+    
+    /**
+     * Constructor: OpenLayers.Renderer.Elements
+     * 
+     * Parameters:
+     * containerID - {String}
+     * options - {Object} options for this renderer. Supported options are:
+     *     * yOrdering - {Boolean} Whether to use y-ordering
+     *     * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
+     *         if yOrdering is set to true.
+     */
+    initialize: function(containerID, options) {
+        OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
+
+        this.rendererRoot = this.createRenderRoot();
+        this.root = this.createRoot("_root");
+        this.vectorRoot = this.createRoot("_vroot");
+        this.textRoot = this.createRoot("_troot");
+        
+        this.root.appendChild(this.vectorRoot);
+        this.root.appendChild(this.textRoot);
+        
+        this.rendererRoot.appendChild(this.root);
+        this.container.appendChild(this.rendererRoot);
+        
+        if(options && (options.zIndexing || options.yOrdering)) {
+            this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering);
+        }
+    },
+    
+    /**
+     * Method: destroy
+     */
+    destroy: function() {
+
+        this.clear(); 
+
+        this.rendererRoot = null;
+        this.root = null;
+        this.xmlns = null;
+
+        OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * Method: clear
+     * Remove all the elements from the root
+     */    
+    clear: function() {
+        if (this.vectorRoot) {
+            while (this.vectorRoot.childNodes.length > 0) {
+                this.vectorRoot.removeChild(this.vectorRoot.firstChild);
+            }
+        }
+        if (this.textRoot) {
+            while (this.textRoot.childNodes.length > 0) {
+                this.textRoot.removeChild(this.textRoot.firstChild);
+            }
+        }
+        if (this.indexer) {
+            this.indexer.clear();
+        }
+    },
+
+    /** 
+     * Method: getNodeType
+     * This function is in charge of asking the specific renderer which type
+     *     of node to create for the given geometry and style. All geometries
+     *     in an Elements-based renderer consist of one node and some
+     *     attributes. We have the nodeFactory() function which creates a node
+     *     for us, but it takes a 'type' as input, and that is precisely what
+     *     this function tells us.  
+     *  
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * 
+     * Returns:
+     * {String} The corresponding node type for the specified geometry
+     */
+    getNodeType: function(geometry, style) { },
+
+    /** 
+     * Method: drawGeometry 
+     * Draw the geometry, creating new nodes, setting paths, setting style,
+     *     setting featureId on the node.  This method should only be called
+     *     by the renderer itself.
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * featureId - {String}
+     * 
+     * Returns:
+     * {Boolean} true if the geometry has been drawn completely; null if
+     *     incomplete; false otherwise
+     */
+    drawGeometry: function(geometry, style, featureId) {
+        var className = geometry.CLASS_NAME;
+        var rendered = true;
+        if ((className == "OpenLayers.Geometry.Collection") ||
+            (className == "OpenLayers.Geometry.MultiPoint") ||
+            (className == "OpenLayers.Geometry.MultiLineString") ||
+            (className == "OpenLayers.Geometry.MultiPolygon")) {
+            for (var i = 0, len=geometry.components.length; i<len; i++) {
+                rendered = this.drawGeometry(
+                    geometry.components[i], style, featureId) && rendered;
+            }
+            return rendered;
+        };
+
+        rendered = false;
+        if (style.display != "none") {
+            if (style.backgroundGraphic) {
+                this.redrawBackgroundNode(geometry.id, geometry, style,
+                    featureId);
+            }
+            rendered = this.redrawNode(geometry.id, geometry, style,
+                featureId);
+        }
+        if (rendered == false) {
+            var node = document.getElementById(geometry.id);
+            if (node) {
+                if (node._style.backgroundGraphic) {
+                    node.parentNode.removeChild(document.getElementById(
+                        geometry.id + this.BACKGROUND_ID_SUFFIX));
+                }
+                node.parentNode.removeChild(node);
+            }
+        }
+        return rendered;
+    },
+    
+    /**
+     * Method: redrawNode
+     * 
+     * Parameters:
+     * id - {String}
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * featureId - {String}
+     * 
+     * Returns:
+     * {Boolean} true if the complete geometry could be drawn, null if parts of
+     *     the geometry could not be drawn, false otherwise
+     */
+    redrawNode: function(id, geometry, style, featureId) {
+        // Get the node if it's already on the map.
+        var node = this.nodeFactory(id, this.getNodeType(geometry, style));
+        
+        // Set the data for the node, then draw it.
+        node._featureId = featureId;
+        node._geometry = geometry;
+        node._geometryClass = geometry.CLASS_NAME;
+        node._style = style;
+
+        var drawResult = this.drawGeometryNode(node, geometry, style);
+        if(drawResult === false) {
+            return false;
+        }
+         
+        node = drawResult.node;
+        
+        // Insert the node into the indexer so it can show us where to
+        // place it. Note that this operation is O(log(n)). If there's a
+        // performance problem (when dragging, for instance) this is
+        // likely where it would be.
+        if (this.indexer) {
+            var insert = this.indexer.insert(node);
+            if (insert) {
+                this.vectorRoot.insertBefore(node, insert);
+            } else {
+                this.vectorRoot.appendChild(node);
+            }
+        } else {
+            // if there's no indexer, simply append the node to root,
+            // but only if the node is a new one
+            if (node.parentNode !== this.vectorRoot){ 
+                this.vectorRoot.appendChild(node);
+            }
+        }
+        
+        this.postDraw(node);
+        
+        return drawResult.complete;
+    },
+    
+    /**
+     * Method: redrawBackgroundNode
+     * Redraws the node using special 'background' style properties. Basically
+     *     just calls redrawNode(), but instead of directly using the 
+     *     'externalGraphic', 'graphicXOffset', 'graphicYOffset', and 
+     *     'graphicZIndex' properties directly from the specified 'style' 
+     *     parameter, we create a new style object and set those properties 
+     *     from the corresponding 'background'-prefixed properties from 
+     *     specified 'style' parameter.
+     * 
+     * Parameters:
+     * id - {String}
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * featureId - {String}
+     * 
+     * Returns:
+     * {Boolean} true if the complete geometry could be drawn, null if parts of
+     *     the geometry could not be drawn, false otherwise
+     */
+    redrawBackgroundNode: function(id, geometry, style, featureId) {
+        var backgroundStyle = OpenLayers.Util.extend({}, style);
+        
+        // Set regular style attributes to apply to the background styles.
+        backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic;
+        backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset;
+        backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset;
+        backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex;
+        backgroundStyle.graphicWidth = backgroundStyle.backgroundWidth || backgroundStyle.graphicWidth;
+        backgroundStyle.graphicHeight = backgroundStyle.backgroundHeight || backgroundStyle.graphicHeight;
+        
+        // Erase background styles.
+        backgroundStyle.backgroundGraphic = null;
+        backgroundStyle.backgroundXOffset = null;
+        backgroundStyle.backgroundYOffset = null;
+        backgroundStyle.backgroundGraphicZIndex = null;
+        
+        return this.redrawNode(
+            id + this.BACKGROUND_ID_SUFFIX, 
+            geometry, 
+            backgroundStyle, 
+            null
+        );
+    },
+
+    /**
+     * Method: drawGeometryNode
+     * Given a node, draw a geometry on the specified layer.
+     *     node and geometry are required arguments, style is optional.
+     *     This method is only called by the render itself.
+     *
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * 
+     * Returns:
+     * {Object} a hash with properties "node" (the drawn node) and "complete"
+     *     (null if parts of the geometry could not be drawn, false if nothing
+     *     could be drawn)
+     */
+    drawGeometryNode: function(node, geometry, style) {
+        style = style || node._style;
+        OpenLayers.Util.applyDefaults(style, this.minimumSymbolizer);
+
+        var options = {
+            'isFilled': style.fill === undefined ?
+                true :
+                style.fill,
+            'isStroked': style.stroke === undefined ?
+                !!style.strokeWidth :
+                style.stroke
+        };
+        var drawn;
+        switch (geometry.CLASS_NAME) {
+            case "OpenLayers.Geometry.Point":
+                if(style.graphic === false) {
+                    options.isFilled = false;
+                    options.isStroked = false;
+                }
+                drawn = this.drawPoint(node, geometry);
+                break;
+            case "OpenLayers.Geometry.LineString":
+                options.isFilled = false;
+                drawn = this.drawLineString(node, geometry);
+                break;
+            case "OpenLayers.Geometry.LinearRing":
+                drawn = this.drawLinearRing(node, geometry);
+                break;
+            case "OpenLayers.Geometry.Polygon":
+                drawn = this.drawPolygon(node, geometry);
+                break;
+            case "OpenLayers.Geometry.Surface":
+                drawn = this.drawSurface(node, geometry);
+                break;
+            case "OpenLayers.Geometry.Rectangle":
+                drawn = this.drawRectangle(node, geometry);
+                break;
+            default:
+                break;
+        }
+
+        node._style = style; 
+        node._options = options; 
+
+        //set style
+        //TBD simplify this
+        if (drawn != false) {
+            return {
+                node: this.setStyle(node, style, options, geometry),
+                complete: drawn
+            };
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: postDraw
+     * Things that have do be done after the geometry node is appended
+     *     to its parent node. To be overridden by subclasses.
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     */
+    postDraw: function(node) {},
+    
+    /**
+     * Method: drawPoint
+     * Virtual function for drawing Point Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the point
+     */ 
+    drawPoint: function(node, geometry) {},
+
+    /**
+     * Method: drawLineString
+     * Virtual function for drawing LineString Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components of
+     *     the linestring, or false if nothing could be drawn
+     */ 
+    drawLineString: function(node, geometry) {},
+
+    /**
+     * Method: drawLinearRing
+     * Virtual function for drawing LinearRing Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components
+     *     of the linear ring, or false if nothing could be drawn
+     */ 
+    drawLinearRing: function(node, geometry) {},
+
+    /**
+     * Method: drawPolygon
+     * Virtual function for drawing Polygon Geometry. 
+     *    Should be implemented by subclasses.
+     *    This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components
+     *     of the polygon, or false if nothing could be drawn
+     */ 
+    drawPolygon: function(node, geometry) {},
+
+    /**
+     * Method: drawRectangle
+     * Virtual function for drawing Rectangle Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the rectangle
+     */ 
+    drawRectangle: function(node, geometry) {},
+
+    /**
+     * Method: drawCircle
+     * Virtual function for drawing Circle Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the circle
+     */ 
+    drawCircle: function(node, geometry) {},
+
+    /**
+     * Method: drawSurface
+     * Virtual function for drawing Surface Geometry. 
+     *     Should be implemented by subclasses.
+     *     This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the surface
+     */ 
+    drawSurface: function(node, geometry) {},
+
+    /**
+     * Method: removeText
+     * Removes a label
+     * 
+     * Parameters:
+     * featureId - {String}
+     */
+    removeText: function(featureId) {
+        var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX);
+        if (label) {
+            this.textRoot.removeChild(label);
+        }
+    },
+
+    /**
+     * Method: getFeatureIdFromEvent
+     * 
+     * Parameters:
+     * evt - {Object} An <OpenLayers.Event> object
+     *
+     * Returns:
+     * {<OpenLayers.Geometry>} A geometry from an event that 
+     *     happened on a layer.
+     */
+    getFeatureIdFromEvent: function(evt) {
+        var target = evt.target;
+        var useElement = target && target.correspondingUseElement;
+        var node = useElement ? useElement : (target || evt.srcElement);
+        var featureId = node._featureId;
+        return featureId;
+    },
+
+    /** 
+     * Method: eraseGeometry
+     * Erase a geometry from the renderer. In the case of a multi-geometry, 
+     *     we cycle through and recurse on ourselves. Otherwise, we look for a 
+     *     node with the geometry.id, destroy its geometry, and remove it from
+     *     the DOM.
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     */
+    eraseGeometry: function(geometry) {
+        if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
+            (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
+            (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon") ||
+            (geometry.CLASS_NAME == "OpenLayers.Geometry.Collection")) {
+            for (var i=0, len=geometry.components.length; i<len; i++) {
+                this.eraseGeometry(geometry.components[i]);
+            }
+        } else {    
+            var element = OpenLayers.Util.getElement(geometry.id);
+            if (element && element.parentNode) {
+                if (element.geometry) {
+                    element.geometry.destroy();
+                    element.geometry = null;
+                }
+                element.parentNode.removeChild(element);
+
+                if (this.indexer) {
+                    this.indexer.remove(element);
+                }
+                
+                if (element._style.backgroundGraphic) {
+                    var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
+                    var bElem = OpenLayers.Util.getElement(backgroundId);
+                    if (bElem && bElem.parentNode) {
+                        // No need to destroy the geometry since the element and the background
+                        // node share the same geometry.
+                        bElem.parentNode.removeChild(bElem);
+                    }
+                }
+            }
+        }
+    },
+
+    /** 
+     * Method: nodeFactory
+     * Create new node of the specified type, with the (optional) specified id.
+     * 
+     * If node already exists with same ID and a different type, we remove it
+     *     and then call ourselves again to recreate it.
+     * 
+     * Parameters:
+     * id - {String}
+     * type - {String} type Kind of node to draw.
+     * 
+     * Returns:
+     * {DOMElement} A new node of the given type and id.
+     */
+    nodeFactory: function(id, type) {
+        var node = OpenLayers.Util.getElement(id);
+        if (node) {
+            if (!this.nodeTypeCompare(node, type)) {
+                node.parentNode.removeChild(node);
+                node = this.nodeFactory(id, type);
+            }
+        } else {
+            node = this.createNode(type, id);
+        }
+        return node;
+    },
+    
+    /** 
+     * Method: nodeTypeCompare
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * type - {String} Kind of node
+     * 
+     * Returns:
+     * {Boolean} Whether or not the specified node is of the specified type
+     *     This function must be overridden by subclasses.
+     */
+    nodeTypeCompare: function(node, type) {},
+    
+    /** 
+     * Method: createNode
+     * 
+     * Parameters:
+     * type - {String} Kind of node to draw.
+     * id - {String} Id for node.
+     * 
+     * Returns:
+     * {DOMElement} A new node of the given type and id.
+     *     This function must be overridden by subclasses.
+     */
+    createNode: function(type, id) {},
+
+    /**
+     * Method: moveRoot
+     * moves this renderer's root to a different renderer.
+     * 
+     * Parameters:
+     * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
+     */
+    moveRoot: function(renderer) {
+        var root = this.root;
+        if(renderer.root.parentNode == this.rendererRoot) {
+            root = renderer.root;
+        }
+        root.parentNode.removeChild(root);
+        renderer.rendererRoot.appendChild(root);
+    },
+    
+    /**
+     * Method: getRenderLayerId
+     * Gets the layer that this renderer's output appears on. If moveRoot was
+     * used, this will be different from the id of the layer containing the
+     * features rendered by this renderer.
+     * 
+     * Returns:
+     * {String} the id of the output layer.
+     */
+    getRenderLayerId: function() {
+        return this.root.parentNode.parentNode.id;
+    },
+    
+    /**
+     * Method: isComplexSymbol
+     * Determines if a symbol cannot be rendered using drawCircle
+     * 
+     * Parameters:
+     * graphicName - {String}
+     * 
+     * Returns
+     * {Boolean} true if the symbol is complex, false if not
+     */
+    isComplexSymbol: function(graphicName) {
+        return (graphicName != "circle") && !!graphicName;
+    },
+
+    CLASS_NAME: "OpenLayers.Renderer.Elements"
+});
+
+
+/**
+ * Constant: OpenLayers.Renderer.symbol
+ * Coordinate arrays for well known (named) symbols.
+ */
+OpenLayers.Renderer.symbol = {
+    "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
+            303,215, 231,161, 321,161, 350,75],
+    "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
+            4,0],
+    "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
+    "square": [0,0, 0,1, 1,1, 1,0, 0,0],
+    "triangle": [0,10, 10,10, 5,0, 0,10]
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/SVG.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/SVG.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/SVG.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,928 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer/Elements.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer.SVG
+ * 
+ * Inherits:
+ *  - <OpenLayers.Renderer.Elements>
+ */
+OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
+
+    /** 
+     * Property: xmlns
+     * {String}
+     */
+    xmlns: "http://www.w3.org/2000/svg",
+    
+    /**
+     * Property: xlinkns
+     * {String}
+     */
+    xlinkns: "http://www.w3.org/1999/xlink",
+
+    /**
+     * Constant: MAX_PIXEL
+     * {Integer} Firefox has a limitation where values larger or smaller than  
+     *           about 15000 in an SVG document lock the browser up. This 
+     *           works around it.
+     */
+    MAX_PIXEL: 15000,
+
+    /**
+     * Property: translationParameters
+     * {Object} Hash with "x" and "y" properties
+     */
+    translationParameters: null,
+    
+    /**
+     * Property: symbolSize
+     * {Object} Cache for symbol sizes according to their svg coordinate space
+     */
+    symbolSize: {},
+    
+    /**
+     * Property: isGecko
+     * {Boolean}
+     */
+    isGecko: null,
+
+    /**
+     * Constructor: OpenLayers.Renderer.SVG
+     * 
+     * Parameters:
+     * containerID - {String}
+     */
+    initialize: function(containerID) {
+        if (!this.supported()) { 
+            return; 
+        }
+        OpenLayers.Renderer.Elements.prototype.initialize.apply(this, 
+                                                                arguments);
+        this.translationParameters = {x: 0, y: 0};
+        this.isGecko = (navigator.userAgent.toLowerCase().indexOf("gecko/") != -1);
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
+    },
+    
+    /**
+     * APIMethod: supported
+     * 
+     * Returns:
+     * {Boolean} Whether or not the browser supports the SVG renderer
+     */
+    supported: function() {
+        var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
+        return (document.implementation && 
+           (document.implementation.hasFeature("org.w3c.svg", "1.0") || 
+            document.implementation.hasFeature(svgFeature + "SVG", "1.1") || 
+            document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
+    },    
+
+    /**
+     * Method: inValidRange
+     * See #669 for more information
+     *
+     * Parameters:
+     * x      - {Integer}
+     * y      - {Integer}
+     * xyOnly - {Boolean} whether or not to just check for x and y, which means
+     *     to not take the current translation parameters into account if true.
+     * 
+     * Returns:
+     * {Boolean} Whether or not the 'x' and 'y' coordinates are in the  
+     *           valid range.
+     */ 
+    inValidRange: function(x, y, xyOnly) {
+        var left = x + (xyOnly ? 0 : this.translationParameters.x);
+        var top = y + (xyOnly ? 0 : this.translationParameters.y);
+        return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
+                top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
+    },
+
+    /**
+     * Method: setExtent
+     * 
+     * Parameters:
+     * extent - {<OpenLayers.Bounds>}
+     * resolutionChanged - {Boolean}
+     * 
+     * Returns:
+     * {Boolean} true to notify the layer that the new extent does not exceed
+     *     the coordinate range, and the features will not need to be redrawn.
+     *     False otherwise.
+     */
+    setExtent: function(extent, resolutionChanged) {
+        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, 
+                                                               arguments);
+        
+        var resolution = this.getResolution();
+        var left = -extent.left / resolution;
+        var top = extent.top / resolution;
+
+        // If the resolution has changed, start over changing the corner, because
+        // the features will redraw.
+        if (resolutionChanged) {
+            this.left = left;
+            this.top = top;
+            // Set the viewbox
+            var extentString = "0 0 " + this.size.w + " " + this.size.h;
+
+            this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
+            this.translate(0, 0);
+            return true;
+        } else {
+            var inRange = this.translate(left - this.left, top - this.top);
+            if (!inRange) {
+                // recenter the coordinate system
+                this.setExtent(extent, true);
+            }
+            return inRange;
+        }
+    },
+    
+    /**
+     * Method: translate
+     * Transforms the SVG coordinate system
+     * 
+     * Parameters:
+     * x - {Float}
+     * y - {Float}
+     * 
+     * Returns:
+     * {Boolean} true if the translation parameters are in the valid coordinates
+     *     range, false otherwise.
+     */
+    translate: function(x, y) {
+        if (!this.inValidRange(x, y, true)) {
+            return false;
+        } else {
+            var transformString = "";
+            if (x || y) {
+                transformString = "translate(" + x + "," + y + ")";
+            }
+            this.root.setAttributeNS(null, "transform", transformString);
+            this.translationParameters = {x: x, y: y};
+            return true;
+        }
+    },
+
+    /**
+     * Method: setSize
+     * Sets the size of the drawing surface.
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>} The size of the drawing surface
+     */
+    setSize: function(size) {
+        OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
+        
+        this.rendererRoot.setAttributeNS(null, "width", this.size.w);
+        this.rendererRoot.setAttributeNS(null, "height", this.size.h);
+    },
+
+    /** 
+     * Method: getNodeType 
+     * 
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     * 
+     * Returns:
+     * {String} The corresponding node type for the specified geometry
+     */
+    getNodeType: function(geometry, style) {
+        var nodeType = null;
+        switch (geometry.CLASS_NAME) {
+            case "OpenLayers.Geometry.Point":
+                if (style.externalGraphic) {
+                    nodeType = "image";
+                } else if (this.isComplexSymbol(style.graphicName)) {
+                    nodeType = "use";
+                } else {
+                    nodeType = "circle";
+                }
+                break;
+            case "OpenLayers.Geometry.Rectangle":
+                nodeType = "rect";
+                break;
+            case "OpenLayers.Geometry.LineString":
+                nodeType = "polyline";
+                break;
+            case "OpenLayers.Geometry.LinearRing":
+                nodeType = "polygon";
+                break;
+            case "OpenLayers.Geometry.Polygon":
+            case "OpenLayers.Geometry.Curve":
+            case "OpenLayers.Geometry.Surface":
+                nodeType = "path";
+                break;
+            default:
+                break;
+        }
+        return nodeType;
+    },
+
+    /** 
+     * Method: setStyle
+     * Use to set all the style attributes to a SVG node.
+     * 
+     * Takes care to adjust stroke width and point radius to be
+     * resolution-relative
+     *
+     * Parameters:
+     * node - {SVGDomElement} An SVG element to decorate
+     * style - {Object}
+     * options - {Object} Currently supported options include 
+     *                              'isFilled' {Boolean} and
+     *                              'isStroked' {Boolean}
+     */
+    setStyle: function(node, style, options) {
+        style = style  || node._style;
+        options = options || node._options;
+        var r = parseFloat(node.getAttributeNS(null, "r"));
+        var widthFactor = 1;
+        var pos;
+        if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
+            node.style.visibility = "";
+            if (style.graphic === false) {
+                node.style.visibility = "hidden";
+            } else if (style.externalGraphic) {
+                pos = this.getPosition(node);
+                
+        		if (style.graphicTitle) {
+                    node.setAttributeNS(null, "title", style.graphicTitle);
+                }
+                if (style.graphicWidth && style.graphicHeight) {
+                  node.setAttributeNS(null, "preserveAspectRatio", "none");
+                }
+                var width = style.graphicWidth || style.graphicHeight;
+                var height = style.graphicHeight || style.graphicWidth;
+                width = width ? width : style.pointRadius*2;
+                height = height ? height : style.pointRadius*2;
+                var xOffset = (style.graphicXOffset != undefined) ?
+                    style.graphicXOffset : -(0.5 * width);
+                var yOffset = (style.graphicYOffset != undefined) ?
+                    style.graphicYOffset : -(0.5 * height);
+
+                var opacity = style.graphicOpacity || style.fillOpacity;
+                
+                node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
+                node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
+                node.setAttributeNS(null, "width", width);
+                node.setAttributeNS(null, "height", height);
+                node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
+                node.setAttributeNS(null, "style", "opacity: "+opacity);
+            } else if (this.isComplexSymbol(style.graphicName)) {
+                // the symbol viewBox is three times as large as the symbol
+                var offset = style.pointRadius * 3;
+                var size = offset * 2;
+                var id = this.importSymbol(style.graphicName);
+                var href = "#" + id;
+                pos = this.getPosition(node);
+                widthFactor = this.symbolSize[id] / size;
+                
+                // remove the node from the dom before we modify it. This
+                // prevents various rendering issues in Safari and FF
+                var parent = node.parentNode;
+                var nextSibling = node.nextSibling;
+                if(parent) {
+                    parent.removeChild(node);
+                }
+                
+                node.setAttributeNS(this.xlinkns, "href", href);
+                node.setAttributeNS(null, "width", size);
+                node.setAttributeNS(null, "height", size);
+                node.setAttributeNS(null, "x", pos.x - offset);
+                node.setAttributeNS(null, "y", pos.y - offset);
+                
+                // now that the node has all its new properties, insert it
+                // back into the dom where it was
+                if(nextSibling) {
+                    parent.insertBefore(node, nextSibling);
+                } else if(parent) {
+                    parent.appendChild(node);
+                }
+            } else {
+                node.setAttributeNS(null, "r", style.pointRadius);
+            }
+
+            if (typeof style.rotation != "undefined" && pos) {
+                var rotation = OpenLayers.String.format(
+                    "rotate(${0} ${1} ${2})", [style.rotation, pos.x, pos.y]);
+                node.setAttributeNS(null, "transform", rotation);
+            }
+        }
+        
+        if (options.isFilled) {
+            node.setAttributeNS(null, "fill", style.fillColor);
+            node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
+        } else {
+            node.setAttributeNS(null, "fill", "none");
+        }
+
+        if (options.isStroked) {
+            node.setAttributeNS(null, "stroke", style.strokeColor);
+            node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
+            node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
+            node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap);
+            // Hard-coded linejoin for now, to make it look the same as in VML.
+            // There is no strokeLinejoin property yet for symbolizers.
+            node.setAttributeNS(null, "stroke-linejoin", "round");
+            node.setAttributeNS(null, "stroke-dasharray", this.dashStyle(style,
+                widthFactor));
+        } else {
+            node.setAttributeNS(null, "stroke", "none");
+        }
+        
+        if (style.pointerEvents) {
+            node.setAttributeNS(null, "pointer-events", style.pointerEvents);
+        }
+		        
+        if (style.cursor != null) {
+            node.setAttributeNS(null, "cursor", style.cursor);
+        }
+        
+        return node;
+    },
+
+    /** 
+     * Method: dashStyle
+     * 
+     * Parameters:
+     * style - {Object}
+     * widthFactor - {Number}
+     * 
+     * Returns:
+     * {String} A SVG compliant 'stroke-dasharray' value
+     */
+    dashStyle: function(style, widthFactor) {
+        var w = style.strokeWidth * widthFactor;
+
+        switch (style.strokeDashstyle) {
+            case 'solid':
+                return 'none';
+            case 'dot':
+                return [1, 4 * w].join();
+            case 'dash':
+                return [4 * w, 4 * w].join();
+            case 'dashdot':
+                return [4 * w, 4 * w, 1, 4 * w].join();
+            case 'longdash':
+                return [8 * w, 4 * w].join();
+            case 'longdashdot':
+                return [8 * w, 4 * w, 1, 4 * w].join();
+            default:
+                return style.strokeDashstyle.replace(/ /g, ",");
+        }
+    },
+    
+    /** 
+     * Method: createNode
+     * 
+     * Parameters:
+     * type - {String} Kind of node to draw
+     * id - {String} Id for node
+     * 
+     * Returns:
+     * {DOMElement} A new node of the given type and id
+     */
+    createNode: function(type, id) {
+        var node = document.createElementNS(this.xmlns, type);
+        if (id) {
+            node.setAttributeNS(null, "id", id);
+        }
+        return node;    
+    },
+    
+    /** 
+     * Method: nodeTypeCompare
+     * 
+     * Parameters:
+     * node - {SVGDomElement} An SVG element
+     * type - {String} Kind of node
+     * 
+     * Returns:
+     * {Boolean} Whether or not the specified node is of the specified type
+     */
+    nodeTypeCompare: function(node, type) {
+        return (type == node.nodeName);
+    },
+   
+    /**
+     * Method: createRenderRoot
+     * 
+     * Returns:
+     * {DOMElement} The specific render engine's root element
+     */
+    createRenderRoot: function() {
+        return this.nodeFactory(this.container.id + "_svgRoot", "svg");
+    },
+
+    /**
+     * Method: createRoot
+     * 
+     * Parameter:
+     * suffix - {String} suffix to append to the id
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    createRoot: function(suffix) {
+        return this.nodeFactory(this.container.id + suffix, "g");
+    },
+
+    /**
+     * Method: createDefs
+     *
+     * Returns:
+     * {DOMElement} The element to which we'll add the symbol definitions
+     */
+    createDefs: function() {
+        var defs = this.nodeFactory(this.container.id + "_defs", "defs");
+        this.rendererRoot.appendChild(defs);
+        return defs;
+    },
+
+    /**************************************
+     *                                    *
+     *     GEOMETRY DRAWING FUNCTIONS     *
+     *                                    *
+     **************************************/
+
+    /**
+     * Method: drawPoint
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the point
+     */ 
+    drawPoint: function(node, geometry) {
+        return this.drawCircle(node, geometry, 1);
+    },
+
+    /**
+     * Method: drawCircle
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * radius - {Float}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the circle
+     */
+    drawCircle: function(node, geometry, radius) {
+        var resolution = this.getResolution();
+        var x = (geometry.x / resolution + this.left);
+        var y = (this.top - geometry.y / resolution);
+
+        if (this.inValidRange(x, y)) { 
+            node.setAttributeNS(null, "cx", x);
+            node.setAttributeNS(null, "cy", y);
+            node.setAttributeNS(null, "r", radius);
+            return node;
+        } else {
+            return false;
+        }    
+            
+    },
+    
+    /**
+     * Method: drawLineString
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components of
+     *     the linestring, or false if nothing could be drawn
+     */ 
+    drawLineString: function(node, geometry) {
+        var componentsResult = this.getComponentsString(geometry.components);
+        if (componentsResult.path) {
+            node.setAttributeNS(null, "points", componentsResult.path);
+            return (componentsResult.complete ? node : null);  
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: drawLinearRing
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components
+     *     of the linear ring, or false if nothing could be drawn
+     */ 
+    drawLinearRing: function(node, geometry) {
+        var componentsResult = this.getComponentsString(geometry.components);
+        if (componentsResult.path) {
+            node.setAttributeNS(null, "points", componentsResult.path);
+            return (componentsResult.complete ? node : null);  
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: drawPolygon
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components
+     *     of the polygon, or false if nothing could be drawn
+     */ 
+    drawPolygon: function(node, geometry) {
+        var d = "";
+        var draw = true;
+        var complete = true;
+        var linearRingResult, path;
+        for (var j=0, len=geometry.components.length; j<len; j++) {
+            d += " M";
+            linearRingResult = this.getComponentsString(
+                geometry.components[j].components, " ");
+            path = linearRingResult.path;
+            if (path) {
+                d += " " + path;
+                complete = linearRingResult.complete && complete;
+            } else {
+                draw = false;
+            }
+        }
+        d += " z";
+        if (draw) {
+            node.setAttributeNS(null, "d", d);
+            node.setAttributeNS(null, "fill-rule", "evenodd");
+            return complete ? node : null;
+        } else {
+            return false;
+        }    
+    },
+    
+    /**
+     * Method: drawRectangle
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the rectangle
+     */ 
+    drawRectangle: function(node, geometry) {
+        var resolution = this.getResolution();
+        var x = (geometry.x / resolution + this.left);
+        var y = (this.top - geometry.y / resolution);
+
+        if (this.inValidRange(x, y)) { 
+            node.setAttributeNS(null, "x", x);
+            node.setAttributeNS(null, "y", y);
+            node.setAttributeNS(null, "width", geometry.width / resolution);
+            node.setAttributeNS(null, "height", geometry.height / resolution);
+            return node;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: drawSurface
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the renderer could not draw the surface
+     */ 
+    drawSurface: function(node, geometry) {
+
+        // create the svg path string representation
+        var d = null;
+        var draw = true;
+        for (var i=0, len=geometry.components.length; i<len; i++) {
+            if ((i%3) == 0 && (i/3) == 0) {
+                var component = this.getShortString(geometry.components[i]);
+                if (!component) { draw = false; }
+                d = "M " + component;
+            } else if ((i%3) == 1) {
+                var component = this.getShortString(geometry.components[i]);
+                if (!component) { draw = false; }
+                d += " C " + component;
+            } else {
+                var component = this.getShortString(geometry.components[i]);
+                if (!component) { draw = false; }
+                d += " " + component;
+            }
+        }
+        d += " Z";
+        if (draw) {
+            node.setAttributeNS(null, "d", d);
+            return node;
+        } else {
+            return false;
+        }    
+    },
+    
+    /**
+     * Method: drawText
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * featureId - {String}
+     * style -
+     * location - {<OpenLayers.Geometry.Point>}
+     */
+    drawText: function(featureId, style, location) {
+        var resolution = this.getResolution();
+        
+        var x = (location.x / resolution + this.left);
+        var y = (location.y / resolution - this.top);
+        
+        var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
+        var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
+
+        label.setAttributeNS(null, "x", x);
+        label.setAttributeNS(null, "y", -y);
+        label.setAttributeNS(null, "pointer-events", "none");
+        
+        if (style.fontColor) {
+            label.setAttributeNS(null, "fill", style.fontColor);
+        }
+        if (style.fontFamily) {
+            label.setAttributeNS(null, "font-family", style.fontFamily);
+        }
+        if (style.fontSize) {
+            label.setAttributeNS(null, "font-size", style.fontSize);
+        }
+        if (style.fontWeight) {
+            label.setAttributeNS(null, "font-weight", style.fontWeight);
+        }
+        var align = style.labelAlign || "cm";
+        label.setAttributeNS(null, "text-anchor",
+            OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
+
+        if (this.isGecko) {
+            label.setAttributeNS(null, "dominant-baseline",
+                OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
+        } else {
+            tspan.setAttributeNS(null, "baseline-shift",
+                OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
+        }
+
+        tspan.textContent = style.label;
+        
+        if(!label.parentNode) {
+            label.appendChild(tspan);
+            this.textRoot.appendChild(label);
+        }   
+    },
+    
+    /** 
+     * Method: getComponentString
+     * 
+     * Parameters:
+     * components - {Array(<OpenLayers.Geometry.Point>)} Array of points
+     * separator - {String} character between coordinate pairs. Defaults to ","
+     * 
+     * Returns:
+     * {Object} hash with properties "path" (the string created from the
+     *     components and "complete" (false if the renderer was unable to
+     *     draw all components)
+     */
+    getComponentsString: function(components, separator) {
+        var renderCmp = [];
+        var complete = true;
+        var len = components.length;
+        var strings = [];
+        var str, component, j;
+        for(var i=0; i<len; i++) {
+            component = components[i];
+            renderCmp.push(component);
+            str = this.getShortString(component);
+            if (str) {
+                strings.push(str);
+            } else {
+                // The current component is outside the valid range. Let's
+                // see if the previous or next component is inside the range.
+                // If so, add the coordinate of the intersection with the
+                // valid range bounds.
+                if (i > 0) {
+                    if (this.getShortString(components[i - 1])) {
+                        strings.push(this.clipLine(components[i],
+                            components[i-1]));
+                    }
+                }
+                if (i < len - 1) {
+                    if (this.getShortString(components[i + 1])) {
+                        strings.push(this.clipLine(components[i],
+                            components[i+1]));
+                    }
+                }
+                complete = false;
+            }
+        }
+
+        return {
+            path: strings.join(separator || ","),
+            complete: complete
+        };
+    },
+    
+    /**
+     * Method: clipLine
+     * Given two points (one inside the valid range, and one outside),
+     * clips the line betweeen the two points so that the new points are both
+     * inside the valid range.
+     * 
+     * Parameters:
+     * badComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
+     *     invalid point
+     * goodComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
+     *     valid point
+     * Returns
+     * {String} the SVG coordinate pair of the clipped point (like
+     *     getShortString), or an empty string if both passed componets are at
+     *     the same point.
+     */
+    clipLine: function(badComponent, goodComponent) {
+        if (goodComponent.equals(badComponent)) {
+            return "";
+        }
+        var resolution = this.getResolution();
+        var maxX = this.MAX_PIXEL - this.translationParameters.x;
+        var maxY = this.MAX_PIXEL - this.translationParameters.y;
+        var x1 = goodComponent.x / resolution + this.left;
+        var y1 = this.top - goodComponent.y / resolution;
+        var x2 = badComponent.x / resolution + this.left;
+        var y2 = this.top - badComponent.y / resolution;
+        var k;
+        if (x2 < -maxX || x2 > maxX) {
+            k = (y2 - y1) / (x2 - x1);
+            x2 = x2 < 0 ? -maxX : maxX;
+            y2 = y1 + (x2 - x1) * k;
+        }
+        if (y2 < -maxY || y2 > maxY) {
+            k = (x2 - x1) / (y2 - y1);
+            y2 = y2 < 0 ? -maxY : maxY;
+            x2 = x1 + (y2 - y1) * k;
+        }
+        return x2 + "," + y2;
+    },
+
+    /** 
+     * Method: getShortString
+     * 
+     * Parameters:
+     * point - {<OpenLayers.Geometry.Point>}
+     * 
+     * Returns:
+     * {String} or false if point is outside the valid range
+     */
+    getShortString: function(point) {
+        var resolution = this.getResolution();
+        var x = (point.x / resolution + this.left);
+        var y = (this.top - point.y / resolution);
+
+        if (this.inValidRange(x, y)) { 
+            return x + "," + y;
+        } else {
+            return false;
+        }
+    },
+    
+    /**
+     * Method: getPosition
+     * Finds the position of an svg node.
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * 
+     * Returns:
+     * {Object} hash with x and y properties, representing the coordinates
+     *     within the svg coordinate system
+     */
+    getPosition: function(node) {
+        return({
+            x: parseFloat(node.getAttributeNS(null, "cx")),
+            y: parseFloat(node.getAttributeNS(null, "cy"))
+        });
+    },
+
+    /**
+     * Method: importSymbol
+     * add a new symbol definition from the rendererer's symbol hash
+     * 
+     * Parameters:
+     * graphicName - {String} name of the symbol to import
+     * 
+     * Returns:
+     * {String} - id of the imported symbol
+     */      
+    importSymbol: function (graphicName)  {
+        if (!this.defs) {
+            // create svg defs tag
+            this.defs = this.createDefs();
+        }
+        var id = this.container.id + "-" + graphicName;
+        
+        // check if symbol already exists in the defs
+        if (document.getElementById(id) != null) {
+            return id;
+        }
+        
+        var symbol = OpenLayers.Renderer.symbol[graphicName];
+        if (!symbol) {
+            throw new Error(graphicName + ' is not a valid symbol name');
+            return;
+        }
+
+        var symbolNode = this.nodeFactory(id, "symbol");
+        var node = this.nodeFactory(null, "polygon");
+        symbolNode.appendChild(node);
+        var symbolExtent = new OpenLayers.Bounds(
+                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
+
+        var points = "";
+        var x,y;
+        for (var i=0; i<symbol.length; i=i+2) {
+            x = symbol[i];
+            y = symbol[i+1];
+            symbolExtent.left = Math.min(symbolExtent.left, x);
+            symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
+            symbolExtent.right = Math.max(symbolExtent.right, x);
+            symbolExtent.top = Math.max(symbolExtent.top, y);
+            points += " " + x + "," + y;
+        }
+        
+        node.setAttributeNS(null, "points", points);
+        
+        var width = symbolExtent.getWidth();
+        var height = symbolExtent.getHeight();
+        // create a viewBox three times as large as the symbol itself,
+        // to allow for strokeWidth being displayed correctly at the corners.
+        var viewBox = [symbolExtent.left - width,
+                        symbolExtent.bottom - height, width * 3, height * 3];
+        symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
+        this.symbolSize[id] = Math.max(width, height) * 3;
+        
+        this.defs.appendChild(symbolNode);
+        return symbolNode.id;
+    },
+
+    CLASS_NAME: "OpenLayers.Renderer.SVG"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
+ * {Object}
+ */
+OpenLayers.Renderer.SVG.LABEL_ALIGN = {
+    "l": "start",
+    "r": "end",
+    "b": "bottom",
+    "t": "hanging"
+};
+
+/**
+ * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
+ * {Object}
+ */
+OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
+    // according to
+    // http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
+    // a baseline-shift of -70% shifts the text exactly from the
+    // bottom to the top of the baseline, so -35% moves the text to
+    // the center of the baseline.
+    "t": "-70%",
+    "b": "0"    
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/VML.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/VML.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Renderer/VML.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,979 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer/Elements.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer.VML
+ * Render vector features in browsers with VML capability.  Construct a new
+ * VML renderer with the <OpenLayers.Renderer.VML> constructor.
+ * 
+ * Note that for all calculations in this class, we use toFixed() to round a 
+ * float value to an integer. This is done because it seems that VML doesn't 
+ * support float values.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Renderer.Elements>
+ */
+OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
+
+    /**
+     * Property: xmlns
+     * {String} XML Namespace URN
+     */
+    xmlns: "urn:schemas-microsoft-com:vml",
+    
+    /**
+     * Property: symbolCache
+     * {DOMElement} node holding symbols. This hash is keyed by symbol name,
+     *     and each value is a hash with a "path" and an "extent" property.
+     */
+    symbolCache: {},
+
+    /**
+     * Property: offset
+     * {Object} Hash with "x" and "y" properties
+     */
+    offset: null,
+    
+    /**
+     * Constructor: OpenLayers.Renderer.VML
+     * Create a new VML renderer.
+     *
+     * Parameters:
+     * containerID - {String} The id for the element that contains the renderer
+     */
+    initialize: function(containerID) {
+        if (!this.supported()) { 
+            return; 
+        }
+        if (!document.namespaces.olv) {
+            document.namespaces.add("olv", this.xmlns);
+            var style = document.createStyleSheet();
+            var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox']; 
+            for (var i = 0, len = shapes.length; i < len; i++) {
+
+                style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " +
+                              "position: absolute; display: inline-block;");
+            }                  
+        }
+        
+        OpenLayers.Renderer.Elements.prototype.initialize.apply(this, 
+                                                                arguments);
+        this.offset = {x: 0, y: 0};
+    },
+
+    /**
+     * APIMethod: destroy
+     * Deconstruct the renderer.
+     */
+    destroy: function() {
+        OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: supported
+     * Determine whether a browser supports this renderer.
+     *
+     * Returns:
+     * {Boolean} The browser supports the VML renderer
+     */
+    supported: function() {
+        return !!(document.namespaces);
+    },    
+
+    /**
+     * Method: setExtent
+     * Set the renderer's extent
+     *
+     * Parameters:
+     * extent - {<OpenLayers.Bounds>}
+     * resolutionChanged - {Boolean}
+     * 
+     * Returns:
+     * {Boolean} true to notify the layer that the new extent does not exceed
+     *     the coordinate range, and the features will not need to be redrawn.
+     */
+    setExtent: function(extent, resolutionChanged) {
+        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, 
+                                                               arguments);
+        var resolution = this.getResolution();
+    
+        var left = extent.left/resolution;
+        var top = extent.top/resolution - this.size.h;
+        if (resolutionChanged) {
+            this.offset = {x: left, y: top};
+            left = 0;
+            top = 0;
+        } else {
+            left = left - this.offset.x;
+            top = top - this.offset.y;
+        }
+
+        
+        var org = left + " " + top;
+        this.root.coordorigin = org;
+        var roots = [this.root, this.vectorRoot, this.textRoot];
+        var root;
+        for(var i=0, len=roots.length; i<len; ++i) {
+            root = roots[i];
+
+            var size = this.size.w + " " + this.size.h;
+            root.coordsize = size;
+            
+        }
+        // flip the VML display Y axis upside down so it 
+        // matches the display Y axis of the map
+        this.root.style.flip = "y";
+        
+        return true;
+    },
+
+
+    /**
+     * Method: setSize
+     * Set the size of the drawing surface
+     *
+     * Parameters:
+     * size - {<OpenLayers.Size>} the size of the drawing surface
+     */
+    setSize: function(size) {
+        OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
+        
+        // setting width and height on all roots to avoid flicker which we
+        // would get with 100% width and height on child roots
+        var roots = [
+            this.rendererRoot,
+            this.root,
+            this.vectorRoot,
+            this.textRoot
+        ];
+        var w = this.size.w + "px";
+        var h = this.size.h + "px";
+        var root;
+        for(var i=0, len=roots.length; i<len; ++i) {
+            root = roots[i];
+            root.style.width = w;
+            root.style.height = h;
+        }
+    },
+
+    /**
+     * Method: getNodeType
+     * Get the node type for a geometry and style
+     *
+     * Parameters:
+     * geometry - {<OpenLayers.Geometry>}
+     * style - {Object}
+     *
+     * Returns:
+     * {String} The corresponding node type for the specified geometry
+     */
+    getNodeType: function(geometry, style) {
+        var nodeType = null;
+        switch (geometry.CLASS_NAME) {
+            case "OpenLayers.Geometry.Point":
+                if (style.externalGraphic) {
+                    nodeType = "olv:rect";
+                } else if (this.isComplexSymbol(style.graphicName)) {
+                    nodeType = "olv:shape";
+                } else {
+                    nodeType = "olv:oval";
+                }
+                break;
+            case "OpenLayers.Geometry.Rectangle":
+                nodeType = "olv:rect";
+                break;
+            case "OpenLayers.Geometry.LineString":
+            case "OpenLayers.Geometry.LinearRing":
+            case "OpenLayers.Geometry.Polygon":
+            case "OpenLayers.Geometry.Curve":
+            case "OpenLayers.Geometry.Surface":
+                nodeType = "olv:shape";
+                break;
+            default:
+                break;
+        }
+        return nodeType;
+    },
+
+    /**
+     * Method: setStyle
+     * Use to set all the style attributes to a VML node.
+     *
+     * Parameters:
+     * node - {DOMElement} An VML element to decorate
+     * style - {Object}
+     * options - {Object} Currently supported options include 
+     *                              'isFilled' {Boolean} and
+     *                              'isStroked' {Boolean}
+     * geometry - {<OpenLayers.Geometry>}
+     */
+    setStyle: function(node, style, options, geometry) {
+        style = style  || node._style;
+        options = options || node._options;
+        var widthFactor = 1;
+        
+        if (node._geometryClass == "OpenLayers.Geometry.Point") {
+            if (style.externalGraphic) {
+        		if (style.graphicTitle) {
+                    node.title=style.graphicTitle;
+                } 
+                var width = style.graphicWidth || style.graphicHeight;
+                var height = style.graphicHeight || style.graphicWidth;
+                width = width ? width : style.pointRadius*2;
+                height = height ? height : style.pointRadius*2;
+
+                var resolution = this.getResolution();
+                var xOffset = (style.graphicXOffset != undefined) ?
+                    style.graphicXOffset : -(0.5 * width);
+                var yOffset = (style.graphicYOffset != undefined) ?
+                    style.graphicYOffset : -(0.5 * height);
+                
+                node.style.left = ((geometry.x/resolution - this.offset.x)+xOffset).toFixed();
+                node.style.top = ((geometry.y/resolution - this.offset.y)-(yOffset+height)).toFixed();
+                node.style.width = width + "px";
+                node.style.height = height + "px";
+                node.style.flip = "y";
+                
+                // modify style/options for fill and stroke styling below
+                style.fillColor = "none";
+                options.isStroked = false;
+            } else if (this.isComplexSymbol(style.graphicName)) {
+                var cache = this.importSymbol(style.graphicName);
+                node.path = cache.path;
+                node.coordorigin = cache.left + "," + cache.bottom;
+                var size = cache.size;
+                node.coordsize = size + "," + size;        
+                this.drawCircle(node, geometry, style.pointRadius);
+                node.style.flip = "y";
+            } else {
+                this.drawCircle(node, geometry, style.pointRadius);
+            }
+        }
+
+        // fill 
+        if (options.isFilled) { 
+            node.fillcolor = style.fillColor; 
+        } else { 
+            node.filled = "false"; 
+        }
+        var fills = node.getElementsByTagName("fill");
+        var fill = (fills.length == 0) ? null : fills[0];
+        if (!options.isFilled) {
+            if (fill) {
+                node.removeChild(fill);
+            }
+        } else {
+            if (!fill) {
+                fill = this.createNode('olv:fill', node.id + "_fill");
+            }
+            fill.opacity = style.fillOpacity;
+
+            if (node._geometryClass == "OpenLayers.Geometry.Point" &&
+                    style.externalGraphic) {
+
+                // override fillOpacity
+                if (style.graphicOpacity) {
+                    fill.opacity = style.graphicOpacity;
+                }
+                
+                fill.src = style.externalGraphic;
+                fill.type = "frame";
+                
+                if (!(style.graphicWidth && style.graphicHeight)) {
+                  fill.aspect = "atmost";
+                }                
+            }
+            if (fill.parentNode != node) {
+                node.appendChild(fill);
+            }
+        }
+
+        // additional rendering for rotated graphics or symbols
+        if (typeof style.rotation != "undefined") {
+            if (style.externalGraphic) {
+                this.graphicRotate(node, xOffset, yOffset);
+                // make the fill fully transparent, because we now have
+                // the graphic as imagedata element. We cannot just remove
+                // the fill, because this is part of the hack described
+                // in graphicRotate
+                fill.opacity = 0;
+            } else {
+                node.style.rotation = style.rotation;
+            }
+        }
+
+        // stroke 
+        if (options.isStroked) { 
+            node.strokecolor = style.strokeColor; 
+            node.strokeweight = style.strokeWidth + "px"; 
+        } else { 
+            node.stroked = false; 
+        }
+        var strokes = node.getElementsByTagName("stroke");
+        var stroke = (strokes.length == 0) ? null : strokes[0];
+        if (!options.isStroked) {
+            if (stroke) {
+                node.removeChild(stroke);
+            }
+        } else {
+            if (!stroke) {
+                stroke = this.createNode('olv:stroke', node.id + "_stroke");
+                node.appendChild(stroke);
+            }
+            stroke.opacity = style.strokeOpacity;
+            stroke.endcap = !style.strokeLinecap || style.strokeLinecap == 'butt' ? 'flat' : style.strokeLinecap;
+            stroke.dashstyle = this.dashStyle(style);
+        }
+        
+        if (style.cursor != "inherit" && style.cursor != null) {
+            node.style.cursor = style.cursor;
+        }
+        return node;
+    },
+
+    /**
+     * Method: graphicRotate
+     * If a point is to be styled with externalGraphic and rotation, VML fills
+     * cannot be used to display the graphic, because rotation of graphic
+     * fills is not supported by the VML implementation of Internet Explorer.
+     * This method creates a olv:imagedata element inside the VML node,
+     * DXImageTransform.Matrix and BasicImage filters for rotation and
+     * opacity, and a 3-step hack to remove rendering artefacts from the
+     * graphic and preserve the ability of graphics to trigger events.
+     * Finally, OpenLayers methods are used to determine the correct
+     * insertion point of the rotated image, because DXImageTransform.Matrix
+     * does the rotation without the ability to specify a rotation center
+     * point.
+     * 
+     * Parameters:
+     * node    - {DOMElement}
+     * xOffset - {Number} rotation center relative to image, x coordinate
+     * yOffset - {Number} rotation center relative to image, y coordinate
+     */
+    graphicRotate: function(node, xOffset, yOffset) {
+        var style = style || node._style;
+        var options = node._options;
+        
+        var aspectRatio, size;
+        if (!(style.graphicWidth && style.graphicHeight)) {
+            // load the image to determine its size
+            var img = new Image();
+            img.onreadystatechange = OpenLayers.Function.bind(function() {
+                if(img.readyState == "complete" ||
+                        img.readyState == "interactive") {
+                    aspectRatio = img.width / img.height;
+                    size = Math.max(style.pointRadius * 2, 
+                        style.graphicWidth || 0,
+                        style.graphicHeight || 0);
+                    xOffset = xOffset * aspectRatio;
+                    style.graphicWidth = size * aspectRatio;
+                    style.graphicHeight = size;
+                    this.graphicRotate(node, xOffset, yOffset);
+                }
+            }, this);
+            img.src = style.externalGraphic;
+            
+            // will be called again by the onreadystate handler
+            return;
+        } else {
+            size = Math.max(style.graphicWidth, style.graphicHeight);
+            aspectRatio = style.graphicWidth / style.graphicHeight;
+        }
+        
+        var width = Math.round(style.graphicWidth || size * aspectRatio);
+        var height = Math.round(style.graphicHeight || size);
+        node.style.width = width + "px";
+        node.style.height = height + "px";
+        
+        // Three steps are required to remove artefacts for images with
+        // transparent backgrounds (resulting from using DXImageTransform
+        // filters on svg objects), while preserving awareness for browser
+        // events on images:
+        // - Use the fill as usual (like for unrotated images) to handle
+        //   events
+        // - specify an imagedata element with the same src as the fill
+        // - style the imagedata element with an AlphaImageLoader filter
+        //   with empty src
+        var image = document.getElementById(node.id + "_image");
+        if (!image) {
+            image = this.createNode("olv:imagedata", node.id + "_image");
+            node.appendChild(image);
+        }
+        image.style.width = width + "px";
+        image.style.height = height + "px";
+        image.src = style.externalGraphic;
+        image.style.filter =
+            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + 
+            "src='', sizingMethod='scale')";
+
+        var rotation = style.rotation * Math.PI / 180;
+        var sintheta = Math.sin(rotation);
+        var costheta = Math.cos(rotation);
+
+        // do the rotation on the image
+        var filter =
+            "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
+            ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
+            ",SizingMethod='auto expand')\n";
+
+        // set the opacity (needed for the imagedata)
+        var opacity = style.graphicOpacity || style.fillOpacity;
+        if (opacity && opacity != 1) {
+            filter += 
+                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + 
+                opacity+")\n";
+        }
+        node.style.filter = filter;
+
+        // do the rotation again on a box, so we know the insertion point
+        var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
+        var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
+        imgBox.rotate(style.rotation, centerPoint);
+        var imgBounds = imgBox.getBounds();
+
+        node.style.left = Math.round(
+            parseInt(node.style.left) + imgBounds.left) + "px";
+        node.style.top = Math.round(
+            parseInt(node.style.top) - imgBounds.bottom) + "px";
+    },
+
+    /**
+     * Method: postDraw
+     * Some versions of Internet Explorer seem to be unable to set fillcolor
+     * and strokecolor to "none" correctly before the fill node is appended to
+     * a visible vml node. This method takes care of that and sets fillcolor
+     * and strokecolor again if needed.
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     */
+    postDraw: function(node) {
+        var fillColor = node._style.fillColor;
+        var strokeColor = node._style.strokeColor;
+        if (fillColor == "none" &&
+                node.fillcolor != fillColor) {
+            node.fillcolor = fillColor;
+        }
+        if (strokeColor == "none" &&
+                node.strokecolor != strokeColor) {
+            node.strokecolor = strokeColor;
+        }
+    },
+
+
+    /**
+     * Method: setNodeDimension
+     * Get the geometry's bounds, convert it to our vml coordinate system, 
+     * then set the node's position, size, and local coordinate system.
+     *   
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     */
+    setNodeDimension: function(node, geometry) {
+
+        var bbox = geometry.getBounds();
+        if(bbox) {
+            var resolution = this.getResolution();
+        
+            var scaledBox = 
+                new OpenLayers.Bounds((bbox.left/resolution - this.offset.x).toFixed(),
+                                      (bbox.bottom/resolution - this.offset.y).toFixed(),
+                                      (bbox.right/resolution - this.offset.x).toFixed(),
+                                      (bbox.top/resolution - this.offset.y).toFixed());
+            
+            // Set the internal coordinate system to draw the path
+            node.style.left = scaledBox.left + "px";
+            node.style.top = scaledBox.top + "px";
+            node.style.width = scaledBox.getWidth() + "px";
+            node.style.height = scaledBox.getHeight() + "px";
+    
+            node.coordorigin = scaledBox.left + " " + scaledBox.top;
+            node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
+        }
+    },
+    
+    /** 
+     * Method: dashStyle
+     * 
+     * Parameters:
+     * style - {Object}
+     * 
+     * Returns:
+     * {String} A VML compliant 'stroke-dasharray' value
+     */
+    dashStyle: function(style) {
+        var dash = style.strokeDashstyle;
+        switch (dash) {
+            case 'solid':
+            case 'dot':
+            case 'dash':
+            case 'dashdot':
+            case 'longdash':
+            case 'longdashdot':
+                return dash;
+            default:
+                // very basic guessing of dash style patterns
+                var parts = dash.split(/[ ,]/);
+                if (parts.length == 2) {
+                    if (1*parts[0] >= 2*parts[1]) {
+                        return "longdash";
+                    }
+                    return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
+                } else if (parts.length == 4) {
+                    return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
+                        "dashdot";
+                }
+                return "solid";
+        }
+    },
+
+    /**
+     * Method: createNode
+     * Create a new node
+     *
+     * Parameters:
+     * type - {String} Kind of node to draw
+     * id - {String} Id for node
+     *
+     * Returns:
+     * {DOMElement} A new node of the given type and id
+     */
+    createNode: function(type, id) {
+        var node = document.createElement(type);
+        if (id) {
+            node.id = id;
+        }
+        
+        // IE hack to make elements unselectable, to prevent 'blue flash'
+        // while dragging vectors; #1410
+        node.unselectable = 'on';
+        node.onselectstart = function() { return(false); };
+        
+        return node;    
+    },
+    
+    /**
+     * Method: nodeTypeCompare
+     * Determine whether a node is of a given type
+     *
+     * Parameters:
+     * node - {DOMElement} An VML element
+     * type - {String} Kind of node
+     *
+     * Returns:
+     * {Boolean} Whether or not the specified node is of the specified type
+     */
+    nodeTypeCompare: function(node, type) {
+
+        //split type
+        var subType = type;
+        var splitIndex = subType.indexOf(":");
+        if (splitIndex != -1) {
+            subType = subType.substr(splitIndex+1);
+        }
+
+        //split nodeName
+        var nodeName = node.nodeName;
+        splitIndex = nodeName.indexOf(":");
+        if (splitIndex != -1) {
+            nodeName = nodeName.substr(splitIndex+1);
+        }
+
+        return (subType == nodeName);
+    },
+
+    /**
+     * Method: createRenderRoot
+     * Create the renderer root
+     *
+     * Returns:
+     * {DOMElement} The specific render engine's root element
+     */
+    createRenderRoot: function() {
+        return this.nodeFactory(this.container.id + "_vmlRoot", "div");
+    },
+
+    /**
+     * Method: createRoot
+     * Create the main root element
+     * 
+     * Parameters:
+     * suffix - {String} suffix to append to the id
+     *
+     * Returns:
+     * {DOMElement}
+     */
+    createRoot: function(suffix) {
+        return this.nodeFactory(this.container.id + suffix, "olv:group");
+    },
+    
+    /**************************************
+     *                                    *
+     *     GEOMETRY DRAWING FUNCTIONS     *
+     *                                    *
+     **************************************/
+    
+    /**
+     * Method: drawPoint
+     * Render a point
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or false if the point could not be drawn
+     */
+    drawPoint: function(node, geometry) {
+        return this.drawCircle(node, geometry, 1);
+    },
+
+    /**
+     * Method: drawCircle
+     * Render a circle.
+     * Size and Center a circle given geometry (x,y center) and radius
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * radius - {float}
+     * 
+     * Returns:
+     * {DOMElement} or false if the circle could not ne drawn
+     */
+    drawCircle: function(node, geometry, radius) {
+        if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
+            var resolution = this.getResolution();
+
+            node.style.left = ((geometry.x /resolution - this.offset.x).toFixed() - radius) + "px";
+            node.style.top = ((geometry.y /resolution - this.offset.y).toFixed() - radius) + "px";
+    
+            var diameter = radius * 2;
+            
+            node.style.width = diameter + "px";
+            node.style.height = diameter + "px";
+            return node;
+        }
+        return false;
+    },
+
+
+    /**
+     * Method: drawLineString
+     * Render a linestring.
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawLineString: function(node, geometry) {
+        return this.drawLine(node, geometry, false);
+    },
+
+    /**
+     * Method: drawLinearRing
+     * Render a linearring
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawLinearRing: function(node, geometry) {
+        return this.drawLine(node, geometry, true);
+    },
+
+    /**
+     * Method: DrawLine
+     * Render a line.
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * closeLine - {Boolean} Close the line? (make it a ring?)
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawLine: function(node, geometry, closeLine) {
+
+        this.setNodeDimension(node, geometry);
+
+        var resolution = this.getResolution();
+        var numComponents = geometry.components.length;
+        var parts = new Array(numComponents);
+
+        var comp, x, y;
+        for (var i = 0; i < numComponents; i++) {
+            comp = geometry.components[i];
+            x = (comp.x/resolution - this.offset.x);
+            y = (comp.y/resolution - this.offset.y);
+            parts[i] = " " + x.toFixed() + "," + y.toFixed() + " l ";
+        }
+        var end = (closeLine) ? " x e" : " e";
+        node.path = "m" + parts.join("") + end;
+        return node;
+    },
+
+    /**
+     * Method: drawPolygon
+     * Render a polygon
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawPolygon: function(node, geometry) {
+        this.setNodeDimension(node, geometry);
+
+        var resolution = this.getResolution();
+    
+        var path = [];
+        var linearRing, i, j, len, ilen, comp, x, y;
+        for (j = 0, len=geometry.components.length; j<len; j++) {
+            linearRing = geometry.components[j];
+
+            path.push("m");
+            for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
+                comp = linearRing.components[i];
+                x = comp.x / resolution - this.offset.x;
+                y = comp.y / resolution - this.offset.y;
+                path.push(" " + x.toFixed() + "," + y.toFixed());
+                if (i==0) {
+                    path.push(" l");
+                }
+            }
+            path.push(" x ");
+        }
+        path.push("e");
+        node.path = path.join("");
+        return node;
+    },
+
+    /**
+     * Method: drawRectangle
+     * Render a rectangle
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawRectangle: function(node, geometry) {
+        var resolution = this.getResolution();
+    
+        node.style.left = (geometry.x/resolution - this.offset.x) + "px";
+        node.style.top = (geometry.y/resolution - this.offset.y) + "px";
+        node.style.width = geometry.width/resolution + "px";
+        node.style.height = geometry.height/resolution + "px";
+        
+        return node;
+    },
+    
+    /**
+     * Method: drawText
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * featureId - {String}
+     * style -
+     * location - {<OpenLayers.Geometry.Point>}
+     */
+    drawText: function(featureId, style, location) {
+        var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect");
+        var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
+        
+        var resolution = this.getResolution();
+        label.style.left = (location.x/resolution - this.offset.x).toFixed() + "px";
+        label.style.top = (location.y/resolution - this.offset.y).toFixed() + "px";
+        label.style.flip = "y";
+
+        textbox.innerText = style.label;
+
+        if (style.fillColor) {
+            textbox.style.color = style.fontColor;
+        }
+        if (style.fontFamily) {
+            textbox.style.fontFamily = style.fontFamily;
+        }
+        if (style.fontSize) {
+            textbox.style.fontSize = style.fontSize;
+        }
+        if (style.fontWeight) {
+            textbox.style.fontWeight = style.fontWeight;
+        }
+        textbox.style.whiteSpace = "nowrap";
+        // fun with IE: IE7 in standards compliant mode does not display any
+        // text with a left inset of 0. So we set this to 1px and subtract one
+        // pixel later when we set label.style.left
+        textbox.inset = "1px,0px,0px,0px";
+
+        if(!label.parentNode) {
+            label.appendChild(textbox);
+            this.textRoot.appendChild(label);
+        }
+
+        var align = style.labelAlign || "cm";
+        var xshift = textbox.clientWidth *
+            (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);
+        var yshift = textbox.clientHeight *
+            (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
+        label.style.left = parseInt(label.style.left)-xshift-1+"px";
+        label.style.top = parseInt(label.style.top)+yshift+"px";
+    },
+
+    /**
+     * Method: drawSurface
+     * 
+     * Parameters:
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement}
+     */
+    drawSurface: function(node, geometry) {
+
+        this.setNodeDimension(node, geometry);
+
+        var resolution = this.getResolution();
+    
+        var path = [];
+        var comp, x, y;
+        for (var i=0, len=geometry.components.length; i<len; i++) {
+            comp = geometry.components[i];
+            x = comp.x / resolution - this.offset.x;
+            y = comp.y / resolution - this.offset.y;
+            if ((i%3)==0 && (i/3)==0) {
+                path.push("m");
+            } else if ((i%3)==1) {
+                path.push(" c");
+            }
+            path.push(" " + x + "," + y);
+        }
+        path.push(" x e");
+
+        node.path = path.join("");
+        return node;
+    },
+    
+    /**
+     * Method: moveRoot
+     * moves this renderer's root to a different renderer.
+     * 
+     * Parameters:
+     * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
+     * root - {DOMElement} optional root node. To be used when this renderer
+     *     holds roots from multiple layers to tell this method which one to
+     *     detach
+     * 
+     * Returns:
+     * {Boolean} true if successful, false otherwise
+     */
+    moveRoot: function(renderer) {
+        var layer = this.map.getLayer(renderer.container.id);
+        if(layer instanceof OpenLayers.Layer.Vector.RootContainer) {
+            layer = this.map.getLayer(this.container.id);
+        }
+        layer && layer.renderer.clear();
+        OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
+        layer && layer.redraw();
+    },
+    
+    /**
+     * Method: importSymbol
+     * add a new symbol definition from the rendererer's symbol hash
+     * 
+     * Parameters:
+     * graphicName - {String} name of the symbol to import
+     * 
+     * Returns:
+     * {Object} - hash of {DOMElement} "symbol" and {Number} "size"
+     */      
+    importSymbol: function (graphicName)  {
+        var id = this.container.id + "-" + graphicName;
+        
+        // check if symbol already exists in the cache
+        var cache = this.symbolCache[id];
+        if (cache) {
+            return cache;
+        }
+        
+        var symbol = OpenLayers.Renderer.symbol[graphicName];
+        if (!symbol) {
+            throw new Error(graphicName + ' is not a valid symbol name');
+            return;
+        }
+
+        var symbolExtent = new OpenLayers.Bounds(
+                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
+        
+        var pathitems = ["m"];
+        for (var i=0; i<symbol.length; i=i+2) {
+            x = symbol[i];
+            y = symbol[i+1];
+            symbolExtent.left = Math.min(symbolExtent.left, x);
+            symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
+            symbolExtent.right = Math.max(symbolExtent.right, x);
+            symbolExtent.top = Math.max(symbolExtent.top, y);
+
+            pathitems.push(x);
+            pathitems.push(y);
+            if (i == 0) {
+                pathitems.push("l");
+            }
+        }
+        pathitems.push("x e");
+        var path = pathitems.join(" ");
+
+        var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2;
+        if(diff > 0) {
+            symbolExtent.bottom = symbolExtent.bottom - diff;
+            symbolExtent.top = symbolExtent.top + diff;
+        } else {
+            symbolExtent.left = symbolExtent.left - diff;
+            symbolExtent.right = symbolExtent.right + diff;
+        }
+        
+        cache = {
+            path: path,
+            size: symbolExtent.getWidth(), // equals getHeight() now
+            left: symbolExtent.left,
+            bottom: symbolExtent.bottom
+        };
+        this.symbolCache[id] = cache;
+        
+        return cache;
+    },
+    
+    CLASS_NAME: "OpenLayers.Renderer.VML"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT
+ * {Object}
+ */
+OpenLayers.Renderer.VML.LABEL_SHIFT = {
+    "l": 0,
+    "c": .5,
+    "r": 1,
+    "t": 0,
+    "m": .5,
+    "b": 1
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request/XMLHttpRequest.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request/XMLHttpRequest.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request/XMLHttpRequest.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,313 @@
+// Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @requires OpenLayers/Request.js
+ */
+
+(function () {
+
+    // Save reference to earlier defined object implementation (if any)
+    var oXMLHttpRequest    = window.XMLHttpRequest;
+
+    // Define on browser type
+    var bGecko    = !!window.controllers,
+        bIE        = window.document.all && !window.opera;
+
+    // Constructor
+    function cXMLHttpRequest() {
+        this._object    = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject('Microsoft.XMLHTTP');
+    };
+
+    // BUGFIX: Firefox with Firebug installed would break pages if not executed
+    if (bGecko && oXMLHttpRequest.wrapped)
+        cXMLHttpRequest.wrapped    = oXMLHttpRequest.wrapped;
+
+    // Constants
+    cXMLHttpRequest.UNSENT                = 0;
+    cXMLHttpRequest.OPENED                = 1;
+    cXMLHttpRequest.HEADERS_RECEIVED    = 2;
+    cXMLHttpRequest.LOADING                = 3;
+    cXMLHttpRequest.DONE                = 4;
+
+    // Public Properties
+    cXMLHttpRequest.prototype.readyState    = cXMLHttpRequest.UNSENT;
+    cXMLHttpRequest.prototype.responseText    = "";
+    cXMLHttpRequest.prototype.responseXML    = null;
+    cXMLHttpRequest.prototype.status        = 0;
+    cXMLHttpRequest.prototype.statusText    = "";
+
+    // Instance-level Events Handlers
+    cXMLHttpRequest.prototype.onreadystatechange    = null;
+
+    // Class-level Events Handlers
+    cXMLHttpRequest.onreadystatechange    = null;
+    cXMLHttpRequest.onopen                = null;
+    cXMLHttpRequest.onsend                = null;
+    cXMLHttpRequest.onabort                = null;
+
+    // Public Methods
+    cXMLHttpRequest.prototype.open    = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+
+        // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
+        this._async        = bAsync;
+
+        // Set the onreadystatechange handler
+        var oRequest    = this,
+            nState        = this.readyState;
+
+        // BUGFIX: IE - memory leak on page unload (inter-page leak)
+        if (bIE) {
+            var fOnUnload    = function() {
+                if (oRequest._object.readyState != cXMLHttpRequest.DONE)
+                    fCleanTransport(oRequest);
+            };
+            if (bAsync)
+                window.attachEvent("onunload", fOnUnload);
+        }
+
+        this._object.onreadystatechange    = function() {
+            if (bGecko && !bAsync)
+                return;
+
+            // Synchronize state
+            oRequest.readyState        = oRequest._object.readyState;
+
+            //
+            fSynchronizeValues(oRequest);
+
+            // BUGFIX: Firefox fires unneccesary DONE when aborting
+            if (oRequest._aborted) {
+                // Reset readyState to UNSENT
+                oRequest.readyState    = cXMLHttpRequest.UNSENT;
+
+                // Return now
+                return;
+            }
+
+            if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                //
+                fCleanTransport(oRequest);
+// Uncomment this block if you need a fix for IE cache
+/*
+                // BUGFIX: IE - cache issue
+                if (!oRequest._object.getResponseHeader("Date")) {
+                    // Save object to cache
+                    oRequest._cached    = oRequest._object;
+
+                    // Instantiate a new transport object
+                    cXMLHttpRequest.call(oRequest);
+
+                    // Re-send request
+                    oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+                    oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
+                    // Copy headers set
+                    if (oRequest._headers)
+                        for (var sHeader in oRequest._headers)
+                            if (typeof oRequest._headers[sHeader] == "string")    // Some frameworks prototype objects with functions
+                                oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
+
+                    oRequest._object.onreadystatechange    = function() {
+                        // Synchronize state
+                        oRequest.readyState        = oRequest._object.readyState;
+
+                        if (oRequest._aborted) {
+                            //
+                            oRequest.readyState    = cXMLHttpRequest.UNSENT;
+
+                            // Return
+                            return;
+                        }
+
+                        if (oRequest.readyState == cXMLHttpRequest.DONE) {
+                            // Clean Object
+                            fCleanTransport(oRequest);
+
+                            // get cached request
+                            if (oRequest.status == 304)
+                                oRequest._object    = oRequest._cached;
+
+                            //
+                            delete oRequest._cached;
+
+                            //
+                            fSynchronizeValues(oRequest);
+
+                            //
+                            fReadyStateChange(oRequest);
+
+                            // BUGFIX: IE - memory leak in interrupted
+                            if (bIE && bAsync)
+                                window.detachEvent("onunload", fOnUnload);
+                        }
+                    };
+                    oRequest._object.send(null);
+
+                    // Return now - wait untill re-sent request is finished
+                    return;
+                };
+*/
+                // BUGFIX: IE - memory leak in interrupted
+                if (bIE && bAsync)
+                    window.detachEvent("onunload", fOnUnload);
+            }
+
+            // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
+            if (nState != oRequest.readyState)
+                fReadyStateChange(oRequest);
+
+            nState    = oRequest.readyState;
+        };
+
+        // Add method sniffer
+        if (cXMLHttpRequest.onopen)
+            cXMLHttpRequest.onopen.apply(this, arguments);
+
+        this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+
+        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+        if (!bAsync && bGecko) {
+            this.readyState    = cXMLHttpRequest.OPENED;
+
+            fReadyStateChange(this);
+        }
+    };
+    cXMLHttpRequest.prototype.send    = function(vData) {
+        // Add method sniffer
+        if (cXMLHttpRequest.onsend)
+            cXMLHttpRequest.onsend.apply(this, arguments);
+
+        // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
+        // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
+        // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
+        if (vData && vData.nodeType) {
+            vData    = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
+            if (!this._headers["Content-Type"])
+                this._object.setRequestHeader("Content-Type", "application/xml");
+        }
+
+        this._object.send(vData);
+
+        // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+        if (bGecko && !this._async) {
+            this.readyState    = cXMLHttpRequest.OPENED;
+
+            // Synchronize state
+            fSynchronizeValues(this);
+
+            // Simulate missing states
+            while (this.readyState < cXMLHttpRequest.DONE) {
+                this.readyState++;
+                fReadyStateChange(this);
+                // Check if we are aborted
+                if (this._aborted)
+                    return;
+            }
+        }
+    };
+    cXMLHttpRequest.prototype.abort    = function() {
+        // Add method sniffer
+        if (cXMLHttpRequest.onabort)
+            cXMLHttpRequest.onabort.apply(this, arguments);
+
+        // BUGFIX: Gecko - unneccesary DONE when aborting
+        if (this.readyState > cXMLHttpRequest.UNSENT)
+            this._aborted    = true;
+
+        this._object.abort();
+
+        // BUGFIX: IE - memory leak
+        fCleanTransport(this);
+    };
+    cXMLHttpRequest.prototype.getAllResponseHeaders    = function() {
+        return this._object.getAllResponseHeaders();
+    };
+    cXMLHttpRequest.prototype.getResponseHeader    = function(sName) {
+        return this._object.getResponseHeader(sName);
+    };
+    cXMLHttpRequest.prototype.setRequestHeader    = function(sName, sValue) {
+        // BUGFIX: IE - cache issue
+        if (!this._headers)
+            this._headers    = {};
+        this._headers[sName]    = sValue;
+
+        return this._object.setRequestHeader(sName, sValue);
+    };
+    cXMLHttpRequest.prototype.toString    = function() {
+        return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
+    };
+    cXMLHttpRequest.toString    = function() {
+        return '[' + "XMLHttpRequest" + ']';
+    };
+
+    // Helper function
+    function fReadyStateChange(oRequest) {
+        // Execute onreadystatechange
+        if (oRequest.onreadystatechange)
+            oRequest.onreadystatechange.apply(oRequest);
+
+        // Sniffing code
+        if (cXMLHttpRequest.onreadystatechange)
+            cXMLHttpRequest.onreadystatechange.apply(oRequest);
+    };
+
+    function fGetDocument(oRequest) {
+        var oDocument    = oRequest.responseXML;
+        // Try parsing responseText
+        if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+            oDocument    = new ActiveXObject('Microsoft.XMLDOM');
+            oDocument.loadXML(oRequest.responseText);
+        }
+        // Check if there is no error in document
+        if (oDocument)
+            if ((bIE && oDocument.parseError != 0) || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
+                return null;
+        return oDocument;
+    };
+
+    function fSynchronizeValues(oRequest) {
+        try {    oRequest.responseText    = oRequest._object.responseText;    } catch (e) {}
+        try {    oRequest.responseXML    = fGetDocument(oRequest._object);    } catch (e) {}
+        try {    oRequest.status            = oRequest._object.status;            } catch (e) {}
+        try {    oRequest.statusText        = oRequest._object.statusText;        } catch (e) {}
+    };
+
+    function fCleanTransport(oRequest) {
+        // BUGFIX: IE - memory leak (on-page leak)
+        oRequest._object.onreadystatechange    = new window.Function;
+
+        // Delete private properties
+        delete oRequest._headers;
+    };
+
+    // Internet Explorer 5.0 (missing apply)
+    if (!window.Function.prototype.apply) {
+        window.Function.prototype.apply    = function(oRequest, oArguments) {
+            if (!oArguments)
+                oArguments    = [];
+            oRequest.__func    = this;
+            oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
+            delete oRequest.__func;
+        };
+    };
+
+    // Register new object with window
+    /**
+     * Class: OpenLayers.Request.XMLHttpRequest
+     * Standard-compliant (W3C) cross-browser implementation of the
+     *     XMLHttpRequest object.  From
+     *     http://code.google.com/p/xmlhttprequest/.
+     */
+    OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
+})();
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Request.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,332 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Namespace: OpenLayers.Request
+ * The OpenLayers.Request namespace contains convenience methods for working
+ *     with XMLHttpRequests.  These methods work with a cross-browser
+ *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
+ */
+OpenLayers.Request = {
+    
+    /**
+     * Constant: DEFAULT_CONFIG
+     * {Object} Default configuration for all requests.
+     */
+    DEFAULT_CONFIG: {
+        method: "GET",
+        url: window.location.href,
+        async: true,
+        user: undefined,
+        password: undefined,
+        params: null,
+        proxy: OpenLayers.ProxyHost,
+        headers: {},
+        data: null,
+        callback: function() {},
+        success: null,
+        failure: null,
+        scope: null
+    },
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *     events on the {<OpenLayers.Request>} object.
+     *
+     * All event listeners will receive an event object with three properties:
+     * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
+     * config - {Object} The config object sent to the specific request method.
+     * requestUrl - {String} The request url.
+     * 
+     * Supported event types:
+     * complete - Triggered when we have a response from the request, if a
+     *     listener returns false, no further response processing will take
+     *     place.
+     * success - Triggered when the HTTP response has a success code (200-299).
+     * failure - Triggered when the HTTP response does not have a success code.
+     */
+    events: new OpenLayers.Events(this, null, ["complete", "success", "failure"]),
+    
+    /**
+     * APIMethod: issue
+     * Create a new XMLHttpRequest object, open it, set any headers, bind
+     *     a callback to done state, and send any data.  It is recommended that
+     *     you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
+     *     This method is only documented to provide detail on the configuration
+     *     options available to all request methods.
+     *
+     * Parameters:
+     * config - {Object} Object containing properties for configuring the
+     *     request.  Allowed configuration properties are described below.
+     *     This object is modified and should not be reused.
+     *
+     * Allowed config properties:
+     * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
+     *     OPTIONS.  Default is GET.
+     * url - {String} URL for the request.
+     * async - {Boolean} Open an asynchronous request.  Default is true.
+     * user - {String} User for relevant authentication scheme.  Set
+     *     to null to clear current user.
+     * password - {String} Password for relevant authentication scheme.
+     *     Set to null to clear current password.
+     * proxy - {String} Optional proxy.  Defaults to
+     *     <OpenLayers.ProxyHost>.
+     * params - {Object} Any key:value pairs to be appended to the
+     *     url as a query string.  Assumes url doesn't already include a query
+     *     string or hash.  Typically, this is only appropriate for <GET>
+     *     requests where the query string will be appended to the url.
+     *     Parameter values that are arrays will be
+     *     concatenated with a comma (note that this goes against form-encoding)
+     *     as is done with <OpenLayers.Util.getParameterString>.
+     * headers - {Object} Object with header:value pairs to be set on
+     *     the request.
+     * data - {String | Document} Optional data to send with the request.
+     *     Typically, this is only used with <POST> and <PUT> requests.
+     *     Make sure to provide the appropriate "Content-Type" header for your
+     *     data.  For <POST> and <PUT> requests, the content type defaults to
+     *     "application-xml".  If your data is a different content type, or
+     *     if you are using a different HTTP method, set the "Content-Type"
+     *     header to match your data type.
+     * callback - {Function} Function to call when request is done.
+     *     To determine if the request failed, check request.status (200
+     *     indicates success).
+     * success - {Function} Optional function to call if request status is in
+     *     the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * failure - {Function} Optional function to call if request status is not
+     *     in the 200s.  This will be called in addition to callback above and
+     *     would typically only be used as an alternative.
+     * scope - {Object} If callback is a public method on some object,
+     *     set the scope to that object.
+     *
+     * Returns:
+     * {XMLHttpRequest} Request object.  To abort the request before a response
+     *     is received, call abort() on the request object.
+     */
+    issue: function(config) {        
+        // apply default config - proxy host may have changed
+        var defaultConfig = OpenLayers.Util.extend(
+            this.DEFAULT_CONFIG,
+            {proxy: OpenLayers.ProxyHost}
+        );
+        config = OpenLayers.Util.applyDefaults(config, defaultConfig);
+
+        // create request, open, and set headers
+        var request = new OpenLayers.Request.XMLHttpRequest();
+        var url = config.url;
+        if(config.params) {
+            var paramString = OpenLayers.Util.getParameterString(config.params);
+            if(paramString.length > 0) {
+                var separator = (url.indexOf('?') > -1) ? '&' : '?';
+                url += separator + paramString;
+            }
+        }
+        if(config.proxy && (url.indexOf("http") == 0)) {
+            url = config.proxy + encodeURIComponent(url);
+        }
+        request.open(
+            config.method, url, config.async, config.user, config.password
+        );
+        for(var header in config.headers) {
+            request.setRequestHeader(header, config.headers[header]);
+        }
+
+        // bind callbacks to readyState 4 (done)
+        var complete = (config.scope) ?
+            OpenLayers.Function.bind(config.callback, config.scope) :
+            config.callback;
+        
+        // optional success callback
+        var success;
+        if(config.success) {
+            success = (config.scope) ?
+                OpenLayers.Function.bind(config.success, config.scope) :
+                config.success;
+        }
+
+        // optional failure callback
+        var failure;
+        if(config.failure) {
+            failure = (config.scope) ?
+                OpenLayers.Function.bind(config.failure, config.scope) :
+                config.failure;
+        }
+        
+        var events = this.events;
+         
+        request.onreadystatechange = function() {
+            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+                var proceed = events.triggerEvent(
+                    "complete",
+                    {request: request, config: config, requestUrl: url}
+                );
+                if(proceed !== false) {
+                    complete(request);
+                    if (!request.status || (request.status >= 200 && request.status < 300)) {
+                        events.triggerEvent(
+                            "success",
+                            {request: request, config: config, requestUrl: url}
+                        );
+                        if(success) {
+                            success(request);
+                        }
+                    }
+                    if(request.status && (request.status < 200 || request.status >= 300)) {                    
+                        events.triggerEvent(
+                            "failure",
+                            {request: request, config: config, requestUrl: url}
+                        );
+                        if(failure) {
+                            failure(request);
+                        }
+                    }
+                }
+            }
+        };
+        
+        // send request (optionally with data) and return
+        // call in a timeout for asynchronous requests so the return is
+        // available before readyState == 4 for cached docs
+        if(config.async === false) {
+            request.send(config.data);
+        } else {
+            window.setTimeout(function(){
+                request.send(config.data);
+            }, 0);
+        }
+        return request;
+    },
+    
+    /**
+     * APIMethod: GET
+     * Send an HTTP GET request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to GET.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    GET: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "GET"});
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: POST
+     * Send a POST request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to POST and "Content-Type" header set to "application/xml".
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    POST: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "POST"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
+        }
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: PUT
+     * Send an HTTP PUT request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to PUT and "Content-Type" header set to "application/xml".
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.  The
+     *     default "Content-Type" header will be set to "application-xml" if
+     *     none is provided.  This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    PUT: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "PUT"});
+        // set content type to application/xml if it isn't already set
+        config.headers = config.headers ? config.headers : {};
+        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+            config.headers["Content-Type"] = "application/xml";
+        }
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: DELETE
+     * Send an HTTP DELETE request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to DELETE.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    DELETE: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "DELETE"});
+        return OpenLayers.Request.issue(config);
+    },
+  
+    /**
+     * APIMethod: HEAD
+     * Send an HTTP HEAD request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to HEAD.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    HEAD: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "HEAD"});
+        return OpenLayers.Request.issue(config);
+    },
+    
+    /**
+     * APIMethod: OPTIONS
+     * Send an HTTP OPTIONS request.  Additional configuration properties are
+     *     documented in the <issue> method, with the method property set
+     *     to OPTIONS.
+     *
+     * Parameters:
+     * config - {Object} Object with properties for configuring the request.
+     *     See the <issue> method for documentation of allowed properties.
+     *     This object is modified and should not be reused.
+     * 
+     * Returns:
+     * {XMLHttpRequest} Request object.
+     */
+    OPTIONS: function(config) {
+        config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
+        return OpenLayers.Request.issue(config);
+    }
+
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/SingleFile.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/SingleFile.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/SingleFile.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,9 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+var OpenLayers = {
+    singleFile: true
+};
+
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/BBOX.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/BBOX.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/BBOX.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,270 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ * @requires OpenLayers/Filter/Spatial.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.BBOX
+ * A simple strategy that reads new features when the viewport invalidates
+ *     some bounds.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
+    
+    /**
+     * Property: bounds
+     * {<OpenLayers.Bounds>} The current data bounds (in the same projection
+     *     as the layer - not always the same projection as the map).
+     */
+    bounds: null,
+    
+    /** 
+     * Property: resolution 
+     * {Float} The current data resolution. 
+     */ 
+    resolution: null, 
+           
+    /**
+     * APIProperty: ratio
+     * {Float} The ratio of the data bounds to the viewport bounds (in each
+     *     dimension).  Default is 2.
+     */
+    ratio: 2,
+
+    /** 
+     * Property: resFactor 
+     * {Float} Optional factor used to determine when previously requested 
+     *     features are invalid.  If set, the resFactor will be compared to the
+     *     resolution of the previous request to the current map resolution.
+     *     If resFactor > (old / new) and 1/resFactor < (old / new).  If you
+     *     set a resFactor of 1, data will be requested every time the
+     *     resolution changes.  If you set a resFactor of 3, data will be
+     *     requested if the old resolution is 3 times the new, or if the new is
+     *     3 times the old.  If the old bounds do not contain the new bounds
+     *     new data will always be requested (with or without considering
+     *     resFactor). 
+     */ 
+    resFactor: null, 
+    
+    /**
+     * Property: response
+     * {<OpenLayers.Protocol.Response>} The protocol response object returned
+     *      by the layer protocol.
+     */
+    response: null,
+
+    /**
+     * Constructor: OpenLayers.Strategy.BBOX
+     * Create a new BBOX strategy.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * Method: activate
+     * Set up strategy with regard to reading new batches of remote data.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully activated.
+     */
+    activate: function() {
+        var activated = OpenLayers.Strategy.prototype.activate.call(this);
+        if(activated) {
+            this.layer.events.on({
+                "moveend": this.update,
+                scope: this
+            });
+            this.layer.events.on({
+                "refresh": this.update,
+                scope: this
+            });
+        }
+        return activated;
+    },
+    
+    /**
+     * Method: deactivate
+     * Tear down strategy with regard to reading new batches of remote data.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+        if(deactivated) {
+            this.layer.events.un({
+                "moveend": this.update,
+                scope: this
+            });
+            this.layer.events.un({
+                "refresh": this.update,
+                scope: this
+            });
+        }
+        return deactivated;
+    },
+
+    /**
+     * Method: update
+     * Callback function called on "moveend" or "refresh" layer events.
+     *
+     * Parameters:
+     * options - {Object} An object with a property named "force", this
+     *      property references a boolean value indicating if new data
+     *      must be incondtionally read.
+     */
+    update: function(options) {
+        var mapBounds = this.getMapBounds();
+        if ((options && options.force) || this.invalidBounds(mapBounds)) {
+            this.calculateBounds(mapBounds);
+            this.resolution = this.layer.map.getResolution(); 
+            this.triggerRead();
+        }
+    },
+    
+    /**
+     * Method: getMapBounds
+     * Get the map bounds expressed in the same projection as this layer.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Map bounds in the projection of the layer.
+     */
+    getMapBounds: function() {
+        var bounds = this.layer.map.getExtent();
+        if(!this.layer.projection.equals(this.layer.map.getProjectionObject())) {
+            bounds = bounds.clone().transform(
+                this.layer.map.getProjectionObject(), this.layer.projection
+            );
+        }
+        return bounds;
+    },
+
+    /**
+     * Method: invalidBounds
+     * Determine whether the previously requested set of features is invalid. 
+     *     This occurs when the new map bounds do not contain the previously 
+     *     requested bounds.  In addition, if <resFactor> is set, it will be 
+     *     considered.
+     *
+     * Parameters:
+     * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+     *      retrieved from the map object if not provided
+     *
+     * Returns:
+     * {Boolean} 
+     */
+    invalidBounds: function(mapBounds) {
+        if(!mapBounds) {
+            mapBounds = this.getMapBounds();
+        }
+        var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);
+        if(!invalid && this.resFactor) {
+            var ratio = this.resolution / this.layer.map.getResolution();
+            invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));
+        }
+        return invalid;
+    },
+ 
+    /**
+     * Method: calculateBounds
+     *
+     * Parameters:
+     * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+     *      retrieved from the map object if not provided
+     */
+    calculateBounds: function(mapBounds) {
+        if(!mapBounds) {
+            mapBounds = this.getMapBounds();
+        }
+        var center = mapBounds.getCenterLonLat();
+        var dataWidth = mapBounds.getWidth() * this.ratio;
+        var dataHeight = mapBounds.getHeight() * this.ratio;
+        this.bounds = new OpenLayers.Bounds(
+            center.lon - (dataWidth / 2),
+            center.lat - (dataHeight / 2),
+            center.lon + (dataWidth / 2),
+            center.lat + (dataHeight / 2)
+        );
+    },
+    
+    /**
+     * Method: triggerRead
+     *
+     * Returns:
+     * {<OpenLayers.Protocol.Response>} The protocol response object
+     *      returned by the layer protocol.
+     */
+    triggerRead: function() {
+        this.layer.protocol.abort(this.response);
+        this.layer.events.triggerEvent("loadstart");
+        this.response = this.layer.protocol.read({
+            filter: this.createFilter(),
+            callback: this.merge,
+            scope: this
+        });
+    },
+ 
+    /**
+     * Method: createFilter
+     *
+     * Returns
+     * {<OpenLayers.Filter>} The filter object.
+     */
+    createFilter: function() {
+        var filter = new OpenLayers.Filter.Spatial({
+            type: OpenLayers.Filter.Spatial.BBOX,
+            value: this.bounds,
+            projection: this.layer.projection
+        });
+        if (this.layer.filter) {
+            filter = new OpenLayers.Filter.Logical({
+                type: OpenLayers.Filter.Logical.AND,
+                filters: [this.layer.filter, filter]
+            });
+        }
+        return filter;
+    },
+   
+    /**
+     * Method: merge
+     * Given a list of features, determine which ones to add to the layer.
+     *     If the layer projection differs from the map projection, features
+     *     will be transformed from the layer projection to the map projection.
+     *
+     * Parameters:
+     * resp - {<OpenLayers.Protocol.Response>} The response object passed
+     *      by the protocol.
+     */
+    merge: function(resp) {
+        this.layer.destroyFeatures();
+        var features = resp.features;
+        if(features && features.length > 0) {
+            var remote = this.layer.projection;
+            var local = this.layer.map.getProjectionObject();
+            if(!local.equals(remote)) {
+                var geom;
+                for(var i=0, len=features.length; i<len; ++i) {
+                    geom = features[i].geometry;
+                    if(geom) {
+                        geom.transform(remote, local);
+                    }
+                }
+            }
+            this.layer.addFeatures(features);
+        }
+        this.layer.events.triggerEvent("loadend");
+    },
+   
+    CLASS_NAME: "OpenLayers.Strategy.BBOX" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Cluster.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Cluster.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Cluster.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,279 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Cluster
+ * Strategy for vector feature clustering.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
+    
+    /**
+     * APIProperty: distance
+     * {Integer} Pixel distance between features that should be considered a
+     *     single cluster.  Default is 20 pixels.
+     */
+    distance: 20,
+    
+    /**
+     * APIProperty: threshold
+     * {Integer} Optional threshold below which original features will be
+     *     added to the layer instead of clusters.  For example, a threshold
+     *     of 3 would mean that any time there are 2 or fewer features in
+     *     a cluster, those features will be added directly to the layer instead
+     *     of a cluster representing those features.  Default is null (which is
+     *     equivalent to 1 - meaning that clusters may contain just one feature).
+     */
+    threshold: null,
+    
+    /**
+     * Property: features
+     * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+     */
+    features: null,
+    
+    /**
+     * Property: clusters
+     * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
+     */
+    clusters: null,
+    
+    /**
+     * Property: clustering
+     * {Boolean} The strategy is currently clustering features.
+     */
+    clustering: false,
+    
+    /**
+     * Property: resolution
+     * {Float} The resolution (map units per pixel) of the current cluster set.
+     */
+    resolution: null,
+
+    /**
+     * Constructor: OpenLayers.Strategy.Cluster
+     * Create a new clustering strategy.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: activate
+     * Activate the strategy.  Register any listeners, do appropriate setup.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully activated.
+     */
+    activate: function() {
+        var activated = OpenLayers.Strategy.prototype.activate.call(this);
+        if(activated) {
+            this.layer.events.on({
+                "beforefeaturesadded": this.cacheFeatures,
+                "moveend": this.cluster,
+                scope: this
+            });
+        }
+        return activated;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the strategy.  Unregister any listeners, do appropriate
+     *     tear-down.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+        if(deactivated) {
+            this.clearCache();
+            this.layer.events.un({
+                "beforefeaturesadded": this.cacheFeatures,
+                "moveend": this.cluster,
+                scope: this
+            });
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: cacheFeatures
+     * Cache features before they are added to the layer.
+     *
+     * Parameters:
+     * event - {Object} The event that this was listening for.  This will come
+     *     with a batch of features to be clustered.
+     *     
+     * Returns:
+     * {Boolean} False to stop layer from being added to the layer.
+     */
+    cacheFeatures: function(event) {
+        var propagate = true;
+        if(!this.clustering) {
+            this.clearCache();
+            this.features = event.features;
+            this.cluster();
+            propagate = false;
+        }
+        return propagate;
+    },
+    
+    /**
+     * Method: clearCache
+     * Clear out the cached features.
+     */
+    clearCache: function() {
+        this.features = null;
+    },
+    
+    /**
+     * Method: cluster
+     * Cluster features based on some threshold distance.
+     *
+     * Parameters:
+     * event - {Object} The event received when cluster is called as a
+     *     result of a moveend event.
+     */
+    cluster: function(event) {
+        if((!event || event.zoomChanged) && this.features) {
+            var resolution = this.layer.map.getResolution();
+            if(resolution != this.resolution || !this.clustersExist()) {
+                this.resolution = resolution;
+                var clusters = [];
+                var feature, clustered, cluster;
+                for(var i=0; i<this.features.length; ++i) {
+                    feature = this.features[i];
+                    if(feature.geometry) {
+                        clustered = false;
+                        for(var j=0; j<clusters.length; ++j) {
+                            cluster = clusters[j];
+                            if(this.shouldCluster(cluster, feature)) {
+                                this.addToCluster(cluster, feature);
+                                clustered = true;
+                                break;
+                            }
+                        }
+                        if(!clustered) {
+                            clusters.push(this.createCluster(this.features[i]));
+                        }
+                    }
+                }
+                this.layer.destroyFeatures();
+                if(clusters.length > 0) {
+                    if(this.threshold > 1) {
+                        var clone = clusters.slice();
+                        clusters = [];
+                        var candidate;
+                        for(var i=0, len=clone.length; i<len; ++i) {
+                            candidate = clone[i];
+                            if(candidate.attributes.count < this.threshold) {
+                                Array.prototype.push.apply(clusters, candidate.cluster);
+                            } else {
+                                clusters.push(candidate);
+                            }
+                        }
+                    }
+                    this.clustering = true;
+                    // A legitimate feature addition could occur during this
+                    // addFeatures call.  For clustering to behave well, features
+                    // should be removed from a layer before requesting a new batch.
+                    this.layer.addFeatures(clusters);
+                    this.clustering = false;
+                }
+                this.clusters = clusters;
+            }
+        }
+    },
+    
+    /**
+     * Method: clustersExist
+     * Determine whether calculated clusters are already on the layer.
+     *
+     * Returns:
+     * {Boolean} The calculated clusters are already on the layer.
+     */
+    clustersExist: function() {
+        var exist = false;
+        if(this.clusters && this.clusters.length > 0 &&
+           this.clusters.length == this.layer.features.length) {
+            exist = true;
+            for(var i=0; i<this.clusters.length; ++i) {
+                if(this.clusters[i] != this.layer.features[i]) {
+                    exist = false;
+                    break;
+                }
+            }
+        }
+        return exist;
+    },
+    
+    /**
+     * Method: shouldCluster
+     * Determine whether to include a feature in a given cluster.
+     *
+     * Parameters:
+     * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+     * feature - {<OpenLayers.Feature.Vector>} A feature.
+     *
+     * Returns:
+     * {Boolean} The feature should be included in the cluster.
+     */
+    shouldCluster: function(cluster, feature) {
+        var cc = cluster.geometry.getBounds().getCenterLonLat();
+        var fc = feature.geometry.getBounds().getCenterLonLat();
+        var distance = (
+            Math.sqrt(
+                Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
+            ) / this.resolution
+        );
+        return (distance <= this.distance);
+    },
+    
+    /**
+     * Method: addToCluster
+     * Add a feature to a cluster.
+     *
+     * Parameters:
+     * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+     * feature - {<OpenLayers.Feature.Vector>} A feature.
+     */
+    addToCluster: function(cluster, feature) {
+        cluster.cluster.push(feature);
+        cluster.attributes.count += 1;
+    },
+    
+    /**
+     * Method: createCluster
+     * Given a feature, create a cluster.
+     *
+     * Parameters:
+     * feature - {<OpenLayers.Feature.Vector>}
+     *
+     * Returns:
+     * {<OpenLayers.Feature.Vector>} A cluster.
+     */
+    createCluster: function(feature) {
+        var center = feature.geometry.getBounds().getCenterLonLat();
+        var cluster = new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(center.lon, center.lat),
+            {count: 1}
+        );
+        cluster.cluster = [feature];
+        return cluster;
+    },
+
+    CLASS_NAME: "OpenLayers.Strategy.Cluster" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Fixed.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Fixed.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Fixed.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,136 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Fixed
+ * A simple strategy that requests features once and never requests new data.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
+    
+    /**
+     * APIProperty: preload
+     * {Boolean} Load data before layer made visible. Enabling this may result
+     *   in considerable overhead if your application loads many data layers
+     *   that are not visible by default. Default is true.
+     */
+    preload: false,
+
+    /**
+     * Constructor: OpenLayers.Strategy.Fixed
+     * Create a new Fixed strategy.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+    },
+
+    /**
+     * APIMethod: destroy
+     * Clean up the strategy.
+     */
+    destroy: function() {
+        OpenLayers.Strategy.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * Method: activate
+     * Activate the strategy: load data or add listener to load when visible
+     *
+     * Returns:
+     * {Boolean} True if the strategy was successfully activated or false if
+     *      the strategy was already active.
+     */
+    activate: function() {
+        if(OpenLayers.Strategy.prototype.activate.apply(this, arguments)) {
+            this.layer.events.on({
+                "refresh": this.load,
+                scope: this
+            });
+            if(this.layer.visibility == true || this.preload) {
+                this.load();
+            } else {
+                this.layer.events.on({
+                    "visibilitychanged": this.load,
+                    scope: this
+                });
+            }
+            return true;
+        }
+        return false;
+    },
+    
+    /**
+     * Method: deactivate
+     * Deactivate the strategy.  Undo what is done in <activate>.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+        if(deactivated) {
+            this.layer.events.un({
+                "refresh": this.load,
+                "visibilitychanged": this.load,
+                scope: this
+            });
+        }
+        return deactivated;
+    },
+
+    /**
+     * Method: load
+     * Tells protocol to load data and unhooks the visibilitychanged event
+     *
+     * Parameters:
+     * options - {Object} options to pass to protocol read.
+     */
+    load: function(options) {
+        this.layer.events.triggerEvent("loadstart");
+        this.layer.protocol.read(OpenLayers.Util.applyDefaults({
+            callback: this.merge,
+            scope: this
+        }, options));
+        this.layer.events.un({
+            "visibilitychanged": this.load,
+            scope: this
+        });
+    },
+
+    /**
+     * Method: merge
+     * Add all features to the layer.
+     */
+    merge: function(resp) {
+        this.layer.destroyFeatures();
+        var features = resp.features;
+        if (features && features.length > 0) {
+            var remote = this.layer.projection;
+            var local = this.layer.map.getProjectionObject();
+            if(!local.equals(remote)) {
+                var geom;
+                for(var i=0, len=features.length; i<len; ++i) {
+                    geom = features[i].geometry;
+                    if(geom) {
+                        geom.transform(remote, local);
+                    }
+                }
+            }
+            this.layer.addFeatures(features);
+        }
+        this.layer.events.triggerEvent("loadend");
+    },
+
+    CLASS_NAME: "OpenLayers.Strategy.Fixed"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Paging.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Paging.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Paging.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,235 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Paging
+ * Strategy for vector feature paging
+ *
+ * Inherits from:
+ *  - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
+    
+    /**
+     * Property: features
+     * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+     */
+    features: null,
+    
+    /**
+     * Property: length
+     * {Integer} Number of features per page.  Default is 10.
+     */
+    length: 10,
+    
+    /**
+     * Property: num
+     * {Integer} The currently displayed page number.
+     */
+    num: null,
+    
+    /**
+     * Property: paging
+     * {Boolean} The strategy is currently changing pages.
+     */
+    paging: false,
+
+    /**
+     * Constructor: OpenLayers.Strategy.Paging
+     * Create a new paging strategy.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: activate
+     * Activate the strategy.  Register any listeners, do appropriate setup.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully activated.
+     */
+    activate: function() {
+        var activated = OpenLayers.Strategy.prototype.activate.call(this);
+        if(activated) {
+            this.layer.events.on({
+                "beforefeaturesadded": this.cacheFeatures,
+                scope: this
+            });
+        }
+        return activated;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the strategy.  Unregister any listeners, do appropriate
+     *     tear-down.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+        if(deactivated) {
+            this.clearCache();
+            this.layer.events.un({
+                "beforefeaturesadded": this.cacheFeatures,
+                scope: this
+            });
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: cacheFeatures
+     * Cache features before they are added to the layer.
+     *
+     * Parameters:
+     * event - {Object} The event that this was listening for.  This will come
+     *     with a batch of features to be paged.
+     */
+    cacheFeatures: function(event) {
+        if(!this.paging) {
+            this.clearCache();
+            this.features = event.features;
+            this.pageNext(event);
+        }
+    },
+    
+    /**
+     * Method: clearCache
+     * Clear out the cached features.  This destroys features, assuming
+     *     nothing else has a reference.
+     */
+    clearCache: function() {
+        if(this.features) {
+            for(var i=0; i<this.features.length; ++i) {
+                this.features[i].destroy();
+            }
+        }
+        this.features = null;
+        this.num = null;
+    },
+    
+    /**
+     * APIMethod: pageCount
+     * Get the total count of pages given the current cache of features.
+     *
+     * Returns:
+     * {Integer} The page count.
+     */
+    pageCount: function() {
+        var numFeatures = this.features ? this.features.length : 0;
+        return Math.ceil(numFeatures / this.length);
+    },
+
+    /**
+     * APIMethod: pageNum
+     * Get the zero based page number.
+     *
+     * Returns:
+     * {Integer} The current page number being displayed.
+     */
+    pageNum: function() {
+        return this.num;
+    },
+
+    /**
+     * APIMethod: pageLength
+     * Gets or sets page length.
+     *
+     * Parameters:
+     * newLength: {Integer} Optional length to be set.
+     *
+     * Returns:
+     * {Integer} The length of a page (number of features per page).
+     */
+    pageLength: function(newLength) {
+        if(newLength && newLength > 0) {
+            this.length = newLength;
+        }
+        return this.length;
+    },
+
+    /**
+     * APIMethod: pageNext
+     * Display the next page of features.
+     *
+     * Returns:
+     * {Boolean} A new page was displayed.
+     */
+    pageNext: function(event) {
+        var changed = false;
+        if(this.features) {
+            if(this.num === null) {
+                this.num = -1;
+            }
+            var start = (this.num + 1) * this.length;
+            changed = this.page(start, event);
+        }
+        return changed;
+    },
+
+    /**
+     * APIMethod: pagePrevious
+     * Display the previous page of features.
+     *
+     * Returns:
+     * {Boolean} A new page was displayed.
+     */
+    pagePrevious: function() {
+        var changed = false;
+        if(this.features) {
+            if(this.num === null) {
+                this.num = this.pageCount();
+            }
+            var start = (this.num - 1) * this.length;
+            changed = this.page(start);
+        }
+        return changed;
+    },
+    
+    /**
+     * Method: page
+     * Display the page starting at the given index from the cache.
+     *
+     * Returns:
+     * {Boolean} A new page was displayed.
+     */
+    page: function(start, event) {
+        var changed = false;
+        if(this.features) {
+            if(start >= 0 && start < this.features.length) {
+                var num = Math.floor(start / this.length);
+                if(num != this.num) {
+                    this.paging = true;
+                    var features = this.features.slice(start, start + this.length);
+                    this.layer.removeFeatures(this.layer.features);
+                    this.num = num;
+                    // modify the event if any
+                    if(event && event.features) {
+                        // this.was called by an event listener
+                        event.features = features;
+                    } else {
+                        // this was called directly on the strategy
+                        this.layer.addFeatures(features);
+                    }
+                    this.paging = false;
+                    changed = true;
+                }
+            }
+        }
+        return changed;
+    },
+    
+    CLASS_NAME: "OpenLayers.Strategy.Paging" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Save.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Save.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy/Save.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,194 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Save
+ * A strategy that commits newly created or modified features.  By default
+ *     the strategy waits for a call to <save> before persisting changes.  By
+ *     configuring the strategy with the <auto> option, changes can be saved
+ *     automatically.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {
+    
+    /**
+     * APIProperty: auto
+     * {Boolean | Number} Auto-save.  Default is false.  If true, features will be
+     *     saved immediately after being added to the layer and with each
+     *     modification or deletion.  If auto is a number, features will be
+     *     saved on an interval provided by the value (in seconds).
+     */
+    auto: false,
+    
+    /**
+     * Property: timer
+     * {Number} The id of the timer.
+     */
+    timer: null,
+
+    /**
+     * Constructor: OpenLayers.Strategy.Save
+     * Create a new Save strategy.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+    },
+   
+    /**
+     * APIMethod: activate
+     * Activate the strategy.  Register any listeners, do appropriate setup.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully activated.
+     */
+    activate: function() {
+        var activated = OpenLayers.Strategy.prototype.activate.call(this);
+        if(activated) {
+            if(this.auto) {
+                if(typeof this.auto === "number") {
+                    this.timer = window.setInterval(
+                        OpenLayers.Function.bind(this.save, this),
+                        this.auto * 1000
+                    )
+                } else {
+                    this.layer.events.on({
+                        "featureadded": this.triggerSave,
+                        "afterfeaturemodified": this.triggerSave,
+                        scope: this
+                    });
+                }
+            }
+        }
+        return activated;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Deactivate the strategy.  Unregister any listeners, do appropriate
+     *     tear-down.
+     * 
+     * Returns:
+     * {Boolean} The strategy was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+        if(deactivated) {
+            if(this.auto) {
+                if(typeof this.auto === "number") {
+                    window.clearInterval(this.timer);
+                } else {
+                    this.layer.events.un({
+                        "featureadded": this.triggerSave,
+                        "afterfeaturemodified": this.triggerSave,
+                        scope: this
+                    })
+                }
+            }
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: triggerSave
+     * Registered as a listener.  Calls save if a feature has insert, update,
+     *     or delete state.
+     *
+     * Parameters:
+     * event - {Object} The event this function is listening for.
+     */
+    triggerSave: function(event) {
+        var feature = event.feature;
+        if(feature.state === OpenLayers.State.INSERT ||
+           feature.state === OpenLayers.State.UPDATE ||
+           feature.state === OpenLayers.State.DELETE) {
+            this.save([event.feature]);
+        }
+    },
+    
+    /**
+     * APIMethod: save
+     * Tell the layer protocol to commit unsaved features.  If the layer
+     *     projection differs from the map projection, features will be
+     *     transformed into the layer projection before being committed.
+     *
+     * Parameters:
+     * features - {Array} Features to be saved.  If null, then default is all
+     *     features in the layer.  Features are assumed to be in the map
+     *     projection.
+     */
+    save: function(features) {
+        if(!features) {
+            features = this.layer.features;
+        }
+        var remote = this.layer.projection;
+        var local = this.layer.map.getProjectionObject();
+        if(!local.equals(remote)) {
+            var len = features.length;
+            var clones = new Array(len);
+            var orig, clone;
+            for(var i=0; i<len; ++i) {
+                orig = features[i];
+                clone = orig.clone();
+                clone.fid = orig.fid;
+                clone.state = orig.state;
+                clone._original = orig;
+                clone.geometry.transform(local, remote);
+                clones[i] = clone;
+            }
+            features = clones;
+        }
+        this.layer.protocol.commit(features, {
+            callback: this.onCommit,
+            scope: this
+        });
+    },
+    
+    /**
+     * Method: onCommit
+     * Called after protocol commit.
+     *
+     * Parameters:
+     * response - {<OpenLayers.Protocol.Response>} A response object.
+     */
+    onCommit: function(response) {
+        if(response.success()) {
+            var features = response.reqFeatures;
+            // deal with inserts, updates, and deletes
+            var state, feature;
+            var destroys = [];
+            var insertIds = response.insertIds || [];
+            var j = 0;
+            for(var i=0, len=features.length; i<len; ++i) {
+                feature = features[i];
+                // if projection was different, we may be dealing with clones
+                feature = feature._original || feature;
+                state = feature.state;
+                if(state) {
+                    if(state == OpenLayers.State.DELETE) {
+                        destroys.push(feature);
+                    } else if(state == OpenLayers.State.INSERT) {
+                        feature.fid = insertIds[j];
+                        ++j;
+                    }
+                    feature.state = null;
+                }
+            }
+            if(destroys.length > 0) {
+                this.layer.destroyFeatures(destroys);
+            }
+        }
+    },    
+   
+    CLASS_NAME: "OpenLayers.Strategy.Save" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Strategy.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,116 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Strategy
+ * Abstract vector layer strategy class.  Not to be instantiated directly.  Use
+ *     one of the strategy subclasses instead.
+ */
+OpenLayers.Strategy = OpenLayers.Class({
+    
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
+     */
+    layer: null,
+    
+    /**
+     * Property: options
+     * {Object} Any options sent to the constructor.
+     */
+    options: null,
+
+    /** 
+     * Property: active 
+     * {Boolean} The control is active.
+     */
+    active: null,
+
+    /**
+     * Property: autoActivate
+     * {Boolean} The creator of the strategy can set autoActivate to false
+     *      to fully control when the protocol is activated and deactivated.
+     *      Defaults to true.
+     */
+    autoActivate: true,
+
+    /**
+     * Property: autoDestroy
+     * {Boolean} The creator of the strategy can set autoDestroy to false
+     *      to fully control when the strategy is destroyed. Defaults to
+     *      true.
+     */
+    autoDestroy: true,
+
+    /**
+     * Constructor: OpenLayers.Strategy
+     * Abstract class for vector strategies.  Create instances of a subclass.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+    initialize: function(options) {
+        OpenLayers.Util.extend(this, options);
+        this.options = options;
+        // set the active property here, so that user cannot override it
+        this.active = false;
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Clean up the strategy.
+     */
+    destroy: function() {
+        this.deactivate();
+        this.layer = null;
+        this.options = null;
+    },
+
+    /**
+     * Method: setLayer
+     * Called to set the <layer> property.
+     *
+     * Parameters:
+     * {<OpenLayers.Layer.Vector>}
+     */
+    setLayer: function(layer) {
+        this.layer = layer;
+    },
+    
+    /**
+     * Method: activate
+     * Activate the strategy.  Register any listeners, do appropriate setup.
+     *
+     * Returns:
+     * {Boolean} True if the strategy was successfully activated or false if
+     *      the strategy was already active.
+     */
+    activate: function() {
+        if (!this.active) {
+            this.active = true;
+            return true;
+        }
+        return false;
+    },
+    
+    /**
+     * Method: deactivate
+     * Deactivate the strategy.  Unregister any listeners, do appropriate
+     *     tear-down.
+     *
+     * Returns:
+     * {Boolean} True if the strategy was successfully deactivated or false if
+     *      the strategy was already inactive.
+     */
+    deactivate: function() {
+        if (this.active) {
+            this.active = false;
+            return true;
+        }
+        return false;
+    },
+   
+    CLASS_NAME: "OpenLayers.Strategy" 
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/StyleMap.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/StyleMap.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/StyleMap.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,159 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+ 
+/**
+ * Class: OpenLayers.StyleMap
+ */
+OpenLayers.StyleMap = OpenLayers.Class({
+    
+    /**
+     * Property: styles
+     * Hash of {<OpenLayers.Style>}, keyed by names of well known
+     * rendering intents (e.g. "default", "temporary", "select", "delete").
+     */
+    styles: null,
+    
+    /**
+     * Property: extendDefault
+     * {Boolean} if true, every render intent will extend the symbolizers
+     * specified for the "default" intent at rendering time. Otherwise, every
+     * rendering intent will be treated as a completely independent style.
+     */
+    extendDefault: true,
+    
+    /**
+     * Constructor: OpenLayers.StyleMap
+     * 
+     * Parameters:
+     * style   - {Object} Optional. Either a style hash, or a style object, or
+     *           a hash of style objects (style hashes) keyed by rendering
+     *           intent. If just one style hash or style object is passed,
+     *           this will be used for all known render intents (default,
+     *           select, temporary)
+     * options - {Object} optional hash of additional options for this
+     *           instance
+     */
+    initialize: function (style, options) {
+        this.styles = {
+            "default": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["default"]),
+            "select": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["select"]),
+            "temporary": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["temporary"]),
+            "delete": new OpenLayers.Style(
+                OpenLayers.Feature.Vector.style["delete"])
+        };
+        
+        // take whatever the user passed as style parameter and convert it
+        // into parts of stylemap.
+        if(style instanceof OpenLayers.Style) {
+            // user passed a style object
+            this.styles["default"] = style;
+            this.styles["select"] = style;
+            this.styles["temporary"] = style;
+            this.styles["delete"] = style;
+        } else if(typeof style == "object") {
+            for(var key in style) {
+                if(style[key] instanceof OpenLayers.Style) {
+                    // user passed a hash of style objects
+                    this.styles[key] = style[key];
+                } else if(typeof style[key] == "object") {
+                    // user passsed a hash of style hashes
+                    this.styles[key] = new OpenLayers.Style(style[key]);
+                } else {
+                    // user passed a style hash (i.e. symbolizer)
+                    this.styles["default"] = new OpenLayers.Style(style);
+                    this.styles["select"] = new OpenLayers.Style(style);
+                    this.styles["temporary"] = new OpenLayers.Style(style);
+                    this.styles["delete"] = new OpenLayers.Style(style);
+                    break;
+                }
+            }
+        }
+        OpenLayers.Util.extend(this, options);
+    },
+
+    /**
+     * Method: destroy
+     */
+    destroy: function() {
+        for(var key in this.styles) {
+            this.styles[key].destroy();
+        }
+        this.styles = null;
+    },
+    
+    /**
+     * Method: createSymbolizer
+     * Creates the symbolizer for a feature for a render intent.
+     * 
+     * Parameters:
+     * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
+     *           of the intended style against.
+     * intent  - {String} The intent determines the symbolizer that will be
+     *           used to draw the feature. Well known intents are "default"
+     *           (for just drawing the features), "select" (for selected
+     *           features) and "temporary" (for drawing features).
+     * 
+     * Returns:
+     * {Object} symbolizer hash
+     */
+    createSymbolizer: function(feature, intent) {
+        if(!feature) {
+            feature = new OpenLayers.Feature.Vector();
+        }
+        if(!this.styles[intent]) {
+            intent = "default";
+        }
+        feature.renderIntent = intent;
+        var defaultSymbolizer = {};
+        if(this.extendDefault && intent != "default") {
+            defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
+        }
+        return OpenLayers.Util.extend(defaultSymbolizer,
+            this.styles[intent].createSymbolizer(feature));
+    },
+    
+    /**
+     * Method: addUniqueValueRules
+     * Convenience method to create comparison rules for unique values of a
+     * property. The rules will be added to the style object for a specified
+     * rendering intent. This method is a shortcut for creating something like
+     * the "unique value legends" familiar from well known desktop GIS systems
+     * 
+     * Parameters:
+     * renderIntent - {String} rendering intent to add the rules to
+     * property     - {String} values of feature attributes to create the
+     *                rules for
+     * symbolizers  - {Object} Hash of symbolizers, keyed by the desired
+     *                property values 
+     * context      - {Object} An optional object with properties that
+     *                symbolizers' property values should be evaluated
+     *                against. If no context is specified, feature.attributes
+     *                will be used
+     */
+    addUniqueValueRules: function(renderIntent, property, symbolizers, context) {
+        var rules = [];
+        for (var value in symbolizers) {
+            rules.push(new OpenLayers.Rule({
+                symbolizer: symbolizers[value],
+                context: context,
+                filter: new OpenLayers.Filter.Comparison({
+                    type: OpenLayers.Filter.Comparison.EQUAL_TO,
+                    property: property,
+                    value: value
+                })
+            }));
+        }
+        this.styles[renderIntent].addRules(rules);
+    },
+
+    CLASS_NAME: "OpenLayers.StyleMap"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/Image.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/Image.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/Image.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,576 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile.js
+ */
+
+/**
+ * Class: OpenLayers.Tile.Image
+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles
+ * used by various layers.  Create a new image tile with the
+ * <OpenLayers.Tile.Image> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+
+    /** 
+     * Property: url
+     * {String} The URL of the image being requested. No default. Filled in by
+     * layer.getURL() function. 
+     */
+    url: null,
+    
+    /** 
+     * Property: imgDiv
+     * {DOMElement} The div element which wraps the image.
+     */
+    imgDiv: null,
+
+    /**
+     * Property: frame
+     * {DOMElement} The image element is appended to the frame.  Any gutter on
+     * the image will be hidden behind the frame. 
+     */ 
+    frame: null, 
+    
+    /**
+     * Property: layerAlphaHack
+     * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
+     */
+    layerAlphaHack: null,
+    
+    /**
+     * Property: isBackBuffer
+     * {Boolean} Is this tile a back buffer tile?
+     */
+    isBackBuffer: false,
+    
+    /**
+     * Property: lastRatio
+     * {Float} Used in transition code only.  This is the previous ratio
+     *     of the back buffer tile resolution to the map resolution.  Compared
+     *     with the current ratio to determine if zooming occurred.
+     */
+    lastRatio: 1,
+
+    /**
+     * Property: isFirstDraw
+     * {Boolean} Is this the first time the tile is being drawn?
+     *     This is used to force resetBackBuffer to synchronize
+     *     the backBufferTile with the foreground tile the first time
+     *     the foreground tile loads so that if the user zooms
+     *     before the layer has fully loaded, the backBufferTile for
+     *     tiles that have been loaded can be used.
+     */
+    isFirstDraw: true,
+        
+    /**
+     * Property: backBufferTile
+     * {<OpenLayers.Tile>} A clone of the tile used to create transition
+     *     effects when the tile is moved or changes resolution.
+     */
+    backBufferTile: null,
+
+    /** TBD 3.0 - reorder the parameters to the init function to remove 
+     *             URL. the getUrl() function on the layer gets called on 
+     *             each draw(), so no need to specify it here.
+     * 
+     * Constructor: OpenLayers.Tile.Image
+     * Constructor for a new <OpenLayers.Tile.Image> instance.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+     * position - {<OpenLayers.Pixel>}
+     * bounds - {<OpenLayers.Bounds>}
+     * url - {<String>} Deprecated. Remove me in 3.0.
+     * size - {<OpenLayers.Size>}
+     */   
+    initialize: function(layer, position, bounds, url, size) {
+        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+
+        this.url = url; //deprecated remove me
+        
+        this.frame = document.createElement('div'); 
+        this.frame.style.overflow = 'hidden'; 
+        this.frame.style.position = 'absolute'; 
+
+        this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
+    },
+
+    /** 
+     * APIMethod: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        if (this.imgDiv != null)  {
+            if (this.layerAlphaHack) {
+                // unregister the "load" handler
+                OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0].id);                
+            }
+
+            // unregister the "load" and "error" handlers. Only the "error" handler if
+            // this.layerAlphaHack is true.
+            OpenLayers.Event.stopObservingElement(this.imgDiv.id);
+            
+            if (this.imgDiv.parentNode == this.frame) {
+                this.frame.removeChild(this.imgDiv);
+                this.imgDiv.map = null;
+            }
+            this.imgDiv.urls = null;
+            // abort any currently loading image
+            this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+        }
+        this.imgDiv = null;
+        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
+            this.layer.div.removeChild(this.frame); 
+        }
+        this.frame = null; 
+        
+        /* clean up the backBufferTile if it exists */
+        if (this.backBufferTile) {
+            this.backBufferTile.destroy();
+            this.backBufferTile = null;
+        }
+        
+        this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+        
+        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * Method: clone
+     *
+     * Parameters:
+     * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
+     *
+     * Returns:
+     * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+     */
+    clone: function (obj) {
+        if (obj == null) {
+            obj = new OpenLayers.Tile.Image(this.layer, 
+                                            this.position, 
+                                            this.bounds, 
+                                            this.url, 
+                                            this.size);        
+        } 
+        
+        //pick up properties from superclass
+        obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
+        
+        //dont want to directly copy the image div
+        obj.imgDiv = null;
+            
+        
+        return obj;
+    },
+    
+    /**
+     * Method: draw
+     * Check that a tile should be drawn, and draw it.
+     * 
+     * Returns:
+     * {Boolean} Always returns true.
+     */
+    draw: function() {
+        if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+            this.bounds = this.getBoundsFromBaseLayer(this.position);
+        }
+        var drawTile = OpenLayers.Tile.prototype.draw.apply(this, arguments);
+        
+        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) {
+            if (drawTile) {
+                //we use a clone of this tile to create a double buffer for visual
+                //continuity.  The backBufferTile is used to create transition
+                //effects while the tile in the grid is repositioned and redrawn
+                if (!this.backBufferTile) {
+                    this.backBufferTile = this.clone();
+                    this.backBufferTile.hide();
+                    // this is important.  It allows the backBuffer to place itself
+                    // appropriately in the DOM.  The Image subclass needs to put
+                    // the backBufferTile behind the main tile so the tiles can
+                    // load over top and display as soon as they are loaded.
+                    this.backBufferTile.isBackBuffer = true;
+                    
+                    // potentially end any transition effects when the tile loads
+                    this.events.register('loadend', this, this.resetBackBuffer);
+                    
+                    // clear transition back buffer tile only after all tiles in
+                    // this layer have loaded to avoid visual glitches
+                    this.layer.events.register("loadend", this, this.resetBackBuffer);
+                }
+                // run any transition effects
+                this.startTransition();
+            } else {
+                // if we aren't going to draw the tile, then the backBuffer should
+                // be hidden too!
+                if (this.backBufferTile) {
+                    this.backBufferTile.clear();
+                }
+            }
+        } else {
+            if (drawTile && this.isFirstDraw) {
+                this.events.register('loadend', this, this.showTile);
+                this.isFirstDraw = false;
+            }   
+        }    
+        
+        if (!drawTile) {
+            return false;
+        }
+        
+        if (this.isLoading) {
+            //if we're already loading, send 'reload' instead of 'loadstart'.
+            this.events.triggerEvent("reload"); 
+        } else {
+            this.isLoading = true;
+            this.events.triggerEvent("loadstart");
+        }
+        
+        return this.renderTile();
+    },
+    
+    /** 
+     * Method: resetBackBuffer
+     * Triggered by two different events, layer loadend, and tile loadend.
+     *     In any of these cases, we check to see if we can hide the 
+     *     backBufferTile yet and update its parameters to match the 
+     *     foreground tile.
+     *
+     * Basic logic:
+     *  - If the backBufferTile hasn't been drawn yet, reset it
+     *  - If layer is still loading, show foreground tile but don't hide
+     *    the backBufferTile yet
+     *  - If layer is done loading, reset backBuffer tile and show 
+     *    foreground tile
+     */
+    resetBackBuffer: function() {
+        this.showTile();
+        if (this.backBufferTile && 
+            (this.isFirstDraw || !this.layer.numLoadingTiles)) {
+            this.isFirstDraw = false;
+            // check to see if the backBufferTile is within the max extents
+            // before rendering it 
+            var maxExtent = this.layer.maxExtent;
+            var withinMaxExtent = (maxExtent &&
+                                   this.bounds.intersectsBounds(maxExtent, false));
+            if (withinMaxExtent) {
+                this.backBufferTile.position = this.position;
+                this.backBufferTile.bounds = this.bounds;
+                this.backBufferTile.size = this.size;
+                this.backBufferTile.imageSize = this.layer.imageSize || this.size;
+                this.backBufferTile.imageOffset = this.layer.imageOffset;
+                this.backBufferTile.resolution = this.layer.getResolution();
+                this.backBufferTile.renderTile();
+            }
+
+            this.backBufferTile.hide();
+        }
+    },
+    
+    /**
+     * Method: renderTile
+     * Internal function to actually initialize the image tile,
+     *     position it correctly, and set its url.
+     */
+    renderTile: function() {
+        if (this.imgDiv == null) {
+            this.initImgDiv();
+        }
+
+        this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+        
+        if (this.layer.async) {
+            // Asyncronous image requests call the asynchronous getURL method
+            // on the layer to fetch an image that covers 'this.bounds', in the scope of
+            // 'this', setting the 'url' property of the layer itself, and running
+            // the callback 'positionFrame' when the image request returns.
+            this.layer.getURLasync(this.bounds, this, "url", this.positionImage);
+        } else {
+            // syncronous image requests get the url and position the frame immediately,
+            // and don't wait for an image request to come back.
+          
+            // needed for changing to a different server for onload error
+            if (this.layer.url instanceof Array) {
+                this.imgDiv.urls = this.layer.url.slice();
+            }
+          
+            this.url = this.layer.getURL(this.bounds);
+          
+            // position the frame immediately
+            this.positionImage(); 
+        }
+        return true;
+    },
+
+    /**
+     * Method: positionImage
+     * Using the properties currenty set on the layer, position the tile correctly.
+     * This method is used both by the async and non-async versions of the Tile.Image
+     * code.
+     */
+     positionImage: function() {
+        // if the this layer doesn't exist at the point the image is
+        // returned, do not attempt to use it for size computation
+        if ( this.layer == null )
+            return;
+        
+        // position the frame 
+        OpenLayers.Util.modifyDOMElement(this.frame, 
+                                          null, this.position, this.size);   
+
+        var imageSize = this.layer.getImageSize(); 
+        if (this.layerAlphaHack) {
+            OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
+                    null, null, imageSize, this.url);
+        } else {
+            OpenLayers.Util.modifyDOMElement(this.imgDiv,
+                    null, null, imageSize) ;
+            this.imgDiv.src = this.url;
+        }
+    },
+
+    /** 
+     * Method: clear
+     *  Clear the tile of any bounds/position-related data so that it can 
+     *   be reused in a new location.
+     */
+    clear: function() {
+        if(this.imgDiv) {
+            this.hide();
+            if (OpenLayers.Tile.Image.useBlankTile) { 
+                this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+            }    
+        }
+    },
+
+    /**
+     * Method: initImgDiv
+     * Creates the imgDiv property on the tile.
+     */
+    initImgDiv: function() {
+        
+        var offset = this.layer.imageOffset; 
+        var size = this.layer.getImageSize(); 
+     
+        if (this.layerAlphaHack) {
+            this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
+                                                           offset,
+                                                           size,
+                                                           null,
+                                                           "relative",
+                                                           null,
+                                                           null,
+                                                           null,
+                                                           true);
+        } else {
+            this.imgDiv = OpenLayers.Util.createImage(null,
+                                                      offset,
+                                                      size,
+                                                      null,
+                                                      "relative",
+                                                      null,
+                                                      null,
+                                                      true);
+        }
+        
+        this.imgDiv.className = 'olTileImage';
+
+        /* checkImgURL used to be used to called as a work around, but it
+           ended up hiding problems instead of solving them and broke things
+           like relative URLs. See discussion on the dev list:
+           http://openlayers.org/pipermail/dev/2007-January/000205.html
+
+        OpenLayers.Event.observe( this.imgDiv, "load",
+            OpenLayers.Function.bind(this.checkImgURL, this) );
+        */
+        this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
+        this.frame.appendChild(this.imgDiv); 
+        this.layer.div.appendChild(this.frame); 
+
+        if(this.layer.opacity != null) {
+            
+            OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
+                                             null, null, null, 
+                                             this.layer.opacity);
+        }
+
+        // we need this reference to check back the viewRequestID
+        this.imgDiv.map = this.layer.map;
+
+        //bind a listener to the onload of the image div so that we 
+        // can register when a tile has finished loading.
+        var onload = function() {
+            
+            //normally isLoading should always be true here but there are some 
+            // right funky conditions where loading and then reloading a tile
+            // with the same url *really*fast*. this check prevents sending 
+            // a 'loadend' if the msg has already been sent
+            //
+            if (this.isLoading) { 
+                this.isLoading = false; 
+                this.events.triggerEvent("loadend"); 
+            }
+        };
+        
+        if (this.layerAlphaHack) { 
+            OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load', 
+                                     OpenLayers.Function.bind(onload, this));    
+        } else { 
+            OpenLayers.Event.observe(this.imgDiv, 'load', 
+                                 OpenLayers.Function.bind(onload, this)); 
+        } 
+        
+
+        // Bind a listener to the onerror of the image div so that we
+        // can registere when a tile has finished loading with errors.
+        var onerror = function() {
+
+            // If we have gone through all image reload attempts, it is time
+            // to realize that we are done with this image. Since
+            // OpenLayers.Util.onImageLoadError already has taken care about
+            // the error, we can continue as if the image was loaded
+            // successfully.
+            if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+                onload.call(this);
+            }
+        };
+        OpenLayers.Event.observe(this.imgDiv, "error",
+                                 OpenLayers.Function.bind(onerror, this));
+    },
+
+    /**
+     * Method: checkImgURL
+     * Make sure that the image that just loaded is the one this tile is meant
+     * to display, since panning/zooming might have changed the tile's URL in
+     * the meantime. If the tile URL did change before the image loaded, set
+     * the imgDiv display to 'none', as either (a) it will be reset to visible
+     * when the new URL loads in the image, or (b) we don't want to display
+     * this tile after all because its new bounds are outside our maxExtent.
+     * 
+     * This function should no longer  be neccesary with the improvements to
+     * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
+     * caused problems in 2.2, but it's possible that with the improved 
+     * isEquivilant URL function, this might be neccesary at some point.
+     * 
+     * See discussion in the thread at 
+     * http://openlayers.org/pipermail/dev/2007-January/000205.html
+     */
+    checkImgURL: function () {
+        // Sometimes our image will load after it has already been removed
+        // from the map, in which case this check is not needed.  
+        if (this.layer) {
+            var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
+            if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
+                this.hide();
+            }
+        }
+    },
+    
+    /**
+     * Method: startTransition
+     * This method is invoked on tiles that are backBuffers for tiles in the
+     *     grid.  The grid tile is about to be cleared and a new tile source
+     *     loaded.  This is where the transition effect needs to be started
+     *     to provide visual continuity.
+     */
+    startTransition: function() {
+        // backBufferTile has to be valid and ready to use
+        if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
+            return;
+        }
+
+        // calculate the ratio of change between the current resolution of the
+        // backBufferTile and the layer.  If several animations happen in a
+        // row, then the backBufferTile will scale itself appropriately for
+        // each request.
+        var ratio = 1;
+        if (this.backBufferTile.resolution) {
+            ratio = this.backBufferTile.resolution / this.layer.getResolution();
+        }
+        
+        // if the ratio is not the same as it was last time (i.e. we are
+        // zooming), then we need to adjust the backBuffer tile
+        if (ratio != this.lastRatio) {
+            if (this.layer.transitionEffect == 'resize') {
+                // In this case, we can just immediately resize the 
+                // backBufferTile.
+                var upperLeft = new OpenLayers.LonLat(
+                    this.backBufferTile.bounds.left, 
+                    this.backBufferTile.bounds.top
+                );
+                var size = new OpenLayers.Size(
+                    this.backBufferTile.size.w * ratio,
+                    this.backBufferTile.size.h * ratio
+                );
+
+                var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
+                OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 
+                                                 null, px, size);
+                var imageSize = this.backBufferTile.imageSize;
+                imageSize = new OpenLayers.Size(imageSize.w * ratio, 
+                                                imageSize.h * ratio);
+                var imageOffset = this.backBufferTile.imageOffset;
+                if(imageOffset) {
+                    imageOffset = new OpenLayers.Pixel(
+                        imageOffset.x * ratio, imageOffset.y * ratio
+                    );
+                }
+
+                OpenLayers.Util.modifyDOMElement(
+                    this.backBufferTile.imgDiv, null, imageOffset, imageSize
+                ) ;
+
+                this.backBufferTile.show();
+            }
+        } else {
+            // default effect is just to leave the existing tile
+            // until the new one loads if this is a singleTile and
+            // there was no change in resolution.  Otherwise we
+            // don't bother to show the backBufferTile at all
+            if (this.layer.singleTile) {
+                this.backBufferTile.show();
+            } else {
+                this.backBufferTile.hide();
+            }
+        }
+        this.lastRatio = ratio;
+
+    },
+    
+    /** 
+     * Method: show
+     * Show the tile by showing its frame.
+     */
+    show: function() {
+        this.frame.style.display = '';
+        // Force a reflow on gecko based browsers to actually show the element
+        // before continuing execution.
+        if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, 
+                this.layer.transitionEffect) != -1) {
+            if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) { 
+                this.frame.scrollLeft = this.frame.scrollLeft; 
+            } 
+        }
+    },
+    
+    /** 
+     * Method: hide
+     * Hide the tile by hiding its frame.
+     */
+    hide: function() {
+        this.frame.style.display = 'none';
+    },
+    
+    CLASS_NAME: "OpenLayers.Tile.Image"
+  }
+);
+
+OpenLayers.Tile.Image.useBlankTile = ( 
+    OpenLayers.Util.getBrowserName() == "safari" || 
+    OpenLayers.Util.getBrowserName() == "opera"); 

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/WFS.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/WFS.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile/WFS.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,191 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+ 
+/**
+ * @requires OpenLayers/Tile.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Tile.WFS
+ * Instances of OpenLayers.Tile.WFS are used to manage the image tiles
+ * used by various layers.  Create a new image tile with the
+ * <OpenLayers.Tile.WFS> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.WFS = OpenLayers.Class(OpenLayers.Tile, {
+
+    /** 
+     * Property: features 
+     * {Array(<OpenLayers.Feature>)} list of features in this tile 
+     */
+    features: null,
+
+    /** 
+     * Property: url 
+     * {String} 
+     */
+    url: null,
+    
+    /** 
+     * Property: request 
+     * {<OpenLayers.Request.XMLHttpRequest>} 
+     */ 
+    request: null,     
+    
+    /** TBD 3.0 - reorder the parameters to the init function to put URL 
+     *             as last, so we can continue to call tile.initialize() 
+     *             without changing the arguments. 
+     * 
+     * Constructor: OpenLayers.Tile.WFS
+     * Constructor for a new <OpenLayers.Tile.WFS> instance.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+     * position - {<OpenLayers.Pixel>}
+     * bounds - {<OpenLayers.Bounds>}
+     * url - {<String>}
+     * size - {<OpenLayers.Size>}
+     */   
+    initialize: function(layer, position, bounds, url, size) {
+        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+        this.url = url;        
+        this.features = [];
+    },
+
+    /** 
+     * APIMethod: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+        this.destroyAllFeatures();
+        this.features = null;
+        this.url = null;
+        if(this.request) {
+            this.request.abort();
+            //this.request.destroy();
+            this.request = null;
+        }
+    },
+
+    /** 
+     * Method: clear
+     *  Clear the tile of any bounds/position-related data so that it can 
+     *   be reused in a new location.
+     */
+    clear: function() {
+        this.destroyAllFeatures();
+    },
+    
+    /**
+     * Method: draw
+     * Check that a tile should be drawn, and load features for it.
+     */
+    draw:function() {
+        if (OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
+            if (this.isLoading) {
+                //if already loading, send 'reload' instead of 'loadstart'.
+                this.events.triggerEvent("reload"); 
+            } else {
+                this.isLoading = true;
+                this.events.triggerEvent("loadstart");
+            }
+            this.loadFeaturesForRegion(this.requestSuccess);
+        }
+    },
+
+    /** 
+    * Method: loadFeaturesForRegion
+    * Abort any pending requests and issue another request for data. 
+    *
+    * Input are function pointers for what to do on success and failure.
+    *
+    * Parameters:
+    * success - {function}
+    * failure - {function}
+    */
+    loadFeaturesForRegion:function(success, failure) {
+        if(this.request) {
+            this.request.abort();
+        }
+        this.request = OpenLayers.Request.GET({
+            url: this.url,
+            success: success,
+            failure: failure,
+            scope: this
+        });
+    },
+    
+    /**
+    * Method: requestSuccess
+    * Called on return from request succcess. Adds results via 
+    * layer.addFeatures in vector mode, addResults otherwise. 
+    *
+    * Parameters:
+    * request - {<OpenLayers.Request.XMLHttpRequest>}
+    */
+    requestSuccess:function(request) {
+        if (this.features) {
+            var doc = request.responseXML;
+            if (!doc || !doc.documentElement) {
+                doc = request.responseText; 
+            }
+            if (this.layer.vectorMode) {
+                this.layer.addFeatures(this.layer.formatObject.read(doc));
+            } else {
+                var xml = new OpenLayers.Format.XML();
+                if (typeof doc == "string") {
+                    doc = xml.read(doc);
+                }
+                var resultFeatures = xml.getElementsByTagNameNS(
+                    doc, "http://www.opengis.net/gml", "featureMember"
+                );
+                this.addResults(resultFeatures);
+            }
+        }
+        if (this.events) {
+            this.events.triggerEvent("loadend"); 
+        }
+
+        //request produced with success, we can delete the request object.
+        //this.request.destroy();
+        this.request = null;
+    },
+
+    /**
+     * Method: addResults
+     * Construct new feature via layer featureClass constructor, and add to
+     * this.features.
+     * 
+     * Parameters:
+     * results - {Object}
+     */
+    addResults: function(results) {
+        for (var i=0; i < results.length; i++) {
+            var feature = new this.layer.featureClass(this.layer, 
+                                                      results[i]);
+            this.features.push(feature);
+        }
+    },
+
+
+    /** 
+     * Method: destroyAllFeatures
+     * Iterate through and call destroy() on each feature, removing it from
+     *   the local array
+     */
+    destroyAllFeatures: function() {
+        while(this.features.length > 0) {
+            var feature = this.features.shift();
+            feature.destroy();
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Tile.WFS"
+  }
+);

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tile.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,280 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/*
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Console.js
+ */
+
+/*
+ * Class: OpenLayers.Tile 
+ * This is a class designed to designate a single tile, however
+ *     it is explicitly designed to do relatively little. Tiles store 
+ *     information about themselves -- such as the URL that they are related
+ *     to, and their size - but do not add themselves to the layer div 
+ *     automatically, for example. Create a new tile with the 
+ *     <OpenLayers.Tile> constructor, or a subclass. 
+ * 
+ * TBD 3.0 - remove reference to url in above paragraph
+ * 
+ */
+OpenLayers.Tile = OpenLayers.Class({
+    
+    /** 
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types
+     */
+    EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *                       events on the tile.
+     */
+    events: null,
+
+    /**
+     * Property: id 
+     * {String} null
+     */
+    id: null,
+    
+    /** 
+     * Property: layer 
+     * {<OpenLayers.Layer>} layer the tile is attached to 
+     */
+    layer: null,
+    
+    /**
+     * Property: url
+     * {String} url of the request.
+     *
+     * TBD 3.0 
+     * Deprecated. The base tile class does not need an url. This should be 
+     * handled in subclasses. Does not belong here.
+     */
+    url: null,
+
+    /** 
+     * APIProperty: bounds 
+     * {<OpenLayers.Bounds>} null
+     */
+    bounds: null,
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} null
+     */
+    size: null,
+    
+    /** 
+     * Property: position 
+     * {<OpenLayers.Pixel>} Top Left pixel of the tile
+     */    
+    position: null,
+
+    /**
+     * Property: isLoading
+     * {Boolean} Is the tile loading?
+     */
+    isLoading: false,
+        
+    /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
+     *             there is no need for the base tile class to have a url.
+     * 
+     * Constructor: OpenLayers.Tile
+     * Constructor for a new <OpenLayers.Tile> instance.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+     * position - {<OpenLayers.Pixel>}
+     * bounds - {<OpenLayers.Bounds>}
+     * url - {<String>}
+     * size - {<OpenLayers.Size>}
+     */   
+    initialize: function(layer, position, bounds, url, size) {
+        this.layer = layer;
+        this.position = position.clone();
+        this.bounds = bounds.clone();
+        this.url = url;
+        this.size = size.clone();
+
+        //give the tile a unique id based on its BBOX.
+        this.id = OpenLayers.Util.createUniqueID("Tile_");
+        
+        this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+    },
+
+    /**
+     * Method: unload
+     * Call immediately before destroying if you are listening to tile
+     * events, so that counters are properly handled if tile is still
+     * loading at destroy-time. Will only fire an event if the tile is
+     * still loading.
+     */
+    unload: function() {
+       if (this.isLoading) { 
+           this.isLoading = false; 
+           this.events.triggerEvent("unload"); 
+       }
+    },
+    
+    /** 
+     * APIMethod: destroy
+     * Nullify references to prevent circular references and memory leaks.
+     */
+    destroy:function() {
+        this.layer  = null;
+        this.bounds = null;
+        this.size = null;
+        this.position = null;
+        
+        this.events.destroy();
+        this.events = null;
+    },
+    
+    /**
+     * Method: clone
+     *
+     * Parameters:
+     * obj - {<OpenLayers.Tile>} The tile to be cloned
+     *
+     * Returns:
+     * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
+     */
+    clone: function (obj) {
+        if (obj == null) {
+            obj = new OpenLayers.Tile(this.layer, 
+                                      this.position, 
+                                      this.bounds, 
+                                      this.url, 
+                                      this.size);
+        } 
+        
+        // catch any randomly tagged-on properties
+        OpenLayers.Util.applyDefaults(obj, this);
+        
+        return obj;
+    },
+
+    /**
+     * Method: draw
+     * Clear whatever is currently in the tile, then return whether or not 
+     *     it should actually be re-drawn.
+     * 
+     * Returns:
+     * {Boolean} Whether or not the tile should actually be drawn. Note that 
+     *     this is not really the best way of doing things, but such is 
+     *     the way the code has been developed. Subclasses call this and
+     *     depend on the return to know if they should draw or not.
+     */
+    draw: function() {
+        var maxExtent = this.layer.maxExtent;
+        var withinMaxExtent = (maxExtent &&
+                               this.bounds.intersectsBounds(maxExtent, false));
+ 
+        // The only case where we *wouldn't* want to draw the tile is if the 
+        // tile is outside its layer's maxExtent.
+        this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
+                
+        //clear tile's contents and mark as not drawn
+        this.clear();
+        
+        return this.shouldDraw;
+    },
+    
+    /** 
+     * Method: moveTo
+     * Reposition the tile.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * redraw - {Boolean} Call draw method on tile after moving.
+     *     Default is true
+     */
+    moveTo: function (bounds, position, redraw) {
+        if (redraw == null) {
+            redraw = true;
+        }
+
+        this.bounds = bounds.clone();
+        this.position = position.clone();
+        if (redraw) {
+            this.draw();
+        }
+    },
+
+    /** 
+     * Method: clear
+     * Clear the tile of any bounds/position-related data so that it can 
+     *     be reused in a new location. To be implemented by subclasses.
+     */
+    clear: function() {
+        // to be implemented by subclasses
+    },
+    
+    /**   
+     * Method: getBoundsFromBaseLayer
+     * Take the pixel locations of the corner of the tile, and pass them to 
+     *     the base layer and ask for the location of those pixels, so that 
+     *     displaying tiles over Google works fine.
+     *
+     * Parameters:
+     * position - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * bounds - {<OpenLayers.Bounds>} 
+     */
+    getBoundsFromBaseLayer: function(position) {
+        var msg = OpenLayers.i18n('reprojectDeprecated',
+                                              {'layerName':this.layer.name});
+        OpenLayers.Console.warn(msg);
+        var topLeft = this.layer.map.getLonLatFromLayerPx(position); 
+        var bottomRightPx = position.clone();
+        bottomRightPx.x += this.size.w;
+        bottomRightPx.y += this.size.h;
+        var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx); 
+        // Handle the case where the base layer wraps around the date line.
+        // Google does this, and it breaks WMS servers to request bounds in 
+        // that fashion.  
+        if (topLeft.lon > bottomRight.lon) {
+            if (topLeft.lon < 0) {
+                topLeft.lon = -180 - (topLeft.lon+180);
+            } else {
+                bottomRight.lon = 180+bottomRight.lon+180;
+            }        
+        }
+        var bounds = new OpenLayers.Bounds(topLeft.lon, 
+                                       bottomRight.lat, 
+                                       bottomRight.lon, 
+                                       topLeft.lat);  
+        return bounds;
+    },        
+        
+    /** 
+     * Method: showTile
+     * Show the tile only if it should be drawn.
+     */
+    showTile: function() { 
+        if (this.shouldDraw) {
+            this.show();
+        }
+    },
+    
+    /** 
+     * Method: show
+     * Show the tile.  To be implemented by subclasses.
+     */
+    show: function() { },
+    
+    /** 
+     * Method: hide
+     * Hide the tile.  To be implemented by subclasses.
+     */
+    hide: function() { },
+    
+    CLASS_NAME: "OpenLayers.Tile"
+});

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tween.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tween.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/OpenLayers/Tween.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,322 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Namespace: OpenLayers.Tween
+ */
+OpenLayers.Tween = OpenLayers.Class({
+    
+    /**
+     * Constant: INTERVAL
+     * {int} Interval in milliseconds between 2 steps
+     */
+    INTERVAL: 10,
+    
+    /**
+     * APIProperty: easing
+     * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
+     *     Defaultly set to OpenLayers.Easing.Expo.easeOut
+     */
+    easing: null,
+    
+    /**
+     * APIProperty: begin
+     * {Object} Values to start the animation with
+     */
+    begin: null,
+    
+    /**
+     * APIProperty: finish
+     * {Object} Values to finish the animation with
+     */
+    finish: null,
+    
+    /**
+     * APIProperty: duration
+     * {int} duration of the tween (number of steps)
+     */
+    duration: null,
+    
+    /**
+     * APIProperty: callbacks
+     * {Object} An object with start, eachStep and done properties whose values
+     *     are functions to be call during the animation. They are passed the
+     *     current computed value as argument.
+     */
+    callbacks: null,
+    
+    /**
+     * Property: time
+     * {int} Step counter
+     */
+    time: null,
+    
+    /**
+     * Property: interval
+     * {int} Interval id returned by window.setInterval
+     */
+    interval: null,
+    
+    /**
+     * Property: playing
+     * {Boolean} Tells if the easing is currently playing
+     */
+    playing: false,
+    
+    /** 
+     * Constructor: OpenLayers.Tween
+     * Creates a Tween.
+     *
+     * Parameters:
+     * easing - {<OpenLayers.Easing>(Function)} easing function method to use
+     */ 
+    initialize: function(easing) {
+        this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
+    },
+    
+    /**
+     * APIMethod: start
+     * Plays the Tween, and calls the callback method on each step
+     * 
+     * Parameters:
+     * begin - {Object} values to start the animation with
+     * finish - {Object} values to finish the animation with
+     * duration - {int} duration of the tween (number of steps)
+     * options - {Object} hash of options (for example callbacks (start, eachStep, done))
+     */
+    start: function(begin, finish, duration, options) {
+        this.playing = true;
+        this.begin = begin;
+        this.finish = finish;
+        this.duration = duration;
+        this.callbacks = options.callbacks;
+        this.time = 0;
+        if (this.interval) {
+            window.clearInterval(this.interval);
+            this.interval = null;
+        }
+        if (this.callbacks && this.callbacks.start) {
+            this.callbacks.start.call(this, this.begin);
+        }
+        this.interval = window.setInterval(
+            OpenLayers.Function.bind(this.play, this), this.INTERVAL);
+    },
+    
+    /**
+     * APIMethod: stop
+     * Stops the Tween, and calls the done callback
+     *     Doesn't do anything if animation is already finished
+     */
+    stop: function() {
+        if (!this.playing) {
+            return;
+        }
+        
+        if (this.callbacks && this.callbacks.done) {
+            this.callbacks.done.call(this, this.finish);
+        }
+        window.clearInterval(this.interval);
+        this.interval = null;
+        this.playing = false;
+    },
+    
+    /**
+     * Method: play
+     * Calls the appropriate easing method
+     */
+    play: function() {
+        var value = {};
+        for (var i in this.begin) {
+            var b = this.begin[i];
+            var f = this.finish[i];
+            if (b == null || f == null || isNaN(b) || isNaN(f)) {
+                OpenLayers.Console.error('invalid value for Tween');
+            }
+            
+            var c = f - b;
+            value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
+        }
+        this.time++;
+        
+        if (this.callbacks && this.callbacks.eachStep) {
+            this.callbacks.eachStep.call(this, value);
+        }
+        
+        if (this.time > this.duration) {
+            if (this.callbacks && this.callbacks.done) {
+                this.callbacks.done.call(this, this.finish);
+                this.playing = false;
+            }
+            window.clearInterval(this.interval);
+            this.interval = null;
+        }
+    },
+    
+    /**
+     * Create empty functions for all easing methods.
+     */
+    CLASS_NAME: "OpenLayers.Tween"
+});
+
+/**
+ * Namespace: OpenLayers.Easing
+ * 
+ * Credits:
+ *      Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
+ */
+OpenLayers.Easing = {
+    /**
+     * Create empty functions for all easing methods.
+     */
+    CLASS_NAME: "OpenLayers.Easing"
+};
+
+/**
+ * Namespace: OpenLayers.Easing.Linear
+ */
+OpenLayers.Easing.Linear = {
+    
+    /**
+     * Function: easeIn
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeIn: function(t, b, c, d) {
+        return c*t/d + b;
+    },
+    
+    /**
+     * Function: easeOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeOut: function(t, b, c, d) {
+        return c*t/d + b;
+    },
+    
+    /**
+     * Function: easeInOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeInOut: function(t, b, c, d) {
+        return c*t/d + b;
+    },
+
+    CLASS_NAME: "OpenLayers.Easing.Linear"
+};
+
+/**
+ * Namespace: OpenLayers.Easing.Expo
+ */
+OpenLayers.Easing.Expo = {
+    
+    /**
+     * Function: easeIn
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeIn: function(t, b, c, d) {
+        return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+    },
+    
+    /**
+     * Function: easeOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeOut: function(t, b, c, d) {
+        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+    },
+    
+    /**
+     * Function: easeInOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeInOut: function(t, b, c, d) {
+        if (t==0) return b;
+        if (t==d) return b+c;
+        if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+        return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+    },
+
+    CLASS_NAME: "OpenLayers.Easing.Expo"
+};
+
+/**
+ * Namespace: OpenLayers.Easing.Quad
+ */
+OpenLayers.Easing.Quad = {
+    
+    /**
+     * Function: easeIn
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeIn: function(t, b, c, d) {
+        return c*(t/=d)*t + b;
+    },
+    
+    /**
+     * Function: easeOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeOut: function(t, b, c, d) {
+        return -c *(t/=d)*(t-2) + b;
+    },
+    
+    /**
+     * Function: easeInOut
+     * 
+     * Parameters:
+     * t - {Float} time
+     * b - {Float} beginning position
+     * c - {Float} total change
+     * d - {Float} duration of the transition
+     */
+    easeInOut: function(t, b, c, d) {
+        if ((t/=d/2) < 1) return c/2*t*t + b;
+        return -c/2 * ((--t)*(t-2) - 1) + b;
+    },
+
+    CLASS_NAME: "OpenLayers.Easing.Quad"
+};

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/lib/Rico/Corner.js
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/lib/Rico/Corner.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/lib/Rico/Corner.js	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,330 @@
+/*
+ * This file has been edited substantially from the Rico-released
+ * version by the OpenLayers development team.
+ *  
+ *  Copyright 2005 Sabre Airline Solutions  
+ *  
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the
+ *  License. You may obtain a copy of the License at
+ *  
+ *         http://www.apache.org/licenses/LICENSE-2.0  
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the * License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or
+ * implied. See the License for the specific language governing
+ * permissions * and limitations under the License.
+ *
+ */  
+OpenLayers.Rico = new Object();
+OpenLayers.Rico.Corner = {
+
+    round: function(e, options) {
+        e = OpenLayers.Util.getElement(e);
+        this._setOptions(options);
+
+        var color = this.options.color;
+        if ( this.options.color == "fromElement" ) {
+            color = this._background(e);
+        }
+        var bgColor = this.options.bgColor;
+        if ( this.options.bgColor == "fromParent" ) {
+            bgColor = this._background(e.offsetParent);
+        }
+        this._roundCornersImpl(e, color, bgColor);
+    },
+
+    /**   This is a helper function to change the background
+    *     color of <div> that has had Rico rounded corners added.
+    *
+    *     It seems we cannot just set the background color for the
+    *     outer <div> so each <span> element used to create the
+    *     corners must have its background color set individually.
+    *
+    * @param {DOM} theDiv - A child of the outer <div> that was
+    *                        supplied to the `round` method.
+    *
+    * @param {String} newColor - The new background color to use.
+    */
+    changeColor: function(theDiv, newColor) {
+   
+        theDiv.style.backgroundColor = newColor;
+
+        var spanElements = theDiv.parentNode.getElementsByTagName("span");
+        
+        for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
+            spanElements[currIdx].style.backgroundColor = newColor;
+        }
+    }, 
+
+
+    /**   This is a helper function to change the background
+    *     opacity of <div> that has had Rico rounded corners added.
+    *
+    *     See changeColor (above) for algorithm explanation
+    *
+    * @param {DOM} theDiv A child of the outer <div> that was
+    *                        supplied to the `round` method.
+    *
+    * @param {int} newOpacity The new opacity to use (0-1).
+    */
+    changeOpacity: function(theDiv, newOpacity) {
+   
+        var mozillaOpacity = newOpacity;
+        var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';
+        
+        theDiv.style.opacity = mozillaOpacity;
+        theDiv.style.filter = ieOpacity;
+
+        var spanElements = theDiv.parentNode.getElementsByTagName("span");
+        
+        for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
+            spanElements[currIdx].style.opacity = mozillaOpacity;
+            spanElements[currIdx].style.filter = ieOpacity;
+        }
+
+    },
+
+    /** this function takes care of redoing the rico cornering
+    *    
+    *    you can't just call updateRicoCorners() again and pass it a 
+    *    new options string. you have to first remove the divs that 
+    *    rico puts on top and below the content div.
+    *
+    * @param {DOM} theDiv - A child of the outer <div> that was
+    *                        supplied to the `round` method.
+    *
+    * @param {Object} options - list of options
+    */
+    reRound: function(theDiv, options) {
+
+        var topRico = theDiv.parentNode.childNodes[0];
+        //theDiv would be theDiv.parentNode.childNodes[1]
+        var bottomRico = theDiv.parentNode.childNodes[2];
+       
+        theDiv.parentNode.removeChild(topRico);
+        theDiv.parentNode.removeChild(bottomRico); 
+
+        this.round(theDiv.parentNode, options);
+    }, 
+
+   _roundCornersImpl: function(e, color, bgColor) {
+      if(this.options.border) {
+         this._renderBorder(e,bgColor);
+      }
+      if(this._isTopRounded()) {
+         this._roundTopCorners(e,color,bgColor);
+      }
+      if(this._isBottomRounded()) {
+         this._roundBottomCorners(e,color,bgColor);
+      }
+   },
+
+   _renderBorder: function(el,bgColor) {
+      var borderValue = "1px solid " + this._borderColor(bgColor);
+      var borderL = "border-left: "  + borderValue;
+      var borderR = "border-right: " + borderValue;
+      var style   = "style='" + borderL + ";" + borderR +  "'";
+      el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
+   },
+
+   _roundTopCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=0 ; i < this.options.numSlices ; i++ ) {
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
+      }
+      el.style.paddingTop = 0;
+      el.insertBefore(corner,el.firstChild);
+   },
+
+   _roundBottomCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) {
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+      }
+      el.style.paddingBottom = 0;
+      el.appendChild(corner);
+   },
+
+   _createCorner: function(bgColor) {
+      var corner = document.createElement("div");
+      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+      return corner;
+   },
+
+   _createCornerSlice: function(color,bgColor, n, position) {
+      var slice = document.createElement("span");
+
+      var inStyle = slice.style;
+      inStyle.backgroundColor = color;
+      inStyle.display  = "block";
+      inStyle.height   = "1px";
+      inStyle.overflow = "hidden";
+      inStyle.fontSize = "1px";
+
+      var borderColor = this._borderColor(color,bgColor);
+      if ( this.options.border && n == 0 ) {
+         inStyle.borderTopStyle    = "solid";
+         inStyle.borderTopWidth    = "1px";
+         inStyle.borderLeftWidth   = "0px";
+         inStyle.borderRightWidth  = "0px";
+         inStyle.borderBottomWidth = "0px";
+         inStyle.height            = "0px"; // assumes css compliant box model
+         inStyle.borderColor       = borderColor;
+      }
+      else if(borderColor) {
+         inStyle.borderColor = borderColor;
+         inStyle.borderStyle = "solid";
+         inStyle.borderWidth = "0px 1px";
+      }
+
+      if ( !this.options.compact && (n == (this.options.numSlices-1)) ) {
+         inStyle.height = "2px";
+      }
+      this._setMargin(slice, n, position);
+      this._setBorder(slice, n, position);
+      return slice;
+   },
+
+   _setOptions: function(options) {
+      this.options = {
+         corners : "all",
+         color   : "fromElement",
+         bgColor : "fromParent",
+         blend   : true,
+         border  : false,
+         compact : false
+      };
+      OpenLayers.Util.extend(this.options, options || {});
+
+      this.options.numSlices = this.options.compact ? 2 : 4;
+      if ( this._isTransparent() ) {
+         this.options.blend = false;
+      }
+   },
+
+   _whichSideTop: function() {
+      if ( this._hasString(this.options.corners, "all", "top") ) {
+         return "";
+      }
+      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) {
+         return "";
+      }
+      if (this.options.corners.indexOf("tl") >= 0) {
+         return "left";
+      } else if (this.options.corners.indexOf("tr") >= 0) {
+          return "right";
+      }
+      return "";
+   },
+
+   _whichSideBottom: function() {
+      if ( this._hasString(this.options.corners, "all", "bottom") ) {
+         return "";
+      }
+      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) {
+         return "";
+      }
+
+      if(this.options.corners.indexOf("bl") >=0) {
+         return "left";
+      } else if(this.options.corners.indexOf("br")>=0) {
+         return "right";
+      }
+      return "";
+   },
+
+   _borderColor : function(color,bgColor) {
+      if ( color == "transparent" ) {
+         return bgColor;
+      } else if ( this.options.border ) {
+         return this.options.border;
+      } else if ( this.options.blend ) {
+         return this._blend( bgColor, color );
+      } else {
+         return "";
+      }
+   },
+
+
+   _setMargin: function(el, n, corners) {
+      var marginSize = this._marginSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+      if ( whichSide == "left" ) {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
+      }
+      else {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+      }
+   },
+
+   _setBorder: function(el,n,corners) {
+      var borderSize = this._borderSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+      if ( whichSide == "left" ) {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
+      }
+      else {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+      }
+      if (this.options.border != false) {
+        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+      }
+   },
+
+   _marginSize: function(n) {
+      if ( this._isTransparent() ) {
+         return 0;
+      }
+      var marginSizes          = [ 5, 3, 2, 1 ];
+      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
+      var compactMarginSizes   = [ 2, 1 ];
+      var smBlendedMarginSizes = [ 1, 0 ];
+
+      if ( this.options.compact && this.options.blend ) {
+         return smBlendedMarginSizes[n];
+      } else if ( this.options.compact ) {
+         return compactMarginSizes[n];
+      } else if ( this.options.blend ) {
+         return blendedMarginSizes[n];
+      } else {
+         return marginSizes[n];
+      }
+   },
+
+   _borderSize: function(n) {
+      var transparentBorderSizes = [ 5, 3, 2, 1 ];
+      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
+      var compactBorderSizes     = [ 1, 0 ];
+      var actualBorderSizes      = [ 0, 2, 0, 0 ];
+
+      if ( this.options.compact && (this.options.blend || this._isTransparent()) ) {
+         return 1;
+      } else if ( this.options.compact ) {
+         return compactBorderSizes[n];
+      } else if ( this.options.blend ) {
+         return blendedBorderSizes[n];
+      } else if ( this.options.border ) {
+         return actualBorderSizes[n];
+      } else if ( this._isTransparent() ) {
+         return transparentBorderSizes[n];
+      }
+      return 0;
+   },
+
+   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) { return true; } return false; },
+   _blend: function(c1, c2) { var cc1 = OpenLayers.Rico.Color.createFromHex(c1); cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); return cc1; },
+   _background: function(el) { try { return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
+   _isTransparent: function() { return this.options.color == "transparent"; },
+   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
+   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
+   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
+};
\ No newline at end of file

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/google.css
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/google.css	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/google.css	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,9 @@
+.olLayerGoogleCopyright {
+    right: 3px;
+    bottom: 2px;  
+}
+.olLayerGooglePoweredBy {
+    left: 2px;
+    bottom: 2px;   
+}
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/ie6-style.css
===================================================================
--- trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/ie6-style.css	                        (rev 0)
+++ trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/ie6-style.css	2009-09-03 14:07:47 UTC (rev 4593)
@@ -0,0 +1,7 @@
+.olControlZoomPanel div {
+    background-image: url(img/zoom-panel-NOALPHA.png);
+}
+.olControlPanPanel div {
+    background-image: url(img/pan-panel-NOALPHA.png);
+}
+

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/close.gif
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/close.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/drag-rectangle-off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/drag-rectangle-off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_line_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_point_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_polygon_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/draw_polygon_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/editing_tool_bar.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/editing_tool_bar.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/move_feature_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/overview_replacement.gif
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/overview_replacement.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan-panel-NOALPHA.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan-panel-NOALPHA.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/pan_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/panning-hand-on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/remove_point_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/ruler.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/ruler.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/save_features_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_off.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_off.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_on.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/view_previous_on.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel-NOALPHA.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel-NOALPHA.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/OpenLayers-2.8/theme/default/img/zoom-panel.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream



More information about the Mapbender_commits mailing list