vendor/assets/javascripts/openlayers/OpenLayers.js in openlayers-rails-0.0.3 vs vendor/assets/javascripts/openlayers/OpenLayers.js in openlayers-rails-0.0.4

- old
+ new

@@ -57,20 +57,20 @@ */ /* ====================================================================== OpenLayers/SingleFile.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ var OpenLayers = { /** * Constant: VERSION_NUMBER */ - VERSION_NUMBER: "Release 2.13 dev", + VERSION_NUMBER: "Release 2.14 dev", /** * Constant: singleFile * TODO: remove this in 3.0 when we stop supporting build profiles that * include OpenLayers.js @@ -139,11 +139,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes/Class.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -264,11 +264,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -393,11 +393,13 @@ var subs = match.split(/\.+/); for (var i=0; i< subs.length; i++) { if (i == 0) { replacement = context; } - + if (replacement === undefined) { + break; + } replacement = replacement[subs[i]]; } if(typeof replacement == "function") { replacement = args ? @@ -729,11 +731,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes/Bounds.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -794,11 +796,11 @@ * * Parameters (four arguments): * 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. + * calculations, this is assumed to be less than the top value. * right - {Number} The right bounds. * top - {Number} The top bounds. * * Parameters (single argument): * bounds - {Array(Number)} [left, bottom, right, top] @@ -895,11 +897,11 @@ /** * APIMethod: toBBOX * Returns a boundingbox-string representation of the bounds object. * * Parameters: - * decimal - {Integer} How many significant digits in the bbox coords? + * decimal - {Integer} How many decimal places in the bbox coords? * Default is 6 * reverseAxisOrder - {Boolean} Should we reverse the axis order? * * Returns: * {String} Simple String representation of bounds object. @@ -1086,47 +1088,67 @@ * object - {<OpenLayers.LonLat>, <OpenLayers.Geometry.Point> or * <OpenLayers.Bounds>} The object to be included in the new bounds * object. */ 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); + case "OpenLayers.LonLat": + this.extendXY(object.lon, object.lat); break; case "OpenLayers.Geometry.Point": - bounds = new OpenLayers.Bounds(object.x, object.y, - object.x, object.y); + this.extendXY(object.x, object.y); break; - - case "OpenLayers.Bounds": - bounds = object; + + case "OpenLayers.Bounds": + // clear cached center location + this.centerLonLat = null; + + if ( (this.left == null) || (object.left < this.left)) { + this.left = object.left; + } + if ( (this.bottom == null) || (object.bottom < this.bottom) ) { + this.bottom = object.bottom; + } + if ( (this.right == null) || (object.right > this.right) ) { + this.right = object.right; + } + if ( (this.top == null) || (object.top > this.top) ) { + this.top = object.top; + } 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: extendXY + * Extend the bounds to include the XY coordinate specified. + * + * Parameters: + * x - {number} The X part of the the coordinate. + * y - {number} The Y part of the the coordinate. + */ + extendXY:function(x, y) { + // clear cached center location + this.centerLonLat = null; + + if ((this.left == null) || (x < this.left)) { + this.left = x; + } + if ((this.bottom == null) || (y < this.bottom)) { + this.bottom = y; + } + if ((this.right == null) || (x > this.right)) { + this.right = x; + } + if ((this.top == null) || (y > this.top)) { + this.top = y; + } + }, + + /** * APIMethod: containsLonLat * Returns whether the bounds object contains the given <OpenLayers.LonLat>. * * Parameters: * ll - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an @@ -1550,11 +1572,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes/Element.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -1743,11 +1765,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes/LonLat.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -1962,11 +1984,11 @@ }; /* ====================================================================== OpenLayers/BaseTypes/Pixel.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -2109,11 +2131,11 @@ }); /* ====================================================================== OpenLayers/BaseTypes/Size.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -2202,11 +2224,11 @@ }); /* ====================================================================== OpenLayers/Console.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -2456,11 +2478,11 @@ })(); /* ====================================================================== OpenLayers/Lang.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -2594,11 +2616,11 @@ OpenLayers.i18n = OpenLayers.Lang.translate; /* ====================================================================== OpenLayers/Util.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -3462,15 +3484,21 @@ * * Parameters: * url - {String} Optional url used to extract the query string. * If url is null or is not supplied, query string is taken * from the page location. + * options - {Object} Additional options. Optional. + * + * Valid options: + * splitArgs - {Boolean} Split comma delimited params into arrays? Default is + * true. * * Returns: * {Object} An object of key/value pairs from the query string. */ -OpenLayers.Util.getParameters = function(url) { +OpenLayers.Util.getParameters = function(url, options) { + options = options || {}; // if no url specified, take it from the location bar url = (url === null || url === undefined) ? window.location.href : url; //parse out parameters portion of url string var paramsString = ""; @@ -3502,11 +3530,13 @@ } catch (err) { value = unescape(value); } // follow OGC convention of comma delimited values - value = value.split(","); + if (options.splitArgs !== false) { + value = value.split(","); + } //if there's only one value, do not return as array if (value.length == 1) { value = value[0]; } @@ -3895,11 +3925,12 @@ options = options || {}; OpenLayers.Util.applyDefaults(options, { ignoreCase: true, ignorePort80: true, - ignoreHash: true + ignoreHash: true, + splitArgs: false }); var urlObj1 = OpenLayers.Util.createUrlObject(url1, options); var urlObj2 = OpenLayers.Util.createUrlObject(url2, options); @@ -3936,10 +3967,12 @@ * * Valid options: * ignoreCase - {Boolean} lowercase url, * ignorePort80 - {Boolean} don't include explicit port if port is 80, * ignoreHash - {Boolean} Don't include part of url after the hash (#). + * splitArgs - {Boolean} Split comma delimited params into arrays? Default is + * true. * * Returns: * {Object} An object with separate url, a, port, host, and args parsed out * and ready for comparison */ @@ -3991,11 +4024,12 @@ var queryString = a.search; if (!queryString) { var qMark = url.indexOf("?"); queryString = (qMark != -1) ? url.substr(qMark) : ""; } - urlObject.args = OpenLayers.Util.getParameters(queryString); + urlObject.args = OpenLayers.Util.getParameters(queryString, + {splitArgs: options.splitArgs}); // pathname // // This is a workaround for Internet Explorer where // window.location.pathname has a leading "/", but @@ -4355,15 +4389,41 @@ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); } return str; }; +/** + * Function: getConstructor + * Take an OpenLayers style CLASS_NAME and return a constructor. + * + * Parameters: + * className - {String} The dot delimited class name (e.g. 'OpenLayers.Foo'). + * + * Returns: + * {Function} The constructor. + */ +OpenLayers.Util.getConstructor = function(className) { + var Constructor; + var parts = className.split('.'); + if (parts[0] === "OpenLayers") { + Constructor = OpenLayers; + } else { + // someone extended our base class and used their own namespace + // this will not work when the library is evaluated in a closure + // but it is the best we can do (until we ourselves provide a global) + Constructor = window[parts[0]]; + } + for (var i = 1, ii = parts.length; i < ii; ++i) { + Constructor = Constructor[parts[i]]; + } + return Constructor; +}; /* ====================================================================== OpenLayers/Format.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -4486,11 +4546,11 @@ }); /* ====================================================================== OpenLayers/Format/XML.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -5514,11 +5574,11 @@ }; /* ====================================================================== OpenLayers/Feature.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -5743,11 +5803,11 @@ }); /* ====================================================================== OpenLayers/Feature/Vector.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ // TRASH THIS @@ -5817,11 +5877,11 @@ style: null, /** * APIProperty: url * {String} If this property is set it will be taken into account by - * {<OpenLayers.HTTP>} when upadting or deleting the feature. + * {<OpenLayers.HTTP>} when updating or deleting the feature. */ url: null, /** * Property: renderIntent @@ -6167,11 +6227,12 @@ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer. * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer. * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls. * Default is false. * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers. - * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the canvas & SVG renderers. + * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers. + * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers. * fontColor - {String} The font color for the label, to be provided like CSS. * fontOpacity - {Number} Opacity (0-1) for the label * fontFamily - {String} The font family for the label, to be provided like in CSS. * fontSize - {String} The font size for the label, to be provided like in CSS. * fontStyle - {String} The font style for the label, to be provided like in CSS. @@ -6256,11 +6317,11 @@ }; /* ====================================================================== OpenLayers/Geometry.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -6696,25 +6757,52 @@ * point coordinates. * segment - {Object} An object with x1, y1, x2, and y2 properties * representing endpoint coordinates. * * Returns: - * {Object} An object with distance, x, and y properties. The distance + * {Object} An object with distance, along, x, and y properties. The distance * will be the shortest distance between the input point and segment. * The x and y properties represent the coordinates along the segment - * where the shortest distance meets the segment. + * where the shortest distance meets the segment. The along attribute + * describes how far between the two segment points the given point is. */ OpenLayers.Geometry.distanceToSegment = function(point, segment) { + var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment); + result.distance = Math.sqrt(result.distance); + return result; +}; + +/** + * Function: OpenLayers.Geometry.distanceSquaredToSegment + * + * Usually the distanceToSegment function should be used. This variant however + * can be used for comparisons where the exact distance is not important. + * + * Parameters: + * point - {Object} An object with x and y properties representing the + * point coordinates. + * segment - {Object} An object with x1, y1, x2, and y2 properties + * representing endpoint coordinates. + * + * Returns: + * {Object} An object with squared distance, along, x, and y properties. + * The distance will be the shortest distance between the input point and + * segment. The x and y properties represent the coordinates along the + * segment where the shortest distance meets the segment. The along + * attribute describes how far between the two segment points the given + * point is. + */ +OpenLayers.Geometry.distanceSquaredToSegment = function(point, segment) { var x0 = point.x; var y0 = point.y; var x1 = segment.x1; var y1 = segment.y1; var x2 = segment.x2; var y2 = segment.y2; var dx = x2 - x1; var dy = y2 - y1; - var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / + var along = (dx == 0 && dy == 0) ? 0 : ((dx * (x0 - x1)) + (dy * (y0 - y1))) / (Math.pow(dx, 2) + Math.pow(dy, 2)); var x, y; if(along <= 0.0) { x = x1; y = y1; @@ -6724,19 +6812,20 @@ } else { x = x1 + along * dx; y = y1 + along * dy; } return { - distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)), - x: x, y: y + distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2), + x: x, y: y, + along: along }; }; /* ====================================================================== OpenLayers/Geometry/Point.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -7019,11 +7108,11 @@ }); /* ====================================================================== OpenLayers/Geometry/Collection.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -7096,11 +7185,12 @@ * * Returns: * {<OpenLayers.Geometry.Collection>} An exact clone of this collection */ clone: function() { - var geometry = eval("new " + this.CLASS_NAME + "()"); + var Constructor = OpenLayers.Util.getConstructor(this.CLASS_NAME); + var geometry = new Constructor(); for(var i=0, len=this.components.length; i<len; i++) { geometry.addComponent(this.components[i].clone()); } // catch any randomly tagged-on properties @@ -7586,11 +7676,11 @@ }); /* ====================================================================== OpenLayers/Geometry/MultiPoint.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -7656,11 +7746,11 @@ }); /* ====================================================================== OpenLayers/Geometry/Curve.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -7749,11 +7839,11 @@ }); /* ====================================================================== OpenLayers/Geometry/LineString.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -8209,30 +8299,26 @@ for(var i=0, len=segs.length; i<len; ++i) { seg = segs[i]; result = OpenLayers.Geometry.distanceToSegment(geometry, seg); if(result.distance < min) { min = result.distance; - best = result; + if(details) { + best = { + distance: min, + x0: result.x, y0: result.y, + x1: x, y1: y, + index: i, + indexDistance: new OpenLayers.Geometry.Point(seg.x1, seg.y1).distanceTo(geometry) + }; + } else { + best = min; + } if(min === 0) { break; } - } else { - // if distance increases and we cross y0 to the right of x0, no need to keep looking. - if(seg.x2 > x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) { - break; - } } } - if(details) { - best = { - distance: best.distance, - x0: best.x, y0: best.y, - x1: x, y1: y - }; - } else { - best = best.distance; - } } else if(geometry instanceof OpenLayers.Geometry.LineString) { var segs0 = this.getSortedSegments(); var segs1 = geometry.getSortedSegments(); var seg0, seg1, intersection, x0, y0; var len1 = segs1.length; @@ -8399,11 +8485,11 @@ }); /* ====================================================================== OpenLayers/Geometry/LinearRing.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -8836,11 +8922,11 @@ }); /* ====================================================================== OpenLayers/Geometry/Polygon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -9095,11 +9181,11 @@ }; /* ====================================================================== OpenLayers/Events.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -9663,10 +9749,11 @@ this.object = object; this.fallThrough = fallThrough; this.listeners = {}; this.extensions = {}; this.extensionCount = {}; + this._msTouches = []; // if a dom element is specified, add a listeners list // for browser events on the element and register them if (element != null) { this.attachToElement(element); @@ -9729,15 +9816,20 @@ this.clearMouseListener = OpenLayers.Function.bind( this.clearMouseCache, this ); } this.element = element; + var msTouch = !!window.navigator.msMaxTouchPoints; + var type; for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) { + type = this.BROWSER_EVENTS[i]; // register the event cross-browser - OpenLayers.Event.observe( - element, this.BROWSER_EVENTS[i], this.eventHandler + OpenLayers.Event.observe(element, type, this.eventHandler ); + if (msTouch && type.indexOf('touch') === 0) { + this.addMsTouchListener(element, type, this.eventHandler); + } } // disable dragstart in IE so that mousedown/move/up works normally OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop); }, @@ -10111,17 +10203,163 @@ (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1] - this.element.lefttop[1] ); }, + /** + * Method: addMsTouchListener + * + * Parameters: + * element - {DOMElement} The DOM element to register the listener on + * type - {String} The event type + * handler - {Function} the handler + */ + addMsTouchListener: function (element, type, handler) { + var eventHandler = this.eventHandler; + var touches = this._msTouches; + + function msHandler(evt) { + handler(OpenLayers.Util.applyDefaults({ + stopPropagation: function() { + for (var i=touches.length-1; i>=0; --i) { + touches[i].stopPropagation(); + } + }, + preventDefault: function() { + for (var i=touches.length-1; i>=0; --i) { + touches[i].preventDefault(); + } + }, + type: type + }, evt)); + } + + switch (type) { + case 'touchstart': + return this.addMsTouchListenerStart(element, type, msHandler); + case 'touchend': + return this.addMsTouchListenerEnd(element, type, msHandler); + case 'touchmove': + return this.addMsTouchListenerMove(element, type, msHandler); + default: + throw 'Unknown touch event type'; + } + }, + + /** + * Method: addMsTouchListenerStart + * + * Parameters: + * element - {DOMElement} The DOM element to register the listener on + * type - {String} The event type + * handler - {Function} the handler + */ + addMsTouchListenerStart: function(element, type, handler) { + var touches = this._msTouches; + + var cb = function(e) { + + var alreadyInArray = false; + for (var i=0, ii=touches.length; i<ii; ++i) { + if (touches[i].pointerId == e.pointerId) { + alreadyInArray = true; + break; + } + } + if (!alreadyInArray) { + touches.push(e); + } + + e.touches = touches.slice(); + handler(e); + }; + + OpenLayers.Event.observe(element, 'MSPointerDown', cb); + + // Need to also listen for end events to keep the _msTouches list + // accurate + var internalCb = function(e) { + for (var i=0, ii=touches.length; i<ii; ++i) { + if (touches[i].pointerId == e.pointerId) { + touches.splice(i, 1); + break; + } + } + }; + OpenLayers.Event.observe(element, 'MSPointerUp', internalCb); + }, + + /** + * Method: addMsTouchListenerMove + * + * Parameters: + * element - {DOMElement} The DOM element to register the listener on + * type - {String} The event type + * handler - {Function} the handler + */ + addMsTouchListenerMove: function (element, type, handler) { + var touches = this._msTouches; + var cb = function(e) { + + //Don't fire touch moves when mouse isn't down + if (e.pointerType == e.MSPOINTER_TYPE_MOUSE && e.buttons == 0) { + return; + } + + if (touches.length == 1 && touches[0].pageX == e.pageX && + touches[0].pageY == e.pageY) { + // don't trigger event when pointer has not moved + return; + } + for (var i=0, ii=touches.length; i<ii; ++i) { + if (touches[i].pointerId == e.pointerId) { + touches[i] = e; + break; + } + } + + e.touches = touches.slice(); + handler(e); + }; + + OpenLayers.Event.observe(element, 'MSPointerMove', cb); + }, + + /** + * Method: addMsTouchListenerEnd + * + * Parameters: + * element - {DOMElement} The DOM element to register the listener on + * type - {String} The event type + * handler - {Function} the handler + */ + addMsTouchListenerEnd: function (element, type, handler) { + var touches = this._msTouches; + + var cb = function(e) { + + for (var i=0, ii=touches.length; i<ii; ++i) { + if (touches[i].pointerId == e.pointerId) { + touches.splice(i, 1); + break; + } + } + + e.touches = touches.slice(); + handler(e); + }; + + OpenLayers.Event.observe(element, 'MSPointerUp', cb); + }, + CLASS_NAME: "OpenLayers.Events" }); /* ====================================================================== OpenLayers/Request.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -11012,11 +11250,11 @@ })(); /* ====================================================================== OpenLayers/Projection.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -11180,13 +11418,13 @@ /** * APIProperty: defaults * {Object} Defaults for the SRS codes known to OpenLayers (currently * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, - * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, - * maxExtent (the validity extent for the SRS) and yx (true if this SRS is - * known to have a reverse axis order). + * EPSG:102113, EPSG:102100 and OSGEO:41001). Keys are the SRS code, values are + * units, maxExtent (the validity extent for the SRS) and yx (true if this SRS + * is known to have a reverse axis order). */ OpenLayers.Projection.defaults = { "EPSG:4326": { units: "degrees", maxExtent: [-180, -90, 180, 90], @@ -11280,13 +11518,13 @@ return point; }; /** * Note: Transforms for web mercator <-> geographic - * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. - * OpenLayers originally started referring to EPSG:900913 as web mercator. - * The EPSG has declared EPSG:3857 to be web mercator. + * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113, EPSG:102100 and + * OSGEO:41001. OpenLayers originally started referring to EPSG:900913 as web + * mercator. The EPSG has declared EPSG:3857 to be web mercator. * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis * order for EPSG:4326. @@ -11323,11 +11561,11 @@ } } } // list of equivalent codes for web mercator - var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"], + var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100", "OSGEO:41001"], geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"], i; for (i=mercator.length-1; i>=0; --i) { map(mercator[i], geographic); } @@ -11338,11 +11576,11 @@ })(); /* ====================================================================== OpenLayers/Format/KML.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -12568,22 +12806,22 @@ 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); - // output attributes as extendedData if (feature.attributes) { var edNode = this.buildExtendedData(feature.attributes); if (edNode) { placemarkNode.appendChild(edNode); } } + // Geometry node (Point, LineString, etc. nodes) + var geometryNode = this.buildGeometryNode(feature.geometry); + placemarkNode.appendChild(geometryNode); + return placemarkNode; }, /** * Method: buildGeometryNode @@ -12859,11 +13097,11 @@ }); /* ====================================================================== OpenLayers/Geometry/MultiLineString.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -13121,11 +13359,11 @@ }); /* ====================================================================== OpenLayers/Geometry/MultiPolygon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -13167,11 +13405,11 @@ }); /* ====================================================================== OpenLayers/Format/GML.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -14094,11 +14332,11 @@ }); /* ====================================================================== OpenLayers/Format/GML/Base.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -14743,11 +14981,11 @@ }); /* ====================================================================== OpenLayers/Format/GML/v2.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -14940,11 +15178,11 @@ }); /* ====================================================================== OpenLayers/Style.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -15392,11 +15630,11 @@ 'Raster']; /* ====================================================================== OpenLayers/Rule.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -15632,11 +15870,11 @@ }); /* ====================================================================== OpenLayers/Format/OGCExceptionReport.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -15744,11 +15982,11 @@ }); /* ====================================================================== OpenLayers/Format/XML/VersionedOGC.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -15960,11 +16198,11 @@ }); /* ====================================================================== OpenLayers/Filter.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -16051,11 +16289,11 @@ }); /* ====================================================================== OpenLayers/Filter/FeatureId.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -16142,11 +16380,11 @@ }); /* ====================================================================== OpenLayers/Filter/Logical.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -16267,11 +16505,11 @@ OpenLayers.Filter.Logical.NOT = "!"; /* ====================================================================== OpenLayers/Filter/Comparison.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -16384,10 +16622,13 @@ if (context instanceof OpenLayers.Feature.Vector) { context = context.attributes; } var result = false; var got = context[this.property]; + if (got === undefined) { + return false; + } var exp; switch(this.type) { case OpenLayers.Filter.Comparison.EQUAL_TO: exp = this.value; if(!this.matchCase && @@ -16538,11 +16779,11 @@ OpenLayers.Filter.Comparison.IS_NULL = "NULL"; /* ====================================================================== OpenLayers/Filter/Spatial.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -16664,11 +16905,11 @@ OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS"; /* ====================================================================== OpenLayers/Format/SLD.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -16749,11 +16990,11 @@ }); /* ====================================================================== OpenLayers/Format/Filter.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -16806,11 +17047,11 @@ }); /* ====================================================================== OpenLayers/Filter/Function.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -16859,11 +17100,11 @@ /* ====================================================================== OpenLayers/Format/Filter/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Format/Filter.js @@ -17367,11 +17608,11 @@ }); /* ====================================================================== OpenLayers/Format/Filter/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -17555,11 +17796,11 @@ }); /* ====================================================================== OpenLayers/Symbolizer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -17602,11 +17843,11 @@ * Create a copy of this symbolizer. * * Returns a symbolizer of the same type with the same properties. */ clone: function() { - var Type = eval(this.CLASS_NAME); + var Type = OpenLayers.Util.getConstructor(this.CLASS_NAME); return new Type(OpenLayers.Util.extend({}, this)); }, CLASS_NAME: "OpenLayers.Symbolizer" @@ -17614,11 +17855,11 @@ /* ====================================================================== OpenLayers/Symbolizer/Point.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -17775,11 +18016,11 @@ /* ====================================================================== OpenLayers/Symbolizer/Line.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -17853,11 +18094,11 @@ /* ====================================================================== OpenLayers/Symbolizer/Polygon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -17945,11 +18186,11 @@ /* ====================================================================== OpenLayers/Symbolizer/Text.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -18019,11 +18260,11 @@ /* ====================================================================== OpenLayers/Symbolizer/Raster.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -18057,16 +18298,17 @@ }); /* ====================================================================== OpenLayers/Format/SLD/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** + * @requires OpenLayers/BaseTypes.js * @requires OpenLayers/Rule.js * @requires OpenLayers/Format/SLD.js * @requires OpenLayers/Format/Filter/v1_0_0.js * @requires OpenLayers/Symbolizer/Point.js * @requires OpenLayers/Symbolizer/Line.js @@ -18216,11 +18458,11 @@ sld.namedLayers[layer.name] = layer; } }, "NamedStyle": function(node, layer) { layer.namedStyles.push( - this.getChildName(node.firstChild) + this.getChildValue(node.firstChild) ); }, "UserStyle": function(node, layer) { var obj = {defaultsPerSymbolizer: true, rules: []}; this.featureTypeCounter = -1; @@ -18354,11 +18596,11 @@ } }, "Label": function(node, symbolizer) { var value = this.readers.ogc._expression.call(this, node); if (value) { - symbolizer.label = value; + symbolizer.label = OpenLayers.String.trim(value); } }, "Font": function(node, symbolizer) { this.readChildNodes(node, symbolizer); }, @@ -19370,11 +19612,11 @@ }); /* ====================================================================== OpenLayers/Format/SLD/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -19420,11 +19662,11 @@ }); /* ====================================================================== OpenLayers/Format/Context.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -19531,10 +19773,11 @@ }), numZoomLevels: layerContext.numZoomLevels, units: layerContext.units, isBaseLayer: layerContext.isBaseLayer, opacity: layerContext.opacity, + gutter: layerContext.gutter, displayInLayerSwitcher: layerContext.displayInLayerSwitcher, singleTile: layerContext.singleTile, tileSize: (layerContext.tileSize) ? new OpenLayers.Size( layerContext.tileSize.width, @@ -19542,11 +19785,12 @@ ) : undefined, minScale: layerContext.minScale || layerContext.maxScaleDenominator, maxScale: layerContext.maxScale || layerContext.minScaleDenominator, srs: layerContext.srs, dimensions: layerContext.dimensions, - metadataURL: layerContext.metadataURL + metadataURL: layerContext.metadataURL, + attribution: layerContext.attribution }; if (this.layerOptions) { OpenLayers.Util.applyDefaults(options, this.layerOptions); } @@ -19758,11 +20002,11 @@ }; /* ====================================================================== OpenLayers/Format/OWSContext.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -19848,11 +20092,11 @@ }); /* ====================================================================== OpenLayers/Format/OWSCommon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -19930,11 +20174,11 @@ }); /* ====================================================================== OpenLayers/Format/OWSCommon/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -20063,10 +20307,13 @@ this.readChildNodes(node, contactInfo.phone); }, "Voice": function(node, phone) { phone.voice = this.getChildValue(node); }, + "Facsimile": function(node, phone) { + phone.facsimile = this.getChildValue(node); + }, "Address": function(node, contactInfo) { contactInfo.address = {}; this.readChildNodes(node, contactInfo.address); }, "DeliveryPoint": function(node, address) { @@ -20252,11 +20499,11 @@ }); /* ====================================================================== OpenLayers/Format/OWSCommon/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -20318,11 +20565,11 @@ }); /* ====================================================================== OpenLayers/Format/OWSContext/v0_3_1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -20917,11 +21164,11 @@ }); /* ====================================================================== OpenLayers/Format/CSWGetRecords.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -20955,11 +21202,11 @@ }; /* ====================================================================== OpenLayers/Control.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -21256,11 +21503,11 @@ } }, /** * APIMethod: activate - * Explicitly activates a control and it's associated + * Explicitly activates a control and its 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 @@ -21284,11 +21531,11 @@ return true; }, /** * APIMethod: deactivate - * Deactivates a control and it's associated handler if any. The exact + * Deactivates a control and its 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. @@ -21330,11 +21577,11 @@ OpenLayers.Control.TYPE_TOOL = 3; /* ====================================================================== OpenLayers/Events/buttonclick.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -21502,10 +21749,16 @@ break; } } else if (this.startEvt) { if (this.completeRegEx.test(evt.type)) { var pos = OpenLayers.Util.pagePosition(button); + var viewportElement = OpenLayers.Util.getViewportElement(); + var scrollTop = window.pageYOffset || viewportElement.scrollTop; + var scrollLeft = window.pageXOffset || viewportElement.scrollLeft; + pos[0] = pos[0] - scrollLeft; + pos[1] = pos[1] - scrollTop; + this.target.triggerEvent("buttonclick", { buttonElement: button, buttonXY: { x: this.startEvt.clientX - pos[0], y: this.startEvt.clientY - pos[1] @@ -21534,16 +21787,16 @@ }); /* ====================================================================== OpenLayers/Util/vendorPrefix.js ====================================================================== */ -/** - * Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. - * + * full text of the license. */ + +/** * @requires OpenLayers/SingleFile.js */ OpenLayers.Util = OpenLayers.Util || {}; /** @@ -21669,16 +21922,16 @@ }()); /* ====================================================================== OpenLayers/Animation.js ====================================================================== */ -/** - * Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. - * + * full text of the license. */ + +/** * @requires OpenLayers/SingleFile.js * @requires OpenLayers/Util/vendorPrefix.js */ /** @@ -21775,11 +22028,11 @@ })(window); /* ====================================================================== OpenLayers/Tween.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -22140,18 +22393,19 @@ }; /* ====================================================================== OpenLayers/Map.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes/Class.js * @requires OpenLayers/Util.js + * @requires OpenLayers/Util/vendorPrefix.js * @requires OpenLayers/Events.js * @requires OpenLayers/Tween.js * @requires OpenLayers/Projection.js */ @@ -22211,21 +22465,25 @@ * aborted. * 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, - * opacity change, params change, visibility change (due to resolution - * thresholds) or attribution change (due to extent change). 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, - * order, opacity, params, visibility or attribution). + * opacity change, params change, visibility change (actual visibility, + * not the layer's visibility property) or attribution change (due to + * extent change). 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, order, opacity, params, visibility or + * attribution). * movestart - triggered after the start of a drag, pan, or zoom. The event * object may include a *zoomChanged* property that tells whether the * zoom has changed. * move - triggered after each drag, pan, or zoom * moveend - triggered after a drag, pan, or zoom completes + * zoomstart - triggered when a zoom starts. Listeners receive an object + * with *center* and *zoom* properties, for the target center and zoom + * level. * zoomend - triggered after a zoom completes * mouseover - triggered after mouseover the map * mouseout - triggered after mouseout the map * mousemove - triggered after mousemove the map * changebaselayer - triggered after the base layer changes @@ -22512,19 +22770,20 @@ * 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: tileManager - * {<OpenLayers.TileManager>} If configured at construction time, the map - * will use the TileManager to queue image requests and to cache tile image - * elements. Note: make sure that OpenLayers/TileManager.js is included in - * your build profile. + * {<OpenLayers.TileManager>|Object} By default, and if the build contains + * TileManager.js, the map will use the TileManager to queue image requests + * and to cache tile image elements. To create a map without a TileManager + * configure the map with tileManager: null. To create a TileManager with + * non-default options, supply the options instead or alternatively supply + * an instance of {<OpenLayers.TileManager>}. */ - tileManager: 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) @@ -22538,25 +22797,25 @@ * when the resize event is fired. Default is true. */ autoUpdateSize: 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, /** + * Property: panTween + * {<OpenLayers.Tween>} Animated panning tween object, see panTo() + */ + panTween: 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. */ @@ -22570,10 +22829,32 @@ * Default is 50. */ panDuration: 50, /** + * Property: zoomTween + * {<OpenLayers.Tween>} Animated zooming tween object, see zoomTo() + */ + zoomTween: null, + + /** + * APIProperty: zoomMethod + * {Function} The Easing function to be used for tweening. Default is + * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off + * animated zooming. + */ + zoomMethod: OpenLayers.Easing.Quad.easeOut, + + /** + * Property: zoomDuration + * {Integer} The number of steps to be passed to the + * OpenLayers.Tween.start() method when the map is zoomed. + * Default is 20. + */ + zoomDuration: 20, + + /** * Property: paddingForPopups * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent * the popup from getting too close to the map border. */ paddingForPopups : null, @@ -22625,14 +22906,10 @@ * zoom - {Number} The initial zoom level for the map. Only specify if * <layers> is provided. * Note that if an ArgParser/Permalink control is present, * and the querystring contains a zoom level, zoom will be set * by that, and this option will be ignored. - * extent - {<OpenLayers.Bounds>|Array} The initial extent of the map. - * If provided as an array, the array should consist of - * four values (left, bottom, right, top). - * Only specify if <center> and <zoom> are not provided. * * Examples: * (code) * // create a map with default options in an element with the id "map1" * var map = new OpenLayers.Map("map1"); @@ -22731,19 +23008,23 @@ this.events = new OpenLayers.Events( this, this.viewPortDiv, null, this.fallThrough, {includeXY: true} ); - if (this.tileManager) { + if (OpenLayers.TileManager && this.tileManager !== null) { + if (!(this.tileManager instanceof OpenLayers.TileManager)) { + this.tileManager = new OpenLayers.TileManager(this.tileManager); + } this.tileManager.addMap(this); } // the layerContainerDiv is the one that holds all the layers id = this.id + "_OpenLayers_Container"; this.layerContainerDiv = OpenLayers.Util.createDiv(id); this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1; this.layerContainerOriginPx = {x: 0, y: 0}; + this.applyTransform(); this.viewPortDiv.appendChild(this.layerContainerDiv); this.updateSize(); if(this.eventListeners instanceof Object) { @@ -22835,10 +23116,17 @@ if (options.center && !this.getCenter()) { // zoom can be undefined here this.setCenter(options.center, options.zoom); } } + + if (this.panMethod) { + this.panTween = new OpenLayers.Tween(this.panMethod); + } + if (this.zoomMethod && this.applyTransform.transform) { + this.zoomTween = new OpenLayers.Tween(this.zoomMethod); + } }, /** * APIMethod: getViewport * Get the DOMElement representing the view port. @@ -22903,10 +23191,15 @@ // make sure panning doesn't continue after destruction if(this.panTween) { this.panTween.stop(); this.panTween = null; } + // make sure zooming doesn't continue after destruction + if(this.zoomTween) { + this.zoomTween.stop(); + this.zoomTween = null; + } // map has been destroyed. dont do it again! OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy); this.unloadDestroy = null; @@ -23386,10 +23679,11 @@ // ensure newBaseLayer is already loaded if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) { // preserve center and scale when changing base layers var center = this.getCachedCenter(); + var oldResolution = this.getResolution(); var newResolution = OpenLayers.Util.getResolutionFromScale( this.getScale(), newBaseLayer.units ); // make the old base layer invisible @@ -23414,11 +23708,11 @@ // new zoom level derived from old scale var newZoom = this.getZoomForResolution( newResolution || this.resolution, true ); // zoom and force zoom change - this.setCenter(center, newZoom, false, true); + this.setCenter(center, newZoom, false, oldResolution != newResolution); } this.events.triggerEvent("changebaselayer", { layer: this.baseLayer }); @@ -23816,21 +24110,18 @@ }, /** * APIMethod: panTo - * Allows user to pan to a new lonlat + * 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); - } + if (this.panTween && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) { var center = this.getCachedCenter(); // center will not change, don't do nothing if (lonlat.equals(center)) { return; @@ -23877,11 +24168,16 @@ * change events (needed on baseLayer change) * * TBD: reconsider forceZoomChange in 3.0 */ setCenter: function(lonlat, zoom, dragging, forceZoomChange) { - this.panTween && this.panTween.stop(); + if (this.panTween) { + this.panTween.stop(); + } + if (this.zoomTween) { + this.zoomTween.stop(); + } this.moveTo(lonlat, zoom, { 'dragging': dragging, 'forceZoomChange': forceZoomChange }); }, @@ -23918,21 +24214,20 @@ this.dragging = true; this.events.triggerEvent("movestart"); } this.center = null; if (dx) { - this.layerContainerDiv.style.left = - (this.layerContainerOriginPx.x -= dx) + "px"; + this.layerContainerOriginPx.x -= dx; this.minPx.x -= dx; this.maxPx.x -= dx; } if (dy) { - this.layerContainerDiv.style.top = - (this.layerContainerOriginPx.y -= dy) + "px"; + this.layerContainerOriginPx.y -= dy; this.minPx.y -= dy; this.maxPx.y -= dy; } + this.applyTransform(); var layer, i, len; for (i=0, len=this.layers.length; i<len; ++i) { layer = this.layers[i]; if (layer.visibility && (layer === this.baseLayer || layer.inRange)) { @@ -24088,15 +24383,13 @@ var res = zoomChanged ? this.getResolutionForZoom(zoom) : this.getResolution(); // (re)set the layerContainerDiv's location if (zoomChanged || this.layerContainerOrigin == null) { this.layerContainerOrigin = this.getCachedCenter(); - var style = this.layerContainerDiv.style; - style.left = "0px"; - style.top = "0px"; this.layerContainerOriginPx.x = 0; this.layerContainerOriginPx.y = 0; + this.applyTransform(); var maxExtent = this.getMaxExtent({restricted: true}); var maxExtentCenter = maxExtent.getCenterLonLat(); var lonDelta = this.center.lon - maxExtentCenter.lon; var latDelta = maxExtentCenter.lat - this.center.lat; var extentWidth = Math.round(maxExtent.getWidth() / res); @@ -24140,11 +24433,13 @@ // 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, options.dragging); options.dragging || layer.events.triggerEvent( "moveend", {zoomChanged: zoomChanged} @@ -24180,14 +24475,13 @@ if ((originPx != null) && (newPx != null)) { var oldLeft = this.layerContainerOriginPx.x; var oldTop = this.layerContainerOriginPx.y; var newLeft = Math.round(originPx.x - newPx.x); var newTop = Math.round(originPx.y - newPx.y); - this.layerContainerDiv.style.left = - (this.layerContainerOriginPx.x = newLeft) + "px"; - this.layerContainerDiv.style.top = - (this.layerContainerOriginPx.y = newTop) + "px"; + this.applyTransform( + (this.layerContainerOriginPx.x = newLeft), + (this.layerContainerOriginPx.y = newTop)); var dx = oldLeft - newLeft; var dy = oldTop - newTop; this.minPx.x -= dx; this.maxPx.x -= dx; this.minPx.y -= dy; @@ -24482,34 +24776,90 @@ /* */ /********************************************************/ /** * APIMethod: zoomTo - * Zoom to a specific zoom level + * Zoom to a specific zoom level. Zooming will be animated unless the map + * is configured with {zoomMethod: null}. To zoom without animation, use + * <setCenter> without a lonlat argument. * * Parameters: * zoom - {Integer} */ - zoomTo: function(zoom) { - if (this.isValidZoomLevel(zoom)) { - this.setCenter(null, zoom); + zoomTo: function(zoom, xy) { + // non-API arguments: + // xy - {<OpenLayers.Pixel>} optional zoom origin + + var map = this; + if (map.isValidZoomLevel(zoom)) { + if (map.baseLayer.wrapDateLine) { + zoom = map.adjustZoom(zoom); + } + var center = xy ? + map.getZoomTargetCenter(xy, map.getResolutionForZoom(zoom)) : + map.getCenter(); + if (center) { + map.events.triggerEvent('zoomstart', { + center: center, + zoom: zoom + }); + } + if (map.zoomTween) { + map.zoomTween.stop(); + var currentRes = map.getResolution(), + targetRes = map.getResolutionForZoom(zoom), + start = {scale: 1}, + end = {scale: currentRes / targetRes}; + if (!xy) { + var size = map.getSize(); + xy = {x: size.w / 2, y: size.h / 2}; + } + map.zoomTween.start(start, end, map.zoomDuration, { + minFrameRate: 50, // don't spend much time zooming + callbacks: { + eachStep: function(data) { + var containerOrigin = map.layerContainerOriginPx, + scale = data.scale, + dx = ((scale - 1) * (containerOrigin.x - xy.x)) | 0, + dy = ((scale - 1) * (containerOrigin.y - xy.y)) | 0; + map.applyTransform(containerOrigin.x + dx, containerOrigin.y + dy, scale); + }, + done: function(data) { + map.applyTransform(); + var resolution = map.getResolution() / data.scale, + newZoom = map.getZoomForResolution(resolution, true), + newCenter = data.scale === 1 ? center : + map.getZoomTargetCenter(xy, resolution); + map.moveTo(newCenter, newZoom); + } + } + }); + } else { + map.setCenter(center, zoom); + } } }, - + /** * APIMethod: zoomIn * */ zoomIn: function() { + if (this.zoomTween) { + this.zoomTween.stop(); + } this.zoomTo(this.getZoom() + 1); }, /** * APIMethod: zoomOut * */ zoomOut: function() { + if (this.zoomTween) { + this.zoomTween.stop(); + } this.zoomTo(this.getZoom() - 1); }, /** * APIMethod: zoomToExtent @@ -24650,11 +25000,36 @@ px = this.baseLayer.getViewPortPxFromLonLat(lonlat); } return px; }, - + /** + * Method: getZoomTargetCenter + * + * Parameters: + * xy - {<OpenLayers.Pixel>} The zoom origin pixel location on the screen + * resolution - {Float} The resolution we want to get the center for + * + * Returns: + * {<OpenLayers.LonLat>} The location of the map center after the + * transformation described by the origin xy and the target resolution. + */ + getZoomTargetCenter: function (xy, resolution) { + var lonlat = null, + size = this.getSize(), + deltaX = size.w/2 - xy.x, + deltaY = xy.y - size.h/2, + zoomPoint = this.getLonLatFromPixel(xy); + if (zoomPoint) { + lonlat = new OpenLayers.LonLat( + zoomPoint.lon + deltaX * resolution, + zoomPoint.lat + deltaY * resolution + ); + } + return lonlat; + }, + // // CONVENIENCE TRANSLATION FUNCTIONS FOR API // /** @@ -24810,10 +25185,80 @@ //adjust for displacement of layerContainerDiv var px = this.getPixelFromLonLat(lonlat); return this.getLayerPxFromViewPortPx(px); }, + /** + * Method: applyTransform + * Applies the given transform to the <layerContainerDiv>. This method has + * a 2-stage fallback from translate3d/scale3d via translate/scale to plain + * style.left/style.top, in which case no scaling is supported. + * + * Parameters: + * x - {Number} x parameter for the translation. Defaults to the x value of + * the map's <layerContainerOriginPx> + * y - {Number} y parameter for the translation. Defaults to the y value of + * the map's <layerContainerOriginPx> + * scale - {Number} scale. Defaults to 1 if not provided. + */ + applyTransform: function(x, y, scale) { + scale = scale || 1; + var origin = this.layerContainerOriginPx, + needTransform = scale !== 1; + x = x || origin.x; + y = y || origin.y; + + var style = this.layerContainerDiv.style, + transform = this.applyTransform.transform, + template = this.applyTransform.template; + + if (transform === undefined) { + transform = OpenLayers.Util.vendorPrefix.style('transform'); + this.applyTransform.transform = transform; + if (transform) { + // Try translate3d, but only if the viewPortDiv has a transform + // defined in a stylesheet + var computedStyle = OpenLayers.Element.getStyle(this.viewPortDiv, + OpenLayers.Util.vendorPrefix.css('transform')); + if (!computedStyle || computedStyle !== 'none') { + template = ['translate3d(', ',0) ', 'scale3d(', ',1)']; + style[transform] = [template[0], '0,0', template[1]].join(''); + } + // If no transform is defined in the stylesheet or translate3d + // does not stick, use translate and scale + if (!template || !~style[transform].indexOf(template[0])) { + template = ['translate(', ') ', 'scale(', ')']; + } + this.applyTransform.template = template; + } + } + + // If we do 3d transforms, we always want to use them. If we do 2d + // transforms, we only use them when we need to. + if (transform !== null && (template[0] === 'translate3d(' || needTransform === true)) { + // Our 2d transforms are combined with style.left and style.top, so + // adjust x and y values and set the origin as left and top + if (needTransform === true && template[0] === 'translate(') { + x -= origin.x; + y -= origin.y; + style.left = origin.x + 'px'; + style.top = origin.y + 'px'; + } + style[transform] = [ + template[0], x, 'px,', y, 'px', template[1], + template[2], scale, ',', scale, template[3] + ].join(''); + } else { + style.left = x + 'px'; + style.top = y + 'px'; + // We previously might have had needTransform, so remove transform + if (transform !== null) { + style[transform] = ''; + } + } + }, + CLASS_NAME: "OpenLayers.Map" }); /** * Constant: TILE_WIDTH @@ -24827,11 +25272,11 @@ OpenLayers.Map.TILE_HEIGHT = 256; /* ====================================================================== OpenLayers/Handler.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -24914,10 +25359,18 @@ * evt property should be restricted to controls in the library * or other applications that are willing to update with changes to * the OpenLayers code. */ evt: null, + + /** + * Property: touch + * {Boolean} Indicates the support of touch events. When touch events are + * started touch will be true and all mouse related listeners will do + * nothing. + */ + touch: false, /** * Constructor: OpenLayers.Handler * Construct a handler. * @@ -25016,15 +25469,37 @@ for (var i=0, len=events.length; i<len; i++) { if (this[events[i]]) { this.unregister(events[i], this[events[i]]); } } + this.touch = false; this.active = false; return true; }, /** + * Method: startTouch + * Start touch events, this method must be called by subclasses in + * "touchstart" method. When touch events are started <touch> will be + * true and all mouse related listeners will do nothing. + */ + startTouch: function() { + if (!this.touch) { + this.touch = true; + var events = [ + "mousedown", "mouseup", "mousemove", "click", "dblclick", + "mouseout" + ]; + for (var i=0, len=events.length; i<len; i++) { + if (this[events[i]]) { + this.unregister(events[i], this[events[i]]); + } + } + } + }, + + /** * Method: callback * Trigger the control's named callback with the given arguments * * Parameters: * name - {String} The key for the callback that is one of the properties @@ -25126,11 +25601,11 @@ /* ====================================================================== OpenLayers/Handler/Click.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -25218,17 +25693,10 @@ /** * Property: timerId * {Number} The id of the timeout waiting to clear the <delayedCall>. */ timerId: null, - - /** - * Property: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, /** * Property: down * {Object} Object that store relevant information about the last * mousedown or touchstart. Its 'xy' OpenLayers.Pixel property gives @@ -25283,14 +25751,11 @@ * * Returns: * {Boolean} Continue propagating this event. */ touchstart: function(evt) { - if (!this.touch) { - this.unregisterMouseListeners(); - this.touch = true; - } + this.startTouch(); this.down = this.getEventInfo(evt); this.last = this.getEventInfo(evt); return true; }, @@ -25323,24 +25788,10 @@ this.handleSingle(evt); this.down = null; } return true; }, - - /** - * Method: unregisterMouseListeners - * In a touch environment, we don't want to handle mouse events. - */ - unregisterMouseListeners: function() { - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - click: this.click, - dblclick: this.dblclick, - scope: this - }); - }, /** * Method: mousedown * Handle mousedown. * @@ -25648,11 +26099,10 @@ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { this.clearTimer(); this.down = null; this.first = null; this.last = null; - this.touch = false; deactivated = true; } return deactivated; }, @@ -25660,11 +26110,11 @@ }); /* ====================================================================== OpenLayers/Handler/Drag.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -25712,17 +26162,10 @@ * Property: dragging * {Boolean} */ dragging: false, - /** - * Property: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, - /** * Property: last * {<OpenLayers.Pixel>} The last pixel location of the drag. */ last: null, @@ -26007,21 +26450,11 @@ * * Returns: * {Boolean} Let the event propagate. */ touchstart: function(evt) { - if (!this.touch) { - this.touch = true; - // unregister mouse listeners - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - scope: this - }); - } + this.startTouch(); return this.dragstart(evt); }, /** * Method: mousemove @@ -26171,11 +26604,10 @@ * {Boolean} The handler was successfully deactivated. */ deactivate: function() { var deactivated = false; if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { - this.touch = false; this.started = false; this.dragging = false; this.start = null; this.last = null; deactivated = true; @@ -26229,11 +26661,11 @@ }); /* ====================================================================== OpenLayers/Control/OverviewMap.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -26983,11 +27415,11 @@ }); /* ====================================================================== OpenLayers/Layer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -27078,11 +27510,15 @@ * a *filter* property holding the OpenLayers.Filter used when * calling read on the protocol. * loadend - Triggered when layer loading ends. When using a Vector layer * with a Fixed or BBOX strategy, the event object includes a * *response* property holding an OpenLayers.Protocol.Response object. - * visibilitychanged - Triggered when layer visibility is changed. + * visibilitychanged - Triggered when the layer's visibility property is + * changed, e.g. by turning the layer on or off in the layer switcher. + * Note that the actual visibility of the layer can also change if it + * gets out of range (see <calculateInRange>). If you also want to catch + * these cases, register for the map's 'changelayer' event instead. * 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. @@ -27128,14 +27564,18 @@ */ visibility: true, /** * APIProperty: attribution - * {String} Attribution string, displayed when an + * {<Object>} or {<String>} Attribution information, displayed when an * <OpenLayers.Control.Attribution> has been added to the map. + * + * An object is required to store the full attribution information + * from a WMS capabilities response. Example attribution object: + * {title:"",href:"",logo:{format:"",width:10,height:10,href:""}} */ - attribution: null, + 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 @@ -27724,10 +28164,16 @@ 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"); } }, /** @@ -27740,15 +28186,10 @@ * display - {Boolean} */ display: function(display) { if (display != (this.div.style.display != "none")) { this.div.style.display = (display && this.calculateInRange()) ? "block" : "none"; - if(this.map){ - this.map.events.triggerEvent("changelayer", { - layer: this, property: "visibility" - }); - } } }, /** * APIMethod: calculateInRange @@ -28359,11 +28800,11 @@ }); /* ====================================================================== OpenLayers/Layer/SphericalMercator.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -28509,11 +28950,11 @@ }; /* ====================================================================== OpenLayers/Layer/EventPane.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -28637,10 +29078,12 @@ // if map didn't load, display warning if (this.mapObject == null) { this.loadWarningMessage(); } + + this.map.events.register('zoomstart', this, this.onZoomStart); }, /** * APIMethod: removeMap * On being removed from the map, we'll like to remove the invisible 'pane' @@ -28648,15 +29091,31 @@ * * Parameters: * map - {<OpenLayers.Map>} */ removeMap: function(map) { + this.map.events.unregister('zoomstart', this, this.onZoomStart); + if (this.pane && this.pane.parentNode) { this.pane.parentNode.removeChild(this.pane); } OpenLayers.Layer.prototype.removeMap.apply(this, arguments); }, + + /** + * Method: onZoomStart + * + * Parameters: + * evt - zoomstart event object with center and zoom properties. + */ + onZoomStart: function(evt) { + if (this.mapObject != null) { + var center = this.getMapObjectLonLatFromOLLonLat(evt.center); + var zoom = this.getMapObjectZoomFromOLZoom(evt.zoom); + this.setMapObjectCenter(center, zoom, false); + } + }, /** * Method: loadWarningMessage * If we can't load the map lib, then display an error message to the * user and tell them where to go for help. @@ -28954,11 +29413,11 @@ }); /* ====================================================================== OpenLayers/Layer/FixedZoomLevels.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -29277,11 +29736,11 @@ /* ====================================================================== OpenLayers/Layer/Google.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -29388,13 +29847,11 @@ * options - {Object} An optional object whose properties will be set * on the layer. */ initialize: function(name, options) { options = options || {}; - if(!options.version) { - options.version = typeof GMap2 === "function" ? "2" : "3"; - } + options.version = "3"; var mixin = OpenLayers.Layer.Google["v" + options.version.replace(/\./g, "_")]; if (mixin) { OpenLayers.Util.applyDefaults(options, mixin); } else { @@ -29553,10 +30010,14 @@ } var poweredBy = cache.poweredBy; if (poweredBy && poweredBy.parentNode) { poweredBy.parentNode.removeChild(poweredBy); } + if (this.mapObject && window.google && google.maps && + google.maps.event && google.maps.event.clearListeners) { + google.maps.event.clearListeners(this.mapObject, 'tilesloaded'); + } } }, /** * APIMethod: removeMap @@ -29740,357 +30201,165 @@ /** * Property: OpenLayers.Layer.Google.cache * {Object} Cache for elements that should only be created once per map. */ OpenLayers.Layer.Google.cache = {}; +/* ====================================================================== + OpenLayers/Format/TMSCapabilities.js + ====================================================================== */ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ /** - * Constant: OpenLayers.Layer.Google.v2 + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/BaseTypes/Bounds.js + * @requires OpenLayers/BaseTypes/LonLat.js + */ + +/** + * Class: OpenLayers.Format.TMSCapabilities + * Parse TMS Capabilities. + * See http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification * - * Mixin providing functionality specific to the Google Maps API v2. - * - * This API has been deprecated by Google. - * Developers are encouraged to migrate to v3 of the API; support for this - * is provided by <OpenLayers.Layer.Google.v3> + * Inherits from: + * - <OpenLayers.Format.XML> */ -OpenLayers.Layer.Google.v2 = { - - /** - * Property: termsOfUse - * {DOMElement} Div for Google's copyright and terms of use link - */ - termsOfUse: null, +OpenLayers.Format.TMSCapabilities = OpenLayers.Class( + OpenLayers.Format.XML, { /** - * Property: poweredBy - * {DOMElement} Div for Google's powered by logo and link + * Property: defaultPrefix */ - poweredBy: null, + defaultPrefix: "tms", /** - * Property: dragObject - * {GDraggableObject} Since 2.93, Google has exposed the ability to get - * the maps GDraggableObject. We can now use this for smooth panning + * 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. */ - dragObject: null, - - /** - * Method: loadMapObject - * Load the GMap and register appropriate event listeners. If we can't - * load GMap2, then display a warning message. - */ - loadMapObject:function() { - if (!this.type) { - this.type = G_NORMAL_MAP; - } - var mapObject, termsOfUse, poweredBy; - var cache = OpenLayers.Layer.Google.cache[this.map.id]; - if (cache) { - // there are already Google layers added to this map - mapObject = cache.mapObject; - termsOfUse = cache.termsOfUse; - poweredBy = cache.poweredBy; - // increment the layer count - ++cache.count; - } else { - // this is the first Google layer for this map - - var container = this.map.viewPortDiv; - var div = document.createElement("div"); - div.id = this.map.id + "_GMap2Container"; - div.style.position = "absolute"; - div.style.width = "100%"; - div.style.height = "100%"; - container.appendChild(div); - - // create GMap and shuffle elements - try { - mapObject = new GMap2(div); - - // move the ToS and branding stuff up to the container div - termsOfUse = div.lastChild; - container.appendChild(termsOfUse); - termsOfUse.style.zIndex = "1100"; - termsOfUse.style.right = ""; - termsOfUse.style.bottom = ""; - termsOfUse.className = "olLayerGoogleCopyright"; - - poweredBy = div.lastChild; - container.appendChild(poweredBy); - poweredBy.style.zIndex = "1100"; - poweredBy.style.right = ""; - poweredBy.style.bottom = ""; - poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; - - } catch (e) { - throw(e); - } - // cache elements for use by any other google layers added to - // this same map - OpenLayers.Layer.Google.cache[this.map.id] = { - mapObject: mapObject, - termsOfUse: termsOfUse, - poweredBy: poweredBy, - count: 1 - }; - } - - this.mapObject = mapObject; - this.termsOfUse = termsOfUse; - this.poweredBy = poweredBy; - - // ensure this layer type is one of the mapObject types - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), - this.type) === -1) { - this.mapObject.addMapType(this.type); - } - - //since v 2.93 getDragObject is now available. - if(typeof mapObject.getDragObject == "function") { - this.dragObject = mapObject.getDragObject(); - } else { - this.dragPanMapObject = null; - } - - if(this.isBaseLayer === false) { - this.setGMapVisibility(this.div.style.display !== "none"); - } - - }, - - /** - * APIMethod: onMapResize - */ - 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: setGMapVisibility - * Display the GMap container and associated elements. - * - * Parameters: - * visible - {Boolean} Display the GMap elements. - */ - setGMapVisibility: function(visible) { - var cache = OpenLayers.Layer.Google.cache[this.map.id]; - if (cache) { - var container = this.mapObject.getContainer(); - if (visible === true) { - this.mapObject.setMapType(this.type); - container.style.display = ""; - this.termsOfUse.style.left = ""; - this.termsOfUse.style.display = ""; - this.poweredBy.style.display = ""; - cache.displayed = this.id; - } else { - if (cache.displayed === this.id) { - delete cache.displayed; + readers: { + "tms": { + "Services": function(node, obj) { + obj.services = []; + this.readChildNodes(node, obj); + }, + "TileMapService": function(node, obj) { + if (obj.services) { + obj.services.push({ + service: 'TMS', + version: node.getAttribute("version"), + title: node.getAttribute("title"), + href: node.getAttribute("href") + }); + } else { + this.readChildNodes(node, obj); } - if (!cache.displayed) { - container.style.display = "none"; - this.termsOfUse.style.display = "none"; - // move ToU far to the left in addition to setting display - // to "none", because at the end of the GMap2 load - // sequence, display: none will be unset and ToU would be - // visible after loading a map with a google layer that is - // initially hidden. - this.termsOfUse.style.left = "-9999px"; - this.poweredBy.style.display = "none"; + }, + "TileMaps": function(node, obj) { + obj.tileMaps = []; + this.readChildNodes(node, obj); + }, + "TileMap": function(node, obj) { + if (obj.tileMaps) { + obj.tileMaps.push({ + href: node.getAttribute("href"), + srs: node.getAttribute("srs"), + title: node.getAttribute("title"), + profile: node.getAttribute("profile") + }); + } else { + obj.version = node.getAttribute("version"); + obj.tileMapService = node.getAttribute("tilemapservice"); + this.readChildNodes(node, obj); } + }, + "Title": function(node, obj) { + obj.title = this.getChildValue(node); + }, + "Abstract": function(node, obj) { + obj['abstract'] = this.getChildValue(node); + }, + "SRS": function(node, obj) { + obj.srs = this.getChildValue(node); + }, + "BoundingBox": function(node, obj) { + obj.bbox = new OpenLayers.Bounds( + node.getAttribute("minx"), + node.getAttribute("miny"), + node.getAttribute("maxx"), + node.getAttribute("maxy")); + }, + "Origin": function(node, obj) { + obj.origin = new OpenLayers.LonLat( + node.getAttribute("x"), + node.getAttribute("y")); + }, + "TileFormat": function(node, obj) { + obj.tileFormat = { + width: parseInt(node.getAttribute("width"), 10), + height: parseInt(node.getAttribute("height"), 10), + mimeType: node.getAttribute("mime-type"), + extension: node.getAttribute("extension") + }; + }, + "TileSets": function(node, obj) { + obj.tileSets = []; + this.readChildNodes(node, obj); + }, + "TileSet": function(node, obj) { + obj.tileSets.push({ + href: node.getAttribute("href"), + unitsPerPixel: parseFloat(node.getAttribute("units-per-pixel")), + order: parseInt(node.getAttribute("order"), 10) + }); + }, + "TileMapServerError": function(node, obj) { + obj.error = true; + }, + "Message": function(node, obj) { + obj.message = this.getChildValue(node); } } }, - - /** - * Method: getMapContainer - * - * Returns: - * {DOMElement} the GMap container's div - */ - getMapContainer: function() { - return this.mapObject.getContainer(); - }, - // - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds - // - /** - * APIMethod: getMapObjectBoundsFromOLBounds + * APIMethod: read + * Read TMS capabilities data from a string, and return a list of tilesets. * - * Parameters: - * olBounds - {<OpenLayers.Bounds>} - * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * * Returns: - * {Object} A MapObject Bounds, translated from olBounds - * Returns null if null value is passed in + * {Object} Information about the services served by this TMS instance. */ - 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)); + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); } - return moBounds; - }, - - - /************************************ - * * - * 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)); - }, - - - // 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: 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); + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; } - return gLatLng; + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; }, - // Pixel - - /** - * 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.Format.TMSCapabilities" + +}); /* ====================================================================== OpenLayers/Format/WFST.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -30124,11 +30393,11 @@ }; /* ====================================================================== OpenLayers/Format/WFST/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -30314,12 +30583,12 @@ * - *modified* is not set at all: The geometry and all attributes will be * included. * - *modified.geometry* is set (null or a geometry): The geometry will be * included. If *modified.attributes* is not set, all attributes will * be included. - * - *modified.attributes* is set: Only the attributes set (i.e. to null or - * a value) in *modified.attributes* will be included. + * - *modified.attributes* is set: Only the attributes set in + * *modified.attributes* will be included. * If *modified.geometry* is not set, the geometry will not be included. * * Valid options include: * - *multi* {Boolean} If set to true, geometries will be casted to * Multi geometries before writing. @@ -30462,11 +30731,11 @@ // add in attributes for(var key in feature.attributes) { if(feature.attributes[key] !== undefined && (!modified || !modified.attributes || - (modified.attributes && modified.attributes[key] !== undefined))) { + (modified.attributes && (key in modified.attributes)))) { this.writeNode( "Property", {name: key, value: feature.attributes[key]}, node ); } } @@ -30574,11 +30843,11 @@ }); /* ====================================================================== OpenLayers/Format/GML/v3.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -30713,11 +30982,14 @@ } else { point = new OpenLayers.Geometry.Point( coords[1], coords[0], coords[2] ); } - obj.points = [point]; + if(!!!obj.points) { + obj.points = []; + } + obj.points.push(point); }, "posList": function(node, obj) { var str = this.getChildValue(node).replace( this.regExes.trimSpace, "" ); @@ -30804,10 +31076,11 @@ 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) ); @@ -31055,11 +31328,11 @@ }); /* ====================================================================== OpenLayers/Format/Filter/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -31281,11 +31554,11 @@ }); /* ====================================================================== OpenLayers/Format/WFST/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -31471,416 +31744,14 @@ }, CLASS_NAME: "OpenLayers.Format.WFST.v1_1_0" }); /* ====================================================================== - OpenLayers/Format/JSON.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository 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, - - /** - * Property: nativeJSON - * {Boolean} Does the browser support native json? - */ - nativeJSON: (function() { - return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function"); - })(), - - /** - * Constructor: OpenLayers.Format.JSON - * Create a new parser for JSON. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * 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) { - var object; - if (this.nativeJSON) { - object = JSON.parse(json, filter); - } else try { - /** - * 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. - */ - 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. - */ - 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); - } - } - } catch(e) { - // Fall through if the regexp test fails. - } - - if(this.keepData) { - this.data = object; - } - - return object; - }, - - /** - * 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.pretty && this.nativeJSON) ? - JSON.stringify(value) : - 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" - -}); -/* ====================================================================== OpenLayers/Format/WFSCapabilities.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -31927,11 +31798,11 @@ }); /* ====================================================================== OpenLayers/Format/WFSCapabilities/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32124,19 +31995,20 @@ else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; else if (this.geometryType != "point" && this.geometryType != "polygon") return null; - var points = this.decode(encoded, 2); - var pointGeometries = new Array(); - for (var i in points) { - var point = points[i]; - pointGeometries.push( - new OpenLayers.Geometry.Point(point[1] * 1e-5, point[0] * 1e-5) - ); + var flatPoints = this.decodeDeltas(encoded, 2); + var flatPointsLength = flatPoints.length; + + var pointGeometries = []; + for (var i = 0; i + 1 < flatPointsLength;) { + var y = flatPoints[i++], x = flatPoints[i++]; + pointGeometries.push(new OpenLayers.Geometry.Point(x, y)); } + if (this.geometryType == "point") return new OpenLayers.Feature.Vector( pointGeometries[0] ); @@ -32163,34 +32035,24 @@ * * Returns: * {Array(Array(int))} An array containing n-dimensional arrays of * coordinates. */ - decode: function(encoded, dims) { - var points = new Array(); - var point = new Array(dims); + decode: function(encoded, dims, opt_factor) { + var factor = opt_factor || 1e5; + var flatPoints = this.decodeDeltas(encoded, dims, factor); + var flatPointsLength = flatPoints.length; - // Reset the point array - for (var i = 0; i < point.length; ++i) - point[i] = 0; + var points = []; + for (var i = 0; i + (dims - 1) < flatPointsLength;) { + var point = []; - for (var i = 0; i < encoded.length;) { for (var dim = 0; dim < dims; ++dim) { - var result = 0; - var shift = 0; - - var b; - do { - b = encoded.charCodeAt(i++) - 63; - result |= (b & 0x1f) << shift; - shift += 5; - } while (b >= 0x20); - - point[dim] += ((result & 1) ? ~(result >> 1) : (result >> 1)); + point.push(flatPoints[i++]) } - points.push(point.slice(0)); + points.push(point); } return points; }, @@ -32225,20 +32087,20 @@ else if (type == "polygon") pointGeometries = geometry.components[0].components; else return null; - var points = new Array(); - for (var i in pointGeometries) { + var flatPoints = []; + + var pointGeometriesLength = pointGeometries.length; + for (var i = 0; i < pointGeometriesLength; ++i) { var pointGeometry = pointGeometries[i]; - var point = [Math.round(pointGeometry.y * 1e5), - Math.round(pointGeometry.x * 1e5)]; - points.push(point); + flatPoints.push(pointGeometry.y); + flatPoints.push(pointGeometry.x); } - var result = this.encode(points, 2); - return result; + return this.encodeDeltas(flatPoints, 2); }, /** * APIMethod: encode * Serialize an array of n-dimensional points and return an encoded string @@ -32249,80 +32111,392 @@ * dims - {int} The dimension of the points that should be read * * Returns: * {String} An encoded string */ - encode: function (points, dims) { - var encoded_points = ""; + encode: function (points, dims, opt_factor) { + var factor = opt_factor || 1e5; + var flatPoints = []; - var lastPoint = new Array(dims); - for (var i = 0; i < lastPoint.length; ++i) - lastPoint[i] = 0; - - for (var i = 0; i < points.length; i++) { + var pointsLength = points.length; + for (var i = 0; i < pointsLength; ++i) { var point = points[i]; - for (var dim = 0; dim < lastPoint.length; ++dim) { - var delta = point[dim] - lastPoint[dim]; - encoded_points += this.encodeSignedNumber(delta); + for (var dim = 0; dim < dims; ++dim) { + flatPoints.push(point[dim]); } + } - lastPoint = point; + return this.encodeDeltas(flatPoints, dims, factor); + }, + + /** + * APIMethod: encodeDeltas + * Encode a list of n-dimensional points and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of n-dimensional points. + * dimension - {number} The dimension of the points in the list. + * opt_factor - {number=} The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeDeltas: function(numbers, dimension, opt_factor) { + var factor = opt_factor || 1e5; + var d; + + var lastNumbers = new Array(dimension); + for (d = 0; d < dimension; ++d) { + lastNumbers[d] = 0; + } + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength;) { + for (d = 0; d < dimension; ++d, ++i) { + var num = numbers[i]; + var delta = num - lastNumbers[d]; + lastNumbers[d] = num; + + numbers[i] = delta; } - return encoded_points; + } + + return this.encodeFloats(numbers, factor); }, + /** - * Method: encodeSignedNumber + * APIMethod: decodeDeltas + * Decode a list of n-dimensional points from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * dimension - {number} The dimension of the points in the encoded string. + * opt_factor - {number=} The factor by which the resulting numbers will + * be divided. + * + * Returns: + * {Array.<number>} A list of n-dimensional points. + */ + decodeDeltas: function(encoded, dimension, opt_factor) { + var factor = opt_factor || 1e5; + var d; + + var lastNumbers = new Array(dimension); + for (d = 0; d < dimension; ++d) { + lastNumbers[d] = 0; + } + + var numbers = this.decodeFloats(encoded, factor); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength;) { + for (d = 0; d < dimension; ++d, ++i) { + lastNumbers[d] += numbers[i]; + + numbers[i] = lastNumbers[d]; + } + } + + return numbers; + }, + + + /** + * APIMethod: encodeFloats + * Encode a list of floating point numbers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of floating point numbers. + * opt_factor - {number=} The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeFloats: function(numbers, opt_factor) { + var factor = opt_factor || 1e5; + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + numbers[i] = Math.round(numbers[i] * factor); + } + + return this.encodeSignedIntegers(numbers); + }, + + + /** + * APIMethod: decodeFloats + * Decode a list of floating point numbers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * opt_factor - {number=} The factor by which the result will be divided. + * + * Returns: + * {Array.<number>} A list of floating point numbers. + */ + decodeFloats: function(encoded, opt_factor) { + var factor = opt_factor || 1e5; + + var numbers = this.decodeSignedIntegers(encoded); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + numbers[i] /= factor; + } + + return numbers; + }, + + + /** + * APIMethod: encodeSignedIntegers + * Encode a list of signed integers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * Parameters: + * numbers - {Array.<number>} A list of signed integers. + * + * Returns: + * {string} The encoded string. + */ + encodeSignedIntegers: function(numbers) { + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + var num = numbers[i]; + + var signedNum = num << 1; + if (num < 0) { + signedNum = ~(signedNum); + } + + numbers[i] = signedNum; + } + + return this.encodeUnsignedIntegers(numbers); + }, + + + /** + * APIMethod: decodeSignedIntegers + * Decode a list of signed integers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {Array.<number>} A list of signed integers. + */ + decodeSignedIntegers: function(encoded) { + var numbers = this.decodeUnsignedIntegers(encoded); + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + var num = numbers[i]; + numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); + } + + return numbers; + }, + + + /** + * APIMethod: encodeUnsignedIntegers + * Encode a list of unsigned integers and return an encoded string + * + * Parameters: + * numbers - {Array.<number>} A list of unsigned integers. + * + * Returns: + * {string} The encoded string. + */ + encodeUnsignedIntegers: function(numbers) { + var encoded = ''; + + var numbersLength = numbers.length; + for (var i = 0; i < numbersLength; ++i) { + encoded += this.encodeUnsignedInteger(numbers[i]); + } + + return encoded; + }, + + + /** + * APIMethod: decodeUnsignedIntegers + * Decode a list of unsigned integers from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {Array.<number>} A list of unsigned integers. + */ + decodeUnsignedIntegers: function(encoded) { + var numbers = []; + + var current = 0; + var shift = 0; + + var encodedLength = encoded.length; + for (var i = 0; i < encodedLength; ++i) { + var b = encoded.charCodeAt(i) - 63; + + current |= (b & 0x1f) << shift; + + if (b < 0x20) { + numbers.push(current); + current = 0; + shift = 0; + } else { + shift += 5; + } + } + + return numbers; + }, + + + /** + * Method: encodeFloat + * Encode one single floating point number and return an encoded string + * + * Parameters: + * num - {number} Floating point number that should be encoded. + * opt_factor - {number=} The factor by which num will be multiplied. + * The remaining decimal places will get rounded away. + * + * Returns: + * {string} The encoded string. + */ + encodeFloat: function(num, opt_factor) { + num = Math.round(num * (opt_factor || 1e5)); + return this.encodeSignedInteger(num); + }, + + + /** + * Method: decodeFloat + * Decode one single floating point number from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * opt_factor - {number=} The factor by which the result will be divided. + * + * Returns: + * {number} The decoded floating point number. + */ + decodeFloat: function(encoded, opt_factor) { + var result = this.decodeSignedInteger(encoded); + return result / (opt_factor || 1e5); + }, + + + /** + * Method: encodeSignedInteger * Encode one single signed integer and return an encoded string * * Parameters: - * num - {int} A signed integer that should be encoded + * num - {number} Signed integer that should be encoded. * * Returns: - * {String} An encoded string + * {string} The encoded string. */ - encodeSignedNumber: function (num) { - var sgn_num = num << 1; - if (num < 0) - sgn_num = ~(sgn_num); + encodeSignedInteger: function(num) { + var signedNum = num << 1; + if (num < 0) { + signedNum = ~(signedNum); + } - return this.encodeNumber(sgn_num); + return this.encodeUnsignedInteger(signedNum); }, + /** - * Method: encodeNumber + * Method: decodeSignedInteger + * Decode one single signed integer from an encoded string + * + * Parameters: + * encoded - {string} An encoded string. + * + * Returns: + * {number} The decoded signed integer. + */ + decodeSignedInteger: function(encoded) { + var result = this.decodeUnsignedInteger(encoded); + return ((result & 1) ? ~(result >> 1) : (result >> 1)); + }, + + + /** + * Method: encodeUnsignedInteger * Encode one single unsigned integer and return an encoded string * - * encodeSignedNumber should be used instead of using this method directly! + * Parameters: + * num - {number} Unsigned integer that should be encoded. * + * Returns: + * {string} The encoded string. + */ + encodeUnsignedInteger: function(num) { + var value, encoded = ''; + while (num >= 0x20) { + value = (0x20 | (num & 0x1f)) + 63; + encoded += (String.fromCharCode(value)); + num >>= 5; + } + value = num + 63; + encoded += (String.fromCharCode(value)); + return encoded; + }, + + + /** + * Method: decodeUnsignedInteger + * Decode one single unsigned integer from an encoded string + * * Parameters: - * num - {int} An unsigned integer that should be encoded + * encoded - {string} An encoded string. * * Returns: - * {String} An encoded string + * {number} The decoded unsigned integer. */ - encodeNumber: function (num) { - var encodeString = ""; - var value; - while (num >= 0x20) { - value = (0x20 | (num & 0x1f)) + 63; - encodeString += (String.fromCharCode(value)); - num >>= 5; - } - value = num + 63; - encodeString += (String.fromCharCode(value)); - return encodeString; + decodeUnsignedInteger: function(encoded) { + var result = 0; + var shift = 0; + + var encodedLength = encoded.length; + for (var i = 0; i < encodedLength; ++i) { + var b = encoded.charCodeAt(i) - 63; + + result |= (b & 0x1f) << shift; + + if (b < 0x20) + break; + + shift += 5; + } + + return result; }, CLASS_NAME: "OpenLayers.Format.EncodedPolyline" }); /* ====================================================================== OpenLayers/Control/Panel.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32753,11 +32927,11 @@ /* ====================================================================== OpenLayers/Control/Button.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32801,11 +32975,11 @@ }); /* ====================================================================== OpenLayers/Control/ZoomIn.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32834,11 +33008,11 @@ }); /* ====================================================================== OpenLayers/Control/ZoomOut.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32867,11 +33041,11 @@ }); /* ====================================================================== OpenLayers/Control/ZoomToMaxExtent.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32906,11 +33080,11 @@ }); /* ====================================================================== OpenLayers/Control/ZoomPanel.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -32964,11 +33138,11 @@ }); /* ====================================================================== OpenLayers/Layer/HTTPRequest.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -32982,10 +33156,19 @@ * Inherits from: * - <OpenLayers.Layer> */ OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, { + /** + * APIProperty: events + * {<OpenLayers.Events>} + * + * Supported event types (in addition to those from <OpenLayers.Layer.events>): + * refresh - Triggered when a redraw is forced, to re-fetch data from the + * server. + */ + /** * 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. */ @@ -33110,10 +33293,11 @@ * Returns: * {Boolean} The layer was redrawn. */ redraw: function(force) { if (force) { + this.events.triggerEvent('refresh'); return this.mergeNewParams({"_olSalt": Math.random()}); } else { return OpenLayers.Layer.prototype.redraw.apply(this, []); } }, @@ -33198,11 +33382,11 @@ }); /* ====================================================================== OpenLayers/Tile.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -33494,19 +33678,20 @@ }); /* ====================================================================== OpenLayers/Tile/Image.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Tile.js * @requires OpenLayers/Animation.js + * @requires OpenLayers/Util.js */ /** * Class: OpenLayers.Tile.Image * Instances of OpenLayers.Tile.Image are used to manage the image tiles @@ -33809,15 +33994,21 @@ /** * Method: initImage * Creates the content for the frame on the tile. */ initImage: function() { + if (!this.url && !this.imgDiv) { + // fast path out - if there is no tile url and no previous image + this.isLoading = false; + return; + } this.events.triggerEvent('beforeload'); this.layer.div.appendChild(this.getTile()); this.events.triggerEvent(this._loadEvent); var img = this.getImage(); - if (this.url && img.getAttribute("src") == this.url) { + var src = img.getAttribute('src') || ''; + if (this.url && OpenLayers.Util.isEquivalentUrl(src, this.url)) { this._loadTimeout = window.setTimeout( OpenLayers.Function.bind(this.onImageLoad, this), 0 ); } else { this.stopLoading(); @@ -34001,11 +34192,11 @@ /* ====================================================================== OpenLayers/Layer/Grid.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -34080,17 +34271,18 @@ 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. + * Default value is 1.5. */ 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 + * extra rows and columns of tiles on each side which will * surround the minimum grid tiles to cover the map. * For very slow loading layers, a larger value may increase * performance somewhat when dragging, but will increase bandwidth * use significantly. */ @@ -34099,20 +34291,25 @@ /** * APIProperty: transitionEffect * {String} The transition effect to use when the map is zoomed. * Two posible 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. + * effect of the zoom having taken place immediately. As the + * new tiles become available, they are drawn on top of the + * resized tiles (this is the default setting). + * "map-resize" - Existing tiles are resized on zoom and placed below the + * base layer. New tiles for the base layer will cover existing tiles. + * This setting is recommended when having an overlay duplicated during + * the transition is undesirable (e.g. street labels or big transparent + * fills). + * null - No transition effect. * * Using "resize" on non-opaque layers can cause undesired visual - * effects. This is therefore discouraged. + * effects. Set transitionEffect to null in this case. */ - transitionEffect: null, + transitionEffect: "resize", /** * APIProperty: numLoadingTiles * {Integer} How many tiles are still loading? */ @@ -34653,11 +34850,15 @@ if(!backBuffer) { backBuffer = this.createBackBuffer(); if(!backBuffer) { return; } - this.div.insertBefore(backBuffer, this.div.firstChild); + if (resolution === this.gridResolution) { + this.div.insertBefore(backBuffer, this.div.firstChild); + } else { + this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div); + } this.backBuffer = backBuffer; // set some information in the instance for subsequent // calls to applyBackBuffer where the same back buffer // is reused @@ -34673,12 +34874,12 @@ // scale the tiles inside the back buffer var tiles = backBuffer.childNodes, tile; for (var i=tiles.length-1; i>=0; --i) { tile = tiles[i]; - tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px'; - tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px'; + tile.style.top = ((ratio * tile._i * backBuffer._th) | 0) + 'px'; + tile.style.left = ((ratio * tile._j * backBuffer._tw) | 0) + 'px'; tile.style.width = Math.round(ratio * tile._w) + 'px'; tile.style.height = Math.round(ratio * tile._h) + 'px'; } // and position it (based on the grid's top-left corner) @@ -34703,24 +34904,33 @@ if(this.grid.length > 0) { backBuffer = document.createElement('div'); backBuffer.id = this.div.id + '_bb'; backBuffer.className = 'olBackBuffer'; backBuffer.style.position = 'absolute'; + var map = this.map; + backBuffer.style.zIndex = this.transitionEffect === 'resize' ? + this.getZIndex() - 1 : + // 'map-resize': + map.Z_INDEX_BASE.BaseLayer - + (map.getNumLayers() - map.getLayerIndex(this)); for(var i=0, lenI=this.grid.length; i<lenI; i++) { for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) { var tile = this.grid[i][j], markup = this.grid[i][j].createBackBuffer(); if (markup) { markup._i = i; markup._j = j; - markup._w = tile.size.w; + markup._w = this.singleTile ? + this.getImageSize(tile.bounds).w : tile.size.w; markup._h = tile.size.h; markup.id = tile.id + '_bb'; backBuffer.appendChild(markup); } } } + backBuffer._tw = this.tileSize.w; + backBuffer._th = this.tileSize.h; } return backBuffer; }, /** @@ -34734,11 +34944,13 @@ this.transitionendEvents[i], this._removeBackBuffer); } delete this._transitionElement; } if(this.backBuffer) { - this.div.removeChild(this.backBuffer); + if (this.backBuffer.parentNode) { + this.backBuffer.parentNode.removeChild(this.backBuffer); + } this.backBuffer = null; this.backBufferResolution = null; if(this.backBufferTimerId !== null) { window.clearTimeout(this.backBufferTimerId); this.backBufferTimerId = null; @@ -34820,11 +35032,23 @@ var tileBounds = new OpenLayers.Bounds(center.lon - (tileWidth/2), center.lat - (tileHeight/2), center.lon + (tileWidth/2), center.lat + (tileHeight/2)); + + // store the resolution of the grid + this.gridResolution = this.getServerResolution(); + // same logic as OpenLayers.Tile#shouldDraw + var maxExtent = this.maxExtent; + if (maxExtent && (!this.displayOutsideMaxExtent || + (this.map.baseLayer.wrapDateLine && + this.maxExtent.equals(this.map.getMaxExtent())))) { + tileBounds.left = Math.max(tileBounds.left, maxExtent.left); + tileBounds.right = Math.min(tileBounds.right, maxExtent.right); + } + var px = this.map.getLayerPxFromLonLat({ lon: tileBounds.left, lat: tileBounds.top }); @@ -34833,23 +35057,20 @@ } 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); - - // store the resolution of the grid - this.gridResolution = this.getServerResolution(); }, /** * Method: calculateGridLayout * Generate parameters for the grid layout. @@ -34881,11 +35102,22 @@ tilelon: tilelon, tilelat: tilelat, startcol: tilecol, startrow: tilerow }; }, - + + getImageSize: function(bounds) { + var tileSize = OpenLayers.Layer.HTTPRequest.prototype.getImageSize.apply(this, arguments); + if (this.singleTile) { + tileSize = new OpenLayers.Size( + Math.round(bounds.getWidth() / this.gridResolution), + tileSize.h + ); + } + return tileSize; + }, + /** * Method: getTileOrigin * Determine the origin for aligning the grid of tiles. If a <tileOrigin> * property is supplied, that will be returned. Otherwise, the origin * will be derived from the layer's <maxExtent> property. In this case, @@ -35017,11 +35249,11 @@ rowidx += 1; } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer) || rowidx < minRows); - //shave off exceess rows and colums + //shave off excess rows and columns this.removeExcessTiles(rowidx, colidx); var resolution = this.getServerResolution(); // store the resolution of the grid this.gridResolution = resolution; @@ -35044,11 +35276,11 @@ * {<OpenLayers.Bounds>} */ getMaxExtent: function() { return this.maxExtent; }, - + /** * APIMethod: addTile * Create a tile, initialize it, and add it to the layer div. * * Parameters @@ -35085,11 +35317,11 @@ this.events.triggerEvent("loadstart"); } this.events.triggerEvent("tileloadstart", {tile: tile}); this.numLoadingTiles++; if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) { - OpenLayers.Element.addClass(tile.imgDiv, replacingCls); + OpenLayers.Element.addClass(tile.getTile(), replacingCls); } }; tile.onLoadEnd = function(evt) { this.numLoadingTiles--; @@ -35097,32 +35329,41 @@ this.events.triggerEvent("tileloaded", { tile: tile, aborted: aborted }); if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) { - if (OpenLayers.Element.getStyle(tile.imgDiv, 'display') === 'none') { + var tileDiv = tile.getTile(); + if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') { var bufferTile = document.getElementById(tile.id + '_bb'); if (bufferTile) { bufferTile.parentNode.removeChild(bufferTile); } } - OpenLayers.Element.removeClass(tile.imgDiv, replacingCls); + OpenLayers.Element.removeClass(tileDiv, replacingCls); } //if that was the last tile, then trigger a 'loadend' on the layer if (this.numLoadingTiles === 0) { - if(this.backBuffer) { - this._transitionElement = tile.imgDiv; - for (var i=this.transitionendEvents.length-1; i>=0; --i) { - OpenLayers.Event.observe(this._transitionElement, - this.transitionendEvents[i], - this._removeBackBuffer); + if (this.backBuffer) { + if (this.backBuffer.childNodes.length === 0) { + // no tiles transitioning, remove immediately + this.removeBackBuffer(); + } else { + // wait until transition has ended or delay has passed + this._transitionElement = aborted ? + this.div.lastChild : tile.imgDiv; + var transitionendEvents = this.transitionendEvents; + for (var i=transitionendEvents.length-1; i>=0; --i) { + OpenLayers.Event.observe(this._transitionElement, + transitionendEvents[i], + this._removeBackBuffer); + } + // the removal of the back buffer is delayed to prevent + // flash effects due to the animation of tile displaying + this.backBufferTimerId = window.setTimeout( + this._removeBackBuffer, this.removeBackBufferDelay + ); } - // the removal of the back buffer is delayed to prevent - // flash effects due to the animation of tile displaying - this.backBufferTimerId = window.setTimeout( - this._removeBackBuffer, this.removeBackBufferDelay - ); } this.loading = false; this.events.triggerEvent("loadend"); } }; @@ -35321,11 +35562,11 @@ }); /* ====================================================================== OpenLayers/Format/ArcXML.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -36353,11 +36594,11 @@ }); /* ====================================================================== OpenLayers/Layer/ArcIMS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -36782,11 +37023,11 @@ }); /* ====================================================================== OpenLayers/Control/PanZoom.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -36849,11 +37090,11 @@ /** * APIMethod: destroy */ destroy: function() { - if (this.map) { + if (this.map && !this.outsideViewport) { this.map.events.unregister("buttonclick", this, this.onButtonClick); } this.removeButtons(); this.buttons = null; this.position = null; @@ -36866,11 +37107,18 @@ * Properties: * map - {<OpenLayers.Map>} */ setMap: function(map) { OpenLayers.Control.prototype.setMap.apply(this, arguments); - this.map.events.register("buttonclick", this, this.onButtonClick); + var target; + if (this.outsideViewport) { + this.events.attachToElement(this.div); + target = this; + } else { + target = this.map; + } + target.events.register('buttonclick', this, this.onButtonClick); }, /** * Method: draw * @@ -37019,11 +37267,11 @@ OpenLayers.Control.PanZoom.Y = 4; /* ====================================================================== OpenLayers/Control/PanZoomBar.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -37138,10 +37386,15 @@ * Parameters: * map - {<OpenLayers.Map>} */ setMap: function(map) { OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); + + if (this.outsideViewport) { + this.events.attachToElement(this.div); + } + this.map.events.on({ "changebaselayer": this.redraw, "updatesize": this.redraw, scope: this }); @@ -37337,16 +37590,18 @@ */ zoomBarDown:function(evt) { if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { return; } - this.map.events.on({ - "touchmove": this.passEventToSlider, - "mousemove": this.passEventToSlider, - "mouseup": this.passEventToSlider, + var target = this.outsideViewport ? this : this.map; + target.events.on({ + touchmove: this.passEventToSlider, + mousemove: this.passEventToSlider, + mouseup: this.passEventToSlider, scope: this }); + this.mouseDragStart = evt.xy.clone(); this.zoomStart = evt.xy.clone(); this.div.style.cursor = "move"; // reset the div offsets just in case the div moved this.zoombarDiv.offsets = null; @@ -37391,11 +37646,12 @@ if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { return; } if (this.mouseDragStart) { this.div.style.cursor=""; - this.map.events.un({ + var target = this.outsideViewport ? this : this.map; + target.events.un({ "touchmove": this.passEventToSlider, "mouseup": this.passEventToSlider, "mousemove": this.passEventToSlider, scope: this }); @@ -37431,11 +37687,11 @@ }); /* ====================================================================== OpenLayers/Format/WFSCapabilities/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -37498,11 +37754,11 @@ }); /* ====================================================================== OpenLayers/Layer/Image.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -37761,11 +38017,11 @@ }); /* ====================================================================== OpenLayers/Strategy.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -37886,11 +38142,11 @@ }); /* ====================================================================== OpenLayers/Strategy/Save.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -38118,14 +38374,339 @@ }, CLASS_NAME: "OpenLayers.Strategy.Save" }); /* ====================================================================== + OpenLayers/Events/featureclick.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Events.js + */ + +/** + * Class: OpenLayers.Events.featureclick + * + * Extension event type for handling feature click events, including overlapping + * features. + * + * Event types provided by this extension: + * - featureclick + */ +OpenLayers.Events.featureclick = OpenLayers.Class({ + + /** + * Property: cache + * {Object} A cache of features under the mouse. + */ + cache: null, + + /** + * Property: map + * {<OpenLayers.Map>} The map to register browser events on. + */ + map: null, + + /** + * Property: provides + * {Array(String)} The event types provided by this extension. + */ + provides: ["featureclick", "nofeatureclick", "featureover", "featureout"], + + /** + * Constructor: OpenLayers.Events.featureclick + * Create a new featureclick event type. + * + * Parameters: + * target - {<OpenLayers.Events>} The events instance to create the events + * for. + */ + initialize: function(target) { + this.target = target; + if (target.object instanceof OpenLayers.Map) { + this.setMap(target.object); + } else if (target.object instanceof OpenLayers.Layer.Vector) { + if (target.object.map) { + this.setMap(target.object.map); + } else { + target.object.events.register("added", this, function(evt) { + this.setMap(target.object.map); + }); + } + } else { + throw("Listeners for '" + this.provides.join("', '") + + "' events can only be registered for OpenLayers.Layer.Vector " + + "or OpenLayers.Map instances"); + } + for (var i=this.provides.length-1; i>=0; --i) { + target.extensions[this.provides[i]] = true; + } + }, + + /** + * Method: setMap + * + * Parameters: + * map - {<OpenLayers.Map>} The map to register browser events on. + */ + setMap: function(map) { + this.map = map; + this.cache = {}; + map.events.register("mousedown", this, this.start, {extension: true}); + map.events.register("mouseup", this, this.onClick, {extension: true}); + map.events.register("touchstart", this, this.start, {extension: true}); + map.events.register("touchmove", this, this.cancel, {extension: true}); + map.events.register("touchend", this, this.onClick, {extension: true}); + map.events.register("mousemove", this, this.onMousemove, {extension: true}); + }, + + /** + * Method: start + * Sets startEvt = evt. + * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + start: function(evt) { + this.startEvt = evt; + }, + + /** + * Method: cancel + * Deletes the start event. + * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + cancel: function(evt) { + delete this.startEvt; + }, + + /** + * Method: onClick + * Listener for the click event. + * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + onClick: function(evt) { + if (!this.startEvt || evt.type !== "touchend" && + !OpenLayers.Event.isLeftClick(evt)) { + return; + } + var features = this.getFeatures(this.startEvt); + delete this.startEvt; + // fire featureclick events + var feature, layer, more, clicked = {}; + for (var i=0, len=features.length; i<len; ++i) { + feature = features[i]; + layer = feature.layer; + clicked[layer.id] = true; + more = this.triggerEvent("featureclick", {feature: feature}); + if (more === false) { + break; + } + } + // fire nofeatureclick events on all vector layers with no targets + for (i=0, len=this.map.layers.length; i<len; ++i) { + layer = this.map.layers[i]; + if (layer instanceof OpenLayers.Layer.Vector && !clicked[layer.id]) { + this.triggerEvent("nofeatureclick", {layer: layer}); + } + } + }, + + /** + * Method: onMousemove + * Listener for the mousemove event. + * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + onMousemove: function(evt) { + delete this.startEvt; + var features = this.getFeatures(evt); + var over = {}, newly = [], feature; + for (var i=0, len=features.length; i<len; ++i) { + feature = features[i]; + over[feature.id] = feature; + if (!this.cache[feature.id]) { + newly.push(feature); + } + } + // check if already over features + var out = []; + for (var id in this.cache) { + feature = this.cache[id]; + if (feature.layer && feature.layer.map) { + if (!over[feature.id]) { + out.push(feature); + } + } else { + // removed + delete this.cache[id]; + } + } + // fire featureover events + var more; + for (i=0, len=newly.length; i<len; ++i) { + feature = newly[i]; + this.cache[feature.id] = feature; + more = this.triggerEvent("featureover", {feature: feature}); + if (more === false) { + break; + } + } + // fire featureout events + for (i=0, len=out.length; i<len; ++i) { + feature = out[i]; + delete this.cache[feature.id]; + more = this.triggerEvent("featureout", {feature: feature}); + if (more === false) { + break; + } + } + }, + + /** + * Method: triggerEvent + * Determines where to trigger the event and triggers it. + * + * Parameters: + * type - {String} The event type to trigger + * evt - {Object} The listener argument + * + * Returns: + * {Boolean} The last listener return. + */ + triggerEvent: function(type, evt) { + var layer = evt.feature ? evt.feature.layer : evt.layer, + object = this.target.object; + if (object instanceof OpenLayers.Map || object === layer) { + return this.target.triggerEvent(type, evt); + } + }, + + /** + * Method: getFeatures + * Get all features at the given screen location. + * + * Parameters: + * evt - {Object} Event object. + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} List of features at the given point. + */ + getFeatures: function(evt) { + var x = evt.clientX, y = evt.clientY, + features = [], targets = [], layers = [], + layer, target, feature, i, len; + // go through all layers looking for targets + for (i=this.map.layers.length-1; i>=0; --i) { + layer = this.map.layers[i]; + if (layer.div.style.display !== "none") { + if (layer.renderer instanceof OpenLayers.Renderer.Elements) { + if (layer instanceof OpenLayers.Layer.Vector) { + target = document.elementFromPoint(x, y); + while (target && target._featureId) { + feature = layer.getFeatureById(target._featureId); + if (feature) { + features.push(feature); + target.style.display = "none"; + targets.push(target); + target = document.elementFromPoint(x, y); + } else { + // sketch, all bets off + target = false; + } + } + } + layers.push(layer); + layer.div.style.display = "none"; + } else if (layer.renderer instanceof OpenLayers.Renderer.Canvas) { + feature = layer.renderer.getFeatureIdFromEvent(evt); + if (feature) { + features.push(feature); + layers.push(layer); + } + } + } + } + // restore feature visibility + for (i=0, len=targets.length; i<len; ++i) { + targets[i].style.display = ""; + } + // restore layer visibility + for (i=layers.length-1; i>=0; --i) { + layers[i].div.style.display = "block"; + } + return features; + }, + + /** + * APIMethod: destroy + * Clean up. + */ + destroy: function() { + for (var i=this.provides.length-1; i>=0; --i) { + delete this.target.extensions[this.provides[i]]; + } + this.map.events.un({ + mousemove: this.onMousemove, + mousedown: this.start, + mouseup: this.onClick, + touchstart: this.start, + touchmove: this.cancel, + touchend: this.onClick, + scope: this + }); + delete this.cache; + delete this.map; + delete this.target; + } + +}); + +/** + * Class: OpenLayers.Events.nofeatureclick + * + * Extension event type for handling click events that do not hit a feature. + * + * Event types provided by this extension: + * - nofeatureclick + */ +OpenLayers.Events.nofeatureclick = OpenLayers.Events.featureclick; + +/** + * Class: OpenLayers.Events.featureover + * + * Extension event type for handling hovering over a feature. + * + * Event types provided by this extension: + * - featureover + */ +OpenLayers.Events.featureover = OpenLayers.Events.featureclick; + +/** + * Class: OpenLayers.Events.featureout + * + * Extension event type for handling leaving a feature. + * + * Event types provided by this extension: + * - featureout + */ +OpenLayers.Events.featureout = OpenLayers.Events.featureclick; +/* ====================================================================== OpenLayers/Format/GPX.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -38373,15 +38954,15 @@ * Returns: * {DOMElement} */ buildMetadataNode: function(metadata) { var types = ['name', 'desc', 'author'], - node = this.createElementNSPlus('gpx:metadata'); + node = this.createElementNS(this.namespaces.gpx, 'metadata'); for (var i=0; i < types.length; i++) { var type = types[i]; if (metadata[type]) { - var n = this.createElementNSPlus("gpx:" + type); + var n = this.createElementNS(this.namespaces.gpx, type); n.appendChild(this.createTextNode(metadata[type])); node.appendChild(n); } } return node; @@ -38407,11 +38988,11 @@ if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { var wpt = this.buildWptNode(geometry); this.appendAttributesNode(wpt, feature); return wpt; } else { - var trkNode = this.createElementNSPlus("gpx:trk"); + var trkNode = this.createElementNS(this.namespaces.gpx, "trk"); this.appendAttributesNode(trkNode, feature); var trkSegNodes = this.buildTrkSegNode(geometry); trkSegNodes = OpenLayers.Util.isArray(trkSegNodes) ? trkSegNodes : [trkSegNodes]; for (var i = 0, len = trkSegNodes.length; i < len; i++) { @@ -38435,11 +39016,11 @@ len, point, nodes; if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" || geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { - node = this.createElementNSPlus("gpx:trkseg"); + node = this.createElementNS(this.namespaces.gpx, "trkseg"); for (i = 0, len=geometry.components.length; i < len; i++) { point = geometry.components[i]; node.appendChild(this.buildTrkPtNode(point)); } return node; @@ -38461,11 +39042,11 @@ * * Returns: * {DOMElement} A trkpt node */ buildTrkPtNode: function(point) { - var node = this.createElementNSPlus("gpx:trkpt"); + var node = this.createElementNS(this.namespaces.gpx, "trkpt"); node.setAttribute("lon", point.x); node.setAttribute("lat", point.y); return node; }, @@ -38478,11 +39059,11 @@ * * Returns: * {DOMElement} A wpt node */ buildWptNode: function(geometry) { - var node = this.createElementNSPlus("gpx:wpt"); + var node = this.createElementNS(this.namespaces.gpx, "wpt"); node.setAttribute("lon", geometry.x); node.setAttribute("lat", geometry.y); return node; }, @@ -38493,15 +39074,15 @@ * Parameters: * node - {DOMElement} the node to append the attribute nodes to. * feature - {<OpenLayers.Feature.Vector>} */ appendAttributesNode: function(node, feature) { - var name = this.createElementNSPlus('gpx:name'); + var name = this.createElementNS(this.namespaces.gpx, 'name'); name.appendChild(this.createTextNode( feature.attributes.name || feature.id)); node.appendChild(name); - var desc = this.createElementNSPlus('gpx:desc'); + var desc = this.createElementNS(this.namespaces.gpx, 'desc'); desc.appendChild(this.createTextNode( feature.attributes.description || this.defaultDesc)); node.appendChild(desc); // TBD - deal with remaining (non name/description) attributes. }, @@ -38510,11 +39091,11 @@ }); /* ====================================================================== OpenLayers/Format/WFSDescribeFeatureType.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -38748,11 +39329,11 @@ }); /* ====================================================================== OpenLayers/Renderer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -39184,11 +39765,11 @@ }; /* ====================================================================== OpenLayers/Renderer/Canvas.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -39255,10 +39836,11 @@ initialize: function(containerID, options) { OpenLayers.Renderer.prototype.initialize.apply(this, arguments); this.root = document.createElement("canvas"); this.container.appendChild(this.root); this.canvas = this.root.getContext("2d"); + this._clearRectId = OpenLayers.Util.createUniqueID(); this.features = {}; if (this.hitDetection) { this.hitCanvas = document.createElement("canvas"); this.hitContext = this.hitCanvas.getContext("2d"); } @@ -39440,15 +40022,17 @@ 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 _clearRectId = this._clearRectId; var opacity = style.graphicOpacity || style.fillOpacity; var onLoad = function() { - if(!this.features[featureId]) { + if(!this.features[featureId] || + _clearRectId !== this._clearRectId) { return; } var pt = this.getLocalXY(geometry); var p0 = pt[0]; var p1 = pt[1]; @@ -39471,13 +40055,16 @@ this.setHitContextStyle("fill", featureId); this.hitContext.fillRect(x, y, width, height); } } }; - img.onload = OpenLayers.Function.bind(onLoad, this); img.src = style.externalGraphic; + if (img.complete) { + img.onload(); + img.onload = null; + } }, /** * Method: drawNamedSymbol * Called to draw Well Known Graphic Symbol Name. @@ -39898,10 +40485,11 @@ this.canvas.measureText('xx').width; pt[1] += lineHeight*vfactor*(numRows-1); for (var i = 0; i < numRows; i++) { if (style.labelOutlineWidth) { this.canvas.save(); + this.canvas.globalAlpha = style.labelOutlineOpacity || style.fontOpacity || 1.0; this.canvas.strokeStyle = style.labelOutlineColor; this.canvas.lineWidth = style.labelOutlineWidth; this.canvas.strokeText(labelRows[i], pt[0], pt[1] + (lineHeight*i) + 1); this.canvas.restore(); } @@ -39952,14 +40540,23 @@ /** * Method: clear * Clear all vectors from the renderer. */ clear: function() { + this.clearCanvas(); + this.features = {}; + }, + + /** + * Method: clearCanvas + * Clear the canvas element of the renderer. + */ + clearCanvas: function() { var height = this.root.height; var width = this.root.width; this.canvas.clearRect(0, 0, width, height); - this.features = {}; + this._clearRectId = OpenLayers.Util.createUniqueID(); if (this.hitDetection) { this.hitContext.clearRect(0, 0, width, height); } }, @@ -40029,16 +40626,11 @@ * with things once they're drawn, to remove them, for example, so * instead we have to just clear everything and draw from scratch. */ redraw: function() { if (!this.locked) { - var height = this.root.height; - var width = this.root.width; - this.canvas.clearRect(0, 0, width, height); - if (this.hitDetection) { - this.hitContext.clearRect(0, 0, width, height); - } + this.clearCanvas(); var labelMap = []; var feature, geometry, style; var worldBounds = (this.map.baseLayer && this.map.baseLayer.wrapDateLine) && this.map.getMaxExtent(); for (var id in this.features) { if (!this.features.hasOwnProperty(id)) { continue; } @@ -40090,250 +40682,991 @@ * is always 1 except for Android 2.1 devices, to work around * http://code.google.com/p/android/issues/detail?id=5141. */ OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; /* ====================================================================== - OpenLayers/Format/OSM.js + OpenLayers/Format/WCSDescribeCoverage.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WCSDescribeCoverage + * Parse results from WCS DescribeCoverage request. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WCSDescribeCoverage = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WCSDescribeCoverage + * Create a new parser for WCS DescribeCoverage response. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read response data from a string, and return a list of coverage descriptions. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of coverage descriptions. + */ + + CLASS_NAME: "OpenLayers.Format.WCSDescribeCoverage" + +}); +/* ====================================================================== + OpenLayers/Format/WCSDescribeCoverage/v1.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSDescribeCoverage.js * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.WCSDescribeCoverage.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WCSDescribeCoverage.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + regExes: { + trimSpace: (/^\s*|\s*$/g), + splitSpace: (/\s+/) + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wcs", + + /** + * APIMethod: read + * + * Parameters: + * data - {DOMElement|String} A WCS DescribeCoverage document. + * + * Returns: + * {Object} An object representing the WCS DescribeCoverage response. + */ + 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 schema = {}; + if (data.nodeName.split(":").pop() === 'ExceptionReport') { + // an exception must have occurred, so parse it + var parser = new OpenLayers.Format.OGCExceptionReport(); + schema.error = parser.read(data); + } else { + this.readNode(data, schema); + } + return schema; + }, + + CLASS_NAME: "OpenLayers.Format.WCSDescribeCoverage.v1" + +}); +/* ====================================================================== + OpenLayers/Format/WCSCapabilities.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities + * Read WCS Capabilities. + * + * Inherits from: + * - <OpenLayers.Format.XML.VersionedOGC> + */ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WCSCapabilities + * Create a new parser for WCS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of coverages. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named coverages. + */ + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" + +}); +/* ====================================================================== + OpenLayers/Format/WCSCapabilities/v1.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + regExes: { + trimSpace: (/^\s*|\s*$/g), + splitSpace: (/\s+/) + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wcs", + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of coverages. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named coverages. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" + +}); +/* ====================================================================== + OpenLayers/Format/WCSCapabilities/v1_0_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities/v1.js + * @requires OpenLayers/Format/GML/v3.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 + * Read WCS Capabilities version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WCSCapabilities.v1> + * - <OpenLayers.Format.GML.v3> + */ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.GML.v3, OpenLayers.Format.WCSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 + * Create a new parser for WCS capabilities version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows" + }, + + /** + * Property: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "serviceIdentification", + + /** + * 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. Where possible, the 1.0.0 readers attempt to make + * their output compatible with 1.1.0 to reduce client complexity. + */ + readers: { + "wcs": { + "WCS_Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "Service": function(node, obj) { + var children = {}; + this.readChildNodes(node, children); + + // Rearrange things a little to get a tree that is + // compatible with 1.1.0 + var providerName = children.serviceContact.providerName; + delete children.serviceContact.providerName; + + obj.serviceProvider = { + providerName: providerName, + serviceContact: children.serviceContact }; + children.serviceContact = undefined; + obj.serviceIdentification = children; + }, + "keywords": function(node, serviceIdentification) { + serviceIdentification.keywords = []; + this.readChildNodes(node, serviceIdentification.keywords); + }, + "keyword": function(node, keywords) { + // Append the keyword to the keywords list + keywords.push(this.getChildValue(node)); + }, + "responsibleParty": function(node, serviceIdentification) { + serviceIdentification.serviceContact = {}; + this.readChildNodes(node, serviceIdentification.serviceContact); + }, + "individualName": function(node, serviceContact) { + serviceContact.individualName = this.getChildValue(node); + }, + "organisationName": function(node, serviceContact) { + serviceContact.providerName = this.getChildValue(node); + }, + "positionName": function(node, serviceContact) { + serviceContact.positionName = this.getChildValue(node); + }, + "contactInfo": function(node, serviceContact) { + serviceContact.contactInfo = {}; + this.readChildNodes(node, serviceContact.contactInfo); + }, + "phone": function(node, contactInfo) { + contactInfo.phone = {}; + this.readChildNodes(node, contactInfo.phone); + }, + "voice": function(node, phone) { + phone.voice = this.getChildValue(node); + }, + "facsimile": function(node, phone) { + phone.facsimile = this.getChildValue(node); + }, + "address": function(node, contactInfo) { + contactInfo.address = {}; + this.readChildNodes(node, contactInfo.address); + }, + "deliveryPoint": function(node, address) { + address.deliveryPoint = this.getChildValue(node); + }, + "city": function(node, address) { + address.city = this.getChildValue(node); + }, + "postalCode": function(node, address) { + address.postalCode = this.getChildValue(node); + }, + "country": function(node, address) { + address.country = this.getChildValue(node); + }, + "electronicMailAddress": function(node, address) { + address.electronicMailAddress = this.getChildValue(node); + }, + "fees": function(node, serviceIdentification) { + serviceIdentification.fees = this.getChildValue(node); + }, + "accessConstraints": function(node, serviceIdentification) { + serviceIdentification.accessConstraints = this.getChildValue(node); + }, + "ContentMetadata": function(node, obj) { + obj.contentMetadata = []; + this.readChildNodes(node, obj.contentMetadata); + }, + "CoverageOfferingBrief": function(node, contentMetadata) { + var coverageOfferingBrief = {}; + this.readChildNodes(node, coverageOfferingBrief); + contentMetadata.push(coverageOfferingBrief); + }, + "name": function(node, serviceOrCoverageOfferingBrief) { + // split/pop used to strip off any namespace prefixes + if(node.parentNode.nodeName.split(':').pop() === "Service") { + // We're parsing a service description + serviceOrCoverageOfferingBrief.title = this.getChildValue(node); + } + else { // node.parentNode.nodeName === "CoverageOfferingBrief" + // We're parsing a dataset + serviceOrCoverageOfferingBrief.identifier = this.getChildValue(node); + } + }, + "label": function(node, serviceOrCoverageOfferingBrief) { + // split/pop used to strip off any namespace prefixes + if(node.parentNode.nodeName.split(':').pop() === "Service") { + // We're parsing a service description + serviceOrCoverageOfferingBrief['abstract'] = this.getChildValue(node); + } + else { // node.parentNode.nodeName === "CoverageOfferingBrief" + // We"re parsing a dataset + serviceOrCoverageOfferingBrief.title = this.getChildValue(node); + } + }, + "lonLatEnvelope": function(node, coverageOfferingBrief) { + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); + + // We expect two nodes here, to create the corners of a bounding box + if(nodeList.length == 2) { + var min = {}; + var max = {}; + + this.xy = true; // Affirm we don't want our coordinates switched around + this.readers.gml.pos.apply(this, [nodeList[0], min]); + this.readers.gml.pos.apply(this, [nodeList[1], max]); + + coverageOfferingBrief.lonLatEnvelope = {}; + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; + coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; + } + } + }, + "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"] + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" + +}); +/* ====================================================================== + OpenLayers/Format/WCSDescribeCoverage/v1_0_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSDescribeCoverage/v1.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + * @requires OpenLayers/Format/GML/v3.js + * @requires OpenLayers/Format/WCSCapabilities/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.WCSDescribeCoverage/v1_0_0 + * Read WCS DescribeCoverage version 1.0.0. + * + * Inherits from: + * - <OpenLayers.Format.WCSDescribeCoverage.v1> + */ +OpenLayers.Format.WCSDescribeCoverage.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WCSDescribeCoverage.v1, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows", + gml: "http://www.opengis.net/gml" + }, + + /** + * Constructor: OpenLayers.Format.WCSDescribeCoverage.v1_0_0 + * Create a new parser for WCS DescribeCoverage version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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: { + "wcs": { + // Root object, contains one or more CoverageDecription entries + // In 1.0.0, this is CoverageDescription, in 1.1.0, + // it will be CoverageDescriptions (plural) + "CoverageDescription": function(node, obj) { + obj.coverageDescriptions = {}; + this.readChildNodes(node, obj.coverageDescriptions); + + // Make a list of keys for easy access + obj.coverageDescriptionKeys = []; + for(var key in obj.coverageDescriptions) { + obj.coverageDescriptionKeys.push(key); + } + }, + // In 1.1.0, this element is called CoverageDescription. We'll use + // that name because it's... better. + "CoverageOffering": function(node, descriptions) { + var description = {}; + this.readChildNodes(node, description); + descriptions[description.identifier] = description; + + // Provide a consistent handle on the native CRS + description.nativeCRS = description.supportedCRSs.nativeCRSs[0]; + }, + // As with GetCapabilities, we'll use the 1.1.0 element name + // (identifier) because it is less ambiguous + "name": function(node, description) { + description.identifier = this.getChildValue(node); + }, + // As with GetCapabilities, we'll use the 1.1.0 element name + // (title) because it is less ambiguous + "label": function(node, description) { + description.title = this.getChildValue(node); + }, + // This format is the same as that used by GetCapabilities 1.0.0, + // so we can reuse that reader + "lonLatEnvelope": function(node, description) { + OpenLayers.Format.WCSCapabilities.v1_0_0.prototype.readers.wcs.lonLatEnvelope.call(this, node, description); + }, + // Essentially the same as domain in 1.1.0 + "domainSet": function(node, description) { + description.domain = {}; + this.readChildNodes(node, description.domain); + }, + "spatialDomain": function(node, domain) { + domain.spatialDomain = { boundingBoxes: {} }; + this.readChildNodes(node, domain.spatialDomain); + }, + "nativeCRSs": function(node, description) { + if(!description.nativeCRSs) { + description.nativeCRSs = []; + } + var crs = this.getChildValue(node); + description.nativeCRSs.push(crs); + }, + "supportedCRSs": function(node, description) { + if(!description.supportedCRSs) { + description.supportedCRSs = []; + } + this.readChildNodes(node, description.supportedCRSs) + }, + // There will be several of these within the supportedCRSs tag + "requestResponseCRSs" : function(node, supportedCRSs) { + supportedCRSs.push(this.getChildValue(node)); + }, + "supportedFormats": function(node, description) { + if(!description.supportedFormats) { + description.supportedFormats = []; + } + this.readChildNodes(node, description.supportedFormats) + }, + // There will be several of these within the supportedFormats tag + "formats" : function(node, supportedFormats) { + supportedFormats.push(this.getChildValue(node)); + } + }, + + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"], + "gml": OpenLayers.Util.applyDefaults({ + // Use custom Envelope reader that understands the srsName attribute + "Envelope": function(node, spatialDomain) { + var srsName = node.getAttribute("srsName"); + if(!srsName) { // No SRS? What does this envelope mean?!? + return; + } + + var obj = {points: []}; + this.readChildNodes(node, obj); + + var min = obj.points[0]; + var max = obj.points[1]; + var bounds = new OpenLayers.Bounds(min.x, min.y, max.x, max.y); + spatialDomain.boundingBoxes[srsName] = bounds; + } + }, OpenLayers.Format.GML.v3.prototype.readers["gml"]) + }, + + CLASS_NAME: "OpenLayers.Format.WCSDescribeCoverage.v1_0_0" + +}); +/* ====================================================================== + OpenLayers/Format/OSM.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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/Projection.js */ -/** +/** * Class: OpenLayers.Format.OSM - * OSM parser. Create a new instance with the + * 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, /** + * APIProperty: shareNode + * {Boolean} Should nodes be shared between geometries. + */ + shareNode: 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, - + 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 + * {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, - + areaTags: null, + /** + * APIProperty: relationsParsers + * {Map({String, Function})} Map relation type to a functions that parce the relation. + * This can be set for example to: + * { + * multipolygon: OpenLayers.Format.OSM.multipolygonParser, + * boundary: OpenLayers.Format.OSM.multipolygonParser, + * route: OpenLayers.Format.OSM.routeParser + * } + */ + relationsParsers: {}, + + /** * 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', + 'interestingTagsExclude': ['source', 'source_ref', 'source:ref', 'history', 'attribution', 'created_by'], 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', - 'historic', 'landuse', 'military', 'natural', 'sport'] + 'historic', 'landuse', 'military', 'natural', 'sport'] }; - + options = options ? options : {}; + 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; // OSM coordinates are always in longlat WGS84 this.externalProjection = new OpenLayers.Projection("EPSG:4326"); - + OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); }, - + /** * APIMethod: read * Return a list of features from a OSM doc - + * Parameters: * doc - {Element} * * Returns: * Array({<OpenLayers.Feature.Vector>}) */ read: function(doc) { - if (typeof doc == "string") { + if (typeof doc == "string") { doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); } var nodes = this.getNodes(doc); var ways = this.getWays(doc); - + var relations = this.getRelations(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 feat_list = []; + + for (var relation_id in relations) { + var relation = relations[relation_id]; + if (this.relationsParsers[relation.tags.type]) { + var features = this.relationsParsers[relation.tags.type](relation, this, nodes, ways, relations); + for (var i = 0, len = features.length ; i < len ; i++) { + feat_list.push(features[i]); + } } - var geometry = null; - if (poly) { - geometry = new OpenLayers.Geometry.Polygon( - new OpenLayers.Geometry.LinearRing(point_list)); - } else { - geometry = new OpenLayers.Geometry.LineString(point_list); + } + + for (var way_id in ways) { + var way = ways[way_id]; + + if (way.interesting) { + var poly = this.isWayArea(way) ? 1 : 0; + var point_list = this.getPointList(way, nodes); + var geometry = null; + if (poly) { + geometry = new OpenLayers.Geometry.Polygon( + new OpenLayers.Geometry.LinearRing(point_list)); + } + else { + geometry = new OpenLayers.Geometry.LineString(point_list); + } + var feat = new OpenLayers.Feature.Vector(geometry, + way.tags); + feat.osm_id = parseInt(way.id); + feat.osm_version = parseInt(way.version); + // Since OSM is topological, we stash the node ID internally. + feat.geometry.osm_id = feat.osm_id; + feat.type = "way"; + feat.fid = "way." + feat.osm_id; + feat_list.push(feat); } - 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; - } + if (!node.used || !this.checkTags || Object.keys(node.attributes).length > 1) { + feat_list.push(node); + } + } return feat_list; }, /** - * Method: getNodes - * Return the node items from a doc. + * Method: getPointList + * Return a list of points corresponds with with the way. * * Parameters: + * way - way where we can find the nodes id. + * nodes - nodes the nodes map where we can find the nodes by id. + */ + getPointList: function(way, nodes) { + if (!way) { + // the way will not be on the bbox + return []; + } + // We know the minimal of this one ahead of time. (Could be -1 + // due to areas/polygons) + var point_list = new Array(way.nodes.length); + for (var j = 0; j < way.nodes.length; j++) { + var node = nodes[way.nodes[j]]; + node.used = true; + + var point = node.geometry; + if (!this.shareNode) { + point = new OpenLayers.Geometry.Point(node.geometry.x, node.geometry.y); + // Since OSM is topological, we stash the node ID internally. + point.osm_id = node.osm_id; + } + + point_list[j] = point; + } + return point_list; + }, + + /** + * Method: concatPathsIfLinear + * Return result.succed if pass are linear, result.lastPointList with the new way. + * + * Parameters: + * lastPointList - array of <OpenLayer.Geometry.Points>, the old concanated path + * pointList - array of <OpenLayer.Geometry.Points>, the new path + */ + concatPathsIfLinear: function(lastPointList, pointList) { + var result = {}; + if (lastPointList.length == 0) { + result.succed = true; + result.lastPointList = pointList; + return result; + } + if (pointList.length == 0) { + result.succed = true; + result.lastPointList = lastPointList; + return result; + } + if (lastPointList[lastPointList.length-1].x == pointList[0].x + && lastPointList[lastPointList.length-1].y == pointList[0].y) { + pointList = pointList.slice(1, pointList.length); + lastPointList = lastPointList.concat(pointList); + result.succed = true; + result.lastPointList = lastPointList; + return result; + } + else if (lastPointList[0].x == pointList[pointList.length-1].x + && lastPointList[0].y == pointList[pointList.length-1].y) { + lastPointList = lastPointList.slice(1, lastPointList.length); + lastPointList = pointList.concat(lastPointList); + result.succed = true; + result.lastPointList = lastPointList; + return result; + } + else if (lastPointList[0].x == pointList[0].x + && lastPointList[0].y == pointList[0].y) { + if (lastPointList.length > pointList.length) { + pointList = pointList.slice(1, pointList.length); + lastPointList = pointList.reverse().concat(lastPointList); + } + else { + lastPointList = lastPointList.slice(1, lastPointList.length); + lastPointList = lastPointList.reverse().concat(pointList); + } + result.succed = true; + result.lastPointList = lastPointList; + return result; + } + else if (lastPointList[lastPointList.length-1].x == pointList[pointList.length-1].x + && lastPointList[lastPointList.length-1].y == pointList[pointList.length-1].y) { + if (lastPointList.length > pointList.length) { + pointList = pointList.slice(0, pointList.length - 1); + lastPointList = lastPointList.concat(pointList.reverse()); + } + else { + lastPointList = lastPointList.slice(0, lastPointList.length - 1); + lastPointList = pointList.concat(lastPointList.reverse()); + } + result.succed = true; + result.lastPointList = lastPointList; + return result; + } + result.succed = false; + return result; + }, + + /** + * Method: gets + * Return the node items from a doc. + * + * Parameters: * doc - {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 - }; + var geom = new OpenLayers.Geometry.Point( + node.getAttribute("lon"), + node.getAttribute("lat")) + if (this.internalProjection && this.externalProjection) { + geom.transform(this.externalProjection, + this.internalProjection); + } + var feat = new OpenLayers.Feature.Vector(geom, this.getTags(node)); + feat.osm_id = parseInt(id); + feat.osm_version = parseInt(node.getAttribute("version")); + feat.type = "node"; + feat.fid = "node." + feat.osm_id; + + // Since OSM is topological, we stash the node ID internally. + feat.geometry.osm_id = feat.osm_id; + + nodes[id] = feat; } return nodes; }, /** + * Method: getRelations + * Return the relation items from a doc. + * + * Parameters: + * node - {DOMElement} node to parse tags from + */ + getRelations: function(doc) { + var relation_list = doc.getElementsByTagName("relation"); + var return_relations = {}; + for (var i = 0; i < relation_list.length; i++) { + var relation = relation_list[i]; + var id = relation.getAttribute("id"); + var relation_object = { + id: id, + version: relation.getAttribute("version") + }; + + relation_object.tags = this.getTags(relation); + relation_object.nodes = []; + relation_object.ways = []; + relation_object.relations = []; + + var member_list = relation.getElementsByTagName("member"); + + for (var j = 0; j < member_list.length; j++) { + var member = member_list[j]; + var type = member.getAttribute("type"); + if (type == 'node') { + relation_object.nodes[relation_object.nodes.length] = member; + } + else if (type == 'way') { + relation_object.ways[relation_object.ways.length] = member; + } + else if (type == 'relation') { + relation_object.relations[relation_object.relations.length] = member; + } + } + return_relations[id] = relation_object; + } + return return_relations; + + }, + + /** * Method: getWays - * Return the way items from a doc. + * Return the way items from a doc. * * Parameters: * doc - {DOMElement} node to parse tags from */ getWays: function(doc) { var way_list = doc.getElementsByTagName("way"); - var return_ways = []; + var return_ways = {}; for (var i = 0; i < way_list.length; i++) { var way = way_list[i]; + var id = way.getAttribute("id"); var way_object = { - id: way.getAttribute("id") + id: id, + version: way.getAttribute("version") }; - - way_object.tags = this.getTags(way); - + + if (this.checkTags) { + var result = this.getTags(way, true); + way_object.interesting = result[1]; + way_object.tags = result[0]; + } else { + way_object.interesting = true; + 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_ways[id] = way_object; } - return return_ways; - - }, - + return return_ways; + + }, + /** * Method: getTags * Return the tags list attached to a specific DOM element. * * Parameters: * dom_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' -- + * 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. */ @@ -40341,72 +41674,72 @@ 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; + if (!this.checkTags || !this.interestingTagsExclude[key]) { + tags[key] = tag_list[j].getAttribute("v"); + } + if (interesting_tags && !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) { + 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); - }, + } + return poly_shaped && (this.checkTags ? poly_tags : true); + }, /** - * APIMethod: write + * 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) { + write: function(features) { if (!(OpenLayers.Util.isArray(features))) { 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 + // 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]); }, /** @@ -40428,11 +41761,11 @@ 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. @@ -40442,52 +41775,52 @@ */ createXML: { 'point': function(point) { var id = null; var geometry = point.geometry ? point.geometry : point; - + if (this.internalProjection && this.externalProjection) { geometry = geometry.clone(); - geometry.transform(this.internalProjection, + geometry.transform(this.internalProjection, this.externalProjection); - } - + } + 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++; + this.osm_id++; } if (already_exists) { node = this.created_nodes[id]; - } else { + } else { var node = this.createElementNS(null, "node"); } this.created_nodes[id] = node; node.setAttribute("id", id); - node.setAttribute("lon", geometry.x); + 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 id; var nodes = []; var geometry = feature.geometry; if (feature.osm_id) { id = feature.osm_id; } else { id = -this.osm_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]]); @@ -40504,17 +41837,19 @@ 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); + var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); feat.osm_id = feature.osm_id; + // Since OSM is topological, we stash the node ID internally. + feat.geometry.osm_id = feat.osm_id; return this.createXML['linestring'].apply(this, [feat]); } }, /** @@ -40533,11 +41868,11 @@ node.appendChild(tag); } }, /** - * Method: setState + * 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>} @@ -40553,2822 +41888,258 @@ state = "delete"; } if (state) { node.setAttribute("action", state); } - } - }, - - CLASS_NAME: "OpenLayers.Format.OSM" -}); -/* ====================================================================== - OpenLayers/Handler/Feature.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository 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. - * - * Inherits from: - * - <OpenLayers.Handler> - */ -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}, - 'touchstart': {'in': 'click', 'out': 'clickout'} - }, - - /** - * 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: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, - - /** - * 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: touchstart - * Handle touchstart events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - touchstart: function(evt) { - if(!this.touch) { - this.touch = true; - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - dblclick: this.dblclick, - scope: this - }); } - return OpenLayers.Event.isMultiTouch(evt) ? - true : this.mousedown(evt); }, - /** - * Method: touchmove - * Handle touchmove events. We just prevent the browser default behavior, - * for Android Webkit not to select text when moving the finger after - * selecting a feature. - * - * Parameters: - * evt - {Event} - */ - touchmove: function(evt) { - OpenLayers.Event.stop(evt); - }, - - /** - * 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) { - // Feature selection is only done with a left click. Other handlers may stop the - // propagation of left-click mousedown events but not right-click mousedown events. - // This mismatch causes problems when comparing the location of the down and up - // events in the click function so it is important ignore right-clicks. - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(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" || type == "touchstart"); - 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) { - if(type === "touchstart") { - // stop the event to prevent Android Webkit from - // "flashing" the map div - OpenLayers.Event.stop(evt); - } - 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.touch = false; - 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.type == "removelayer" || 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" + CLASS_NAME: "OpenLayers.Format.OSM" }); -/* ====================================================================== - OpenLayers/Control/DragFeature.js - ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - /** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Handler/Drag.js - * @requires OpenLayers/Handler/Feature.js - */ - -/** - * Class: OpenLayers.Control.DragFeature - * The DragFeature control moves a feature with a drag of the mouse. Create a - * new control with the <OpenLayers.Control.DragFeature> constructor. + * Function that parse a multypolygone. Use the roles inner and enclave + * for inner border. all others will be considère as outer border. * - * Inherits From: - * - <OpenLayers.Control> - */ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: geometryTypes - * {Array(String)} To restrict dragging to a limited set of geometry types, - * send a list of strings corresponding to the geometry class names. - */ - geometryTypes: null, - - /** - * APIProperty: onStart - * {Function} Define this function if you want to know when a drag starts. - * The function should expect to receive two arguments: the feature - * that is about to be dragged and the pixel location of the mouse. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be - * dragged. - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. - */ - onStart: function(feature, pixel) {}, - - /** - * APIProperty: onDrag - * {Function} Define this function if you want to know about each move of a - * feature. The function should expect to receive two arguments: the - * feature that is being dragged and the pixel location of the mouse. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. - */ - onDrag: function(feature, pixel) {}, - - /** - * APIProperty: onComplete - * {Function} Define this function if you want to know when a feature is - * done dragging. The function should expect to receive two arguments: - * the feature that is being dragged and the pixel location of the - * mouse. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. - */ - onComplete: function(feature, pixel) {}, - - /** - * APIProperty: onEnter - * {Function} Define this function if you want to know when the mouse - * goes over a feature and thereby makes this feature a candidate - * for dragging. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that is ready - * to be dragged. - */ - onEnter: function(feature) {}, - - /** - * APIProperty: onLeave - * {Function} Define this function if you want to know when the mouse - * goes out of the feature that was dragged. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. - */ - onLeave: function(feature) {}, - - /** - * APIProperty: documentDrag - * {Boolean} If set to true, mouse dragging will continue even if the - * mouse cursor leaves the map viewport. Default is false. - */ - documentDrag: false, - - /** - * Property: layer - * {<OpenLayers.Layer.Vector>} - */ - layer: null, - - /** - * Property: feature - * {<OpenLayers.Feature.Vector>} - */ - feature: null, - - /** - * Property: dragCallbacks - * {Object} The functions that are sent to the drag handler for callback. - */ - dragCallbacks: {}, - - /** - * Property: featureCallbacks - * {Object} The functions that are sent to the feature handler for callback. - */ - featureCallbacks: {}, - - /** - * Property: lastPixel - * {<OpenLayers.Pixel>} - */ - lastPixel: null, - - /** - * Constructor: OpenLayers.Control.DragFeature - * Create a new control to drag features. - * - * Parameters: - * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be - * dragged. - * options - {Object} Optional object whose properties will be set on the - * control. - */ - initialize: function(layer, options) { - OpenLayers.Control.prototype.initialize.apply(this, [options]); - this.layer = layer; - this.handlers = { - drag: new OpenLayers.Handler.Drag( - this, OpenLayers.Util.extend({ - down: this.downFeature, - move: this.moveFeature, - up: this.upFeature, - out: this.cancel, - done: this.doneDragging - }, this.dragCallbacks), { - documentDrag: this.documentDrag - } - ), - feature: new OpenLayers.Handler.Feature( - this, this.layer, OpenLayers.Util.extend({ - // 'click' and 'clickout' callback are for the mobile - // support: no 'over' or 'out' in touch based browsers. - click: this.clickFeature, - clickout: this.clickoutFeature, - over: this.overFeature, - out: this.outFeature - }, this.featureCallbacks), - {geometryTypes: this.geometryTypes} - ) - }; - }, - - /** - * Method: clickFeature - * Called when the feature handler detects a click-in on a feature. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - clickFeature: function(feature) { - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { - this.handlers.drag.dragstart(this.handlers.feature.evt); - // to let the events propagate to the feature handler (click callback) - this.handlers.drag.stopDown = false; - } - }, - - /** - * Method: clickoutFeature - * Called when the feature handler detects a click-out on a feature. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - clickoutFeature: function(feature) { - if (this.handlers.feature.touch && this.over) { - this.outFeature(feature); - this.handlers.drag.stopDown = true; - } - }, - - /** - * APIMethod: destroy - * Take care of things that are not handled in superclass - */ - destroy: function() { - this.layer = null; - OpenLayers.Control.prototype.destroy.apply(this, []); - }, - - /** - * APIMethod: activate - * Activate the control and the feature handler. - * - * Returns: - * {Boolean} Successfully activated the control and feature handler. - */ - activate: function() { - return (this.handlers.feature.activate() && - OpenLayers.Control.prototype.activate.apply(this, arguments)); - }, - - /** - * APIMethod: deactivate - * Deactivate the control and all handlers. - * - * Returns: - * {Boolean} Successfully deactivated the control. - */ - deactivate: function() { - // the return from the handlers is unimportant in this case - this.handlers.drag.deactivate(); - this.handlers.feature.deactivate(); - this.feature = null; - this.dragging = false; - this.lastPixel = null; - OpenLayers.Element.removeClass( - this.map.viewPortDiv, this.displayClass + "Over" - ); - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); - }, - - /** - * Method: overFeature - * Called when the feature handler detects a mouse-over on a feature. - * This activates the drag handler. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The selected feature. - * - * Returns: - * {Boolean} Successfully activated the drag handler. - */ - overFeature: function(feature) { - var activated = false; - if(!this.handlers.drag.dragging) { - this.feature = feature; - this.handlers.drag.activate(); - activated = true; - this.over = true; - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); - this.onEnter(feature); - } else { - if(this.feature.id == feature.id) { - this.over = true; - } else { - this.over = false; - } - } - return activated; - }, - - /** - * Method: downFeature - * Called when the drag handler detects a mouse-down. - * - * Parameters: - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. - */ - downFeature: function(pixel) { - this.lastPixel = pixel; - this.onStart(this.feature, pixel); - }, - - /** - * Method: moveFeature - * Called when the drag handler detects a mouse-move. Also calls the - * optional onDrag method. - * - * Parameters: - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. - */ - moveFeature: function(pixel) { - var res = this.map.getResolution(); - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), - res * (this.lastPixel.y - pixel.y)); - this.layer.drawFeature(this.feature); - this.lastPixel = pixel; - this.onDrag(this.feature, pixel); - }, - - /** - * Method: upFeature - * Called when the drag handler detects a mouse-up. - * - * Parameters: - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. - */ - upFeature: function(pixel) { - if(!this.over) { - this.handlers.drag.deactivate(); - } - }, - - /** - * Method: doneDragging - * Called when the drag handler is done dragging. - * - * Parameters: - * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event - * came from a mouseout, this may not be in the map viewport. - */ - doneDragging: function(pixel) { - this.onComplete(this.feature, pixel); - }, - - /** - * Method: outFeature - * Called when the feature handler detects a mouse-out on a feature. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. - */ - outFeature: function(feature) { - if(!this.handlers.drag.dragging) { - this.over = false; - this.handlers.drag.deactivate(); - OpenLayers.Element.removeClass( - this.map.viewPortDiv, this.displayClass + "Over" - ); - this.onLeave(feature); - this.feature = null; - } else { - if(this.feature.id == feature.id) { - this.over = false; - } - } - }, - - /** - * Method: cancel - * Called when the drag handler detects a mouse-out (from the map viewport). - */ - cancel: function() { - this.handlers.drag.deactivate(); - this.over = false; - }, - - /** - * Method: setMap - * Set the map property for the control and all handlers. - * - * Parameters: - * map - {<OpenLayers.Map>} The control's map. - */ - setMap: function(map) { - this.handlers.drag.setMap(map); - this.handlers.feature.setMap(map); - OpenLayers.Control.prototype.setMap.apply(this, arguments); - }, - - CLASS_NAME: "OpenLayers.Control.DragFeature" -}); -/* ====================================================================== - OpenLayers/StyleMap.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Style.js - * @requires OpenLayers/Feature/Vector.js - */ - -/** - * Class: OpenLayers.StyleMap - */ -OpenLayers.StyleMap = OpenLayers.Class({ - - /** - * Property: styles - * {Object} 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" -}); -/* ====================================================================== - OpenLayers/Layer/Vector.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository 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 - * @requires OpenLayers/Lang.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. + * Parameters: + * relation - {DOMElement} the relation to parse + * parser - <OpenLayers.parser.OSM> the parser + * nodes - {Array({DOMElement})} all the available nodes + * ways - {Array({DOMElement})} all the available ways + * relations - {Array({DOMElement})} all the available relations * - * Inherits from: - * - <OpenLayers.Layer> + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} a list of one element that represent the multypolygone */ -OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { +OpenLayers.Format.OSM.multipolygonParser = function(relation, parser, nodes, ways, relations) { + var lastRole = ''; + var lastPointList = []; + var innerLignes = []; + var outerLignes = []; - /** - * APIProperty: events - * {<OpenLayers.Events>} - * - * 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.events>): - * 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. - * beforefeaturesremoved - Triggered before multiple features are removed. - * Listeners will receive an object with a *features* property - * referencing the features 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. - * beforefeatureselected - Triggered before a feature is selected. Listeners - * will receive an object with a *feature* property referencing the - * feature to be selected. To stop the feature from being selectd, a - * listener should return false. - * 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. - * vertexremoved - Triggered when a vertex within any feature geometry - * has been deleted. 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 - * removal. - * 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. - */ + for (var j = 0; j < relation.ways.length; j++) { + var way = relation.ways[j] + var ref = way.getAttribute("ref"); + var role = way.getAttribute("role"); - /** - * APIProperty: isBaseLayer - * {Boolean} The layer is a base layer. Default is false. Set this property - * in the layer options. - */ - isBaseLayer: false, - - /** - * APIProperty: isFixed - * {Boolean} Whether the layer remains in one place while dragging the - * map. Note that setting this to true will move the layer to the bottom - * of the layer stack. - */ - isFixed: false, - - /** - * APIProperty: features - * {Array(<OpenLayers.Feature.Vector>)} - */ - features: null, - - /** - * Property: filter - * {<OpenLayers.Filter>} The filter set in this layer, - * a strategy launching read requests can combined - * this filter with its own filter. - */ - filter: 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, - - /** - * APIProperty: ratio - * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map. - */ - ratio: 1, - - /** - * 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) { - OpenLayers.Layer.prototype.initialize.apply(this, arguments); - - // allow user-set renderer, otherwise assign one - if (!this.renderer || !this.renderer.supported()) { - this.assignRenderer(); + var pointList = parser.getPointList(ways[ref], nodes); + if (pointList.length == 0) { + continue; } - - // 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(); + var newPath = true; + if (lastRole == '') { + lastRole = role; } - - 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); + if (lastRole == role) { + var result = parser.concatPathsIfLinear(lastPointList, pointList); + if (result.succed) { + newPath = false; + lastPointList = result.lastPointList; } } - }, - - /** - * 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(); + if (newPath) { + if (lastPointList.length > 0) { + if (lastRole == 'inner' || lastRole == 'enclave') { + var geometry = new OpenLayers.Geometry.LinearRing(lastPointList) + innerLignes.push(geometry); } - } - 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: clone - * Create a clone of this layer. - * - * Note: Features of the layer are also cloned. - * - * Returns: - * {<OpenLayers.Layer.Vector>} An exact clone of this layer - */ - clone: function (obj) { - - if (obj == null) { - obj = new OpenLayers.Layer.Vector(this.name, this.getOptions()); - } - - //get all additions from superclasses - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); - - // copy/set any non-init, non-simple values here - var features = this.features; - var len = features.length; - var clonedFeatures = new Array(len); - for(var i=0; i<len; ++i) { - clonedFeatures[i] = features[i].clone(); - } - obj.features = clonedFeatures; - - return obj; - }, - - /** - * 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 = this.renderers[i]; - var renderer = (typeof rendererClass == "function") ? - rendererClass : - OpenLayers.Renderer[rendererClass]; - if (renderer && renderer.prototype.supported()) { - this.renderer = new renderer(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; - - var newSize = this.map.getSize(); - newSize.w = newSize.w * this.ratio; - newSize.h = newSize.h * this.ratio; - this.renderer.setSize(newSize); - } - }, - - /** - * 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(); + else { // if (lastRole == 'outer') { + var geometry = new OpenLayers.Geometry.LinearRing(lastPointList) + outerLignes.push(geometry); } } + lastPointList = pointList; + lastRole = role; } - }, - - /** - * Method: removeMap - * The layer has been removed from the map. - * - * Parameters: - * map - {<OpenLayers.Map>} - */ - removeMap: function(map) { - this.drawn = false; - 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(); - } - } + } + if (lastPointList.length > 0) { + if (lastRole == 'inner' || lastRole == 'enclave') { + var geometry = new OpenLayers.Geometry.LinearRing(lastPointList) + innerLignes.push(geometry); } - }, - - /** - * Method: onMapResize - * Notify the renderer of the change in size. - * - */ - onMapResize: function() { - OpenLayers.Layer.prototype.onMapResize.apply(this, arguments); - - var newSize = this.map.getSize(); - newSize.w = newSize.w * this.ratio; - newSize.h = newSize.h * this.ratio; - this.renderer.setSize(newSize); - }, - - /** - * 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'; - - var viewSize = this.map.getSize(), - viewWidth = viewSize.w, - viewHeight = viewSize.h, - offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2, - offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2; - offsetLeft += this.map.layerContainerOriginPx.x; - offsetLeft = -Math.round(offsetLeft); - offsetTop += this.map.layerContainerOriginPx.y; - offsetTop = -Math.round(offsetTop); - - this.div.style.left = offsetLeft + 'px'; - this.div.style.top = offsetTop + 'px'; - - var extent = this.map.getExtent().scale(this.ratio); - 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 (OpenLayers.IS_GECKO === true) { - this.div.scrollLeft = this.div.scrollLeft; - } - - if (!zoomChanged && coordSysUnchanged) { - for (var i in this.unrenderedFeatures) { - var feature = this.unrenderedFeatures[i]; - this.drawFeature(feature); - } - } + else { // if (lastRole == 'outer') { + var geometry = new OpenLayers.Geometry.LinearRing(lastPointList) + outerLignes.push(geometry); } - 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 (!(OpenLayers.Util.isArray(features))) { - features = [features]; + var polygons = []; + for (var j = 0 ; j < outerLignes.length ; j++) { + if (innerLignes.length == 0) { + polygons.push(new OpenLayers.Geometry.Polygon([outerLignes[j]])); } - - 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; - } - - // Track successfully added features for featuresadded event, since - // beforefeatureadded can veto single features. - var featuresAdded = []; - 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)) { - throw new TypeError('addFeatures: component should be an ' + - this.geometryType.prototype.CLASS_NAME); - } - - //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; + else { + var currentInners = []; + for (var k = 0 ; k < innerLignes.length ; k++) { + var inner = innerLignes[k]; + if (outerLignes[j].containsPoint(inner.getCentroid())) { + currentInners.push(inner); } - this.preFeatureInsert(feature); } - - featuresAdded.push(feature); - this.features.push(feature); - this.drawFeature(feature); - - if (notify) { - this.events.triggerEvent("featureadded", { - feature: feature - }); - this.onFeatureInsert(feature); - } + polygons.push(new OpenLayers.Geometry.Polygon( + [outerLignes[j]].concat(currentInners))); } - - if(notify) { - this.events.triggerEvent("featuresadded", {features: featuresAdded}); - } - }, + } + var geometry = new OpenLayers.Geometry.MultiPolygon(polygons); + var feat = new OpenLayers.Feature.Vector(geometry, relation.tags); + feat.osm_id = parseInt(relation.id); + feat.type = "relation"; + feat.fid = "relation." + feat.osm_id; + return [feat]; +}, +/** + * Function that convert all the ways of a relation into a LineStrings. + * + * Parameters: + * relation - {DOMElement} the relation to parse + * parser - <OpenLayers.parser.OSM> the parser + * nodes - {Array({DOMElement})} all the available nodes + * ways - {Array({DOMElement})} all the available ways + * + * Returns: + * {Array(<OpenLayers.Geometry.LineString>)} + */ +OpenLayers.Format.OSM.getLineStrings = function(relation, parser, nodes, ways) { + var geometries = []; + for (var j = 0; j < relation.ways.length; j++) { + var way = relation.ways[j] + var ref = way.getAttribute("ref"); - /** - * 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; + // TODO considere to create some area + var pointList = parser.getPointList(ways[ref], nodes); + if (pointList.length == 0) { + continue; } - if (features === this.features) { - return this.removeAllFeatures(options); - } - if (!(OpenLayers.Util.isArray(features))) { - features = [features]; - } - if (features === this.selectedFeatures) { - features = features.slice(); - } - var notify = !options || !options.silent; - - if (notify) { - this.events.triggerEvent( - "beforefeaturesremoved", {features: features} - ); - } + geometries.push(new OpenLayers.Geometry.LineString(pointList)); + } + return geometries; +} - 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: removeAllFeatures - * Remove all features from the layer. - * - * Parameters: - * options - {Object} Optional properties for changing behavior of the - * removal. - * - * Valid options: - * silent - {Boolean} Supress event triggering. Default is false. - */ - removeAllFeatures: function(options) { - var notify = !options || !options.silent; - var features = this.features; - if (notify) { - this.events.triggerEvent( - "beforefeaturesremoved", {features: features} - ); - } - var feature; - for (var i = features.length-1; i >= 0; i--) { - feature = features[i]; - if (notify) { - this.events.triggerEvent("beforefeatureremoved", { - feature: feature - }); - } - feature.layer = null; - if (notify) { - this.events.triggerEvent("featureremoved", { - feature: feature - }); - } - } - this.renderer.clear(); - this.features = []; - this.unrenderedFeatures = {}; - this.selectedFeatures = []; - 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 - {String | Object} Named render intent or full symbolizer object. - */ - 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); - } - } - - var drawn = this.renderer.drawFeature(feature, style); - //TODO remove the check for null when we get rid of Renderer.SVG - if (drawn === false || drawn === null) { - 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) { - throw new Error('getFeatureFromEvent called on layer with no ' + - 'renderer. This usually means you destroyed a ' + - 'layer, but not some handler which is associated ' + - 'with it.'); - } - var feature = null; - var featureId = this.renderer.getFeatureIdFromEvent(evt); - if (featureId) { - if (typeof featureId === "string") { - feature = this.getFeatureById(featureId); - } else { - feature = featureId; - } - } - return feature; - }, - - /** - * APIMethod: getFeatureBy - * Given a property value, return the feature if it exists in the features array - * - * Parameters: - * property - {String} - * value - {String} - * - * Returns: - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given - * property value or null if there is no such feature. - */ - getFeatureBy: function(property, value) { - //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][property] == value) { - feature = this.features[i]; - break; - } - } - return feature; - }, - - /** - * 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 or null if there is no such feature. - */ - getFeatureById: function(featureId) { - return this.getFeatureBy('id', featureId); - }, - - /** - * APIMethod: getFeatureByFid - * Given a feature fid, return the feature if it exists in the features array - * - * Parameters: - * featureFid - {String} - * - * Returns: - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given - * featureFid or null if there is no such feature. - */ - getFeatureByFid: function(featureFid) { - return this.getFeatureBy('fid', featureFid); - }, - - /** - * APIMethod: getFeaturesByAttribute - * Returns an array of features that have the given attribute key set to the - * given value. Comparison of attribute values takes care of datatypes, e.g. - * the string '1234' is not equal to the number 1234. - * - * Parameters: - * attrName - {String} - * attrValue - {Mixed} - * - * Returns: - * Array({<OpenLayers.Feature.Vector>}) An array of features that have the - * passed named attribute set to the given value. - */ - getFeaturesByAttribute: function(attrName, attrValue) { - var i, - feature, - len = this.features.length, - foundFeatures = []; - for(i = 0; i < len; i++) { - feature = this.features[i]; - if(feature && feature.attributes) { - if (feature.attributes[attrName] === attrValue) { - foundFeatures.push(feature); - } - } - } - return foundFeatures; - }, - - /** - * 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. - * - * Parameters: - * 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>} or null if the layer has no features with - * geometries. - */ - getDataExtent: function () { - var maxExtent = null; - var features = this.features; - if(features && (features.length > 0)) { - var geometry = null; - for(var i=0, len=features.length; i<len; i++) { - geometry = features[i].geometry; - if (geometry) { - if (maxExtent === null) { - maxExtent = new OpenLayers.Bounds(); - } - maxExtent.extend(geometry.getBounds()); - } - } - } - return maxExtent; - }, - - CLASS_NAME: "OpenLayers.Layer.Vector" -}); -/* ====================================================================== - OpenLayers/Layer/Vector/RootContainer.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - /** - * @requires OpenLayers/Layer/Vector.js + * Function that parse a route. All the inner ways will be converted into a MultiLineString. + * + * Parameters: + * relation - {DOMElement} the relation to parse + * parser - <OpenLayers.parser.OSM> the parser + * nodes - {Array({DOMElement})} all the available nodes + * ways - {Array({DOMElement})} all the available ways + * relations - {Array({DOMElement})} all the available relations + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} a list of one element that represent the route. */ +OpenLayers.Format.OSM.routeParser = function(relation, parser, nodes, ways, relations) { + var geometries = OpenLayers.Format.OSM.getLineStrings(relation, parser, nodes, ways); + var geometry = new OpenLayers.Geometry.MultiLineString(geometries); + var feat = new OpenLayers.Feature.Vector(geometry, relation.tags); + feat.osm_id = parseInt(relation.id); + feat.type = "relation"; + feat.fid = "relation." + feat.osm_id; + return [feat]; +} /** - * Class: OpenLayers.Layer.Vector.RootContainer - * A special layer type to combine multiple vector layers inside a single - * renderer root container. This class is not supposed to be instantiated - * from user space, it is a helper class for controls that require event - * processing for multiple vector layers. + * Function that parse a relation. All inerr way will be converten into LineLtrings, + * and all inner nodes into Points. * - * Inherits from: - * - <OpenLayers.Layer.Vector> + * Parameters: + * relation - {DOMElement} the relation to parse + * parser - <OpenLayers.parser.OSM> the parser + * nodes - {Array({DOMElement})} all the available nodes + * ways - {Array({DOMElement})} all the available ways + * relations - {Array({DOMElement})} all the available relations + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} a lint of one element that represent the relation. */ -OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { - - /** - * Property: displayInLayerSwitcher - * Set to false for this layer type - */ - displayInLayerSwitcher: false, - - /** - * APIProperty: layers - * Layers that are attached to this container. Required config option. - */ - layers: null, - - /** - * Constructor: OpenLayers.Layer.Vector.RootContainer - * Create a new root container for multiple vector layer. This constructor - * is not supposed to be used from user space, it is only to be used by - * controls that need feature selection across multiple vector layers. - * - * Parameters: - * name - {String} A name for the layer - * options - {Object} Optional object with non-default properties to set on - * the layer. - * - * Required options properties: - * layers - {Array(<OpenLayers.Layer.Vector>)} The layers managed by this - * container - * - * Returns: - * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root - * container - */ - - /** - * Method: display - */ - display: function() {}, - - /** - * Method: getFeatureFromEvent - * walk through the layers to find the feature returned by the event - * - * Parameters: - * evt - {Object} event object with a feature property - * - * Returns: - * {<OpenLayers.Feature.Vector>} - */ - getFeatureFromEvent: function(evt) { - var layers = this.layers; - var feature; - for(var i=0; i<layers.length; i++) { - feature = layers[i].getFeatureFromEvent(evt); - if(feature) { - return feature; - } - } - }, - - /** - * Method: setMap - * - * Parameters: - * map - {<OpenLayers.Map>} - */ - setMap: function(map) { - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); - this.collectRoots(); - map.events.register("changelayer", this, this.handleChangeLayer); - }, - - /** - * Method: removeMap - * - * Parameters: - * map - {<OpenLayers.Map>} - */ - removeMap: function(map) { - map.events.unregister("changelayer", this, this.handleChangeLayer); - this.resetRoots(); - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); - }, - - /** - * Method: collectRoots - * Collects the root nodes of all layers this control is configured with - * and moveswien the nodes to this control's layer - */ - collectRoots: function() { - var layer; - // walk through all map layers, because we want to keep the order - for(var i=0; i<this.map.layers.length; ++i) { - layer = this.map.layers[i]; - if(OpenLayers.Util.indexOf(this.layers, layer) != -1) { - layer.renderer.moveRoot(this.renderer); - } - } - }, - - /** - * Method: resetRoots - * Resets the root nodes back into the layers they belong to. - */ - resetRoots: function() { - var layer; - for(var i=0; i<this.layers.length; ++i) { - layer = this.layers[i]; - if(this.renderer && layer.renderer.getRenderLayerId() == this.id) { - this.renderer.moveRoot(layer.renderer); - } - } - }, - - /** - * Method: handleChangeLayer - * Event handler for the map's changelayer event. We need to rebuild - * this container's layer dom if order of one of its layers changes. - * This handler is added with the setMap method, and removed with the - * removeMap method. - * - * Parameters: - * evt - {Object} - */ - handleChangeLayer: function(evt) { - var layer = evt.layer; - if(evt.property == "order" && - OpenLayers.Util.indexOf(this.layers, layer) != -1) { - this.resetRoots(); - this.collectRoots(); - } - }, +OpenLayers.Format.OSM.genericParser = function(relation, parser, nodes, ways, relations) { + var geometries = OpenLayers.Format.OSM.getLineStrings(relation, parser, nodes, ways); + for (var j = 0; j < relation.nodes.length; j++) { + var node = relation.nodes[j] + geometries.push(new OpenLayers.Geometry.Node(node)); + } + var geometry = new OpenLayers.Geometry.Collection(geometries); + var feat = new OpenLayers.Feature.Vector(geometry, relation.tags); + feat.osm_id = parseInt(relation.id); + feat.type = "relation"; + feat.fid = "relation." + feat.osm_id; + return [feat]; +} - CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" -}); -/* ====================================================================== - OpenLayers/Control/SelectFeature.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - /** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Feature/Vector.js - * @requires OpenLayers/Handler/Feature.js - * @requires OpenLayers/Layer/Vector/RootContainer.js - */ - -/** - * Class: OpenLayers.Control.SelectFeature - * The SelectFeature control selects vector features from a given layer on - * click or hover. + * Function that parse a route. All linear ways with the same role + * will be converted into one LineString. * - * Inherits from: - * - <OpenLayers.Control> + * Parameters: + * relation - {DOMElement} the relation to parse + * parser - <OpenLayers.parser.OSM> the parser + * nodes - {Array({DOMElement})} all the available nodes + * ways - {Array({DOMElement})} all the available ways + * relations - {Array({DOMElement})} all the available relations + * + * Returns: + * {Array(<OpenLayers.Feature.Vector>)} a list of linear LineString. */ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { +OpenLayers.Format.OSM.routeParserWithRoles = function(relation, parser, nodes, ways, relations) { + var geometries = []; + var lastRole = ''; + var lastPointList = []; + var features = []; - /** - * APIProperty: events - * {<OpenLayers.Events>} Events instance for listeners and triggering - * control specific events. - * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) - * - * Supported event types (in addition to those from <OpenLayers.Control.events>): - * beforefeaturehighlighted - Triggered before a feature is highlighted - * featurehighlighted - Triggered when a feature is highlighted - * featureunhighlighted - Triggered when a feature is unhighlighted - * boxselectionstart - Triggered before box selection starts - * boxselectionend - Triggered after box selection ends - */ - - /** - * Property: multipleKey - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets - * the <multiple> property to true. Default is null. - */ - multipleKey: null, - - /** - * Property: toggleKey - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets - * the <toggle> property to true. Default is null. - */ - toggleKey: null, - - /** - * APIProperty: multiple - * {Boolean} Allow selection of multiple geometries. Default is false. - */ - multiple: false, + for (var j = 0; j < relation.ways.length; j++) { + var way = relation.ways[j] + var ref = way.getAttribute("ref"); + var role = way.getAttribute("role"); - /** - * 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 false. Only - * has meaning if hover is false. - */ - toggle: false, - - /** - * APIProperty: hover - * {Boolean} Select on mouse over and deselect on mouse out. If true, this - * ignores clicks and only listens to mouse moves. - */ - hover: false, - - /** - * APIProperty: highlightOnly - * {Boolean} If true do not actually select features (that is place them in - * the layer's selected features array), just highlight them. This property - * has no effect if hover is false. Defaults to false. - */ - highlightOnly: false, - - /** - * APIProperty: box - * {Boolean} Allow feature selection by drawing a box. - */ - box: false, - - /** - * Property: onBeforeSelect - * {Function} Optional function to be called before a feature is selected. - * The function should expect to be called with a feature. - */ - onBeforeSelect: function() {}, - - /** - * APIProperty: onSelect - * {Function} Optional function to be called when a feature is selected. - * The function should expect to be called with a feature. - */ - onSelect: function() {}, - - /** - * APIProperty: onUnselect - * {Function} Optional function to be called when a feature is unselected. - * The function should expect to be called with a feature. - */ - onUnselect: function() {}, - - /** - * Property: scope - * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect - * callbacks. If null the scope will be this control. - */ - scope: null, - - /** - * APIProperty: geometryTypes - * {Array(String)} To restrict selecting to a limited set of geometry types, - * send a list of strings corresponding to the geometry class names. - */ - geometryTypes: null, - - /** - * Property: layer - * {<OpenLayers.Layer.Vector>} The vector layer with a common renderer - * root for all layers this control is configured with (if an array of - * layers was passed to the constructor), or the vector layer the control - * was configured with (if a single layer was passed to the constructor). - */ - layer: null, - - /** - * Property: layers - * {Array(<OpenLayers.Layer.Vector>)} The layers this control will work on, - * or null if the control was configured with a single layer - */ - layers: null, - - /** - * APIProperty: callbacks - * {Object} The functions that are sent to the handlers.feature for callback - */ - callbacks: null, - - /** - * APIProperty: selectStyle - * {Object} Hash of styles - */ - selectStyle: null, - - /** - * Property: renderIntent - * {String} key used to retrieve the select style from the layer's - * style map. - */ - renderIntent: "select", - - /** - * Property: handlers - * {Object} Object with references to multiple <OpenLayers.Handler> - * instances. - */ - handlers: null, - - /** - * Constructor: OpenLayers.Control.SelectFeature - * Create a new control for selecting features. - * - * Parameters: - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The - * layer(s) this control will select features from. - * options - {Object} - */ - initialize: function(layers, options) { - OpenLayers.Control.prototype.initialize.apply(this, [options]); - - if(this.scope === null) { - this.scope = this; + var pointList = parser.getPointList(ways[ref], nodes); + if (pointList.length == 0) { + continue; } - this.initLayer(layers); - var callbacks = { - click: this.clickFeature, - clickout: this.clickoutFeature - }; - if (this.hover) { - callbacks.over = this.overFeature; - callbacks.out = this.outFeature; + var newPath = true; + if (lastRole == '') { + lastRole = role; } - - this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); - this.handlers = { - feature: new OpenLayers.Handler.Feature( - this, this.layer, this.callbacks, - {geometryTypes: this.geometryTypes} - ) - }; - - if (this.box) { - this.handlers.box = new OpenLayers.Handler.Box( - this, {done: this.selectBox}, - {boxDivClassName: "olHandlerBoxSelectFeature"} - ); - } - }, - - /** - * Method: initLayer - * Assign the layer property. If layers is an array, we need to use - * a RootContainer. - * - * Parameters: - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. - */ - initLayer: function(layers) { - if(OpenLayers.Util.isArray(layers)) { - this.layers = layers; - this.layer = new OpenLayers.Layer.Vector.RootContainer( - this.id + "_container", { - layers: layers - } - ); - } else { - this.layer = layers; - } - }, - - /** - * Method: destroy - */ - destroy: function() { - if(this.active && this.layers) { - this.map.removeLayer(this.layer); - } - OpenLayers.Control.prototype.destroy.apply(this, arguments); - if(this.layers) { - this.layer.destroy(); - } - }, - - /** - * Method: activate - * Activates the control. - * - * Returns: - * {Boolean} The control was effectively activated. - */ - activate: function () { - if (!this.active) { - if(this.layers) { - this.map.addLayer(this.layer); + if (lastRole == role) { + var result = parser.concatPathsIfLinear(lastPointList, pointList); + if (result.succed) { + newPath = false; + lastPointList = result.lastPointList; } - this.handlers.feature.activate(); - if(this.box && this.handlers.box) { - this.handlers.box.activate(); - } } - return OpenLayers.Control.prototype.activate.apply( - this, arguments - ); - }, - - /** - * Method: deactivate - * Deactivates the control. - * - * Returns: - * {Boolean} The control was effectively deactivated. - */ - deactivate: function () { - if (this.active) { - this.handlers.feature.deactivate(); - if(this.handlers.box) { - this.handlers.box.deactivate(); + if (newPath) { + var geometry = new OpenLayers.Geometry.LineString(lastPointList) + var feat = new OpenLayers.Feature.Vector(geometry, relation.tags); + if (role) { + feat.attributes.role = role; } - if(this.layers) { - this.map.removeLayer(this.layer); - } + feat.osm_id = parseInt(relation.id); + feat.type = "relation"; + feat.fid = "relation." + feat.osm_id + "." + j; + features.push(feat); + lastPointList = pointList; + lastRole = role; } - return OpenLayers.Control.prototype.deactivate.apply( - this, arguments - ); - }, - - /** - * Method: unselectAll - * Unselect all selected features. To unselect all except for a single - * feature, set the options.except property to the feature. - * - * Parameters: - * options - {Object} Optional configuration object. - */ - unselectAll: function(options) { - // we'll want an option to supress notification here - var layers = this.layers || [this.layer], - layer, feature, l, numExcept; - for(l=0; l<layers.length; ++l) { - layer = layers[l]; - numExcept = 0; - //layer.selectedFeatures is null when layer is destroyed and - //one of it's preremovelayer listener calls setLayer - //with another layer on this control - if(layer.selectedFeatures != null) { - while(layer.selectedFeatures.length > numExcept) { - feature = layer.selectedFeatures[numExcept]; - if(!options || options.except != feature) { - this.unselect(feature); - } else { - ++numExcept; - } - } - } - } - }, - - /** - * Method: clickFeature - * Called on click in a feature - * Only responds if this.hover is false. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - clickFeature: function(feature) { - if(!this.hover) { - var selected = (OpenLayers.Util.indexOf( - feature.layer.selectedFeatures, feature) > -1); - if(selected) { - if(this.toggleSelect()) { - this.unselect(feature); - } else if(!this.multipleSelect()) { - this.unselectAll({except: feature}); - } - } else { - if(!this.multipleSelect()) { - this.unselectAll({except: feature}); - } - this.select(feature); - } - } - }, - - /** - * Method: multipleSelect - * Allow for multiple selected features based on <multiple> property and - * <multipleKey> event modifier. - * - * Returns: - * {Boolean} Allow for multiple selected features. - */ - multipleSelect: function() { - return this.multiple || (this.handlers.feature.evt && - this.handlers.feature.evt[this.multipleKey]); - }, - - /** - * Method: toggleSelect - * Event should toggle the selected state of a feature based on <toggle> - * property and <toggleKey> event modifier. - * - * Returns: - * {Boolean} Toggle the selected state of a feature. - */ - toggleSelect: function() { - return this.toggle || (this.handlers.feature.evt && - this.handlers.feature.evt[this.toggleKey]); - }, - - /** - * Method: clickoutFeature - * Called on click outside a previously clicked (selected) feature. - * Only responds if this.hover is false. - * - * Parameters: - * feature - {<OpenLayers.Vector.Feature>} - */ - clickoutFeature: function(feature) { - if(!this.hover && this.clickout) { - this.unselectAll(); - } - }, - - /** - * Method: overFeature - * Called on over a feature. - * Only responds if this.hover is true. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - overFeature: function(feature) { - var layer = feature.layer; - if(this.hover) { - if(this.highlightOnly) { - this.highlight(feature); - } else if(OpenLayers.Util.indexOf( - layer.selectedFeatures, feature) == -1) { - this.select(feature); - } - } - }, - - /** - * Method: outFeature - * Called on out of a selected feature. - * Only responds if this.hover is true. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - outFeature: function(feature) { - if(this.hover) { - if(this.highlightOnly) { - // we do nothing if we're not the last highlighter of the - // feature - if(feature._lastHighlighter == this.id) { - // if another select control had highlighted the feature before - // we did it ourself then we use that control to highlight the - // feature as it was before we highlighted it, else we just - // unhighlight it - if(feature._prevHighlighter && - feature._prevHighlighter != this.id) { - delete feature._lastHighlighter; - var control = this.map.getControl( - feature._prevHighlighter); - if(control) { - control.highlight(feature); - } - } else { - this.unhighlight(feature); - } - } - } else { - this.unselect(feature); - } - } - }, - - /** - * Method: highlight - * Redraw feature with the select style. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - highlight: function(feature) { - var layer = feature.layer; - var cont = this.events.triggerEvent("beforefeaturehighlighted", { - feature : feature - }); - if(cont !== false) { - feature._prevHighlighter = feature._lastHighlighter; - feature._lastHighlighter = this.id; - var style = this.selectStyle || this.renderIntent; - layer.drawFeature(feature, style); - this.events.triggerEvent("featurehighlighted", {feature : feature}); - } - }, - - /** - * Method: unhighlight - * Redraw feature with the "default" style - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - unhighlight: function(feature) { - var layer = feature.layer; - // three cases: - // 1. there's no other highlighter, in that case _prev is undefined, - // and we just need to undef _last - // 2. another control highlighted the feature after we did it, in - // that case _last references this other control, and we just - // need to undef _prev - // 3. another control highlighted the feature before we did it, in - // that case _prev references this other control, and we need to - // set _last to _prev and undef _prev - if(feature._prevHighlighter == undefined) { - delete feature._lastHighlighter; - } else if(feature._prevHighlighter == this.id) { - delete feature._prevHighlighter; - } else { - feature._lastHighlighter = feature._prevHighlighter; - delete feature._prevHighlighter; - } - layer.drawFeature(feature, feature.style || feature.layer.style || - "default"); - this.events.triggerEvent("featureunhighlighted", {feature : feature}); - }, - - /** - * Method: select - * Add feature to the layer's selectedFeature array, render the feature as - * selected, and call the onSelect function. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - select: function(feature) { - var cont = this.onBeforeSelect.call(this.scope, feature); - var layer = feature.layer; - if(cont !== false) { - cont = layer.events.triggerEvent("beforefeatureselected", { - feature: feature - }); - if(cont !== false) { - layer.selectedFeatures.push(feature); - this.highlight(feature); - // if the feature handler isn't involved in the feature - // selection (because the box handler is used or the - // feature is selected programatically) we fake the - // feature handler to allow unselecting on click - if(!this.handlers.feature.lastFeature) { - this.handlers.feature.lastFeature = layer.selectedFeatures[0]; - } - layer.events.triggerEvent("featureselected", {feature: feature}); - this.onSelect.call(this.scope, feature); - } - } - }, - - /** - * Method: unselect - * Remove feature from the layer's selectedFeature array, render the feature as - * normal, and call the onUnselect function. - * - * Parameters: - * feature - {<OpenLayers.Feature.Vector>} - */ - unselect: function(feature) { - var layer = feature.layer; - // Store feature style for restoration later - this.unhighlight(feature); - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); - layer.events.triggerEvent("featureunselected", {feature: feature}); - this.onUnselect.call(this.scope, feature); - }, - - /** - * Method: selectBox - * Callback from the handlers.box set up when <box> selection is true - * on. - * - * Parameters: - * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> } - */ - selectBox: function(position) { - if (position instanceof OpenLayers.Bounds) { - var minXY = this.map.getLonLatFromPixel({ - x: position.left, - y: position.bottom - }); - var maxXY = this.map.getLonLatFromPixel({ - x: position.right, - y: position.top - }); - var bounds = new OpenLayers.Bounds( - minXY.lon, minXY.lat, maxXY.lon, maxXY.lat - ); - - // if multiple is false, first deselect currently selected features - if (!this.multipleSelect()) { - this.unselectAll(); - } - - // because we're using a box, we consider we want multiple selection - var prevMultiple = this.multiple; - this.multiple = true; - var layers = this.layers || [this.layer]; - this.events.triggerEvent("boxselectionstart", {layers: layers}); - var layer; - for(var l=0; l<layers.length; ++l) { - layer = layers[l]; - for(var i=0, len = layer.features.length; i<len; ++i) { - var feature = layer.features[i]; - // check if the feature is displayed - if (!feature.getVisibility()) { - continue; - } - - if (this.geometryTypes == null || OpenLayers.Util.indexOf( - this.geometryTypes, feature.geometry.CLASS_NAME) > -1) { - if (bounds.toGeometry().intersects(feature.geometry)) { - if (OpenLayers.Util.indexOf(layer.selectedFeatures, feature) == -1) { - this.select(feature); - } - } - } - } - } - this.multiple = prevMultiple; - this.events.triggerEvent("boxselectionend", {layers: layers}); - } - }, - - /** - * Method: setMap - * Set the map property for the control. - * - * Parameters: - * map - {<OpenLayers.Map>} - */ - setMap: function(map) { - this.handlers.feature.setMap(map); - if (this.box) { - this.handlers.box.setMap(map); - } - OpenLayers.Control.prototype.setMap.apply(this, arguments); - }, - - /** - * APIMethod: setLayer - * Attach a new layer to the control, overriding any existing layers. - * - * Parameters: - * layers - Array of {<OpenLayers.Layer.Vector>} or a single - * {<OpenLayers.Layer.Vector>} - */ - setLayer: function(layers) { - var isActive = this.active; - this.unselectAll(); - this.deactivate(); - if(this.layers) { - this.layer.destroy(); - this.layers = null; - } - this.initLayer(layers); - this.handlers.feature.layer = this.layer; - if (isActive) { - this.activate(); - } - }, - - CLASS_NAME: "OpenLayers.Control.SelectFeature" -}); + } + var geometry = new OpenLayers.Geometry.LineString(lastPointList) + var feat = new OpenLayers.Feature.Vector(geometry, relation.tags); + if (role) { + feat.attributes.role = role; + } + feat.osm_id = parseInt(relation.id); + feat.type = "relation"; + feat.fid = "relation." + feat.osm_id; + features.push(feat); + return features; +} /* ====================================================================== OpenLayers/Handler/Keyboard.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -43485,18 +42256,18 @@ }); /* ====================================================================== OpenLayers/Control/ModifyFeature.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Control/DragFeature.js - * @requires OpenLayers/Control/SelectFeature.js + * @requires OpenLayers/Control.js + * @requires OpenLayers/Handler/Drag.js * @requires OpenLayers/Handler/Keyboard.js */ /** * Class: OpenLayers.Control.ModifyFeature @@ -43510,10 +42281,20 @@ * - <OpenLayers.Control> */ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { /** + * APIProperty: bySegment + * {Boolean} If set to true, one segment at a time will be editable (the + * one under the mouse cursor on hover). This supports editing much + * larger geometries. This requires the rbush library + * (https://github.com/mourner/rbush) for spatial indexing. Default is + * false. + */ + bySegment: false, + + /** * APIProperty: documentDrag * {Boolean} If set to true, dragging vertices will continue even if the * mouse cursor leaves the map viewport. Default is false. */ documentDrag: false, @@ -43537,11 +42318,11 @@ * APIProperty: toggle * {Boolean} Unselect a selected feature on click. * Default is true. */ toggle: true, - + /** * APIProperty: standalone * {Boolean} Set to true to create a control without SelectFeature * capabilities. Default is false. If standalone is true, to modify * a feature, call the <selectFeature> method with the target feature. @@ -43554,49 +42335,43 @@ /** * Property: layer * {<OpenLayers.Layer.Vector>} */ layer: null, - + /** * Property: feature * {<OpenLayers.Feature.Vector>} Feature currently available for modification. */ feature: null, - + /** + * Property: vertex + * {<OpenLayers.Feature.Vector>} Vertex currently being modified. + */ + vertex: 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 @@ -43607,11 +42382,11 @@ /** * APIProperty: virtualStyle * {Object} A symbolizer to be used for virtual vertices. */ virtualStyle: null, - + /** * APIProperty: vertexRenderIntent * {String} The renderIntent to use for vertices. If no <virtualStyle> is * provided, this renderIntent will also be used for virtual vertices, with * a fillOpacity and strokeOpacity of 0.3. Default is null, which means @@ -43719,79 +42494,111 @@ this.mode = OpenLayers.Control.ModifyFeature.RESHAPE; OpenLayers.Control.prototype.initialize.apply(this, [options]); if(!(OpenLayers.Util.isArray(this.deleteCodes))) { 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 - }; - if(this.standalone === false) { - this.selectControl = new OpenLayers.Control.SelectFeature( - layer, selectOptions - ); - } - - // configure the drag control - var dragOptions = { - documentDrag: this.documentDrag, - geometryTypes: ["OpenLayers.Geometry.Point"], - onStart: function(feature, pixel) { - control.dragStart.apply(control, [feature, pixel]); + + // configure the drag handler + var dragCallbacks = { + down: function(pixel) { + this.vertex = null; + var feature = this.layer.getFeatureFromEvent( + this.handlers.drag.evt); + if (feature) { + this.dragStart(feature); + } else if (this.clickout) { + this._unselect = this.feature; + } }, - onDrag: function(feature, pixel) { - control.dragVertex.apply(control, [feature, pixel]); + move: function(pixel) { + delete this._unselect; + if (this.vertex) { + this.dragVertex(this.vertex, pixel); + } }, - onComplete: function(feature) { - control.dragComplete.apply(control, [feature]); + up: function() { + this.handlers.drag.stopDown = false; + if (this._unselect) { + this.unselectFeature(this._unselect); + delete this._unselect; + } }, - featureCallbacks: { - over: function(feature) { - /** - * In normal mode, the feature handler is set up to allow - * dragging of all points. In standalone mode, we only - * want to allow dragging of sketch vertices and virtual - * vertices - or, in the case of a modifiable point, the - * point itself. - */ - if(control.standalone !== true || feature._sketch || - control.feature === feature) { - control.dragControl.overFeature.apply( - control.dragControl, [feature]); - } + done: function(pixel) { + if (this.vertex) { + this.dragComplete(this.vertex); } } }; - this.dragControl = new OpenLayers.Control.DragFeature( - layer, dragOptions - ); + var _self = this; + var dragOptions = { + documentDrag: this.documentDrag, + setEvent: function(evt) { + var feature = _self.feature; + _self._lastVertex = feature ? + feature.layer.getFeatureFromEvent(evt) : null; + OpenLayers.Handler.Drag.prototype.setEvent.apply( + this, arguments); + }, + stopDown: false + }; // configure the keyboard handler var keyboardOptions = { keydown: this.handleKeypress }; this.handlers = { - keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions) + keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions), + drag: new OpenLayers.Handler.Drag(this, dragCallbacks, dragOptions) }; + + if (this.bySegment) { + if (!window.rbush) { + throw new Error("The rbush library is required"); + } + if (!OpenLayers.Control.ModifyFeature.BySegment) { + throw new Error("OpenLayers.Control.ModifyFeature.BySegment is missing from the build"); + } else { + OpenLayers.Util.extend(this, OpenLayers.Control.ModifyFeature.BySegment); + } + } }, /** + * Method: createVirtualVertex + * Create a virtual vertex in the middle of the segment. + * + * Parameters: + * point1 - {<OpenLayers.Geometry.Point>} First point of the segment. + * point2 - {<OpenLayers.Geometry.Point>} Second point of the segment. + * + * Returns: + * {<OpenLayers.Feature.Vector>} The virtual vertex created. + */ + createVirtualVertex: function(point1, point2) { + var x = (point1.x + point2.x) / 2; + var y = (point1.y + point2.y) / 2; + var point = new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Point(x, y), + null, this.virtualStyle + ); + point._sketch = true; + return point; + }, + + /** * APIMethod: destroy * Take care of things that are not handled in superclass. */ destroy: function() { + if (this.map) { + this.map.events.un({ + "removelayer": this.handleMapEvents, + "changelayer": this.handleMapEvents, + scope: this + }); + } this.layer = null; - this.standalone || this.selectControl.destroy(); - this.dragControl.destroy(); OpenLayers.Control.prototype.destroy.apply(this, []); }, /** * APIMethod: activate @@ -43799,13 +42606,22 @@ * * Returns: * {Boolean} Successfully activated the control. */ activate: function() { - return ((this.standalone || this.selectControl.activate()) && - this.handlers.keyboard.activate() && - OpenLayers.Control.prototype.activate.apply(this, arguments)); + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { + this.moveLayerToTop(); + this.map.events.on({ + "removelayer": this.handleMapEvents, + "changelayer": this.handleMapEvents, + scope: this + }); + this._lastVertex = null; + return this.handlers.keyboard.activate() && + this.handlers.drag.activate(); + } + return false; }, /** * APIMethod: deactivate * Deactivate the control. @@ -43815,33 +42631,30 @@ */ deactivate: function() { var deactivated = false; // the return from the controls is unimportant in this case if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { + this.moveLayerBack(); + this.map.events.un({ + "removelayer": this.handleMapEvents, + "changelayer": this.handleMapEvents, + scope: this + }); this.layer.removeFeatures(this.vertices, {silent: true}); this.layer.removeFeatures(this.virtualVertices, {silent: true}); this.vertices = []; - this.dragControl.deactivate(); + this.handlers.drag.deactivate(); + this.handlers.keyboard.deactivate(); var feature = this.feature; - var valid = feature && feature.geometry && feature.layer; - if(this.standalone === false) { - if(valid) { - this.selectControl.unselect.apply(this.selectControl, - [feature]); - } - this.selectControl.deactivate(); - } else { - if(valid) { - this.unselectFeature(feature); - } + if (feature && feature.geometry && feature.layer) { + this.unselectFeature(feature); } - this.handlers.keyboard.deactivate(); deactivated = true; } return deactivated; }, - + /** * Method: beforeSelectFeature * Called before a feature is selected. * * Parameters: @@ -43854,23 +42667,32 @@ }, /** * APIMethod: selectFeature * Select a feature for modification in standalone mode. In non-standalone - * mode, this method is called when the select feature control selects a - * feature. Register a listener to the beforefeaturemodified event and - * return false to prevent feature modification. + * mode, this method is called when a feature is selected by clicking. + * Register a listener to the beforefeaturemodified event and return false + * to prevent feature modification. * * Parameters: * feature - {<OpenLayers.Feature.Vector>} the selected feature. */ selectFeature: function(feature) { - if (!this.standalone || this.beforeSelectFeature(feature) !== false) { + if (this.feature === feature || + (this.geometryTypes && OpenLayers.Util.indexOf(this.geometryTypes, + feature.geometry.CLASS_NAME) == -1)) { + return; + } + if (this.beforeSelectFeature(feature) !== false) { + if (this.feature) { + this.unselectFeature(this.feature); + } this.feature = feature; + this.layer.selectedFeatures.push(feature); + this.layer.drawFeature(feature, 'select'); this.modified = false; this.resetVertices(); - this.dragControl.activate(); this.onModificationStart(this.feature); } // keep track of geometry modifications var modified = feature.modified; if (feature.geometry && !(modified && modified.geometry)) { @@ -43896,77 +42718,63 @@ } if(this.radiusHandle) { this.layer.destroyFeatures([this.radiusHandle], {silent: true}); delete this.radiusHandle; } + this.layer.drawFeature(this.feature, 'default'); this.feature = null; - this.dragControl.deactivate(); + OpenLayers.Util.removeItem(this.layer.selectedFeatures, feature); 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). + * Called by the drag handler before a feature is dragged. This method is + * used to differentiate between points and vertices + * of higher order geometries. * * 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.standalone === false && this.feature) { - // unselect the currently selected feature - this.selectControl.clickFeature.apply(this.selectControl, - [this.feature]); + dragStart: function(feature) { + var isPoint = feature.geometry.CLASS_NAME == + 'OpenLayers.Geometry.Point'; + if (!this.standalone && + ((!feature._sketch && isPoint) || !feature._sketch)) { + if (this.toggle && this.feature === feature) { + // mark feature for unselection + this._unselect = feature; } - // check any constraints on the geometry type - if(this.geometryTypes == null || - OpenLayers.Util.indexOf(this.geometryTypes, - feature.geometry.CLASS_NAME) != -1) { - // select the point - this.standalone || this.selectControl.clickFeature.apply( - this.selectControl, [feature]); - /** - * TBD: These lines improve workflow by letting the user - * immediately start dragging after the mouse down. - * However, it is very ugly to be messing with controls - * and their handlers in this way. I'd like a better - * solution if the workflow change is necessary. - */ - // prepare the point for dragging - this.dragControl.overFeature.apply(this.dragControl, - [feature]); - this.dragControl.lastPixel = pixel; - this.dragControl.handlers.drag.started = true; - this.dragControl.handlers.drag.start = pixel; - this.dragControl.handlers.drag.last = pixel; - } + this.selectFeature(feature); } + if (this.feature && + (feature._sketch || isPoint && feature === this.feature)) { + // feature is a drag or virtual handle or point + this.vertex = feature; + this.handlers.drag.stopDown = true; + } }, - + /** * Method: dragVertex - * Called by the drag feature control with each drag move of a vertex. + * Called by the drag handler with each drag move of a vertex. * * Parameters: * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event. */ dragVertex: function(vertex, pixel) { + var pos = this.map.getLonLatFromViewPortPx(pixel); + var geom = vertex.geometry; + geom.move(pos.lon - geom.x, pos.lat - geom.y); this.modified = true; /** * Five cases: * 1) dragging a simple point * 2) dragging a virtual vertex @@ -43974,20 +42782,20 @@ * 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) { + if (vertex._index == -1) { + vertex._index = OpenLayers.Util.indexOf(vertex.geometry.parent.components, vertex._next); + } // dragging a virtual vertex vertex.geometry.parent.addComponent(vertex.geometry, vertex._index); // move from virtual to real vertex delete vertex._index; @@ -44013,21 +42821,21 @@ if(this.virtualVertices.length > 0) { this.layer.destroyFeatures(this.virtualVertices, {silent: true}); this.virtualVertices = []; } this.layer.drawFeature(this.feature, this.standalone ? undefined : - this.selectControl.renderIntent); + 'select'); } // 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. + * Called by the drag handler when the feature dragging is complete. * * Parameters: * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. */ dragComplete: function(vertex) { @@ -44059,20 +42867,10 @@ /** * 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) { @@ -44119,25 +42917,23 @@ 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) { + var vertex = this._lastVertex; + if (vertex && + OpenLayers.Util.indexOf(this.vertices, vertex) != -1 && + !this.handlers.drag.dragging && vertex.geometry.parent) { // remove the vertex vertex.geometry.parent.removeComponent(vertex.geometry); this.layer.events.triggerEvent("vertexremoved", { vertex: vertex.geometry, feature: this.feature, pixel: evt.xy }); this.layer.drawFeature(this.feature, this.standalone ? - undefined : - this.selectControl.renderIntent); + undefined : 'select'); this.modified = true; this.resetVertices(); this.setFeatureState(); this.onModification(this.feature); this.layer.events.triggerEvent("featuremodified", @@ -44184,20 +42980,14 @@ 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 - ); + var point = control.createVirtualVertex.call(control, prevVertex, nextVertex); // set the virtual parent and intended index point.geometry.parent = geometry; point._index = i + 1; - point._sketch = true; control.virtualVertices.push(point); } } } } @@ -44287,15 +43077,53 @@ * * Parameters: * map - {<OpenLayers.Map>} The control's map. */ setMap: function(map) { - this.standalone || this.selectControl.setMap(map); - this.dragControl.setMap(map); + this.handlers.drag.setMap(map); OpenLayers.Control.prototype.setMap.apply(this, arguments); }, + /** + * Method: handleMapEvents + * + * Parameters: + * evt - {Object} + */ + handleMapEvents: function(evt) { + if (evt.type == "removelayer" || 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.Control.ModifyFeature" }); /** * Constant: RESHAPE @@ -44319,11 +43147,11 @@ OpenLayers.Control.ModifyFeature.DRAG = 8; /* ====================================================================== OpenLayers/Layer/XYZ.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -44460,13 +43288,13 @@ * Returns: * {Object} - an object with x, y and z properties. */ getXYZ: function(bounds) { var res = this.getServerResolution(); - var x = Math.round((bounds.left - this.maxExtent.left) / + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); - var y = Math.round((this.maxExtent.top - bounds.top) / + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); var z = this.getServerZoom(); if (this.wrapDateLine) { var limit = Math.pow(2, z); @@ -44485,21 +43313,21 @@ */ setMap: function(map) { OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); if (!this.tileOrigin) { this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, - this.maxExtent.bottom); + this.maxExtent.top); } }, CLASS_NAME: "OpenLayers.Layer.XYZ" }); /* ====================================================================== OpenLayers/Layer/Bing.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -44745,11 +43573,11 @@ var res = metadata.resourceSets[0].resources[0]; var extent = this.map.getExtent().transform( this.map.getProjectionObject(), new OpenLayers.Projection("EPSG:4326") ); - var providers = res.imageryProviders, + var providers = res.imageryProviders || [], zoom = OpenLayers.Util.indexOf(this.serverResolutions, this.getServerResolution()), copyrights = "", provider, i, ii, j, jj, bbox, coverage; for (i=0,ii=providers.length; i<ii; ++i) { provider = providers[i]; @@ -44832,11 +43660,11 @@ }; /* ====================================================================== OpenLayers/Format/SOSGetFeatureOfInterest.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -45026,11 +43854,11 @@ }); /* ====================================================================== OpenLayers/Format/SOSGetObservation.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -45332,11 +44160,11 @@ }); /* ====================================================================== OpenLayers/Handler/MouseWheel.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -45366,10 +44194,18 @@ * Defaults to 0, meaning no interval. */ interval: 0, /** + * Property: maxDelta + * {Integer} Maximum delta to collect before breaking from the current + * interval. In cumulative mode, this also limits the maximum delta + * returned from the handler. Default is Number.POSITIVE_INFINITY. + */ + maxDelta: Number.POSITIVE_INFINITY, + + /** * Property: delta * {Integer} When interval is set, delta collects the mousewheel z-deltas * of the events that occur within the interval. * See also the cumulative option */ @@ -45510,14 +44346,14 @@ } else if (e.detail) { // detail in Firefox on OS X is 1/3 of Windows // so force delta 1 / -1 delta = - (e.detail / Math.abs(e.detail)); } - this.delta = this.delta + delta; + this.delta += delta; - if(this.interval) { - window.clearTimeout(this._timeoutId); + window.clearTimeout(this._timeoutId); + if(this.interval && Math.abs(this.delta) < this.maxDelta) { // store e because window.event might change during delay var evt = OpenLayers.Util.extend({}, e); this._timeoutId = window.setTimeout( OpenLayers.Function.bind(function(){ this.wheelZoom(evt); @@ -45545,13 +44381,15 @@ this.delta = 0; if (delta) { e.xy = this.map.events.getMousePosition(e); if (delta < 0) { - this.callback("down", [e, this.cumulative ? delta : -1]); + this.callback("down", + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); } else { - this.callback("up", [e, this.cumulative ? delta : 1]); + this.callback("up", + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); } } }, /** @@ -45590,11 +44428,11 @@ }); /* ====================================================================== OpenLayers/Format/WFST/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -45768,11 +44606,11 @@ }); /* ====================================================================== OpenLayers/Renderer/Elements.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -45980,20 +44818,17 @@ * 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; - } + for (var nextIndex = index + 1, nextElement = undefined; + (nextIndex < this.order.length) && (nextElement == undefined); + nextIndex++) { + nextElement = OpenLayers.Util.getElement(this.order[nextIndex]); + } + + return nextElement || null; }, CLASS_NAME: "OpenLayers.ElementsIndexer" }); @@ -46825,11 +45660,11 @@ /* ====================================================================== OpenLayers/Control/ArgParser.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -47011,11 +45846,11 @@ }); /* ====================================================================== OpenLayers/Control/Permalink.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -47272,11 +46107,11 @@ }); /* ====================================================================== OpenLayers/Layer/TMS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -47475,298 +46310,14 @@ }, CLASS_NAME: "OpenLayers.Layer.TMS" }); /* ====================================================================== - OpenLayers/Format/WCSCapabilities.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML/VersionedOGC.js - */ - -/** - * Class: OpenLayers.Format.WCSCapabilities - * Read WCS Capabilities. - * - * Inherits from: - * - <OpenLayers.Format.XML.VersionedOGC> - */ -OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { - - /** - * APIProperty: defaultVersion - * {String} Version number to assume if none found. Default is "1.1.0". - */ - defaultVersion: "1.1.0", - - /** - * Constructor: OpenLayers.Format.WCSCapabilities - * Create a new parser for WCS capabilities. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * APIMethod: read - * Read capabilities data from a string, and return a list of coverages. - * - * Parameters: - * data - {String} or {DOMElement} data to read/parse. - * - * Returns: - * {Array} List of named coverages. - */ - - CLASS_NAME: "OpenLayers.Format.WCSCapabilities" - -}); -/* ====================================================================== - OpenLayers/Format/WCSCapabilities/v1.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/WCSCapabilities.js - */ - -/** - * Class: OpenLayers.Format.WCSCapabilities.v1 - * Abstract class not to be instantiated directly. - * - * Inherits from: - * - <OpenLayers.Format.XML> - */ -OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( - OpenLayers.Format.XML, { - - regExes: { - trimSpace: (/^\s*|\s*$/g), - splitSpace: (/\s+/) - }, - - /** - * Property: defaultPrefix - */ - defaultPrefix: "wcs", - - /** - * APIMethod: read - * Read capabilities data from a string, and return a list of coverages. - * - * Parameters: - * data - {String} or {DOMElement} data to read/parse. - * - * Returns: - * {Array} List of named coverages. - */ - read: function(data) { - if(typeof data == "string") { - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); - } - var raw = data; - if(data && data.nodeType == 9) { - data = data.documentElement; - } - var capabilities = {}; - this.readNode(data, capabilities); - return capabilities; - }, - - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" - -}); -/* ====================================================================== - OpenLayers/Format/WCSCapabilities/v1_0_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/WCSCapabilities/v1.js - * @requires OpenLayers/Format/GML/v3.js - */ - -/** - * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 - * Read WCS Capabilities version 1.0.0. - * - * Inherits from: - * - <OpenLayers.Format.WCSCapabilities.v1> - */ -OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( - OpenLayers.Format.WCSCapabilities.v1, { - - /** - * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 - * Create a new parser for WCS capabilities version 1.0.0. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - namespaces: { - wcs: "http://www.opengis.net/wcs", - xlink: "http://www.w3.org/1999/xlink", - xsi: "http://www.w3.org/2001/XMLSchema-instance", - ows: "http://www.opengis.net/ows" - }, - - /** - * Property: errorProperty - * {String} Which property of the returned object to check for in order to - * determine whether or not parsing has failed. In the case that the - * errorProperty is undefined on the returned object, the document will be - * run through an OGCExceptionReport parser. - */ - errorProperty: "service", - - /** - * 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: { - "wcs": { - "WCS_Capabilities": function(node, obj) { - this.readChildNodes(node, obj); - }, - "Service": function(node, obj) { - obj.service = {}; - this.readChildNodes(node, obj.service); - }, - "name": function(node, service) { - service.name = this.getChildValue(node); - }, - "label": function(node, service) { - service.label = this.getChildValue(node); - }, - "keywords": function(node, service) { - service.keywords = []; - this.readChildNodes(node, service.keywords); - }, - "keyword": function(node, keywords) { - // Append the keyword to the keywords list - keywords.push(this.getChildValue(node)); - }, - "responsibleParty": function(node, service) { - service.responsibleParty = {}; - this.readChildNodes(node, service.responsibleParty); - }, - "individualName": function(node, responsibleParty) { - responsibleParty.individualName = this.getChildValue(node); - }, - "organisationName": function(node, responsibleParty) { - responsibleParty.organisationName = this.getChildValue(node); - }, - "positionName": function(node, responsibleParty) { - responsibleParty.positionName = this.getChildValue(node); - }, - "contactInfo": function(node, responsibleParty) { - responsibleParty.contactInfo = {}; - this.readChildNodes(node, responsibleParty.contactInfo); - }, - "phone": function(node, contactInfo) { - contactInfo.phone = {}; - this.readChildNodes(node, contactInfo.phone); - }, - "voice": function(node, phone) { - phone.voice = this.getChildValue(node); - }, - "facsimile": function(node, phone) { - phone.facsimile = this.getChildValue(node); - }, - "address": function(node, contactInfo) { - contactInfo.address = {}; - this.readChildNodes(node, contactInfo.address); - }, - "deliveryPoint": function(node, address) { - address.deliveryPoint = this.getChildValue(node); - }, - "city": function(node, address) { - address.city = this.getChildValue(node); - }, - "postalCode": function(node, address) { - address.postalCode = this.getChildValue(node); - }, - "country": function(node, address) { - address.country = this.getChildValue(node); - }, - "electronicMailAddress": function(node, address) { - address.electronicMailAddress = this.getChildValue(node); - }, - "fees": function(node, service) { - service.fees = this.getChildValue(node); - }, - "accessConstraints": function(node, service) { - service.accessConstraints = this.getChildValue(node); - }, - "ContentMetadata": function(node, obj) { - obj.contentMetadata = []; - this.readChildNodes(node, obj.contentMetadata); - }, - "CoverageOfferingBrief": function(node, contentMetadata) { - var coverageOfferingBrief = {}; - this.readChildNodes(node, coverageOfferingBrief); - contentMetadata.push(coverageOfferingBrief); - }, - "name": function(node, coverageOfferingBrief) { - coverageOfferingBrief.name = this.getChildValue(node); - }, - "label": function(node, coverageOfferingBrief) { - coverageOfferingBrief.label = this.getChildValue(node); - }, - "lonLatEnvelope": function(node, coverageOfferingBrief) { - var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); - - // We expect two nodes here, to create the corners of a bounding box - if(nodeList.length == 2) { - var min = {}; - var max = {}; - - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); - - coverageOfferingBrief.lonLatEnvelope = {}; - coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); - coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; - coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; - } - } - } - }, - - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" - -}); -/* ====================================================================== OpenLayers/Strategy/Fixed.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -47806,11 +46357,12 @@ * 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)) { + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); + if(activated) { this.layer.events.on({ "refresh": this.load, scope: this }); if(this.layer.visibility == true || this.preload) { @@ -47819,13 +46371,12 @@ this.layer.events.on({ "visibilitychanged": this.load, scope: this }); } - return true; } - return false; + return activated; }, /** * Method: deactivate * Deactivate the strategy. Undo what is done in <activate>. @@ -47854,40 +46405,43 @@ */ load: function(options) { var layer = this.layer; layer.events.triggerEvent("loadstart", {filter: layer.filter}); layer.protocol.read(OpenLayers.Util.applyDefaults({ - callback: OpenLayers.Function.bind(this.merge, this, - layer.map.getProjectionObject()), - filter: layer.filter + callback: this.merge, + filter: layer.filter, + scope: this }, options)); layer.events.un({ "visibilitychanged": this.load, scope: this }); }, /** * Method: merge * Add all features 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: - * mapProjection - {<OpenLayers.Projection>} the map projection * resp - {<OpenLayers.Protocol.Response>} The response object passed * by the protocol. */ - merge: function(mapProjection, resp) { + merge: function(resp) { var layer = this.layer; layer.destroyFeatures(); var features = resp.features; if (features && features.length > 0) { - if(!mapProjection.equals(layer.projection)) { + var remote = layer.projection; + var local = 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(layer.projection, mapProjection); + geom.transform(remote, local); } } } layer.addFeatures(features); } @@ -47898,11 +46452,11 @@ }); /* ====================================================================== OpenLayers/Control/Zoom.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48037,14 +46591,1190 @@ }, CLASS_NAME: "OpenLayers.Control.Zoom" }); /* ====================================================================== + OpenLayers/StyleMap.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/BaseTypes/Class.js + * @requires OpenLayers/Style.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.StyleMap + */ +OpenLayers.StyleMap = OpenLayers.Class({ + + /** + * Property: styles + * {Object} 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" +}); +/* ====================================================================== + OpenLayers/Layer/Vector.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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 + * @requires OpenLayers/Lang.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, { + + /** + * APIProperty: events + * {<OpenLayers.Events>} + * + * 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.events>): + * 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. + * beforefeaturesremoved - Triggered before multiple features are removed. + * Listeners will receive an object with a *features* property + * referencing the features 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. + * beforefeatureselected - Triggered before a feature is selected. Listeners + * will receive an object with a *feature* property referencing the + * feature to be selected. To stop the feature from being selectd, a + * listener should return false. + * 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. + * vertexremoved - Triggered when a vertex within any feature geometry + * has been deleted. 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 + * removal. + * 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. + */ + + /** + * APIProperty: isBaseLayer + * {Boolean} The layer is a base layer. Default is false. Set this property + * in the layer options. + */ + isBaseLayer: false, + + /** + * APIProperty: isFixed + * {Boolean} Whether the layer remains in one place while dragging the + * map. Note that setting this to true will move the layer to the bottom + * of the layer stack. + */ + isFixed: false, + + /** + * APIProperty: features + * {Array(<OpenLayers.Feature.Vector>)} + */ + features: null, + + /** + * Property: filter + * {<OpenLayers.Filter>} The filter set in this layer, + * a strategy launching read requests can combined + * this filter with its own filter. + */ + filter: 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, + + /** + * APIProperty: ratio + * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map. + */ + ratio: 1, + + /** + * 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) { + 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: clone + * Create a clone of this layer. + * + * Note: Features of the layer are also cloned. + * + * Returns: + * {<OpenLayers.Layer.Vector>} An exact clone of this layer + */ + clone: function (obj) { + + if (obj == null) { + obj = new OpenLayers.Layer.Vector(this.name, this.getOptions()); + } + + //get all additions from superclasses + obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); + + // copy/set any non-init, non-simple values here + var features = this.features; + var len = features.length; + var clonedFeatures = new Array(len); + for(var i=0; i<len; ++i) { + clonedFeatures[i] = features[i].clone(); + } + obj.features = clonedFeatures; + + return obj; + }, + + /** + * 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 = this.renderers[i]; + var renderer = (typeof rendererClass == "function") ? + rendererClass : + OpenLayers.Renderer[rendererClass]; + if (renderer && renderer.prototype.supported()) { + this.renderer = new renderer(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; + + var newSize = this.map.getSize(); + newSize.w = newSize.w * this.ratio; + newSize.h = newSize.h * this.ratio; + this.renderer.setSize(newSize); + } + }, + + /** + * 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) { + this.drawn = false; + 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); + + var newSize = this.map.getSize(); + newSize.w = newSize.w * this.ratio; + newSize.h = newSize.h * this.ratio; + this.renderer.setSize(newSize); + }, + + /** + * 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'; + + var viewSize = this.map.getSize(), + viewWidth = viewSize.w, + viewHeight = viewSize.h, + offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2, + offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2; + offsetLeft += this.map.layerContainerOriginPx.x; + offsetLeft = -Math.round(offsetLeft); + offsetTop += this.map.layerContainerOriginPx.y; + offsetTop = -Math.round(offsetTop); + + this.div.style.left = offsetLeft + 'px'; + this.div.style.top = offsetTop + 'px'; + + var extent = this.map.getExtent().scale(this.ratio); + 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 (OpenLayers.IS_GECKO === true) { + 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 (!(OpenLayers.Util.isArray(features))) { + 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; + } + + // Track successfully added features for featuresadded event, since + // beforefeatureadded can veto single features. + var featuresAdded = []; + 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)) { + throw new TypeError('addFeatures: component should be an ' + + this.geometryType.prototype.CLASS_NAME); + } + + //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); + } + + featuresAdded.push(feature); + this.features.push(feature); + this.drawFeature(feature); + + if (notify) { + this.events.triggerEvent("featureadded", { + feature: feature + }); + this.onFeatureInsert(feature); + } + } + + if(notify) { + this.events.triggerEvent("featuresadded", {features: featuresAdded}); + } + }, + + + /** + * 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 === this.features) { + return this.removeAllFeatures(options); + } + if (!(OpenLayers.Util.isArray(features))) { + features = [features]; + } + if (features === this.selectedFeatures) { + features = features.slice(); + } + + var notify = !options || !options.silent; + + if (notify) { + this.events.triggerEvent( + "beforefeaturesremoved", {features: features} + ); + } + + 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: removeAllFeatures + * Remove all features from the layer. + * + * Parameters: + * options - {Object} Optional properties for changing behavior of the + * removal. + * + * Valid options: + * silent - {Boolean} Supress event triggering. Default is false. + */ + removeAllFeatures: function(options) { + var notify = !options || !options.silent; + var features = this.features; + if (notify) { + this.events.triggerEvent( + "beforefeaturesremoved", {features: features} + ); + } + var feature; + for (var i = features.length-1; i >= 0; i--) { + feature = features[i]; + if (notify) { + this.events.triggerEvent("beforefeatureremoved", { + feature: feature + }); + } + feature.layer = null; + if (notify) { + this.events.triggerEvent("featureremoved", { + feature: feature + }); + } + } + this.renderer.clear(); + this.features = []; + this.unrenderedFeatures = {}; + this.selectedFeatures = []; + 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 - {String | Object} Named render intent or full symbolizer object. + */ + 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); + } + } + + var drawn = this.renderer.drawFeature(feature, style); + //TODO remove the check for null when we get rid of Renderer.SVG + if (drawn === false || drawn === null) { + 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) { + throw new Error('getFeatureFromEvent called on layer with no ' + + 'renderer. This usually means you destroyed a ' + + 'layer, but not some handler which is associated ' + + 'with it.'); + } + var feature = null; + var featureId = this.renderer.getFeatureIdFromEvent(evt); + if (featureId) { + if (typeof featureId === "string") { + feature = this.getFeatureById(featureId); + } else { + feature = featureId; + } + } + return feature; + }, + + /** + * APIMethod: getFeatureBy + * Given a property value, return the feature if it exists in the features array + * + * Parameters: + * property - {String} + * value - {String} + * + * Returns: + * {<OpenLayers.Feature.Vector>} A feature corresponding to the given + * property value or null if there is no such feature. + */ + getFeatureBy: function(property, value) { + //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][property] == value) { + feature = this.features[i]; + break; + } + } + return feature; + }, + + /** + * 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 or null if there is no such feature. + */ + getFeatureById: function(featureId) { + return this.getFeatureBy('id', featureId); + }, + + /** + * APIMethod: getFeatureByFid + * Given a feature fid, return the feature if it exists in the features array + * + * Parameters: + * featureFid - {String} + * + * Returns: + * {<OpenLayers.Feature.Vector>} A feature corresponding to the given + * featureFid or null if there is no such feature. + */ + getFeatureByFid: function(featureFid) { + return this.getFeatureBy('fid', featureFid); + }, + + /** + * APIMethod: getFeaturesByAttribute + * Returns an array of features that have the given attribute key set to the + * given value. Comparison of attribute values takes care of datatypes, e.g. + * the string '1234' is not equal to the number 1234. + * + * Parameters: + * attrName - {String} + * attrValue - {Mixed} + * + * Returns: + * Array({<OpenLayers.Feature.Vector>}) An array of features that have the + * passed named attribute set to the given value. + */ + getFeaturesByAttribute: function(attrName, attrValue) { + var i, + feature, + len = this.features.length, + foundFeatures = []; + for(i = 0; i < len; i++) { + feature = this.features[i]; + if(feature && feature.attributes) { + if (feature.attributes[attrName] === attrValue) { + foundFeatures.push(feature); + } + } + } + return foundFeatures; + }, + + /** + * 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. + * + * Parameters: + * 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>} or null if the layer has no features with + * geometries. + */ + getDataExtent: function () { + var maxExtent = null; + var features = this.features; + if(features && (features.length > 0)) { + var geometry = null; + for(var i=0, len=features.length; i<len; i++) { + geometry = features[i].geometry; + if (geometry) { + if (maxExtent === null) { + maxExtent = new OpenLayers.Bounds(); + } + maxExtent.extend(geometry.getBounds()); + } + } + } + return maxExtent; + }, + + CLASS_NAME: "OpenLayers.Layer.Vector" +}); +/* ====================================================================== OpenLayers/Layer/PointTrack.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48169,11 +47899,11 @@ OpenLayers.Layer.PointTrack.dataFrom = {'SOURCE_NODE': -1, 'TARGET_NODE': 0}; /* ====================================================================== OpenLayers/Protocol.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48464,11 +48194,11 @@ OpenLayers.Protocol.Response.FAILURE = 0; /* ====================================================================== OpenLayers/Protocol/WFS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48554,11 +48284,11 @@ }; /* ====================================================================== OpenLayers/Layer/Markers.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -48745,11 +48475,11 @@ }); /* ====================================================================== OpenLayers/Control/Pan.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48844,11 +48574,11 @@ OpenLayers.Control.Pan.WEST = "West"; /* ====================================================================== OpenLayers/Format/CSWGetDomain.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -48882,11 +48612,11 @@ }; /* ====================================================================== OpenLayers/Format/CSWGetDomain/v2_0_2.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -49126,11 +48856,11 @@ }); /* ====================================================================== OpenLayers/Format/ArcXML/Features.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -49176,11 +48906,11 @@ }); /* ====================================================================== OpenLayers/Control/Snapping.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -49740,11 +49470,11 @@ }); /* ====================================================================== OpenLayers/Format/OWSCommon/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -49860,11 +49590,11 @@ }); /* ====================================================================== OpenLayers/Format/WCSGetCoverage.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -50060,14 +49790,524 @@ CLASS_NAME: "OpenLayers.Format.WCSGetCoverage" }); /* ====================================================================== + OpenLayers/Format/Filter/v2.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ +/** + * @requires OpenLayers/Format/Filter.js + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Filter/Function.js + * @requires OpenLayers/BaseTypes/Date.js + */ + +/** + * Class: OpenLayers.Format.Filter.v2 + * Superclass for Filter version 2 parsers. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.Filter.v2 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + fes: "http://www.opengis.net/fes/2.0", + gml: "http://www.opengis.net/gml/3.2", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "fes", + + /** + * 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.fes["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: { + "fes": { + "_expression": function(node) { + // only the simplest of fes:expression handled + // "some text and an <ValueReference>attribute</ValueReference>"} + var obj, value = ""; + for(var child=node.firstChild; child; child=child.nextSibling) { + switch(child.nodeType) { + case 1: + obj = this.readNode(child); + if (obj.property) { + value += "${" + obj.property + "}"; + } else if (obj.value !== undefined) { + value += obj.value; + } + break; + case 3: // text node + case 4: // cdata section + value += child.nodeValue; + } + } + return value; + }, + "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 + // (fes: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]; + } + }, + "ResourceId": function(node, obj) { + var fid = node.getAttribute("rid"); + 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); + }, + "Literal": function(node, obj) { + obj.value = OpenLayers.String.numericIf( + this.getChildValue(node), true); + }, + "ValueReference": function(node, filter) { + filter.property = this.getChildValue(node); + }, + "LowerBoundary": function(node, filter) { + filter.lowerBoundary = OpenLayers.String.numericIf( + this.readers.fes._expression.call(this, node), true); + }, + "UpperBoundary": function(node, filter) { + filter.upperBoundary = OpenLayers.String.numericIf( + this.readers.fes._expression.call(this, node), true); + }, + "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"); + }, + "Function": function(node, obj) { + //TODO write decoder for it + return; + }, + "PropertyIsNull": function(node, obj) { + var filter = new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.IS_NULL + }); + this.readChildNodes(node, filter); + obj.filters.push(filter); + } + } + }, + + /** + * Method: readSpatial + * + * Read a {<OpenLayers.Filter.Spatial>} filter. + * + * Parameters: + * node - {DOMElement} A DOM element that contains an fes: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); + }, + + /** + * APIMethod: encodeLiteral + * Generates the string representation of a value for use in <Literal> + * elements. The default encoder writes Date values as ISO 8601 + * strings. + * + * Parameters: + * value - {Object} Literal value to encode + * + * Returns: + * {String} String representation of the provided value. + */ + encodeLiteral: function(value) { + if (value instanceof Date) { + value = OpenLayers.Date.toISOString(value); + } + return value; + }, + + /** + * Method: writeOgcExpression + * Limited support for writing OGC expressions. Currently it supports + * (<OpenLayers.Filter.Function> || String || Number) + * + * Parameters: + * value - (<OpenLayers.Filter.Function> || String || Number) + * node - {DOMElement} A parent DOM element + * + * Returns: + * {DOMElement} Updated node element. + */ + writeOgcExpression: function(value, node) { + if (value instanceof OpenLayers.Filter.Function){ + this.writeNode("Function", value, node); + } else { + this.writeNode("Literal", value, node); + } + return node; + }, + + /** + * Method: write + * + * Parameters: + * filter - {<OpenLayers.Filter>} A filter object. + * + * Returns: + * {DOMElement} An fes:Filter element. + */ + write: function(filter) { + return this.writers.fes["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: { + "fes": { + "Filter": function(filter) { + var node = this.createElementNSPlus("fes:Filter"); + this.writeNode(this.getFilterType(filter), filter, node); + return node; + }, + "_featureIds": function(filter) { + var node = this.createDocumentFragment(); + for (var i=0, ii=filter.fids.length; i<ii; ++i) { + this.writeNode("fes:ResourceId", filter.fids[i], node); + } + return node; + }, + "ResourceId": function(fid) { + return this.createElementNSPlus("fes:ResourceId", { + attributes: {rid: fid} + }); + }, + + "And": function(filter) { + var node = this.createElementNSPlus("fes:And"); + var childFilter; + for (var i=0, ii=filter.filters.length; i<ii; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Or": function(filter) { + var node = this.createElementNSPlus("fes:Or"); + var childFilter; + for (var i=0, ii=filter.filters.length; i<ii; ++i) { + childFilter = filter.filters[i]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + } + return node; + }, + "Not": function(filter) { + var node = this.createElementNSPlus("fes:Not"); + var childFilter = filter.filters[0]; + this.writeNode( + this.getFilterType(childFilter), childFilter, node + ); + return node; + }, + "PropertyIsLessThan": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsLessThan"); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsGreaterThan": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsGreaterThan"); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsLessThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsLessThanOrEqualTo"); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsGreaterThanOrEqualTo": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsGreaterThanOrEqualTo"); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); + return node; + }, + "PropertyIsBetween": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsBetween"); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + this.writeNode("LowerBoundary", filter, node); + this.writeNode("UpperBoundary", filter, node); + return node; + }, + "ValueReference": function(filter) { + // no fes:expression handling for now + return this.createElementNSPlus("fes:ValueReference", { + value: filter.property + }); + }, + "Literal": function(value) { + var encode = this.encodeLiteral || + OpenLayers.Format.Filter.v1.prototype.encodeLiteral; + return this.createElementNSPlus("fes:Literal", { + value: encode(value) + }); + }, + "LowerBoundary": function(filter) { + // handle Literals or Functions for now + var node = this.createElementNSPlus("fes:LowerBoundary"); + this.writeOgcExpression(filter.lowerBoundary, node); + return node; + }, + "UpperBoundary": function(filter) { + // handle Literals or Functions for now + var node = this.createElementNSPlus("fes: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("fes:Distance", { + attributes: { + units: filter.distanceUnits + }, + value: filter.distance + }); + }, + "Function": function(filter) { + var node = this.createElementNSPlus("fes:Function", { + attributes: { + name: filter.name + } + }); + var params = filter.params; + for(var i=0, len=params.length; i<len; i++){ + this.writeOgcExpression(params[i], node); + } + return node; + }, + "PropertyIsNull": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsNull"); + this.writeNode("ValueReference", filter, node); + return node; + } + } + }, + + /** + * 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", + "NULL": "PropertyIsNull", + "BBOX": "BBOX", + "DWITHIN": "DWITHIN", + "WITHIN": "WITHIN", + "CONTAINS": "CONTAINS", + "INTERSECTS": "INTERSECTS", + "FID": "_featureIds" + }, + + CLASS_NAME: "OpenLayers.Format.Filter.v2" + +}); +/* ====================================================================== OpenLayers/Format/WMSCapabilities.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -50123,11 +50363,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -50495,11 +50735,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -50621,11 +50861,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -50679,471 +50919,1551 @@ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" }); /* ====================================================================== - OpenLayers/Protocol/WFS/v1.js + OpenLayers/Strategy/BBOX.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Protocol/WFS.js + * @requires OpenLayers/Strategy.js + * @requires OpenLayers/Filter/Spatial.js */ /** - * Class: OpenLayers.Protocol.WFS.v1 - * Abstract class for for v1.0.0 and v1.1.0 protocol. + * Class: OpenLayers.Strategy.BBOX + * A simple strategy that reads new features when the viewport invalidates + * some bounds. * * Inherits from: - * - <OpenLayers.Protocol> + * - <OpenLayers.Strategy> */ -OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { /** - * Property: version - * {String} WFS version number. + * Property: bounds + * {<OpenLayers.Bounds>} The current data bounds (in the same projection + * as the layer - not always the same projection as the map). */ - version: null, + bounds: null, + /** + * Property: resolution + * {Float} The current data resolution. + */ + resolution: null, + /** - * Property: srsName - * {String} Name of spatial reference system. Default is "EPSG:4326". + * APIProperty: ratio + * {Float} The ratio of the data bounds to the viewport bounds (in each + * dimension). Default is 2. */ - srsName: "EPSG:4326", + 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: featureType - * {String} Local feature typeName. + * Property: response + * {<OpenLayers.Protocol.Response>} The protocol response object returned + * by the layer protocol. */ - featureType: null, + response: null, + + /** + * Constructor: OpenLayers.Strategy.BBOX + * Create a new BBOX strategy. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + */ /** - * Property: featureNS - * {String} Feature namespace. + * Method: activate + * Set up strategy with regard to reading new batches of remote data. + * + * Returns: + * {Boolean} The strategy was successfully activated. */ - featureNS: null, + activate: function() { + var activated = OpenLayers.Strategy.prototype.activate.call(this); + if(activated) { + this.layer.events.on({ + "moveend": this.update, + "refresh": this.update, + "visibilitychanged": this.update, + scope: this + }); + this.update(); + } + return activated; + }, /** - * Property: geometryName - * {String} Name of the geometry attribute for features. Default is - * "the_geom" for WFS <version> 1.0, and null for higher versions. + * Method: deactivate + * Tear down strategy with regard to reading new batches of remote data. + * + * Returns: + * {Boolean} The strategy was successfully deactivated. */ - geometryName: "the_geom", + deactivate: function() { + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); + if(deactivated) { + this.layer.events.un({ + "moveend": this.update, + "refresh": this.update, + "visibilitychanged": this.update, + scope: this + }); + } + return deactivated; + }, /** - * Property: maxFeatures - * {Integer} Optional maximum number of features to retrieve. + * Method: update + * Callback function called on "moveend" or "refresh" layer events. + * + * Parameters: + * options - {Object} Optional object whose properties will determine + * the behaviour of this Strategy + * + * Valid options include: + * force - {Boolean} if true, new data must be unconditionally read. + * noAbort - {Boolean} if true, do not abort previous requests. */ + update: function(options) { + var mapBounds = this.getMapBounds(); + if (mapBounds !== null && ((options && options.force) || + (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { + this.calculateBounds(mapBounds); + this.resolution = this.layer.map.getResolution(); + this.triggerRead(options); + } + }, /** - * 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). + * 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. */ - schema: null, + getMapBounds: function() { + if (this.layer.map === null) { + return null; + } + var bounds = this.layer.map.getExtent(); + if(bounds && !this.layer.projection.equals( + this.layer.map.getProjectionObject())) { + bounds = bounds.clone().transform( + this.layer.map.getProjectionObject(), this.layer.projection + ); + } + return bounds; + }, /** - * Property: featurePrefix - * {String} Namespace alias for feature type. Default is "feature". + * 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} */ - featurePrefix: "feature", + 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) + ); + }, /** - * 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. + * Method: triggerRead + * + * Parameters: + * options - {Object} Additional options for the protocol's read method + * (optional) + * + * Returns: + * {<OpenLayers.Protocol.Response>} The protocol response object + * returned by the layer protocol. */ - formatOptions: null, + triggerRead: function(options) { + if (this.response && !(options && options.noAbort === true)) { + this.layer.protocol.abort(this.response); + this.layer.events.triggerEvent("loadend"); + } + var evt = {filter: this.createFilter()}; + this.layer.events.triggerEvent("loadstart", evt); + this.response = this.layer.protocol.read( + OpenLayers.Util.applyDefaults({ + filter: evt.filter, + callback: this.merge, + scope: this + }, options)); + }, + + /** + * Method: createFilter + * Creates a spatial BBOX filter. If the layer that this strategy belongs + * to has a filter property, this filter will be combined with the BBOX + * filter. + * + * 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(); + if (resp.success()) { + 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); + } + } else { + this.bounds = null; + } + this.response = null; + this.layer.events.triggerEvent("loadend", {response: resp}); + }, + + CLASS_NAME: "OpenLayers.Strategy.BBOX" +}); +/* ====================================================================== + OpenLayers/Handler/Feature.js + ====================================================================== */ - /** - * Property: readFormat - * {<OpenLayers.Format>} For WFS requests it is possible to get a - * different output format than GML. In that case, we cannot parse - * the response with the default format (WFST) and we need a different - * format for reading. - */ - readFormat: null, +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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. + * + * Inherits from: + * - <OpenLayers.Handler> + */ +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}, + 'touchstart': {'in': 'click', 'out': 'clickout'} + }, + + /** + * 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: readOptions - * {Object} Optional object to pass to format's read. + * 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. */ - readOptions: null, + 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.Protocol.WFS - * A class for giving layers WFS protocol. + * Constructor: OpenLayers.Handler.Feature * * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. + * 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: touchstart + * Handle touchstart events * - * 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 - * during the first query if GML is used as readFormat and - * featurePrefix is provided and matches the prefix used by the server - * for this featureType). - * featurePrefix - {String} Feature namespace alias (optional - only used - * for writing if featureNS is provided). Default is 'feature'. - * geometryName - {String} Name of geometry attribute. The default is - * 'the_geom' for WFS <version> 1.0, and null for higher versions. If - * null, it will be set to the name of the first geometry found in the - * first read operation. - * multi - {Boolean} If set to true, geometries will be casted to Multi - * geometries before they are written in a transaction. No casting will - * be done when reading features. + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. */ - 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)); + touchstart: function(evt) { + this.startTouch(); + return OpenLayers.Event.isMultiTouch(evt) ? + true : this.mousedown(evt); + }, + + /** + * Method: touchmove + * Handle touchmove events. We just prevent the browser default behavior, + * for Android Webkit not to select text when moving the finger after + * selecting a feature. + * + * Parameters: + * evt - {Event} + */ + touchmove: function(evt) { + OpenLayers.Event.preventDefault(evt); + }, + + /** + * 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) { + // Feature selection is only done with a left click. Other handlers may stop the + // propagation of left-click mousedown events but not right-click mousedown events. + // This mismatch causes problems when comparing the location of the down and up + // events in the click function so it is important ignore right-clicks. + if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { + this.down = evt.xy; } - if (!options.geometryName && parseFloat(this.format.version) > 1.0) { - this.setGeometryName(null); - } + return this.handle(evt) ? !this.stopDown : true; }, /** - * APIMethod: destroy - * Clean up the protocol. + * Method: mouseup + * Handle mouse up. Stop propagation if a feature is targeted by this + * event. + * + * Parameters: + * evt - {Event} */ - destroy: function() { - if(this.options && !this.options.format) { - this.format.destroy(); - } - this.format = null; - OpenLayers.Protocol.prototype.destroy.apply(this); + mouseup: function(evt) { + this.up = evt.xy; + return this.handle(evt) ? !this.stopUp : true; }, /** - * APIMethod: 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). + * 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: - * options - {Object} Options for the read operation, in addition to the - * options set on the instance (options set here will take precedence). + * evt - {Event} * - * To use a configured protocol to get e.g. a WFS hit count, applications - * could do the following: + * 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. * - * (code) - * protocol.read({ - * readOptions: {output: "object"}, - * resultType: "hits", - * maxFeatures: null, - * callback: function(resp) { - * // process resp.numberOfFeatures here - * } - * }); - * (end) + * Parameters: + * evt - {Event} * - * To use a configured protocol to use WFS paging (if supported by the - * server), applications could do the following: + * 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. * - * (code) - * protocol.read({ - * startIndex: 0, - * count: 50 - * }); - * (end) + * Parameters: + * feature - {<OpenLayers.Vector.Feature>} * - * To limit the attributes returned by the GetFeature request, applications - * can use the propertyNames option to specify the properties to include in - * the response: + * Returns: + * {Boolean} + */ + geometryTypeMatches: function(feature) { + return this.geometryTypes == null || + OpenLayers.Util.indexOf(this.geometryTypes, + feature.geometry.CLASS_NAME) > -1; + }, + + /** + * Method: handle * - * (code) - * protocol.read({ - * propertyNames: ["DURATION", "INTENSITY"] - * }); - * (end) + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} The event occurred over a relevant feature. */ - read: function(options) { - OpenLayers.Protocol.prototype.read.apply(this, arguments); - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options || {}); - var response = new OpenLayers.Protocol.Response({requestType: "read"}); + 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" || type == "touchstart"); + 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) { + if(type === "touchstart") { + // stop the event to prevent Android Webkit from + // "flashing" the map div + OpenLayers.Event.preventDefault(evt); + } + 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); + } + // we're done with this set of events now: clear the cached + // positions so we can't trip over them later (this can occur + // if one of the up/down events gets eaten before it gets to us + // but we still get the click) + this.up = this.down = null; + } 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.type == "removelayer" || 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); - var data = OpenLayers.Format.XML.prototype.write.apply( - this.format, [this.format.writeNode("wfs:GetFeature", options)] - ); + }, + + /** + * 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)); + } + }, - response.priv = OpenLayers.Request.POST({ - url: options.url, - callback: this.createCallback(this.handleRead, response, options), - params: options.params, - headers: options.headers, - data: data - }); + CLASS_NAME: "OpenLayers.Handler.Feature" +}); +/* ====================================================================== + OpenLayers/Layer/Vector/RootContainer.js + ====================================================================== */ - return response; +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Layer/Vector.js + */ + +/** + * Class: OpenLayers.Layer.Vector.RootContainer + * A special layer type to combine multiple vector layers inside a single + * renderer root container. This class is not supposed to be instantiated + * from user space, it is a helper class for controls that require event + * processing for multiple vector layers. + * + * Inherits from: + * - <OpenLayers.Layer.Vector> + */ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { + + /** + * Property: displayInLayerSwitcher + * Set to false for this layer type + */ + displayInLayerSwitcher: false, + + /** + * APIProperty: layers + * Layers that are attached to this container. Required config option. + */ + layers: null, + + /** + * Constructor: OpenLayers.Layer.Vector.RootContainer + * Create a new root container for multiple vector layer. This constructor + * is not supposed to be used from user space, it is only to be used by + * controls that need feature selection across multiple vector layers. + * + * Parameters: + * name - {String} A name for the layer + * options - {Object} Optional object with non-default properties to set on + * the layer. + * + * Required options properties: + * layers - {Array(<OpenLayers.Layer.Vector>)} The layers managed by this + * container + * + * Returns: + * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root + * container + */ + + /** + * Method: display + */ + display: function() {}, + + /** + * Method: getFeatureFromEvent + * walk through the layers to find the feature returned by the event + * + * Parameters: + * evt - {Object} event object with a feature property + * + * Returns: + * {<OpenLayers.Feature.Vector>} + */ + getFeatureFromEvent: function(evt) { + var layers = this.layers; + var feature; + for(var i=0; i<layers.length; i++) { + feature = layers[i].getFeatureFromEvent(evt); + if(feature) { + return feature; + } + } }, + + /** + * Method: setMap + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + setMap: function(map) { + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); + this.collectRoots(); + map.events.register("changelayer", this, this.handleChangeLayer); + }, + + /** + * Method: removeMap + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + removeMap: function(map) { + map.events.unregister("changelayer", this, this.handleChangeLayer); + this.resetRoots(); + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); + }, + + /** + * Method: collectRoots + * Collects the root nodes of all layers this control is configured with + * and moveswien the nodes to this control's layer + */ + collectRoots: function() { + var layer; + // walk through all map layers, because we want to keep the order + for(var i=0; i<this.map.layers.length; ++i) { + layer = this.map.layers[i]; + if(OpenLayers.Util.indexOf(this.layers, layer) != -1) { + layer.renderer.moveRoot(this.renderer); + } + } + }, + + /** + * Method: resetRoots + * Resets the root nodes back into the layers they belong to. + */ + resetRoots: function() { + var layer; + for(var i=0; i<this.layers.length; ++i) { + layer = this.layers[i]; + if(this.renderer && layer.renderer.getRenderLayerId() == this.id) { + this.renderer.moveRoot(layer.renderer); + } + } + }, + + /** + * Method: handleChangeLayer + * Event handler for the map's changelayer event. We need to rebuild + * this container's layer dom if order of one of its layers changes. + * This handler is added with the setMap method, and removed with the + * removeMap method. + * + * Parameters: + * evt - {Object} + */ + handleChangeLayer: function(evt) { + var layer = evt.layer; + if(evt.property == "order" && + OpenLayers.Util.indexOf(this.layers, layer) != -1) { + this.resetRoots(); + this.collectRoots(); + } + }, + CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" +}); +/* ====================================================================== + OpenLayers/Control/SelectFeature.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Feature/Vector.js + * @requires OpenLayers/Handler/Feature.js + * @requires OpenLayers/Layer/Vector/RootContainer.js + */ + +/** + * Class: OpenLayers.Control.SelectFeature + * The SelectFeature control selects vector features from a given layer on + * click or hover. + * + * Inherits from: + * - <OpenLayers.Control> + */ +OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: events + * {<OpenLayers.Events>} Events instance for listeners and triggering + * control specific events. + * + * Register a listener for a particular event with the following syntax: + * (code) + * control.events.register(type, obj, listener); + * (end) + * + * Supported event types (in addition to those from <OpenLayers.Control.events>): + * beforefeaturehighlighted - Triggered before a feature is highlighted + * featurehighlighted - Triggered when a feature is highlighted + * featureunhighlighted - Triggered when a feature is unhighlighted + * boxselectionstart - Triggered before box selection starts + * boxselectionend - Triggered after box selection ends + */ + /** - * APIMethod: setFeatureType - * Change the feature type on the fly. + * Property: multipleKey + * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets + * the <multiple> property to true. Default is null. + */ + multipleKey: null, + + /** + * Property: toggleKey + * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets + * the <toggle> property to true. Default is null. + */ + toggleKey: null, + + /** + * APIProperty: multiple + * {Boolean} Allow selection of multiple geometries. Default is false. + */ + multiple: false, + + /** + * 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 false. Only + * has meaning if hover is false. + */ + toggle: false, + + /** + * APIProperty: hover + * {Boolean} Select on mouse over and deselect on mouse out. If true, this + * ignores clicks and only listens to mouse moves. + */ + hover: false, + + /** + * APIProperty: highlightOnly + * {Boolean} If true do not actually select features (that is place them in + * the layer's selected features array), just highlight them. This property + * has no effect if hover is false. Defaults to false. + */ + highlightOnly: false, + + /** + * APIProperty: box + * {Boolean} Allow feature selection by drawing a box. + */ + box: false, + + /** + * Property: onBeforeSelect + * {Function} Optional function to be called before a feature is selected. + * The function should expect to be called with a feature. + */ + onBeforeSelect: function() {}, + + /** + * APIProperty: onSelect + * {Function} Optional function to be called when a feature is selected. + * The function should expect to be called with a feature. + */ + onSelect: function() {}, + + /** + * APIProperty: onUnselect + * {Function} Optional function to be called when a feature is unselected. + * The function should expect to be called with a feature. + */ + onUnselect: function() {}, + + /** + * Property: scope + * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect + * callbacks. If null the scope will be this control. + */ + scope: null, + + /** + * APIProperty: geometryTypes + * {Array(String)} To restrict selecting to a limited set of geometry types, + * send a list of strings corresponding to the geometry class names. + */ + geometryTypes: null, + + /** + * Property: layer + * {<OpenLayers.Layer.Vector>} The vector layer with a common renderer + * root for all layers this control is configured with (if an array of + * layers was passed to the constructor), or the vector layer the control + * was configured with (if a single layer was passed to the constructor). + */ + layer: null, + + /** + * Property: layers + * {Array(<OpenLayers.Layer.Vector>)} The layers this control will work on, + * or null if the control was configured with a single layer + */ + layers: null, + + /** + * APIProperty: callbacks + * {Object} The functions that are sent to the handlers.feature for callback + */ + callbacks: null, + + /** + * APIProperty: selectStyle + * {Object} Hash of styles + */ + selectStyle: null, + + /** + * Property: renderIntent + * {String} key used to retrieve the select style from the layer's + * style map. + */ + renderIntent: "select", + + /** + * Property: handlers + * {Object} Object with references to multiple <OpenLayers.Handler> + * instances. + */ + handlers: null, + + /** + * Constructor: OpenLayers.Control.SelectFeature + * Create a new control for selecting features. * * Parameters: - * featureType - {String} Local (without prefix) feature typeName. + * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The + * layer(s) this control will select features from. + * options - {Object} */ - setFeatureType: function(featureType) { - this.featureType = featureType; - this.format.featureType = featureType; + initialize: function(layers, options) { + OpenLayers.Control.prototype.initialize.apply(this, [options]); + + if(this.scope === null) { + this.scope = this; + } + this.initLayer(layers); + var callbacks = { + click: this.clickFeature, + clickout: this.clickoutFeature + }; + if (this.hover) { + callbacks.over = this.overFeature; + callbacks.out = this.outFeature; + } + + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); + this.handlers = { + feature: new OpenLayers.Handler.Feature( + this, this.layer, this.callbacks, + {geometryTypes: this.geometryTypes} + ) + }; + + if (this.box) { + this.handlers.box = new OpenLayers.Handler.Box( + this, {done: this.selectBox}, + {boxDivClassName: "olHandlerBoxSelectFeature"} + ); + } }, - + /** - * APIMethod: setGeometryName - * Sets the geometryName option after instantiation. + * Method: initLayer + * Assign the layer property. If layers is an array, we need to use + * a RootContainer. * * Parameters: - * geometryName - {String} Name of geometry attribute. + * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. */ - setGeometryName: function(geometryName) { - this.geometryName = geometryName; - this.format.geometryName = geometryName; + initLayer: function(layers) { + if(OpenLayers.Util.isArray(layers)) { + this.layers = layers; + this.layer = new OpenLayers.Layer.Vector.RootContainer( + this.id + "_container", { + layers: layers + } + ); + } else { + this.layer = layers; + } }, /** - * Method: handleRead - * Deal with response from the read request. + * Method: destroy + */ + destroy: function() { + if(this.active && this.layers) { + this.map.removeLayer(this.layer); + } + OpenLayers.Control.prototype.destroy.apply(this, arguments); + if(this.layers) { + this.layer.destroy(); + } + }, + + /** + * Method: activate + * Activates the control. + * + * Returns: + * {Boolean} The control was effectively activated. + */ + activate: function () { + if (!this.active) { + if(this.layers) { + this.map.addLayer(this.layer); + } + this.handlers.feature.activate(); + if(this.box && this.handlers.box) { + this.handlers.box.activate(); + } + } + return OpenLayers.Control.prototype.activate.apply( + this, arguments + ); + }, + + /** + * Method: deactivate + * Deactivates the control. + * + * Returns: + * {Boolean} The control was effectively deactivated. + */ + deactivate: function () { + if (this.active) { + this.handlers.feature.deactivate(); + if(this.handlers.box) { + this.handlers.box.deactivate(); + } + if(this.layers) { + this.map.removeLayer(this.layer); + } + } + return OpenLayers.Control.prototype.deactivate.apply( + this, arguments + ); + }, + + /** + * Method: unselectAll + * Unselect all selected features. To unselect all except for a single + * feature, set the options.except property to the feature. * * Parameters: - * response - {<OpenLayers.Protocol.Response>} The response object to pass - * to the user callback. - * options - {Object} The user options passed to the read call. + * options - {Object} Optional configuration object. */ - handleRead: function(response, options) { - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options); - - if(options.callback) { - var request = response.priv; - if(request.status >= 200 && request.status < 300) { - // success - var result = this.parseResponse(request, options.readOptions); - if (result && result.success !== false) { - if (options.readOptions && options.readOptions.output == "object") { - OpenLayers.Util.extend(response, result); + unselectAll: function(options) { + // we'll want an option to supress notification here + var layers = this.layers || [this.layer], + layer, feature, l, numExcept; + for(l=0; l<layers.length; ++l) { + layer = layers[l]; + numExcept = 0; + //layer.selectedFeatures is null when layer is destroyed and + //one of it's preremovelayer listener calls setLayer + //with another layer on this control + if(layer.selectedFeatures != null) { + while(layer.selectedFeatures.length > numExcept) { + feature = layer.selectedFeatures[numExcept]; + if(!options || options.except != feature) { + this.unselect(feature); } else { - response.features = result; + ++numExcept; } - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - // failure (service exception) - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = result; } - } else { - // failure - response.code = OpenLayers.Protocol.Response.FAILURE; } - options.callback.call(options.scope, response); } }, /** - * Method: parseResponse - * Read HTTP response body and return features + * Method: clickFeature + * Called on click in a feature + * Only responds if this.hover is false. * * Parameters: - * request - {XMLHttpRequest} The request object - * options - {Object} Optional object to pass to format's read + * feature - {<OpenLayers.Feature.Vector>} + */ + clickFeature: function(feature) { + if(!this.hover) { + var selected = (OpenLayers.Util.indexOf( + feature.layer.selectedFeatures, feature) > -1); + if(selected) { + if(this.toggleSelect()) { + this.unselect(feature); + } else if(!this.multipleSelect()) { + this.unselectAll({except: feature}); + } + } else { + if(!this.multipleSelect()) { + this.unselectAll({except: feature}); + } + this.select(feature); + } + } + }, + + /** + * Method: multipleSelect + * Allow for multiple selected features based on <multiple> property and + * <multipleKey> event modifier. * * Returns: - * {Object} or {Array({<OpenLayers.Feature.Vector>})} or - * {<OpenLayers.Feature.Vector>} - * An object with a features property, an array of features or a single - * feature. + * {Boolean} Allow for multiple selected features. */ - parseResponse: function(request, options) { - var doc = request.responseXML; - if(!doc || !doc.documentElement) { - doc = request.responseText; + multipleSelect: function() { + return this.multiple || (this.handlers.feature.evt && + this.handlers.feature.evt[this.multipleKey]); + }, + + /** + * Method: toggleSelect + * Event should toggle the selected state of a feature based on <toggle> + * property and <toggleKey> event modifier. + * + * Returns: + * {Boolean} Toggle the selected state of a feature. + */ + toggleSelect: function() { + return this.toggle || (this.handlers.feature.evt && + this.handlers.feature.evt[this.toggleKey]); + }, + + /** + * Method: clickoutFeature + * Called on click outside a previously clicked (selected) feature. + * Only responds if this.hover is false. + * + * Parameters: + * feature - {<OpenLayers.Vector.Feature>} + */ + clickoutFeature: function(feature) { + if(!this.hover && this.clickout) { + this.unselectAll(); } - if(!doc || doc.length <= 0) { - return null; - } - var result = (this.readFormat !== null) ? this.readFormat.read(doc) : - this.format.read(doc, options); - if (!this.featureNS) { - var format = this.readFormat || this.format; - this.featureNS = format.featureNS; - // no need to auto-configure again on subsequent reads - format.autoConfig = false; - if (!this.geometryName) { - this.setGeometryName(format.geometryName); + }, + + /** + * Method: overFeature + * Called on over a feature. + * Only responds if this.hover is true. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + overFeature: function(feature) { + var layer = feature.layer; + if(this.hover) { + if(this.highlightOnly) { + this.highlight(feature); + } else if(OpenLayers.Util.indexOf( + layer.selectedFeatures, feature) == -1) { + this.select(feature); } } - return result; }, /** - * 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. + * Method: outFeature + * Called on out of a selected feature. + * Only responds if this.hover is true. * * Parameters: - * features - {Array(<OpenLayers.Feature.Vector>)} - * options - {Object} - * - * Valid options properties: - * nativeElements - {Array({Object})} Array of objects with information for writing - * out <Native> elements, these objects have vendorId, safeToIgnore and - * value properties. The <Native> element is intended to allow access to - * vendor specific capabilities of any particular web feature server or - * datastore. - * - * Returns: - * {<OpenLayers.Protocol.Response>} A response object with a features - * property containing any insertIds and a priv property referencing - * the XMLHttpRequest object. + * feature - {<OpenLayers.Feature.Vector>} */ - commit: function(features, options) { + outFeature: function(feature) { + if(this.hover) { + if(this.highlightOnly) { + // we do nothing if we're not the last highlighter of the + // feature + if(feature._lastHighlighter == this.id) { + // if another select control had highlighted the feature before + // we did it ourself then we use that control to highlight the + // feature as it was before we highlighted it, else we just + // unhighlight it + if(feature._prevHighlighter && + feature._prevHighlighter != this.id) { + delete feature._lastHighlighter; + var control = this.map.getControl( + feature._prevHighlighter); + if(control) { + control.highlight(feature); + } + } else { + this.unhighlight(feature); + } + } + } else { + this.unselect(feature); + } + } + }, - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options); - - var response = new OpenLayers.Protocol.Response({ - requestType: "commit", - reqFeatures: features + /** + * Method: highlight + * Redraw feature with the select style. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + highlight: function(feature) { + var layer = feature.layer; + var cont = this.events.triggerEvent("beforefeaturehighlighted", { + feature : feature }); - response.priv = OpenLayers.Request.POST({ - url: options.url, - headers: options.headers, - data: this.format.write(features, options), - callback: this.createCallback(this.handleCommit, response, options) - }); - - return response; + if(cont !== false) { + feature._prevHighlighter = feature._lastHighlighter; + feature._lastHighlighter = this.id; + var style = this.selectStyle || this.renderIntent; + layer.drawFeature(feature, style); + this.events.triggerEvent("featurehighlighted", {feature : feature}); + } }, + + /** + * Method: unhighlight + * Redraw feature with the "default" style + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + unhighlight: function(feature) { + var layer = feature.layer; + // three cases: + // 1. there's no other highlighter, in that case _prev is undefined, + // and we just need to undef _last + // 2. another control highlighted the feature after we did it, in + // that case _last references this other control, and we just + // need to undef _prev + // 3. another control highlighted the feature before we did it, in + // that case _prev references this other control, and we need to + // set _last to _prev and undef _prev + if(feature._prevHighlighter == undefined) { + delete feature._lastHighlighter; + } else if(feature._prevHighlighter == this.id) { + delete feature._prevHighlighter; + } else { + feature._lastHighlighter = feature._prevHighlighter; + delete feature._prevHighlighter; + } + layer.drawFeature(feature, feature.style || feature.layer.style || + "default"); + this.events.triggerEvent("featureunhighlighted", {feature : feature}); + }, /** - * Method: handleCommit - * Called when the commit request returns. + * Method: select + * Add feature to the layer's selectedFeature array, render the feature as + * selected, and call the onSelect function. * * Parameters: - * response - {<OpenLayers.Protocol.Response>} The response object to pass - * to the user callback. - * options - {Object} The user options passed to the commit call. + * feature - {<OpenLayers.Feature.Vector>} */ - 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; + select: function(feature) { + var cont = this.onBeforeSelect.call(this.scope, feature); + var layer = feature.layer; + if(cont !== false) { + cont = layer.events.triggerEvent("beforefeatureselected", { + feature: feature + }); + if(cont !== false) { + layer.selectedFeatures.push(feature); + this.highlight(feature); + // if the feature handler isn't involved in the feature + // selection (because the box handler is used or the + // feature is selected programatically) we fake the + // feature handler to allow unselecting on click + if(!this.handlers.feature.lastFeature) { + this.handlers.feature.lastFeature = layer.selectedFeatures[0]; + } + layer.events.triggerEvent("featureselected", {feature: feature}); + this.onSelect.call(this.scope, feature); } - - var obj = this.format.read(data) || {}; - - response.insertIds = obj.insertIds || []; - if (obj.success) { - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = obj; - } - options.callback.call(options.scope, response); } }, + + /** + * Method: unselect + * Remove feature from the layer's selectedFeature array, render the feature as + * normal, and call the onUnselect function. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + unselect: function(feature) { + var layer = feature.layer; + // Store feature style for restoration later + this.unhighlight(feature); + OpenLayers.Util.removeItem(layer.selectedFeatures, feature); + layer.events.triggerEvent("featureunselected", {feature: feature}); + this.onUnselect.call(this.scope, feature); + }, /** - * Method: filterDelete - * Send a request that deletes all features by their filter. - * + * Method: selectBox + * Callback from the handlers.box set up when <box> selection is true + * on. + * * Parameters: - * filter - {<OpenLayers.Filter>} filter + * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> } */ - 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 + selectBox: function(position) { + if (position instanceof OpenLayers.Bounds) { + var minXY = this.map.getLonLatFromPixel({ + x: position.left, + y: position.bottom + }); + var maxXY = this.map.getLonLatFromPixel({ + x: position.right, + y: position.top + }); + var bounds = new OpenLayers.Bounds( + minXY.lon, minXY.lat, maxXY.lon, maxXY.lat + ); + + // if multiple is false, first deselect currently selected features + if (!this.multipleSelect()) { + this.unselectAll(); } - }); - - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { - attributes: { - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + - options.featureType + + // because we're using a box, we consider we want multiple selection + var prevMultiple = this.multiple; + this.multiple = true; + var layers = this.layers || [this.layer]; + this.events.triggerEvent("boxselectionstart", {layers: layers}); + var layer; + for(var l=0; l<layers.length; ++l) { + layer = layers[l]; + for(var i=0, len = layer.features.length; i<len; ++i) { + var feature = layer.features[i]; + // check if the feature is displayed + if (!feature.getVisibility()) { + continue; + } + + if (this.geometryTypes == null || OpenLayers.Util.indexOf( + this.geometryTypes, feature.geometry.CLASS_NAME) > -1) { + if (bounds.toGeometry().intersects(feature.geometry)) { + if (OpenLayers.Util.indexOf(layer.selectedFeatures, feature) == -1) { + this.select(feature); + } + } + } + } } - }); - - if(options.featureNS) { - deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS); + this.multiple = prevMultiple; + this.events.triggerEvent("boxselectionend", {layers: layers}); } - 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: setMap + * Set the map property for the control. + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + setMap: function(map) { + this.handlers.feature.setMap(map); + if (this.box) { + this.handlers.box.setMap(map); + } + OpenLayers.Control.prototype.setMap.apply(this, arguments); + }, + /** - * 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). + * APIMethod: setLayer + * Attach a new layer to the control, overriding any existing layers. * * Parameters: - * response - {<OpenLayers.Protocol.Response>} + * layers - Array of {<OpenLayers.Layer.Vector>} or a single + * {<OpenLayers.Layer.Vector>} */ - abort: function(response) { - if (response) { - response.priv.abort(); + setLayer: function(layers) { + var isActive = this.active; + this.unselectAll(); + this.deactivate(); + if(this.layers) { + this.layer.destroy(); + this.layers = null; } + this.initLayer(layers); + this.handlers.feature.layer = this.layer; + if (isActive) { + this.activate(); + } }, - - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" + + CLASS_NAME: "OpenLayers.Control.SelectFeature" }); /* ====================================================================== OpenLayers/Handler/Point.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -51255,16 +52575,10 @@ * no point will be added. Default value is 5. */ pixelTolerance: 5, /** - * Property: touch - * {Boolean} Indcates the support of touch events. - */ - touch: false, - - /** * Property: lastTouchPx * {<OpenLayers.Pixel>} The last pixel used to know the distance between * two touches (for double touch). */ lastTouchPx: null, @@ -51357,11 +52671,10 @@ if (this.layer.map != null) { this.destroyFeature(true); this.layer.destroy(false); } this.layer = null; - this.touch = false; return true; }, /** * Method: destroyFeature @@ -51524,22 +52837,11 @@ * * Returns: * {Boolean} Allow event propagation */ touchstart: function(evt) { - if (!this.touch) { - this.touch = true; - // unregister mouse listeners - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - dblclick: this.dblclick, - scope: this - }); - } + this.startTouch(); this.lastTouchPx = evt.xy; return this.down(evt); }, /** @@ -51717,11 +53019,11 @@ }); /* ====================================================================== OpenLayers/Handler/Path.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -51990,10 +53292,20 @@ var components = geometry.components; var index = this.getCurrentPointIndex() - 1; var target = components[index]; var undone = geometry.removeComponent(target); if (undone) { + // On touch devices, set the current ("mouse location") point to + // match the last digitized point. + if (this.touch && index > 0) { + components = geometry.components; // safety + var lastpt = components[index - 1]; + var curptidx = this.getCurrentPointIndex(); + var curpt = components[curptidx]; + curpt.x = lastpt.x; + curpt.y = lastpt.y; + } if (!this.redoStack) { this.redoStack = []; } this.redoStack.push(target); this.drawFeature(); @@ -52325,11 +53637,11 @@ }; /* ====================================================================== OpenLayers/Control/CacheWrite.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -52586,11 +53898,11 @@ /* ====================================================================== OpenLayers/Control/PanPanel.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -52663,11 +53975,11 @@ }); /* ====================================================================== OpenLayers/Control/Attribution.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -52688,20 +54000,29 @@ /** * APIProperty: separator * {String} String used to separate layers. */ separator: ", ", - + /** * APIProperty: template - * {String} Template for the attribution. This has to include the substring - * "${layers}", which will be replaced by the layer specific + * {String} Template for the global attribution markup. This has to include the + * substring "${layers}", which will be replaced by the layer specific * attributions, separated by <separator>. The default is "${layers}". */ template: "${layers}", - + /** + * APIProperty: layerTemplate + * {String} Template for the layer specific attribution. This has to include + * the substrings "${href}" and "${title}", which will be replaced by + * the layer specific attribution object properties. + * The default is '<a href="${href}" target="_blank">${title}</a>'. + */ + layerTemplate: '<a href="${href}" target="_blank">${title}</a>', + + /** * Constructor: OpenLayers.Control.Attribution * * Parameters: * options - {Object} Options for control. */ @@ -52747,19 +54068,23 @@ /** * Method: updateAttribution * Update attribution string. */ updateAttribution: function() { - var attributions = []; + var attributions = [], attribution; if (this.map && this.map.layers) { for(var i=0, len=this.map.layers.length; i<len; i++) { var layer = this.map.layers[i]; if (layer.attribution && layer.getVisibility()) { + attribution = (typeof layer.attribution == "object") ? + OpenLayers.String.format( + this.layerTemplate, layer.attribution) : + layer.attribution; // add attribution only if attribution text is unique if (OpenLayers.Util.indexOf( - attributions, layer.attribution) === -1) { - attributions.push( layer.attribution ); + attributions, attribution) === -1) { + attributions.push( attribution ); } } } this.div.innerHTML = OpenLayers.String.format(this.template, { layers: attributions.join(this.separator) @@ -52771,11 +54096,11 @@ }); /* ====================================================================== OpenLayers/Kinetic.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -52950,14 +54275,165 @@ }, CLASS_NAME: "OpenLayers.Kinetic" }); /* ====================================================================== + OpenLayers/Format/WFSCapabilities/v2_0_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFSCapabilities.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities.v2_0_0 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - <OpenLayers.Format.XML> + */ +OpenLayers.Format.WFSCapabilities.v2_0_0 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wfs: "http://www.opengis.net/wfs/2.0", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows/1.1" + }, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "featureTypeList", + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wfs", + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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 raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + /** + * 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": { + "WFS_Capabilities": function(node, obj) { + this.readChildNodes(node, obj); + }, + "FeatureTypeList": function(node, request) { + request.featureTypeList = { + featureTypes: [] + }; + this.readChildNodes(node, request.featureTypeList); + }, + "FeatureType": function(node, featureTypeList) { + var featureType = {}; + this.readChildNodes(node, featureType); + featureTypeList.featureTypes.push(featureType); + }, + "Name": function(node, obj) { + var name = this.getChildValue(node); + if(name) { + var parts = name.split(":"); + obj.name = parts.pop(); + if(parts.length > 0) { + obj.featureNS = this.lookupNamespaceURI(node, parts[0]); + } + } + }, + "Title": function(node, obj) { + var title = this.getChildValue(node); + if(title) { + obj.title = title; + } + }, + "Abstract": function(node, obj) { + var abst = this.getChildValue(node); + if(abst) { + obj["abstract"] = abst; + } + }, + "DefaultCRS": function(node, obj) { + var defaultCRS = this.getChildValue(node); + if (defaultCRS) { + obj.srs = defaultCRS; + } + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v2_0_0" + +}); +/* ====================================================================== OpenLayers/Format/WPSExecute.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -53352,11 +54828,11 @@ }); /* ====================================================================== OpenLayers/Layer/GeoRSS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -53621,11 +55097,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_3.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -53636,10 +55112,18 @@ * Class: OpenLayers.Format.WMSCapabilities/v1_3 * Abstract base class for WMS Capabilities version 1.3.X. * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd * + * Note on <MinScaleDenominator> and <MaxScaleDenominator> parsing: If + * the <MinScaleDenominator> value is set to "0", no maxScale will be + * set on the layer object. If the <MaxScaleDenominator> value is set to + * "Infinity", no minScale will be set. This makes it easy to create proper + * {<OpenLayers.Layer.WMS>} configurations directly from the layer object + * literals returned by this format, because no minScale/maxScale modifications + * need to be made. + * * Inherits from: * - <OpenLayers.Format.WMSCapabilities.v1> */ OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class( OpenLayers.Format.WMSCapabilities.v1, { @@ -53692,14 +55176,20 @@ }, "northBoundLatitude": function(node, obj) { obj[3] = this.getChildValue(node); }, "MinScaleDenominator": function(node, obj) { - obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); + var maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); + if (maxScale != 0) { + obj.maxScale = maxScale; + } }, "MaxScaleDenominator": function(node, obj) { - obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16); + var minScale = parseFloat(this.getChildValue(node)).toPrecision(16); + if (minScale != Number.POSITIVE_INFINITY) { + obj.minScale = minScale; + } }, "Dimension": function(node, obj) { // dimension has extra attributes: default, multipleValues, // nearestValue, current which used to be part of Extent. It now // also contains the values. @@ -53753,11 +55243,11 @@ }); /* ====================================================================== OpenLayers/Format/SOSCapabilities.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -53805,11 +55295,11 @@ }); /* ====================================================================== OpenLayers/Layer/WMS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -54004,11 +55494,11 @@ * parameters. */ getURL: function (bounds) { bounds = this.adjustBounds(bounds); - var imageSize = this.getImageSize(); + var imageSize = this.getImageSize(bounds); var newParams = {}; // WMS 1.3 introduced axis order var reverseAxisOrder = this.reverseAxisOrder(); newParams.BBOX = this.encodeBBOX ? bounds.toBBOX(null, reverseAxisOrder) : @@ -54076,11 +55566,11 @@ }); /* ====================================================================== OpenLayers/Layer/KaMap.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -54272,11 +55762,11 @@ }); /* ====================================================================== OpenLayers/Format/WMC.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -54326,20 +55816,22 @@ name: layer.params["LAYERS"], title: layer.name, "abstract": layer.metadata["abstract"], dataURL: layer.metadata.dataURL, metadataURL: layer.metadataURL, + attribution: layer.attribution, server: { - version: layer.params["VERSION"], + version: layer.params["VERSION"], url: layer.url }, maxExtent: layer.maxExtent, transparent: layer.params["TRANSPARENT"], numZoomLevels: layer.numZoomLevels, units: layer.units, isBaseLayer: layer.isBaseLayer, opacity: layer.opacity == 1 ? undefined : layer.opacity, + gutter: layer.gutter == 0 ? undefined : layer.gutter, displayInLayerSwitcher: layer.displayInLayerSwitcher, singleTile: layer.singleTile, tileSize: (layer.singleTile || !layer.tileSize) ? undefined : {width: layer.tileSize.w, height: layer.tileSize.h}, minScale : (layer.options.resolutions || @@ -54458,11 +55950,11 @@ }); /* ====================================================================== OpenLayers/Format/WMC/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -54698,12 +56190,19 @@ */ read_ol_tileSize: function(layerContext, node) { var obj = {"width": node.getAttribute("width"), "height": node.getAttribute("height")}; layerContext.tileSize = obj; }, - + /** + * Method: read_ol_gutter + */ + read_ol_gutter: function(layerContext, node) { + layerContext.gutter = parseInt(this.getChildValue(node)); + }, + + /** * Method: read_ol_isBaseLayer */ read_ol_isBaseLayer: function(layerContext, node) { layerContext.isBaseLayer = (this.getChildValue(node) == "true"); }, @@ -54714,10 +56213,18 @@ read_ol_displayInLayerSwitcher: function(layerContext, node) { layerContext.displayInLayerSwitcher = (this.getChildValue(node) == "true"); }, /** + * Method: read_ol_attribution + */ + read_ol_attribution: function(obj, node) { + obj.attribution = {}; + this.runChildNodes(obj.attribution, node); + }, + + /** * Method: read_wmc_Server */ read_wmc_Server: function(layerContext, node) { layerContext.version = node.getAttribute("version"); layerContext.url = this.getOnlineResource_href(node); @@ -55416,12 +56923,42 @@ node.appendChild(this.write_wmc_URLType("MetadataURL", context.metadataURL)); } return node; }, - + /** + * Method: write_ol_attribution + * Create an attribution node given a layer attribution object. + * + * Parameters: + * attribution - {<Object>} or {<String>} A layer attribution object or string + * + * Returns: + * {Element} A ol:attribution element node. + */ + write_ol_attribution: function(attribution) { + if (typeof attribution == "string") { + attribution = {title: attribution}; + } + var node = this.createElementNS(this.namespaces.ol, "ol:attribution"); + node.appendChild(this.createElementDefaultNS( + "Title", attribution.title + )); + if (attribution.href) { + node.appendChild(this.write_wmc_OnlineResource(attribution.href)); + } + if (attribution.logo) { + node.appendChild( + this.write_wmc_URLType("LogoURL", + attribution.logo.href, attribution.logo) + ); + } + return node; + }, + + /** * Method: write_wmc_LayerExtension * Add OpenLayers specific layer parameters to an Extension element. * * Parameters: * context - {Object} A layer context object. @@ -55449,23 +56986,28 @@ this.namespaces.ol, "ol:tileSize" ); this.setAttributes(size, context.tileSize); node.appendChild(size); } - + var properties = [ "transparent", "numZoomLevels", "units", "isBaseLayer", - "opacity", "displayInLayerSwitcher", "singleTile" + "opacity", "displayInLayerSwitcher", "singleTile", "gutter" ]; var child; for(var i=0, len=properties.length; i<len; ++i) { child = this.createOLPropertyNode(context, properties[i]); if(child) { node.appendChild(child); } } + if (context.attribution) { + var attribution = this.write_ol_attribution(context.attribution); + node.appendChild(attribution); + } + return node; }, /** * Method: createOLPropertyNode @@ -55729,11 +57271,11 @@ }); /* ====================================================================== OpenLayers/Format/WMC/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -55882,11 +57424,11 @@ }); /* ====================================================================== OpenLayers/Format/XLS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -55954,11 +57496,11 @@ }); /* ====================================================================== OpenLayers/Format/XLS/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -56262,11 +57804,11 @@ }); /* ====================================================================== OpenLayers/Format/XLS/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -56311,14 +57853,416 @@ }); // Support non standard implementation OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; /* ====================================================================== + OpenLayers/Format/JSON.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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, + + /** + * Property: nativeJSON + * {Boolean} Does the browser support native json? + */ + nativeJSON: (function() { + return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function"); + })(), + + /** + * Constructor: OpenLayers.Format.JSON + * Create a new parser for JSON. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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) { + var object; + if (this.nativeJSON) { + object = JSON.parse(json, filter); + } else try { + /** + * 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. + */ + 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. + */ + 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); + } + } + } catch(e) { + // Fall through if the regexp test fails. + } + + if(this.keepData) { + this.data = object; + } + + return object; + }, + + /** + * 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.pretty && this.nativeJSON) ? + JSON.stringify(value) : + 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" + +}); +/* ====================================================================== OpenLayers/Renderer/SVG.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -56971,10 +58915,13 @@ if (drawOutline) { var outlineStyle = OpenLayers.Util.extend({}, style); outlineStyle.fontColor = outlineStyle.labelOutlineColor; outlineStyle.fontStrokeColor = outlineStyle.labelOutlineColor; outlineStyle.fontStrokeWidth = style.labelOutlineWidth; + if (style.labelOutlineOpacity) { + outlineStyle.fontOpacity = style.labelOutlineOpacity; + } delete outlineStyle.labelOutlineWidth; this.drawText(featureId, outlineStyle, location); } var resolution = this.getResolution(); @@ -57327,11 +59274,11 @@ }; /* ====================================================================== OpenLayers/Format/WMSDescribeLayer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -57384,11 +59331,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSDescribeLayer/v1_1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -57507,14 +59454,829 @@ // Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 OpenLayers.Format.WMSDescribeLayer.v1_1_0 = OpenLayers.Format.WMSDescribeLayer.v1_1_1; /* ====================================================================== + OpenLayers/Control/TextButtonPanel.js + ====================================================================== */ + +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Control/Panel.js + */ + +/** + * Class: OpenLayers.Control.TextButtonPanel + * The TextButtonPanel is a panel designed primarily to hold TextButton + * controls. By default it has a displayClass of olControlTextButtonPanel, + * which hooks it to a set of text-appropriate styles in the default stylesheet. + * + * Inherits from: + * - <OpenLayers.Control.Panel> + */ +OpenLayers.Control.TextButtonPanel = OpenLayers.Class( + OpenLayers.Control.Panel, { + + /** + * APIProperty: vertical + * {Boolean} Whether the button strip should appear vertically on the map. + */ + vertical: false, + + /** + * APIProperty: additionalClass + * {String} An additional class to be applied in addition to + * .olControlTextButtonPanel to allow for non-default positioning. + */ + additionalClass: null, + + /** + * Constructor: OpenLayers.Control.TextButtonPanel + * Create a panel for holding text-based button controls + * + * Parameters: + * options - {Object} + */ + + /** + * Method: draw + * Overrides the draw method in <OpenLayers.Control.Panel> by applying + * up to two additional CSS classes + * Returns: + * {DOMElement} + */ + draw: function() { + OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); + this.setOrientationClass(); + this.setAdditionalClass(); + return this.div; + }, + + /** + * Method: redraw + * Overrides the redraw method in <OpenLayers.Control.Panel> by setting + * the orientation class. + */ + redraw: function() { + OpenLayers.Control.Panel.prototype.redraw.apply(this, arguments); + this.setOrientationClass(); + }, + + /** + * Method: setOrientationClass + * Adds the "vertical" class if this TextButtonPanel should have a vertical, + * rather than horizontal, layout. + */ + setOrientationClass: function() { + if (this.vertical) { + OpenLayers.Element.addClass(this.div, "vertical"); + } + else { + OpenLayers.Element.removeClass(this.div, "vertical"); + } + }, + + /** + * APIMethod: setAdditionalClass + * Sets an additional CSS class for this TextButtonPanel + * (for example, to override the default placement). This + * allows more than one TextButtonPanel to exist on the map + * at once. + */ + setAdditionalClass: function() { + if (!!this.additionalClass) { + OpenLayers.Element.addClass(this.div, this.additionalClass); + } + }, + + CLASS_NAME: "OpenLayers.Control.TextButtonPanel" +}); +/* ====================================================================== + OpenLayers/Control/ScaleLine.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository 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, + + /** + * APIProperty: geodesic + * {Boolean} Use geodesic measurement. Default is false. The recommended + * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to + * true, the scale will be calculated based on the horizontal size of the + * pixel in the center of the map viewport. + */ + geodesic: false, + + /** + * 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. + */ + + /** + * Method: draw + * + * Returns: + * {DOMElement} + */ + draw: function() { + OpenLayers.Control.prototype.draw.apply(this, arguments); + if (!this.eTop) { + // 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]; + var geodesicRatio = 1; + if(this.geodesic === true) { + var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || + 0.000001) * this.maxWidth; + var maxSizeKilometers = maxSizeData / inches["km"]; + geodesicRatio = maxSizeGeodesic / maxSizeKilometers; + maxSizeData *= geodesicRatio; + } + + // 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 / geodesicRatio; + var bottomPx = bottomMax / res / geodesicRatio; + + // 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" +}); + +/* ====================================================================== + OpenLayers/Icon.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/BaseTypes/Class.js + */ + +/** + * 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>|Object} An OpenLayers.Size or + * an object with a 'w' and 'h' properties. + */ + size: null, + + /** + * Property: offset + * {<OpenLayers.Pixel>|Object} distance in pixels to offset the + * image when being rendered. An OpenLayers.Pixel or an object + * with a 'x' and 'y' properties. + */ + offset: null, + + /** + * Property: calculateOffset + * {Function} Function to calculate the offset (based on the size) + */ + calculateOffset: null, + + /** + * Property: imageDiv + * {DOMElement} + */ + imageDiv: null, + + /** + * Property: px + * {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object + * with a 'x' and 'y' properties. + */ + px: null, + + /** + * Constructor: OpenLayers.Icon + * Creates an icon, which is an image tag in a div. + * + * url - {String} + * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or an + * object with a 'w' and 'h' + * properties. + * offset - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an + * object with a 'x' and 'y' + * properties. + * calculateOffset - {Function} + */ + initialize: function(url, size, offset, calculateOffset) { + this.url = url; + this.size = size || {w: 20, h: 20}; + this.offset = offset || {x: -(this.size.w/2), y: -(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>|Object} An OpenLayers.Size or + * an object with a 'w' and 'h' properties. + */ + 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>|Object} An OpenLayers.Pixel or an + * object with a 'x' and 'y' properties. + * + * 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>|Object} the pixel position to move to. + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. + */ + 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); + } + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { + x: this.px.x + this.offset.x, + y: this.px.y + this.offset.y + }); + } + } + }, + + /** + * 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" +}); +/* ====================================================================== + OpenLayers/Marker.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/BaseTypes/Class.js + * @requires OpenLayers/Events.js + * @requires OpenLayers/Icon.js + */ + +/** + * Class: OpenLayers.Marker + * Instances of OpenLayers.Marker are a combination of a + * <OpenLayers.LonLat> and an <OpenLayers.Icon>. + * + * Markers are generally added to a special layer called + * <OpenLayers.Layer.Markers>. + * + * Example: + * (code) + * var markers = new OpenLayers.Layer.Markers( "Markers" ); + * map.addLayer(markers); + * + * var size = new OpenLayers.Size(21,25); + * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); + * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); + * + * (end) + * + * Note that if you pass an icon into the Marker constructor, it will take + * that icon and use it. This means that you should not share icons between + * markers -- you use them once, but you should clone() for any additional + * markers using that same icon. + */ +OpenLayers.Marker = OpenLayers.Class({ + + /** + * Property: icon + * {<OpenLayers.Icon>} The icon used by this marker. + */ + icon: null, + + /** + * Property: lonlat + * {<OpenLayers.LonLat>} location of object + */ + lonlat: null, + + /** + * Property: events + * {<OpenLayers.Events>} the event handler. + */ + events: null, + + /** + * Property: map + * {<OpenLayers.Map>} the map this marker is attached to + */ + map: null, + + /** + * Constructor: OpenLayers.Marker + * + * Parameters: + * lonlat - {<OpenLayers.LonLat>} the position of this marker + * icon - {<OpenLayers.Icon>} the icon for this marker + */ + initialize: function(lonlat, icon) { + this.lonlat = lonlat; + + var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); + if (this.icon == null) { + this.icon = newIcon; + } else { + this.icon.url = newIcon.url; + this.icon.size = newIcon.size; + this.icon.offset = newIcon.offset; + this.icon.calculateOffset = newIcon.calculateOffset; + } + this.events = new OpenLayers.Events(this, this.icon.imageDiv); + }, + + /** + * APIMethod: destroy + * Destroy the marker. You must first remove the marker from any + * layer which it has been added to, or you will get buggy behavior. + * (This can not be done within the marker since the marker does not + * know which layer it is attached to.) + */ + destroy: function() { + // erase any drawn features + this.erase(); + + this.map = null; + + this.events.destroy(); + this.events = null; + + if (this.icon != null) { + this.icon.destroy(); + this.icon = null; + } + }, + + /** + * Method: draw + * Calls draw on the icon, and returns that output. + * + * Parameters: + * px - {<OpenLayers.Pixel>} + * + * Returns: + * {DOMElement} A new DOM Image with this marker's icon set at the + * location passed-in + */ + draw: function(px) { + return this.icon.draw(px); + }, + + /** + * Method: erase + * Erases any drawn elements for this marker. + */ + erase: function() { + if (this.icon != null) { + this.icon.erase(); + } + }, + + /** + * Method: moveTo + * Move the marker to the new location. + * + * Parameters: + * px - {<OpenLayers.Pixel>|Object} the pixel position to move to. + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. + */ + moveTo: function (px) { + if ((px != null) && (this.icon != null)) { + this.icon.moveTo(px); + } + this.lonlat = this.map.getLonLatFromLayerPx(px); + }, + + /** + * APIMethod: isDrawn + * + * Returns: + * {Boolean} Whether or not the marker is drawn. + */ + isDrawn: function() { + var isDrawn = (this.icon && this.icon.isDrawn()); + return isDrawn; + }, + + /** + * Method: onScreen + * + * Returns: + * {Boolean} Whether or not the marker is currently visible on screen. + */ + onScreen:function() { + + var onScreen = false; + if (this.map) { + var screenBounds = this.map.getExtent(); + onScreen = screenBounds.containsLonLat(this.lonlat); + } + return onScreen; + }, + + /** + * Method: inflate + * Englarges the markers icon by the specified ratio. + * + * Parameters: + * inflate - {float} the ratio to enlarge the marker by (passing 2 + * will double the size). + */ + inflate: function(inflate) { + if (this.icon) { + this.icon.setSize({ + w: this.icon.size.w * inflate, + h: this.icon.size.h * inflate + }); + } + }, + + /** + * Method: setOpacity + * Change the opacity of the marker by changin the opacity of + * its icon + * + * Parameters: + * opacity - {float} Specified as fraction (0.4, etc) + */ + setOpacity: function(opacity) { + this.icon.setOpacity(opacity); + }, + + /** + * Method: setUrl + * Change URL of the Icon Image. + * + * url - {String} + */ + setUrl: function(url) { + this.icon.setUrl(url); + }, + + /** + * Method: display + * Hide or show the icon + * + * display - {Boolean} + */ + display: function(display) { + this.icon.display(display); + }, + + CLASS_NAME: "OpenLayers.Marker" +}); + + +/** + * Function: defaultIcon + * Creates a default <OpenLayers.Icon>. + * + * Returns: + * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker + */ +OpenLayers.Marker.defaultIcon = function() { + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), + {w: 21, h: 25}, {x: -10.5, y: -25}); +}; + + +/* ====================================================================== OpenLayers/Popup.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -58576,1450 +61338,14 @@ OpenLayers.Popup.HEIGHT = 200; OpenLayers.Popup.COLOR = "white"; OpenLayers.Popup.OPACITY = 1; OpenLayers.Popup.BORDER = "0px"; /* ====================================================================== - OpenLayers/Control/ScaleLine.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository 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, - - /** - * APIProperty: geodesic - * {Boolean} Use geodesic measurement. Default is false. The recommended - * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to - * true, the scale will be calculated based on the horizontal size of the - * pixel in the center of the map viewport. - */ - geodesic: false, - - /** - * 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. - */ - - /** - * Method: draw - * - * Returns: - * {DOMElement} - */ - draw: function() { - OpenLayers.Control.prototype.draw.apply(this, arguments); - if (!this.eTop) { - // 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]; - var geodesicRatio = 1; - if(this.geodesic === true) { - var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || - 0.000001) * this.maxWidth; - var maxSizeKilometers = maxSizeData / inches["km"]; - geodesicRatio = maxSizeGeodesic / maxSizeKilometers; - maxSizeData *= geodesicRatio; - } - - // 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 / geodesicRatio; - var bottomPx = bottomMax / res / geodesicRatio; - - // 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" -}); - -/* ====================================================================== - OpenLayers/Icon.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * 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>|Object} An OpenLayers.Size or - * an object with a 'w' and 'h' properties. - */ - size: null, - - /** - * Property: offset - * {<OpenLayers.Pixel>|Object} distance in pixels to offset the - * image when being rendered. An OpenLayers.Pixel or an object - * with a 'x' and 'y' properties. - */ - offset: null, - - /** - * Property: calculateOffset - * {Function} Function to calculate the offset (based on the size) - */ - calculateOffset: null, - - /** - * Property: imageDiv - * {DOMElement} - */ - imageDiv: null, - - /** - * Property: px - * {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object - * with a 'x' and 'y' properties. - */ - px: null, - - /** - * Constructor: OpenLayers.Icon - * Creates an icon, which is an image tag in a div. - * - * url - {String} - * size - {<OpenLayers.Size>|Object} An OpenLayers.Size or an - * object with a 'w' and 'h' - * properties. - * offset - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an - * object with a 'x' and 'y' - * properties. - * calculateOffset - {Function} - */ - initialize: function(url, size, offset, calculateOffset) { - this.url = url; - this.size = size || {w: 20, h: 20}; - this.offset = offset || {x: -(this.size.w/2), y: -(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>|Object} An OpenLayers.Size or - * an object with a 'w' and 'h' properties. - */ - 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>|Object} An OpenLayers.Pixel or an - * object with a 'x' and 'y' properties. - * - * 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>|Object} the pixel position to move to. - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. - */ - 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); - } - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { - x: this.px.x + this.offset.x, - y: this.px.y + this.offset.y - }); - } - } - }, - - /** - * 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" -}); -/* ====================================================================== - OpenLayers/Marker.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Events.js - * @requires OpenLayers/Icon.js - */ - -/** - * Class: OpenLayers.Marker - * Instances of OpenLayers.Marker are a combination of a - * <OpenLayers.LonLat> and an <OpenLayers.Icon>. - * - * Markers are generally added to a special layer called - * <OpenLayers.Layer.Markers>. - * - * Example: - * (code) - * var markers = new OpenLayers.Layer.Markers( "Markers" ); - * map.addLayer(markers); - * - * var size = new OpenLayers.Size(21,25); - * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); - * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); - * - * (end) - * - * Note that if you pass an icon into the Marker constructor, it will take - * that icon and use it. This means that you should not share icons between - * markers -- you use them once, but you should clone() for any additional - * markers using that same icon. - */ -OpenLayers.Marker = OpenLayers.Class({ - - /** - * Property: icon - * {<OpenLayers.Icon>} The icon used by this marker. - */ - icon: null, - - /** - * Property: lonlat - * {<OpenLayers.LonLat>} location of object - */ - lonlat: null, - - /** - * Property: events - * {<OpenLayers.Events>} the event handler. - */ - events: null, - - /** - * Property: map - * {<OpenLayers.Map>} the map this marker is attached to - */ - map: null, - - /** - * Constructor: OpenLayers.Marker - * - * Parameters: - * lonlat - {<OpenLayers.LonLat>} the position of this marker - * icon - {<OpenLayers.Icon>} the icon for this marker - */ - initialize: function(lonlat, icon) { - this.lonlat = lonlat; - - var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); - if (this.icon == null) { - this.icon = newIcon; - } else { - this.icon.url = newIcon.url; - this.icon.size = newIcon.size; - this.icon.offset = newIcon.offset; - this.icon.calculateOffset = newIcon.calculateOffset; - } - this.events = new OpenLayers.Events(this, this.icon.imageDiv); - }, - - /** - * APIMethod: destroy - * Destroy the marker. You must first remove the marker from any - * layer which it has been added to, or you will get buggy behavior. - * (This can not be done within the marker since the marker does not - * know which layer it is attached to.) - */ - destroy: function() { - // erase any drawn features - this.erase(); - - this.map = null; - - this.events.destroy(); - this.events = null; - - if (this.icon != null) { - this.icon.destroy(); - this.icon = null; - } - }, - - /** - * Method: draw - * Calls draw on the icon, and returns that output. - * - * Parameters: - * px - {<OpenLayers.Pixel>} - * - * Returns: - * {DOMElement} A new DOM Image with this marker's icon set at the - * location passed-in - */ - draw: function(px) { - return this.icon.draw(px); - }, - - /** - * Method: erase - * Erases any drawn elements for this marker. - */ - erase: function() { - if (this.icon != null) { - this.icon.erase(); - } - }, - - /** - * Method: moveTo - * Move the marker to the new location. - * - * Parameters: - * px - {<OpenLayers.Pixel>|Object} the pixel position to move to. - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. - */ - moveTo: function (px) { - if ((px != null) && (this.icon != null)) { - this.icon.moveTo(px); - } - this.lonlat = this.map.getLonLatFromLayerPx(px); - }, - - /** - * APIMethod: isDrawn - * - * Returns: - * {Boolean} Whether or not the marker is drawn. - */ - isDrawn: function() { - var isDrawn = (this.icon && this.icon.isDrawn()); - return isDrawn; - }, - - /** - * Method: onScreen - * - * Returns: - * {Boolean} Whether or not the marker is currently visible on screen. - */ - onScreen:function() { - - var onScreen = false; - if (this.map) { - var screenBounds = this.map.getExtent(); - onScreen = screenBounds.containsLonLat(this.lonlat); - } - return onScreen; - }, - - /** - * Method: inflate - * Englarges the markers icon by the specified ratio. - * - * Parameters: - * inflate - {float} the ratio to enlarge the marker by (passing 2 - * will double the size). - */ - inflate: function(inflate) { - if (this.icon) { - this.icon.setSize({ - w: this.icon.size.w * inflate, - h: this.icon.size.h * inflate - }); - } - }, - - /** - * Method: setOpacity - * Change the opacity of the marker by changin the opacity of - * its icon - * - * Parameters: - * opacity - {float} Specified as fraction (0.4, etc) - */ - setOpacity: function(opacity) { - this.icon.setOpacity(opacity); - }, - - /** - * Method: setUrl - * Change URL of the Icon Image. - * - * url - {String} - */ - setUrl: function(url) { - this.icon.setUrl(url); - }, - - /** - * Method: display - * Hide or show the icon - * - * display - {Boolean} - */ - display: function(display) { - this.icon.display(display); - }, - - CLASS_NAME: "OpenLayers.Marker" -}); - - -/** - * Function: defaultIcon - * Creates a default <OpenLayers.Icon>. - * - * Returns: - * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker - */ -OpenLayers.Marker.defaultIcon = function() { - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), - {w: 21, h: 25}, {x: -10.5, y: -25}); -}; - - -/* ====================================================================== - OpenLayers/Format/GeoJSON.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository 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, { - - /** - * APIProperty: ignoreExtraDims - * {Boolean} Ignore dimensions higher than 2 when reading geometry - * coordinates. - */ - ignoreExtraDims: false, - - /** - * Constructor: OpenLayers.Format.GeoJSON - * Create a new parser for GeoJSON. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * 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(!(OpenLayers.Util.isArray(obj.geometries))) { - 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(!(OpenLayers.Util.isArray(obj.coordinates))) { - 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 (this.ignoreExtraDims == false && - 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(OpenLayers.Util.isArray(obj)) { - 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": "name", - "properties": { - "name": "urn:ogc:def:crs:OGC:1.3:CRS84" - } - }; - } else { - crs = { - "type": "name", - "properties": { - "name": "EPSG:" + 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]); - var json = { - "type": "Feature", - "properties": feature.attributes, - "geometry": geom - }; - if (feature.fid != null) { - json.id = feature.fid; - } - return json; - }, - - /** - * 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: - * multilinestring - {<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" - -}); -/* ====================================================================== OpenLayers/Strategy/Paging.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -60252,11 +61578,11 @@ }); /* ====================================================================== OpenLayers/Popup/Anchored.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -60451,11 +61777,11 @@ }); /* ====================================================================== OpenLayers/Popup/Framed.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -60798,11 +62124,11 @@ }); /* ====================================================================== OpenLayers/Handler/Box.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -61046,11 +62372,11 @@ }); /* ====================================================================== OpenLayers/Control/ZoomBox.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -61117,11 +62443,12 @@ * Parameters: * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>} */ zoomBox: function (position) { if (position instanceof OpenLayers.Bounds) { - var bounds; + var bounds, + targetCenterPx = position.getCenterPixel(); if (!this.out) { var minXY = this.map.getLonLatFromPixel({ x: position.left, y: position.bottom }); @@ -61130,47 +62457,59 @@ y: position.top }); 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 pixWidth = position.right - position.left; + var pixHeight = position.bottom - position.top; 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 center = this.map.getLonLatFromPixel(targetCenterPx); 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; bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax); } // always zoom in/out - var lastZoom = this.map.getZoom(); - this.map.zoomToExtent(bounds); + var lastZoom = this.map.getZoom(), + size = this.map.getSize(), + centerPx = {x: size.w / 2, y: size.h / 2}, + zoom = this.map.getZoomForExtent(bounds), + oldRes = this.map.getResolution(), + newRes = this.map.getResolutionForZoom(zoom); + if (oldRes == newRes) { + this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)); + } else { + var zoomOriginPx = { + x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / + (oldRes - newRes), + y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / + (oldRes - newRes) + }; + this.map.zoomTo(zoom, zoomOriginPx); + } if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){ this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); } } else if (this.zoomOnClick) { // it's a pixel if (!this.out) { - this.map.setCenter(this.map.getLonLatFromPixel(position), - this.map.getZoom() + 1); + this.map.zoomTo(this.map.getZoom() + 1, position); } else { - this.map.setCenter(this.map.getLonLatFromPixel(position), - this.map.getZoom() - 1); + this.map.zoomTo(this.map.getZoom() - 1, position); } } }, CLASS_NAME: "OpenLayers.Control.ZoomBox" }); /* ====================================================================== OpenLayers/Control/DragPan.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -61200,15 +62539,16 @@ panned: false, /** * Property: interval * {Integer} The number of milliseconds that should ellapse before - * panning the map again. Defaults to 1 millisecond. In most cases - * you won't want to change this value. For slow machines/devices - * larger values can be tried out. + * panning the map again. Defaults to 0 milliseconds, which means that + * no separate cycle is used for panning. In most cases you won't want + * to change this value. For slow machines/devices larger values can be + * tried out. */ - interval: 1, + interval: 0, /** * APIProperty: documentDrag * {Boolean} If set to true, mouse dragging will continue even if the * mouse cursor leaves the map viewport. Default is false. @@ -61224,15 +62564,15 @@ /** * APIProperty: enableKinetic * {Boolean} Set this option to enable "kinetic dragging". Can be * set to true or to an object. If set to an object this * object will be passed to the {<OpenLayers.Kinetic>} - * constructor. Defaults to false. - * If you set this property, you should ensure that - * OpenLayers/Kinetic.js is included in your build config + * constructor. Defaults to true. + * To get kinetic dragging, ensure that OpenLayers/Kinetic.js is + * included in your build config. */ - enableKinetic: false, + enableKinetic: true, /** * APIProperty: kineticInterval * {Integer} Interval in milliseconds between 2 steps in the "kinetic * scrolling". Applies only if enableKinetic is set. Defaults @@ -61245,11 +62585,11 @@ * Method: draw * Creates a Drag handler, using <panMap> and * <panMapDone> as callbacks. */ draw: function() { - if(this.enableKinetic) { + if (this.enableKinetic && OpenLayers.Kinetic) { var config = {interval: this.kineticInterval}; if(typeof this.enableKinetic === "object") { config = OpenLayers.Util.extend(config, this.enableKinetic); } this.kinetic = new OpenLayers.Kinetic(config); @@ -61325,11 +62665,11 @@ }); /* ====================================================================== OpenLayers/Control/Navigation.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -61404,11 +62744,13 @@ zoomWheelEnabled: true, /** * Property: mouseWheelOptions * {Object} Options passed to the MouseWheel control (only useful if - * <zoomWheelEnabled> is set to true) + * <zoomWheelEnabled> is set to true). Default is no options for maps + * with fractionalZoom set to true, otherwise + * {cumulative: false, interval: 50, maxDelta: 6} */ mouseWheelOptions: null, /** * APIProperty: handleRightClicks @@ -61535,14 +62877,19 @@ ); this.zoomBox = new OpenLayers.Control.ZoomBox( {map: this.map, keyMask: this.zoomBoxKeyMask}); this.dragPan.draw(); this.zoomBox.draw(); + var wheelOptions = this.map.fractionalZoom ? {} : { + cumulative: false, + interval: 50, + maxDelta: 6 + }; this.handlers.wheel = new OpenLayers.Handler.MouseWheel( - this, {"up" : this.wheelUp, - "down": this.wheelDown}, - this.mouseWheelOptions ); + this, {up : this.wheelUp, down: this.wheelDown}, + OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions) + ); if (OpenLayers.Control.PinchZoom) { this.pinchZoom = new OpenLayers.Control.PinchZoom( OpenLayers.Util.extend( {map: this.map}, this.pinchZoomOptions)); } @@ -61565,23 +62912,21 @@ * * Parameters: * evt - {Event} */ defaultDblClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); - this.map.setCenter(newCenter, this.map.zoom + 1); + this.map.zoomTo(this.map.zoom + 1, evt.xy); }, /** * Method: defaultDblRightClick * * Parameters: * evt - {Event} */ defaultDblRightClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); - this.map.setCenter(newCenter, this.map.zoom - 1); + this.map.zoomTo(this.map.zoom - 1, evt.xy); }, /** * Method: wheelChange * @@ -61591,26 +62936,18 @@ */ wheelChange: function(evt, deltaZ) { if (!this.map.fractionalZoom) { deltaZ = Math.round(deltaZ); } - var currentZoom = this.map.getZoom(); - var newZoom = this.map.getZoom() + deltaZ; + var currentZoom = this.map.getZoom(), + newZoom = currentZoom + deltaZ; newZoom = Math.max(newZoom, 0); newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); if (newZoom === currentZoom) { return; } - var size = this.map.getSize(); - var deltaX = size.w/2 - evt.xy.x; - var deltaY = evt.xy.y - size.h/2; - var newRes = this.map.baseLayer.getResolutionForZoom(newZoom); - var zoomPoint = this.map.getLonLatFromPixel(evt.xy); - var newCenter = new OpenLayers.LonLat( - zoomPoint.lon + deltaX * newRes, - zoomPoint.lat + deltaY * newRes ); - this.map.setCenter( newCenter, newZoom ); + this.map.zoomTo(newZoom, evt.xy); }, /** * Method: wheelUp * User spun scroll wheel up @@ -61677,11 +63014,11 @@ }); /* ====================================================================== OpenLayers/Control/DrawFeature.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -61910,11 +63247,11 @@ }); /* ====================================================================== OpenLayers/Handler/Polygon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -62219,11 +63556,11 @@ }); /* ====================================================================== OpenLayers/Control/EditingToolbar.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -62304,11 +63641,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSGetFeatureInfo.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -62326,16 +63663,16 @@ /** * APIProperty: layerIdentifier * {String} All xml nodes containing this search criteria will populate an * internal array of layer nodes. - */ + */ layerIdentifier: '_layer', /** * APIProperty: featureIdentifier - * {String} All xml nodes containing this search criteria will populate an + * {String} All xml nodes containing this search criteria will populate an * internal array of feature nodes for each layer node found. */ featureIdentifier: '_feature', /** @@ -62394,12 +63731,12 @@ } else { result = data; } return result; }, - - + + /** * Method: read_msGMLOutput * Parse msGMLOutput nodes. * * Parameters: @@ -62418,29 +63755,29 @@ var layerName = node.nodeName; if (node.prefix) { layerName = layerName.split(':')[1]; } var layerName = layerName.replace(this.layerIdentifier, ''); - var featureNodes = this.getSiblingNodesByTagCriteria(node, + var featureNodes = this.getSiblingNodesByTagCriteria(node, this.featureIdentifier); if (featureNodes) { for (var j = 0; j < featureNodes.length; j++) { var featureNode = featureNodes[j]; var geomInfo = this.parseGeometry(featureNode); var attributes = this.parseAttributes(featureNode); - var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, + var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, attributes, null); feature.bounds = geomInfo.bounds; feature.type = layerName; response.push(feature); } } } } return response; }, - + /** * Method: read_FeatureInfoResponse * Parse FeatureInfoResponse nodes. * * Parameters: @@ -62456,11 +63793,11 @@ for(var i=0, len=featureNodes.length;i<len;i++) { var featureNode = featureNodes[i]; var geom = null; - // attributes can be actual attributes on the FIELDS tag, + // attributes can be actual attributes on the FIELDS tag, // or FIELD children var attributes = {}; var j; var jlen = featureNode.attributes.length; if (jlen > 0) { @@ -62471,11 +63808,11 @@ } else { var nodes = featureNode.childNodes; for (j=0, jlen=nodes.length; j<jlen; ++j) { var node = nodes[j]; if (node.nodeType != 3) { - attributes[node.getAttribute("name")] = + attributes[node.getAttribute("name")] = node.getAttribute("value"); } } } @@ -62486,22 +63823,22 @@ return response; }, /** * Method: getSiblingNodesByTagCriteria - * Recursively searches passed xml node and all it's descendant levels for - * nodes whose tagName contains the passed search string. This returns an - * array of all sibling nodes which match the criteria from the highest + * Recursively searches passed xml node and all it's descendant levels for + * nodes whose tagName contains the passed search string. This returns an + * array of all sibling nodes which match the criteria from the highest * hierarchial level from which a match is found. - * + * * Parameters: * node - {DOMElement} An xml node - * criteria - {String} Search string which will match some part of a tagName - * + * criteria - {String} Search string which will match some part of a tagName + * * Returns: * Array({DOMElement}) An array of sibling xml nodes - */ + */ getSiblingNodesByTagCriteria: function(node, criteria){ var nodes = []; var children, tagName, n, matchNodes, child; if (node && node.hasChildNodes()) { children = node.childNodes; @@ -62519,11 +63856,11 @@ } else { matchNodes = this.getSiblingNodesByTagCriteria( child, criteria); if(matchNodes.length > 0){ - (nodes.length == 0) ? + (nodes.length == 0) ? nodes = matchNodes : nodes.push(matchNodes); } } } @@ -62537,15 +63874,15 @@ * Parameters: * node - {<DOMElement>} * * Returns: * {Object} An attributes object. - * + * * Notes: * Assumes that attributes are direct child xml nodes of the passed node - * and contain only a single text node. - */ + * and contain only a single text node. + */ parseAttributes: function(node){ var attributes = {}; if (node.nodeType == 1) { var children = node.childNodes; var n = children.length; @@ -62555,38 +63892,46 @@ var grandchildren = child.childNodes; var name = (child.prefix) ? child.nodeName.split(":")[1] : child.nodeName; if (grandchildren.length == 0) { attributes[name] = null; - } else if (grandchildren.length == 1) { + } else if (grandchildren.length == 1 || + // to include separate big tag (with Firefox) + // without including boundedBy and geom. + grandchildren[0].nodeValue.replace( + this.regExes.trimSpace, "").length > 0) { var grandchild = grandchildren[0]; if (grandchild.nodeType == 3 || - grandchild.nodeType == 4) { - var value = grandchild.nodeValue.replace( - this.regExes.trimSpace, ""); - attributes[name] = value; + grandchild.nodeType == 4) { + // wholeText doesn't exist everywhere but we need it for FireFox + // see i.e.: http://msdn.microsoft.com/en-us/library/ie/ff974769%28v=vs.85%29.aspx + var attribute = grandchild.wholeText ? + grandchild.wholeText : + grandchild.nodeValue; + attributes[name] = attribute.replace( + this.regExes.trimSpace, ""); } } } } } return attributes; }, /** * Method: parseGeometry - * Parse the geometry and the feature bounds out of the node using + * Parse the geometry and the feature bounds out of the node using * Format.GML * * Parameters: * node - {<DOMElement>} * * Returns: * {Object} An object containing the geometry and the feature bounds */ parseGeometry: function(node) { - // we need to use the old Format.GML parser since we do not know the + // we need to use the old Format.GML parser since we do not know the // geometry name if (!this.gmlFormat) { this.gmlFormat = new OpenLayers.Format.GML(); } var feature = this.gmlFormat.parseFeature(node); @@ -62598,1139 +63943,1200 @@ } return {geometry: geometry, bounds: bounds}; }, CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" - -}); -/* ====================================================================== - Rico/license.js - ====================================================================== */ -/** - * @license Apache 2 - * - * Contains portions of Rico <http://openrico.org/> - * - * 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. - */ -/* ====================================================================== - Rico/Color.js - ====================================================================== */ - -/** - * @requires Rico/license.js - * @requires OpenLayers/Console.js - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/BaseTypes/Element.js - */ - - -/* - * This file has been edited substantially from the Rico-released version by - * the OpenLayers development team. - */ - -OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); - -OpenLayers.Rico = OpenLayers.Rico || {}; -OpenLayers.Rico.Color = OpenLayers.Class({ - - initialize: function(red, green, blue) { - this.rgb = { r: red, g : green, b : blue }; - }, - - setRed: function(r) { - this.rgb.r = r; - }, - - setGreen: function(g) { - this.rgb.g = g; - }, - - setBlue: function(b) { - this.rgb.b = b; - }, - - setHue: function(h) { - - // get an HSB model, and set the new hue... - var hsb = this.asHSB(); - hsb.h = h; - - // convert back to RGB... - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); - }, - - setSaturation: function(s) { - // get an HSB model, and set the new hue... - var hsb = this.asHSB(); - hsb.s = s; - - // convert back to RGB and set values... - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); - }, - - setBrightness: function(b) { - // get an HSB model, and set the new hue... - var hsb = this.asHSB(); - hsb.b = b; - - // convert back to RGB and set values... - this.rgb = OpenLayers.Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b ); - }, - - darken: function(percent) { - var hsb = this.asHSB(); - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0)); - }, - - brighten: function(percent) { - var hsb = this.asHSB(); - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1)); - }, - - blend: function(other) { - this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2); - this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2); - this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2); - }, - - isBright: function() { - var hsb = this.asHSB(); - return this.asHSB().b > 0.5; - }, - - isDark: function() { - return ! this.isBright(); - }, - - asRGB: function() { - return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; - }, - - asHex: function() { - return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); - }, - - asHSB: function() { - return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); - }, - - toString: function() { - return this.asHex(); - } - }); - -OpenLayers.Rico.Color.createFromHex = function(hexCode) { - if(hexCode.length==4) { - var shortHexCode = hexCode; - var hexCode = '#'; - for(var i=1;i<4;i++) { - hexCode += (shortHexCode.charAt(i) + -shortHexCode.charAt(i)); - } - } - if ( hexCode.indexOf('#') == 0 ) { - hexCode = hexCode.substring(1); - } - var red = hexCode.substring(0,2); - var green = hexCode.substring(2,4); - var blue = hexCode.substring(4,6); - return new OpenLayers.Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) ); -}; - -/** - * Factory method for creating a color from the background of - * an HTML element. - */ -OpenLayers.Rico.Color.createColorFromBackground = function(elem) { - - var actualColor = - OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), - "backgroundColor"); - - if ( actualColor == "transparent" && elem.parentNode ) { - return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); - } - if ( actualColor == null ) { - return new OpenLayers.Rico.Color(255,255,255); - } - if ( actualColor.indexOf("rgb(") == 0 ) { - var colors = actualColor.substring(4, actualColor.length - 1 ); - var colorArray = colors.split(","); - return new OpenLayers.Rico.Color( parseInt( colorArray[0] ), - parseInt( colorArray[1] ), - parseInt( colorArray[2] ) ); - - } - else if ( actualColor.indexOf("#") == 0 ) { - return OpenLayers.Rico.Color.createFromHex(actualColor); - } - else { - return new OpenLayers.Rico.Color(255,255,255); - } -}; - -OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { - - var red = 0; - var green = 0; - var blue = 0; - - if (saturation == 0) { - red = parseInt(brightness * 255.0 + 0.5); - green = red; - blue = red; - } - else { - var h = (hue - Math.floor(hue)) * 6.0; - var f = h - Math.floor(h); - var p = brightness * (1.0 - saturation); - var q = brightness * (1.0 - saturation * f); - var t = brightness * (1.0 - (saturation * (1.0 - f))); - - switch (parseInt(h)) { - case 0: - red = (brightness * 255.0 + 0.5); - green = (t * 255.0 + 0.5); - blue = (p * 255.0 + 0.5); - break; - case 1: - red = (q * 255.0 + 0.5); - green = (brightness * 255.0 + 0.5); - blue = (p * 255.0 + 0.5); - break; - case 2: - red = (p * 255.0 + 0.5); - green = (brightness * 255.0 + 0.5); - blue = (t * 255.0 + 0.5); - break; - case 3: - red = (p * 255.0 + 0.5); - green = (q * 255.0 + 0.5); - blue = (brightness * 255.0 + 0.5); - break; - case 4: - red = (t * 255.0 + 0.5); - green = (p * 255.0 + 0.5); - blue = (brightness * 255.0 + 0.5); - break; - case 5: - red = (brightness * 255.0 + 0.5); - green = (p * 255.0 + 0.5); - blue = (q * 255.0 + 0.5); - break; - } - } - - return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) }; -}; - -OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { - - var hue; - var saturation; - var brightness; - - var cmax = (r > g) ? r : g; - if (b > cmax) { - cmax = b; - } - var cmin = (r < g) ? r : g; - if (b < cmin) { - cmin = b; - } - brightness = cmax / 255.0; - if (cmax != 0) { - saturation = (cmax - cmin)/cmax; - } else { - saturation = 0; - } - if (saturation == 0) { - hue = 0; - } else { - var redc = (cmax - r)/(cmax - cmin); - var greenc = (cmax - g)/(cmax - cmin); - var bluec = (cmax - b)/(cmax - cmin); - - if (r == cmax) { - hue = bluec - greenc; - } else if (g == cmax) { - hue = 2.0 + redc - bluec; - } else { - hue = 4.0 + greenc - redc; - } - hue = hue / 6.0; - if (hue < 0) { - hue = hue + 1.0; - } - } - - return { h : hue, s : saturation, b : brightness }; -}; - /* ====================================================================== - Rico/Corner.js + OpenLayers/Format/GeoJSON.js ====================================================================== */ -/** - * @requires OpenLayers/Console.js - * @requires Rico/Color.js - */ - - -/* - * 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.Console.warn("OpenLayers.Rico is deprecated"); - -OpenLayers.Rico = OpenLayers.Rico || {}; -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; } -}; -/* ====================================================================== - OpenLayers/Popup/AnchoredBubble.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ - /** - * @requires OpenLayers/Popup/Anchored.js + * @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 - * @requires Rico/Corner.js */ /** - * Class: OpenLayers.Popup.AnchoredBubble - * This class is *deprecated*. Use {<OpenLayers.Popup.Anchored>} and - * round corners using CSS3's border-radius property. - * - * Inherits from: - * - <OpenLayers.Popup.Anchored> + * Class: OpenLayers.Format.GeoJSON + * Read and write GeoJSON. Create a new parser with the + * <OpenLayers.Format.GeoJSON> constructor. + * + * Inherits from: + * - <OpenLayers.Format.JSON> */ -OpenLayers.Popup.AnchoredBubble = - OpenLayers.Class(OpenLayers.Popup.Anchored, { +OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, { /** - * Property: rounded - * {Boolean} Has the popup been rounded yet? - */ - rounded: false, + * APIProperty: ignoreExtraDims + * {Boolean} Ignore dimensions higher than 2 when reading geometry + * coordinates. + */ + ignoreExtraDims: false, - /** - * Constructor: OpenLayers.Popup.AnchoredBubble - * + /** + * Constructor: OpenLayers.Format.GeoJSON + * Create a new parser for GeoJSON. + * * 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. + * options - {Object} An optional object whose properties will be set on + * this instance. */ - initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox, - closeBoxCallback) { - OpenLayers.Console.warn('AnchoredBubble is deprecated'); - - this.padding = new OpenLayers.Bounds( - 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE, - 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE - ); - OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments); - }, - - /** - * Method: draw - * + /** + * APIMethod: read + * Deserialize a GeoJSON string. + * * Parameters: - * px - {<OpenLayers.Pixel>} - * - * Returns: - * {DOMElement} Reference to a div that contains the drawn popup. + * 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>. */ - draw: function(px) { - - OpenLayers.Popup.Anchored.prototype.draw.apply(this, arguments); - - this.setContentHTML(); - - //set the popup color and opacity - this.setBackgroundColor(); - this.setOpacity(); - - return this.div; + 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: updateRelativePosition - * The popup has been moved to a new relative location, in which case - * we will want to re-do the rico corners. + * 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. */ - updateRelativePosition: function() { - this.setRicoCorners(); + 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; }, - + /** - * APIMethod: setSize - * + * Method: parseFeature + * Convert a feature object from GeoJSON into an + * <OpenLayers.Feature.Vector>. + * * Parameters: - * contentSize - {<OpenLayers.Size>} the new size for the popup's - * contents div (in pixels). + * obj - {Object} An object created from a GeoJSON object + * + * Returns: + * {<OpenLayers.Feature.Vector>} A feature. */ - setSize:function(contentSize) { - OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments); - - this.setRicoCorners(); - }, - + 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; + }, + /** - * APIMethod: setBackgroundColor - * + * Method: parseGeometry + * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>. + * * Parameters: - * color - {String} + * obj - {Object} An object created from a GeoJSON object + * + * Returns: + * {<OpenLayers.Geometry>} A geometry. */ - setBackgroundColor:function(color) { - if (color != undefined) { - this.backgroundColor = color; + parseGeometry: function(obj) { + if (obj == null) { + return null; } - - if (this.div != null) { - if (this.contentDiv != null) { - this.div.style.background = "transparent"; - OpenLayers.Rico.Corner.changeColor(this.groupDiv, - this.backgroundColor); + var geometry, collection = false; + if(obj.type == "GeometryCollection") { + if(!(OpenLayers.Util.isArray(obj.geometries))) { + 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(!(OpenLayers.Util.isArray(obj.coordinates))) { + 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; + }, /** - * APIMethod: setOpacity - * - * Parameters: - * opacity - {float} + * Property: parseCoords + * Object with properties corresponding to the GeoJSON geometry types. + * Property values are functions that do the actual parsing. */ - setOpacity:function(opacity) { - OpenLayers.Popup.Anchored.prototype.setOpacity.call(this, opacity); + 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 (this.ignoreExtraDims == false && + array.length != 2) { + throw "Only 2D points are supported: " + array; + } + return new OpenLayers.Geometry.Point(array[0], array[1]); + }, - if (this.div != null) { - if (this.groupDiv != null) { - OpenLayers.Rico.Corner.changeOpacity(this.groupDiv, - this.opacity); + /** + * 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]) + ]) + ]); } - }, - - /** - * Method: setBorder - * Always sets border to 0. Bubble Popups can not have a border. - * + + }, + + /** + * APIMethod: write + * Serialize a feature, geometry, array of features into a GeoJSON string. + * * Parameters: - * border - {Integer} + * 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. */ - setBorder:function(border) { - this.border = 0; - }, - - /** - * Method: setRicoCorners - * Update RICO corners according to the popup's current relative postion. - */ - setRicoCorners:function() { - - var corners = this.getCornersToRound(this.relativePosition); - var options = {corners: corners, - color: this.backgroundColor, - bgColor: "transparent", - blend: false}; - - if (!this.rounded) { - OpenLayers.Rico.Corner.round(this.div, options); - this.rounded = true; - } else { - OpenLayers.Rico.Corner.reRound(this.groupDiv, options); - //set the popup color and opacity - this.setBackgroundColor(); - this.setOpacity(); + write: function(obj, pretty) { + var geojson = { + "type": null + }; + if(OpenLayers.Util.isArray(obj)) { + 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: getCornersToRound - * + /** + * Method: createCRSObject + * Create the CRS object for an object. + * + * Parameters: + * object - {<OpenLayers.Feature.Vector>} + * * Returns: - * {String} The proper corners string ("tr tl bl br") for rico to round. + * {Object} An object which can be assigned to the crs property + * of a GeoJSON object. */ - getCornersToRound:function() { + 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": "name", + "properties": { + "name": "urn:ogc:def:crs:OGC:1.3:CRS84" + } + }; + } else { + crs = { + "type": "name", + "properties": { + "name": "EPSG:" + 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]); + var json = { + "type": "Feature", + "properties": feature.attributes, + "geometry": geom + }; + if (feature.fid != null) { + json.id = feature.fid; + } + return json; + }, + + /** + * 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; + }, - var corners = ['tl', 'tr', 'bl', 'br']; + /** + * 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]; + }, - //we want to round all the corners _except_ the opposite one. - var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition); - OpenLayers.Util.removeItem(corners, corner); + /** + * 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; + }, - return corners.join(" "); - }, + /** + * Method: extract.multilinestring + * Return an array of linestring arrays from a linestring. + * + * Parameters: + * multilinestring - {<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; + }, - CLASS_NAME: "OpenLayers.Popup.AnchoredBubble" -}); + /** + * 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; + } + -/** - * Constant: CORNER_SIZE - * {Integer} 5. Border space for the RICO corners. - */ -OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5; + }, + CLASS_NAME: "OpenLayers.Format.GeoJSON" + +}); /* ====================================================================== - OpenLayers/Strategy/BBOX.js + OpenLayers/Protocol/WFS/v1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Strategy.js - * @requires OpenLayers/Filter/Spatial.js + * @requires OpenLayers/Protocol/WFS.js */ /** - * Class: OpenLayers.Strategy.BBOX - * A simple strategy that reads new features when the viewport invalidates - * some bounds. + * Class: OpenLayers.Protocol.WFS.v1 + * Abstract class for for v1.0.0 and v1.1.0 protocol. * * Inherits from: - * - <OpenLayers.Strategy> + * - <OpenLayers.Protocol> */ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { /** - * Property: bounds - * {<OpenLayers.Bounds>} The current data bounds (in the same projection - * as the layer - not always the same projection as the map). + * Property: version + * {String} WFS version number. */ - bounds: null, + version: 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. + * Property: srsName + * {String} Name of spatial reference system. Default is "EPSG:4326". */ - ratio: 2, + 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" for WFS <version> 1.0, and null for higher versions. + */ + geometryName: "the_geom", + /** + * Property: maxFeatures + * {Integer} Optional maximum number of features to retrieve. + */ + + /** + * 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, + /** - * 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). + * Property: readFormat + * {<OpenLayers.Format>} For WFS requests it is possible to get a + * different output format than GML. In that case, we cannot parse + * the response with the default format (WFST) and we need a different + * format for reading. */ - resFactor: null, + readFormat: null, /** - * Property: response - * {<OpenLayers.Protocol.Response>} The protocol response object returned - * by the layer protocol. + * Property: readOptions + * {Object} Optional object to pass to format's read. */ - response: null, - + readOptions: null, + /** - * Constructor: OpenLayers.Strategy.BBOX - * Create a new BBOX strategy. + * 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 + * during the first query if GML is used as readFormat and + * featurePrefix is provided and matches the prefix used by the server + * for this featureType). + * featurePrefix - {String} Feature namespace alias (optional - only used + * for writing if featureNS is provided). Default is 'feature'. + * geometryName - {String} Name of geometry attribute. The default is + * 'the_geom' for WFS <version> 1.0, and null for higher versions. If + * null, it will be set to the name of the first geometry found in the + * first read operation. + * multi - {Boolean} If set to true, geometries will be casted to Multi + * geometries before they are written in a transaction. No casting will + * be done when reading features. */ + 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 (!options.geometryName && parseFloat(this.format.version) > 1.0) { + this.setGeometryName(null); + } + }, /** - * Method: activate - * Set up strategy with regard to reading new batches of remote data. - * - * Returns: - * {Boolean} The strategy was successfully activated. + * APIMethod: destroy + * Clean up the protocol. */ - activate: function() { - var activated = OpenLayers.Strategy.prototype.activate.call(this); - if(activated) { - this.layer.events.on({ - "moveend": this.update, - "refresh": this.update, - "visibilitychanged": this.update, - scope: this - }); - this.update(); + destroy: function() { + if(this.options && !this.options.format) { + this.format.destroy(); } - return activated; + this.format = null; + OpenLayers.Protocol.prototype.destroy.apply(this); }, - + /** - * Method: deactivate - * Tear down strategy with regard to reading new batches of remote data. - * - * Returns: - * {Boolean} The strategy was successfully deactivated. + * APIMethod: 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). + * + * Parameters: + * options - {Object} Options for the read operation, in addition to the + * options set on the instance (options set here will take precedence). + * + * To use a configured protocol to get e.g. a WFS hit count, applications + * could do the following: + * + * (code) + * protocol.read({ + * readOptions: {output: "object"}, + * resultType: "hits", + * maxFeatures: null, + * callback: function(resp) { + * // process resp.numberOfFeatures here + * } + * }); + * (end) + * + * To use a configured protocol to use WFS paging (if supported by the + * server), applications could do the following: + * + * (code) + * protocol.read({ + * startIndex: 0, + * count: 50 + * }); + * (end) + * + * To limit the attributes returned by the GetFeature request, applications + * can use the propertyNames option to specify the properties to include in + * the response: + * + * (code) + * protocol.read({ + * propertyNames: ["DURATION", "INTENSITY"] + * }); + * (end) */ - deactivate: function() { - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); - if(deactivated) { - this.layer.events.un({ - "moveend": this.update, - "refresh": this.update, - "visibilitychanged": this.update, - scope: this - }); - } - return deactivated; + read: function(options) { + OpenLayers.Protocol.prototype.read.apply(this, arguments); + 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: update - * Callback function called on "moveend" or "refresh" layer events. + * APIMethod: setFeatureType + * Change the feature type on the fly. * * Parameters: - * options - {Object} Optional object whose properties will determine - * the behaviour of this Strategy + * featureType - {String} Local (without prefix) feature typeName. + */ + setFeatureType: function(featureType) { + this.featureType = featureType; + this.format.featureType = featureType; + }, + + /** + * APIMethod: setGeometryName + * Sets the geometryName option after instantiation. * - * Valid options include: - * force - {Boolean} if true, new data must be unconditionally read. - * noAbort - {Boolean} if true, do not abort previous requests. + * Parameters: + * geometryName - {String} Name of geometry attribute. */ - update: function(options) { - var mapBounds = this.getMapBounds(); - if (mapBounds !== null && ((options && options.force) || - (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { - this.calculateBounds(mapBounds); - this.resolution = this.layer.map.getResolution(); - this.triggerRead(options); - } + setGeometryName: function(geometryName) { + this.geometryName = geometryName; + this.format.geometryName = geometryName; }, /** - * Method: getMapBounds - * Get the map bounds expressed in the same projection as this layer. + * Method: handleRead + * Deal with response from the read request. * - * Returns: - * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. + * Parameters: + * response - {<OpenLayers.Protocol.Response>} The response object to pass + * to the user callback. + * options - {Object} The user options passed to the read call. */ - getMapBounds: function() { - if (this.layer.map === null) { - return null; + handleRead: function(response, options) { + options = OpenLayers.Util.extend({}, options); + OpenLayers.Util.applyDefaults(options, this.options); + + if(options.callback) { + var request = response.priv; + if(request.status >= 200 && request.status < 300) { + // success + var result = this.parseResponse(request, options.readOptions); + if (result && result.success !== false) { + if (options.readOptions && options.readOptions.output == "object") { + OpenLayers.Util.extend(response, result); + } else { + response.features = result; + } + response.code = OpenLayers.Protocol.Response.SUCCESS; + } else { + // failure (service exception) + response.code = OpenLayers.Protocol.Response.FAILURE; + response.error = result; + } + } else { + // failure + response.code = OpenLayers.Protocol.Response.FAILURE; + } + options.callback.call(options.scope, response); } - var bounds = this.layer.map.getExtent(); - if(bounds && !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. + * Method: parseResponse + * Read HTTP response body and return features * * Parameters: - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be - * retrieved from the map object if not provided + * request - {XMLHttpRequest} The request object + * options - {Object} Optional object to pass to format's read * * Returns: - * {Boolean} + * {Object} or {Array({<OpenLayers.Feature.Vector>})} or + * {<OpenLayers.Feature.Vector>} + * An object with a features property, an array of features or a single + * feature. */ - invalidBounds: function(mapBounds) { - if(!mapBounds) { - mapBounds = this.getMapBounds(); + parseResponse: function(request, options) { + var doc = request.responseXML; + if(!doc || !doc.documentElement) { + doc = request.responseText; } - 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)); + if(!doc || doc.length <= 0) { + return null; } - return invalid; + var result = (this.readFormat !== null) ? this.readFormat.read(doc) : + this.format.read(doc, options); + if (!this.featureNS) { + var format = this.readFormat || this.format; + this.featureNS = format.featureNS; + // no need to auto-configure again on subsequent reads + format.autoConfig = false; + if (!this.geometryName) { + this.setGeometryName(format.geometryName); + } + } + return result; }, - + /** - * Method: calculateBounds + * 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: - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be - * retrieved from the map object if not provided + * features - {Array(<OpenLayers.Feature.Vector>)} + * options - {Object} + * + * Valid options properties: + * nativeElements - {Array({Object})} Array of objects with information for writing + * out <Native> elements, these objects have vendorId, safeToIgnore and + * value properties. The <Native> element is intended to allow access to + * vendor specific capabilities of any particular web feature server or + * datastore. + * + * Returns: + * {<OpenLayers.Protocol.Response>} A response object with a features + * property containing any insertIds and a priv property referencing + * the XMLHttpRequest object. */ - 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) - ); + 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, + headers: options.headers, + data: this.format.write(features, options), + callback: this.createCallback(this.handleCommit, response, options) + }); + + return response; }, /** - * Method: triggerRead - * + * Method: handleCommit + * Called when the commit request returns. + * * Parameters: - * options - {Object} Additional options for the protocol's read method - * (optional) - * - * Returns: - * {<OpenLayers.Protocol.Response>} The protocol response object - * returned by the layer protocol. + * response - {<OpenLayers.Protocol.Response>} The response object to pass + * to the user callback. + * options - {Object} The user options passed to the commit call. */ - triggerRead: function(options) { - if (this.response && !(options && options.noAbort === true)) { - this.layer.protocol.abort(this.response); - this.layer.events.triggerEvent("loadend"); + 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 || []; + if (obj.success) { + response.code = OpenLayers.Protocol.Response.SUCCESS; + } else { + response.code = OpenLayers.Protocol.Response.FAILURE; + response.error = obj; + } + options.callback.call(options.scope, response); } - var evt = {filter: this.createFilter()}; - this.layer.events.triggerEvent("loadstart", evt); - this.response = this.layer.protocol.read( - OpenLayers.Util.applyDefaults({ - filter: evt.filter, - callback: this.merge, - scope: this - }, options)); }, - + /** - * Method: createFilter - * Creates a spatial BBOX filter. If the layer that this strategy belongs - * to has a filter property, this filter will be combined with the BBOX - * filter. + * Method: filterDelete + * Send a request that deletes all features by their filter. * - * Returns - * {<OpenLayers.Filter>} The filter object. + * Parameters: + * filter - {<OpenLayers.Filter>} filter */ - createFilter: function() { - var filter = new OpenLayers.Filter.Spatial({ - type: OpenLayers.Filter.Spatial.BBOX, - value: this.bounds, - projection: this.layer.projection + 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 + } }); - if (this.layer.filter) { - filter = new OpenLayers.Filter.Logical({ - type: OpenLayers.Filter.Logical.AND, - filters: [this.layer.filter, filter] - }); + + 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); } - return filter; + 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: 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. + * 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: - * resp - {<OpenLayers.Protocol.Response>} The response object passed - * by the protocol. + * response - {<OpenLayers.Protocol.Response>} */ - merge: function(resp) { - this.layer.destroyFeatures(); - if (resp.success()) { - 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); - } - } else { - this.bounds = null; + abort: function(response) { + if (response) { + response.priv.abort(); } - this.response = null; - this.layer.events.triggerEvent("loadend", {response: resp}); }, - - CLASS_NAME: "OpenLayers.Strategy.BBOX" + + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" }); /* ====================================================================== OpenLayers/Format/SLD/v1_0_0_GeoServer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** + * @requires OpenLayers/BaseTypes.js * @requires OpenLayers/Format/SLD/v1_0_0.js */ /** * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer @@ -63776,11 +65182,11 @@ readers: OpenLayers.Util.applyDefaults({ "sld": OpenLayers.Util.applyDefaults({ "Priority": function(node, obj) { var value = this.readers.ogc._expression.call(this, node); if (value) { - obj.priority = value; + obj.priority = OpenLayers.String.trim(value); } }, "VendorOption": function(node, obj) { if (!obj.vendorOptions) { obj.vendorOptions = {}; @@ -63874,11 +65280,11 @@ }); /* ====================================================================== OpenLayers/Protocol/CSW.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -63908,11 +65314,11 @@ }; /* ====================================================================== OpenLayers/Protocol/WFS/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -63980,11 +65386,11 @@ }); /* ====================================================================== OpenLayers/Format/WMTSCapabilities.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -64054,10 +65460,13 @@ * layer - {String} The layer identifier. * * Optional config properties: * matrixSet - {String} The matrix set identifier, required if there is * more than one matrix set in the layer capabilities. + * projection - {String} The desired CRS when no matrixSet is specified. + * eg: "EPSG:3857". If the desired projection is not available, + * an error is thrown. * style - {String} The name of the style * format - {String} Image format for the layer. Default is the first * format returned in the GetCapabilities response. * param - {Object} The dimensions values eg: {"Year": "2012"} * @@ -64096,10 +65505,23 @@ // find the matrixSet definition var matrixSet; if (config.matrixSet) { matrixSet = contents.tileMatrixSets[config.matrixSet]; + } else if (config.projection) { + for (var i=0,l=layerDef.tileMatrixSetLinks.length;i<l;i++) { + if (contents.tileMatrixSets[ + layerDef.tileMatrixSetLinks[i].tileMatrixSet + ].supportedCRS.replace( + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3" + ) === config.projection) { + + matrixSet = contents.tileMatrixSets[ + layerDef.tileMatrixSetLinks[i].tileMatrixSet]; + break; + } + } } else if (layerDef.tileMatrixSetLinks.length >= 1) { matrixSet = contents.tileMatrixSets[ layerDef.tileMatrixSetLinks[0].tileMatrixSet]; } if (!matrixSet) { @@ -64122,11 +65544,10 @@ var http = capabilities.operationsMetadata.GetTile.dcp.http; // Get first get method if (http.get[0].constraints) { var constraints = http.get[0].constraints; var allowedValues = constraints.GetEncoding.allowedValues; - // The OGC documentation is not clear if we should use // REST or RESTful, ArcGis use RESTful, // and OpenLayers use REST. if (!allowedValues.KVP && (allowedValues.REST || allowedValues.RESTful)) { @@ -64149,20 +65570,52 @@ } var projection = config.projection || matrixSet.supportedCRS.replace( /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); var units = config.units || - (projection === "EPSG:4326" ? "degrees" : "m"); + (projection === ("EPSG:4326" || "OGC:CRS84") ? "degrees" : "m"); - var resolutions = []; - for (var mid in matrixSet.matrixIds) { - if (matrixSet.matrixIds.hasOwnProperty(mid)) { - resolutions.push( - matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / - OpenLayers.METERS_PER_INCH / - OpenLayers.INCHES_PER_UNIT[units]); + // compute server-supported resolutions array + var resolutions = [], minScaleDenominator, maxScaleDenominator, + reducedMatrixIds = [], tileMatrixSetLink, + tileMatrixSetLinks = layerDef.tileMatrixSetLinks; + var buildResolutionsArray = function(scaleDenominator) { + resolutions.push( + scaleDenominator * 0.28E-3 / OpenLayers.METERS_PER_INCH / + OpenLayers.INCHES_PER_UNIT[units] + ); + if (!minScaleDenominator || minScaleDenominator > scaleDenominator) { + minScaleDenominator = scaleDenominator; } + if (!maxScaleDenominator || maxScaleDenominator < scaleDenominator) { + maxScaleDenominator = scaleDenominator; + } + }; + for (var j=0, l=tileMatrixSetLinks.length; j<l; j++) { + tileMatrixSetLink = tileMatrixSetLinks[j]; + if (tileMatrixSetLink.tileMatrixSet === matrixSet.identifier) { + if (tileMatrixSetLink.tileMatrixSetLimits) { + // reformat matrixSet.matrixIds so that identifiers become keys + var tmpMatrixIds = {}, mid; + for (var k=0, ll=matrixSet.matrixIds.length; k<ll; k++) { + tmpMatrixIds[matrixSet.matrixIds[k].identifier] = matrixSet.matrixIds[k]; + } + // compute resolutions array + scale limits + for (var k=0, ll=tileMatrixSetLink.tileMatrixSetLimits.length; k<ll; k++) { + mid = tmpMatrixIds[tileMatrixSetLink.tileMatrixSetLimits[k].tileMatrix]; + reducedMatrixIds.push(mid); + buildResolutionsArray(mid.scaleDenominator); + } + } else { + // if there are no limits in the tileMatrixSetLink, + // use the resolutions from the full tile matrix set + for (var k=0, ll=matrixSet.matrixIds.length; k<ll; k++) { + buildResolutionsArray(matrixSet.matrixIds[k].scaleDenominator); + }; + } + break; + } } var url; if (requestEncoding === "REST" && layerDef.resourceUrls) { url = []; @@ -64172,12 +65625,11 @@ resourceUrl = layerDef.resourceUrls[t]; if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { url.push(resourceUrl.template); } } - } - else { + } else { var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; url = []; var constraint; for (var i = 0, ii = httpGet.length; i < ii; i++) { constraint = httpGet[i].constraints; @@ -64185,40 +65637,44 @@ GetEncoding.allowedValues[requestEncoding])) { url.push(httpGet[i].url); } } } - - return new OpenLayers.Layer.WMTS( - OpenLayers.Util.applyDefaults(config, { - url: url, - requestEncoding: requestEncoding, - name: layerDef.title, - style: style.identifier, - format: format, - matrixIds: matrixSet.matrixIds, - matrixSet: matrixSet.identifier, - projection: projection, - units: units, - resolutions: config.isBaseLayer === false ? undefined : - resolutions, - serverResolutions: resolutions, - tileFullExtent: matrixSet.bounds, - dimensions: dimensions, - params: params - }) - ); + + resolutions.sort(function(a,b){ + return b-a; + }); + var options = OpenLayers.Util.applyDefaults(config, { + url: url, + requestEncoding: requestEncoding, + name: layerDef.title, + style: style && style.identifier || "", + format: format, + matrixIds: reducedMatrixIds.length ? + reducedMatrixIds : matrixSet.matrixIds, + matrixSet: matrixSet.identifier, + projection: projection, + units: units, + tileFullExtent: matrixSet.bounds, + dimensions: dimensions, + params: params, + resolutions: config.isBaseLayer === false ? undefined : + resolutions, + serverResolutions: resolutions, + minScale: 1/Math.ceil(maxScaleDenominator), + maxScale: 1/Math.floor(minScaleDenominator) + }); + return new OpenLayers.Layer.WMTS(options); }, CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" - }); /* ====================================================================== OpenLayers/Layer/Google/v3.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -64229,11 +65685,17 @@ /** * Constant: OpenLayers.Layer.Google.v3 * * Mixin providing functionality specific to the Google Maps API v3. * - * To use this layer, you must include the GMaps v3 API in your html. + * To use this layer, you must include the GMaps v3 API in your html. To match + * Google's zoom animation better with OpenLayers animated zooming, configure + * your map with a zoomDuration of 10: + * + * (code) + * new OpenLayers.Map('map', {zoomDuration: 10}); + * (end) * * Note that this layer configures the google.maps.map object with the * "disableDefaultUI" option set to true. Using UI controls that the Google * Maps API provides is not supported by the OpenLayers API. */ @@ -64269,14 +65731,13 @@ */ animationEnabled: true, /** * Method: loadMapObject - * Load the GMap and register appropriate event listeners. If we can't - * load GMap2, then display a warning message. + * Load the GMap and register appropriate event listeners. */ - loadMapObject:function() { + loadMapObject: function() { if (!this.type) { this.type = google.maps.MapTypeId.ROADMAP; } var mapObject; var cache = OpenLayers.Layer.Google.cache[this.map.id]; @@ -64357,29 +65818,27 @@ } } var container = this.mapObject.getDiv(); if (visible === true) { if (container.parentNode !== map.div) { - map.div.appendChild(container); if (!cache.rendered) { + var me = this; google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { - cache.googleControl.appendChild(map.viewPortDiv); cache.rendered = true; + me.setGMapVisibility(me.getVisibility()); + me.moveTo(me.map.getCenter()); }); } else { + map.div.appendChild(container); cache.googleControl.appendChild(map.viewPortDiv); + google.maps.event.trigger(this.mapObject, 'resize'); } - google.maps.event.trigger(this.mapObject, 'resize'); } this.mapObject.setMapTypeId(type); - cache.displayed = this.id; - } else { - if (cache.googleControl.hasChildNodes()) { - map.div.appendChild(map.viewPortDiv); - map.div.removeChild(container); - } - delete cache.displayed; + } else if (cache.googleControl.hasChildNodes()) { + map.div.appendChild(map.viewPortDiv); + map.div.removeChild(container); } } }, /** @@ -64572,11 +66031,11 @@ }; /* ====================================================================== OpenLayers/Format/WPSDescribeProcess.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -64761,18 +66220,24 @@ }); /* ====================================================================== OpenLayers/Format/WKT.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Format.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 */ /** * Class: OpenLayers.Format.WKT * Class for reading and writing Well-Known Text. Create a new instance @@ -65151,16 +66616,16 @@ }); /* ====================================================================== OpenLayers/WPSProcess.js ====================================================================== */ -/** - * Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. - * + * full text of the license. */ + +/** * @requires OpenLayers/SingleFile.js */ /** * @requires OpenLayers/Geometry.js @@ -65656,16 +67121,16 @@ }); /* ====================================================================== OpenLayers/WPSClient.js ====================================================================== */ -/** - * Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. - * + * full text of the license. */ + +/** * @requires OpenLayers/SingleFile.js */ /** * @requires OpenLayers/Events.js @@ -65880,475 +67345,263 @@ CLASS_NAME: 'OpenLayers.WPSClient' }); /* ====================================================================== - OpenLayers/Format/CSWGetRecords/v2_0_2.js + OpenLayers/Format/Filter/v2_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Format/CSWGetRecords.js - * @requires OpenLayers/Format/Filter/v1_0_0.js - * @requires OpenLayers/Format/Filter/v1_1_0.js - * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + * @requires OpenLayers/Format/Filter/v2.js + * @requires OpenLayers/Format/GML/v3.js */ /** - * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 - * A format for creating CSWGetRecords v2.0.2 transactions. - * Create a new instance with the - * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. + * Class: OpenLayers.Format.Filter.v2_0_0 + * Writes fes:Filter version 2.0.0. * - * Inherits from: - * - <OpenLayers.Format.XML> + * Differences from the v1.0.0 parser: + * - uses GML v3 instead of GML v2 + * - reads matchCase attribute on fes:PropertyIsEqual and + * fes:PropertyIsNotEqual elements. + * - writes matchCase attribute from comparison filters of type EQUAL_TO, + * NOT_EQUAL_TO and LIKE. + * + * Inherits from: + * - <OpenLayers.Format.GML.v3> + * - <OpenLayers.Format.Filter.v1> */ -OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { +OpenLayers.Format.Filter.v2_0_0 = OpenLayers.Class( + OpenLayers.Format.GML.v3, OpenLayers.Format.Filter.v2, { /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. + * Constant: VERSION + * {String} 2.0.0 */ - namespaces: { - csw: "http://www.opengis.net/cat/csw/2.0.2", - dc: "http://purl.org/dc/elements/1.1/", - dct: "http://purl.org/dc/terms/", - gmd: "http://www.isotc211.org/2005/gmd", - geonet: "http://www.fao.org/geonetwork", - ogc: "http://www.opengis.net/ogc", - ows: "http://www.opengis.net/ows", - xlink: "http://www.w3.org/1999/xlink", - xsi: "http://www.w3.org/2001/XMLSchema-instance" - }, + VERSION: "2.0.0", /** - * Property: defaultPrefix - * {String} The default prefix (used by Format.XML). - */ - defaultPrefix: "csw", - - /** - * Property: version - * {String} CSW version number. - */ - version: "2.0.2", - - /** * Property: schemaLocation - * {String} http://www.opengis.net/cat/csw/2.0.2 - * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd + * {String} http://schemas.opengis.net/filter/2.0/filterAll.xsd */ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", + schemaLocation: "http://schemas.opengis.net/filter/2.0/filterAll.xsd", /** - * APIProperty: requestId - * {String} Value of the requestId attribute of the GetRecords element. - */ - requestId: null, - - /** - * APIProperty: resultType - * {String} Value of the resultType attribute of the GetRecords element, - * specifies the result type in the GetRecords response, "hits" is - * the default. - */ - resultType: null, - - /** - * APIProperty: outputFormat - * {String} Value of the outputFormat attribute of the GetRecords element, - * specifies the format of the GetRecords response, - * "application/xml" is the default. - */ - outputFormat: null, - - /** - * APIProperty: outputSchema - * {String} Value of the outputSchema attribute of the GetRecords element, - * specifies the schema of the GetRecords response. - */ - outputSchema: null, - - /** - * APIProperty: startPosition - * {String} Value of the startPosition attribute of the GetRecords element, - * specifies the start position (offset+1) for the GetRecords response, - * 1 is the default. - */ - startPosition: null, - - /** - * APIProperty: maxRecords - * {String} Value of the maxRecords attribute of the GetRecords element, - * specifies the maximum number of records in the GetRecords response, - * 10 is the default. - */ - maxRecords: null, - - /** - * APIProperty: DistributedSearch - * {String} Value of the csw:DistributedSearch element, used when writing - * a csw:GetRecords document. - */ - DistributedSearch: null, - - /** - * APIProperty: ResponseHandler - * {Array({String})} Values of the csw:ResponseHandler elements, used when - * writting a csw:GetRecords document. - */ - ResponseHandler: null, - - /** - * APIProperty: Query - * {String} Value of the csw:Query element, used when writing a csw:GetRecords - * document. - */ - Query: 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.CSWGetRecords.v2_0_2 - * A class for parsing and generating CSWGetRecords v2.0.2 transactions. + * 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} Optional object whose properties will be set on the - * instance. - * - * Valid options properties (documented as class properties): - * - requestId - * - resultType - * - outputFormat - * - outputSchema - * - startPosition - * - maxRecords - * - DistributedSearch - * - ResponseHandler - * - Query + * options - {Object} An optional object whose properties will be set on + * this instance. */ initialize: function(options) { - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + OpenLayers.Format.GML.v3.prototype.initialize.apply( + this, [options] + ); }, /** - * APIMethod: read - * Parse the response from a GetRecords request. - */ - 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); - 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: { - "csw": { - "GetRecordsResponse": function(node, obj) { - obj.records = []; - this.readChildNodes(node, obj); - var version = this.getAttributeNS(node, "", 'version'); - if (version != "") { - obj.version = version; - } + "fes": 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); }, - "RequestId": function(node, obj) { - obj.RequestId = this.getChildValue(node); + "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); }, - "SearchStatus": function(node, obj) { - obj.SearchStatus = {}; - var timestamp = this.getAttributeNS(node, "", 'timestamp'); - if (timestamp != "") { - obj.SearchStatus.timestamp = timestamp; - } - }, - "SearchResults": function(node, obj) { - this.readChildNodes(node, obj); - var attrs = node.attributes; - var SearchResults = {}; - for(var i=0, len=attrs.length; i<len; ++i) { - if ((attrs[i].name == "numberOfRecordsMatched") || - (attrs[i].name == "numberOfRecordsReturned") || - (attrs[i].name == "nextRecord")) { - SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); - } else { - SearchResults[attrs[i].name] = attrs[i].nodeValue; - } - } - obj.SearchResults = SearchResults; - }, - "SummaryRecord": function(node, obj) { - var record = {type: "SummaryRecord"}; - this.readChildNodes(node, record); - obj.records.push(record); - }, - "BriefRecord": function(node, obj) { - var record = {type: "BriefRecord"}; - this.readChildNodes(node, record); - obj.records.push(record); - }, - "DCMIRecord": function(node, obj) { - var record = {type: "DCMIRecord"}; - this.readChildNodes(node, record); - obj.records.push(record); - }, - "Record": function(node, obj) { - var record = {type: "Record"}; - this.readChildNodes(node, record); - obj.records.push(record); - }, - "*": function(node, obj) { - var name = node.localName || node.nodeName.split(":").pop(); - obj[name] = this.getChildValue(node); + "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("escapeChar"); + filter.value2regex(wildCard, singleChar, esc); + obj.filters.push(filter); } - }, - "geonet": { - "info": function(node, obj) { - var gninfo = {}; - this.readChildNodes(node, gninfo); - obj.gninfo = gninfo; - } - }, - "dc": { - // audience, contributor, coverage, creator, date, description, format, - // identifier, language, provenance, publisher, relation, rights, - // rightsHolder, source, subject, title, type, URI - "*": function(node, obj) { - var name = node.localName || node.nodeName.split(":").pop(); - if (!(OpenLayers.Util.isArray(obj[name]))) { - obj[name] = []; - } - var dc_element = {}; - var attrs = node.attributes; - for(var i=0, len=attrs.length; i<len; ++i) { - dc_element[attrs[i].name] = attrs[i].nodeValue; - } - dc_element.value = this.getChildValue(node); - if (dc_element.value != "") { - obj[name].push(dc_element); - } - } - }, - "dct": { - // abstract, modified, spatial - "*": function(node, obj) { - var name = node.localName || node.nodeName.split(":").pop(); - if (!(OpenLayers.Util.isArray(obj[name]))) { - obj[name] = []; - } - obj[name].push(this.getChildValue(node)); - } - }, - "ows": OpenLayers.Util.applyDefaults({ - "BoundingBox": function(node, obj) { - if (obj.bounds) { - obj.BoundingBox = [{crs: obj.projection, value: - [ - obj.bounds.left, - obj.bounds.bottom, - obj.bounds.right, - obj.bounds.top - ] - }]; - delete obj.projection; - delete obj.bounds; - } - OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( - this, arguments); - } - }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) + }, OpenLayers.Format.Filter.v2.prototype.readers["fes"]), + "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"] }, - - /** - * Method: write - * Given an configuration js object, write a CSWGetRecords request. - * - * Parameters: - * options - {Object} A object mapping the request. - * - * Returns: - * {String} A serialized CSWGetRecords request. - */ - write: function(options) { - var node = this.writeNode("csw:GetRecords", options); - node.setAttribute("xmlns:gmd", this.namespaces.gmd); - 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: { - "csw": { - "GetRecords": function(options) { - if (!options) { - options = {}; - } - var node = this.createElementNSPlus("csw:GetRecords", { - attributes: { - service: "CSW", - version: this.version, - requestId: options.requestId || this.requestId, - resultType: options.resultType || this.resultType, - outputFormat: options.outputFormat || this.outputFormat, - outputSchema: options.outputSchema || this.outputSchema, - startPosition: options.startPosition || this.startPosition, - maxRecords: options.maxRecords || this.maxRecords - } + "fes": OpenLayers.Util.applyDefaults({ + "PropertyIsEqualTo": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsEqualTo", { + attributes: {matchCase: filter.matchCase} }); - if (options.DistributedSearch || this.DistributedSearch) { - this.writeNode( - "csw:DistributedSearch", - options.DistributedSearch || this.DistributedSearch, - node - ); - } - var ResponseHandler = options.ResponseHandler || this.ResponseHandler; - if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { - // ResponseHandler must be a non-empty array - for(var i=0, len=ResponseHandler.length; i<len; i++) { - this.writeNode( - "csw:ResponseHandler", - ResponseHandler[i], - node - ); - } - } - this.writeNode("Query", options.Query || this.Query, node); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); return node; }, - "DistributedSearch": function(options) { - var node = this.createElementNSPlus("csw:DistributedSearch", { - attributes: { - hopCount: options.hopCount - } + "PropertyIsNotEqualTo": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsNotEqualTo", { + attributes: {matchCase: filter.matchCase} }); + // no fes:expression handling for ValueReference for now + this.writeNode("ValueReference", filter, node); + // handle Literals or Functions for now + this.writeOgcExpression(filter.value, node); return node; }, - "ResponseHandler": function(options) { - var node = this.createElementNSPlus("csw:ResponseHandler", { - value: options.value + "PropertyIsLike": function(filter) { + var node = this.createElementNSPlus("fes:PropertyIsLike", { + attributes: { + matchCase: filter.matchCase, + wildCard: "*", singleChar: ".", escapeChar: "!" + } }); + // no fes:expression handling for now + this.writeNode("ValueReference", filter, node); + // convert regex string to ogc string + this.writeNode("Literal", filter.regex2value(), node); return node; }, - "Query": function(options) { - if (!options) { - options = {}; + "BBOX": function(filter) { + var node = this.createElementNSPlus("fes:BBOX"); + // ValueReference is optional in 1.1.0 + filter.property && this.writeNode("ValueReference", filter, node); + var box = this.writeNode("gml:Envelope", filter.value); + if(filter.projection) { + box.setAttribute("srsName", filter.projection); } - var node = this.createElementNSPlus("csw:Query", { - attributes: { - typeNames: options.typeNames || "csw:Record" - } - }); - var ElementName = options.ElementName; - if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { - // ElementName must be a non-empty array - for(var i=0, len=ElementName.length; i<len; i++) { - this.writeNode( - "csw:ElementName", - ElementName[i], - node - ); - } - } else { + node.appendChild(box); + return node; + }, + "SortBy": function(sortProperties) { + var node = this.createElementNSPlus("fes:SortBy"); + for (var i=0,l=sortProperties.length;i<l;i++) { this.writeNode( - "csw:ElementSetName", - options.ElementSetName || {value: 'summary'}, + "fes:SortProperty", + sortProperties[i], node ); } - if (options.Constraint) { - this.writeNode( - "csw:Constraint", - options.Constraint, - node - ); - } - if (options.SortBy) { - this.writeNode( - "ogc:SortBy", - options.SortBy, - node - ); - } return node; - }, - "ElementName": function(options) { - var node = this.createElementNSPlus("csw:ElementName", { - value: options.value - }); + }, + "SortProperty": function(sortProperty) { + var node = this.createElementNSPlus("fes:SortProperty"); + this.writeNode( + "fes:ValueReference", + sortProperty, + node + ); + this.writeNode( + "fes:SortOrder", + (sortProperty.order == 'DESC') ? 'DESC' : 'ASC', + node + ); return node; }, - "ElementSetName": function(options) { - var node = this.createElementNSPlus("csw:ElementSetName", { - attributes: { - typeNames: options.typeNames - }, - value: options.value + "SortOrder": function(value) { + var node = this.createElementNSPlus("fes:SortOrder", { + value: value }); return node; - }, - "Constraint": function(options) { - var node = this.createElementNSPlus("csw:Constraint", { - attributes: { - version: options.version - } - }); - if (options.Filter) { - var format = new OpenLayers.Format.Filter({ - version: options.version - }); - node.appendChild(format.write(options.Filter)); - } else if (options.CqlText) { - var child = this.createElementNSPlus("CqlText", { - value: options.CqlText.value - }); - node.appendChild(child); - } - return node; } - }, - "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] + }, OpenLayers.Format.Filter.v2.prototype.writers["fes"]), + "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"] }, - - CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" + + /** + * 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("fes:"+name); + this.writeNode("ValueReference", filter, node); + if(filter.value instanceof OpenLayers.Filter.Function) { + this.writeNode("Function", filter.value, node); + } else { + 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.v2_0_0" + }); /* ====================================================================== + Rico/license.js + ====================================================================== */ + +/** + * @license Apache 2 + * + * Contains portions of Rico <http://openrico.org/> + * + * 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/Marker/Box.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -66468,11 +67721,11 @@ /* ====================================================================== OpenLayers/Format/Text.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -66623,11 +67876,11 @@ }); /* ====================================================================== OpenLayers/Layer/Text.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -66891,20 +68144,179 @@ }, CLASS_NAME: "OpenLayers.Layer.Text" }); /* ====================================================================== - OpenLayers/Control/Scale.js + OpenLayers/Format/WCSDescribeCoverage/v1_1_0.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ +/** + * @requires OpenLayers/Format/WCSDescribeCoverage/v1.js + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js + * @requires OpenLayers/BaseTypes/Bounds.js + */ /** + * Class: OpenLayers.Format.WCSDescribeCoverage/v1_1_0 + * Read WCS DescribeCoverage version 1.1.0. + * + * Inherits from: + * - <OpenLayers.Format.WCSDescribeCoverage.v1> + */ +OpenLayers.Format.WCSDescribeCoverage.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WCSDescribeCoverage.v1, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs/1.1", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows/1.1" + }, + + /** + * Constructor: OpenLayers.Format.WCSDescribeCoverage.v1_1_0 + * Create a new parser for WCS DescribeCoverage version 1.1.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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: { + "wcs": { + // Root object, contains one or more CoverageDescription entries + // In 1.0.0, this was CoverageDescription, in 1.1.0, it's + // CoverageDescriptions (plural) + "CoverageDescriptions": function(node, obj) { + obj.coverageDescriptions = {}; + this.readChildNodes(node, obj.coverageDescriptions); + + obj.coverageDescriptionKeys = []; + for(var key in obj.coverageDescriptions) { + obj.coverageDescriptionKeys.push(key); + } + // This would be more efficient, but only in newer browsers: + // obj.coverageDescriptionKeys = Object.keys(obj.coverageDescriptions); + }, + // In 1.0.0, CoverageDescription was called CoverageOffering + "CoverageDescription": function(node, descriptions) { + var description = {}; + this.readChildNodes(node, description); + descriptions[description.identifier] = description; + + // Provide a consistent handle on the native CRS + description.nativeCRS = + description.domain.spatialDomain.gridCRS.gridBaseCRS; + }, + "Identifier": function(node, description) { + description.identifier = this.getChildValue(node); + }, + "Title": function(node, description) { + description.title = this.getChildValue(node); + }, + "Domain": function(node, description) { + description.domain = {}; + this.readChildNodes(node, description.domain); + }, + "SpatialDomain": function(node, domain) { + domain.spatialDomain = { boundingBoxes:{} }; + + var bb = { BoundingBox:[] }; + + this.readChildNodes(node, bb); + + // Repack structure so bounding box list is indexed by CRS -- + // this will make it easier to find the one we want, and + // provides a consistent structure with 1.0.0 + for(var i=0, len=bb.BoundingBox.length; i<len;i++) { + if(!!bb.BoundingBox[i].crs) { + domain.spatialDomain.boundingBoxes[bb.BoundingBox[i].crs] = + bb.BoundingBox[i].bounds; + } + } + domain.spatialDomain.gridCRS = bb.gridCRS; + }, + "GridCRS": function(node, spatialDomain) { + spatialDomain.gridCRS = {}; + this.readChildNodes(node, spatialDomain.gridCRS); + }, + "GridBaseCRS": function(node, gridCRS) { + gridCRS.gridBaseCRS = this.getChildValue(node); + }, + "GridType": function(node, gridCRS) { + gridCRS.gridType = this.getChildValue(node); + }, + "GridOrigin": function(node, gridCRS) { + var xy = this.getChildValue(node).split(' '); + if(xy.length == 2) { + gridCRS.gridOrigin = {}; + gridCRS.gridOrigin.x = Number(xy[0]); + gridCRS.gridOrigin.y = Number(xy[1]); + } + }, + "GridOffsets": function(node, gridCRS) { + var xy = this.getChildValue(node).split(' '); + if(xy.length == 2) { + gridCRS.gridOffsets = {}; + gridCRS.gridOffsets.x = Number(xy[0]); + gridCRS.gridOffsets.y = Number(xy[1]); + } + }, + "GridCS": function(node, gridCRS) { + gridCRS.gridCS = this.getChildValue(node); + }, + "SupportedCRS": function(node, description) { + if(!!!description.supportedCRSs) { + description.supportedCRSs = []; + } + + var crs = this.getChildValue(node); + description.supportedCRSs.push(crs); + }, + "SupportedFormat": function(node, description) { + if(!!!description.supportedFormats) { + description.supportedFormats = []; + } + + var format = this.getChildValue(node); + description.supportedFormats.push(format); + } + }, + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WCSDescribeCoverage.v1_1_0" + +}); +/* ====================================================================== + OpenLayers/Control/Scale.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** * @requires OpenLayers/Control.js * @requires OpenLayers/Lang.js */ /** @@ -66995,14 +68407,317 @@ CLASS_NAME: "OpenLayers.Control.Scale" }); /* ====================================================================== + OpenLayers/Layer/PointGrid.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Layer/Vector.js + * @requires OpenLayers/Geometry/Polygon.js + */ + +/** + * Class: OpenLayers.Layer.PointGrid + * A point grid layer dynamically generates a regularly spaced grid of point + * features. This is a specialty layer for cases where an application needs + * a regular grid of points. It can be used, for example, in an editing + * environment to snap to a grid. + * + * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. + * (code) + * // create a grid with points spaced at 10 map units + * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); + * + * // create a grid with different x/y spacing rotated 15 degrees clockwise. + * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); + * (end) + * + * Inherits from: + * - <OpenLayers.Layer.Vector> + */ +OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { + + /** + * APIProperty: dx + * {Number} Point grid spacing in the x-axis direction (map units). + * Read-only. Use the <setSpacing> method to modify this value. + */ + dx: null, + + /** + * APIProperty: dy + * {Number} Point grid spacing in the y-axis direction (map units). + * Read-only. Use the <setSpacing> method to modify this value. + */ + dy: null, + + /** + * APIProperty: ratio + * {Number} Ratio of the desired grid size to the map viewport size. + * Default is 1.5. Larger ratios mean the grid is recalculated less often + * while panning. The <maxFeatures> setting has precedence when determining + * grid size. Read-only. Use the <setRatio> method to modify this value. + */ + ratio: 1.5, + + /** + * APIProperty: maxFeatures + * {Number} The maximum number of points to generate in the grid. Default + * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. + */ + maxFeatures: 250, + + /** + * APIProperty: rotation + * {Number} Grid rotation (in degrees clockwise from the positive x-axis). + * Default is 0. Read-only. Use the <setRotation> method to modify this + * value. + */ + rotation: 0, + + /** + * APIProperty: origin + * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with + * the origin. If not set at construction, the center of the map's maximum + * extent is used. Read-only. Use the <setOrigin> method to modify this + * value. + */ + origin: null, + + /** + * Property: gridBounds + * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional + * rotation applied). + */ + gridBounds: null, + + /** + * Constructor: OpenLayers.Layer.PointGrid + * Creates a new point grid layer. + * + * Parameters: + * config - {Object} An object containing all configuration properties for + * the layer. The <dx> and <dy> properties are required to be set at + * construction. Any other layer properties may be set in this object. + */ + initialize: function(config) { + config = config || {}; + OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); + }, + + /** + * Method: setMap + * The layer has been added to the map. + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + setMap: function(map) { + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); + map.events.register("moveend", this, this.onMoveEnd); + }, + + /** + * Method: removeMap + * The layer has been removed from the map. + * + * Parameters: + * map - {<OpenLayers.Map>} + */ + removeMap: function(map) { + map.events.unregister("moveend", this, this.onMoveEnd); + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); + }, + + /** + * APIMethod: setRatio + * Set the grid <ratio> property and update the grid. Can only be called + * after the layer has been added to a map with a center/extent. + * + * Parameters: + * ratio - {Number} + */ + setRatio: function(ratio) { + this.ratio = ratio; + this.updateGrid(true); + }, + + /** + * APIMethod: setMaxFeatures + * Set the grid <maxFeatures> property and update the grid. Can only be + * called after the layer has been added to a map with a center/extent. + * + * Parameters: + * maxFeatures - {Number} + */ + setMaxFeatures: function(maxFeatures) { + this.maxFeatures = maxFeatures; + this.updateGrid(true); + }, + + /** + * APIMethod: setSpacing + * Set the grid <dx> and <dy> properties and update the grid. If only one + * argument is provided, it will be set as <dx> and <dy>. Can only be + * called after the layer has been added to a map with a center/extent. + * + * Parameters: + * dx - {Number} + * dy - {Number} + */ + setSpacing: function(dx, dy) { + this.dx = dx; + this.dy = dy || dx; + this.updateGrid(true); + }, + + /** + * APIMethod: setOrigin + * Set the grid <origin> property and update the grid. Can only be called + * after the layer has been added to a map with a center/extent. + * + * Parameters: + * origin - {<OpenLayers.LonLat>} + */ + setOrigin: function(origin) { + this.origin = origin; + this.updateGrid(true); + }, + + /** + * APIMethod: getOrigin + * Get the grid <origin> property. + * + * Returns: + * {<OpenLayers.LonLat>} The grid origin. + */ + getOrigin: function() { + if (!this.origin) { + this.origin = this.map.getExtent().getCenterLonLat(); + } + return this.origin; + }, + + /** + * APIMethod: setRotation + * Set the grid <rotation> property and update the grid. Rotation values + * are in degrees clockwise from the positive x-axis (negative values + * for counter-clockwise rotation). Can only be called after the layer + * has been added to a map with a center/extent. + * + * Parameters: + * rotation - {Number} Degrees clockwise from the positive x-axis. + */ + setRotation: function(rotation) { + this.rotation = rotation; + this.updateGrid(true); + }, + + /** + * Method: onMoveEnd + * Listener for map "moveend" events. + */ + onMoveEnd: function() { + this.updateGrid(); + }, + + /** + * Method: getViewBounds + * Gets the (potentially rotated) view bounds for grid calculations. + * + * Returns: + * {<OpenLayers.Bounds>} + */ + getViewBounds: function() { + var bounds = this.map.getExtent(); + if (this.rotation) { + var origin = this.getOrigin(); + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); + var rect = bounds.toGeometry(); + rect.rotate(-this.rotation, rotationOrigin); + bounds = rect.getBounds(); + } + return bounds; + }, + + /** + * Method: updateGrid + * Update the grid. + * + * Parameters: + * force - {Boolean} Update the grid even if the previous bounds are still + * valid. + */ + updateGrid: function(force) { + if (force || this.invalidBounds()) { + var viewBounds = this.getViewBounds(); + var origin = this.getOrigin(); + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); + var viewBoundsWidth = viewBounds.getWidth(); + var viewBoundsHeight = viewBounds.getHeight(); + var aspectRatio = viewBoundsWidth / viewBoundsHeight; + var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); + var maxWidth = maxHeight * aspectRatio; + var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); + var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); + var center = viewBounds.getCenterLonLat(); + this.gridBounds = new OpenLayers.Bounds( + center.lon - (gridWidth / 2), + center.lat - (gridHeight / 2), + center.lon + (gridWidth / 2), + center.lat + (gridHeight / 2) + ); + var rows = Math.floor(gridHeight / this.dy); + var cols = Math.floor(gridWidth / this.dx); + var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); + var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); + var features = new Array(rows * cols); + var x, y, point; + for (var i=0; i<cols; ++i) { + x = gridLeft + (i * this.dx); + for (var j=0; j<rows; ++j) { + y = gridBottom + (j * this.dy); + point = new OpenLayers.Geometry.Point(x, y); + if (this.rotation) { + point.rotate(this.rotation, rotationOrigin); + } + features[(i*rows)+j] = new OpenLayers.Feature.Vector(point); + } + } + this.destroyFeatures(this.features, {silent: true}); + this.addFeatures(features, {silent: true}); + } + }, + + /** + * Method: invalidBounds + * Determine whether the previously generated point grid is invalid. + * This occurs when the map bounds extends beyond the previously + * generated grid bounds. + * + * Returns: + * {Boolean} + */ + invalidBounds: function() { + return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); + }, + + CLASS_NAME: "OpenLayers.Layer.PointGrid" + +}); +/* ====================================================================== OpenLayers/Layer/MapGuide.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -67445,11 +69160,11 @@ }); /* ====================================================================== OpenLayers/Control/Measure.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -67464,11 +69179,11 @@ * Inherits from: * - <OpenLayers.Control> */ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { - /** + /** * APIProperty: events * {<OpenLayers.Events>} Events instance for listeners and triggering * control specific events. * * Register a listener for a particular event with the following syntax: @@ -67488,32 +69203,32 @@ /** * APIProperty: handlerOptions * {Object} Used to set non-default properties on the control's handler */ - + /** * Property: callbacks * {Object} The functions that are sent to the handler for callback */ callbacks: null, - + /** - * Property: displaySystem + * APIProperty: displaySystem * {String} Display system for output measurements. Supported values * are 'english', 'metric', and 'geographic'. Default is 'metric'. */ displaySystem: 'metric', - + /** - * Property: geodesic + * APIProperty: 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. @@ -67558,32 +69273,32 @@ */ immediate : false, /** * Constructor: OpenLayers.Control.Measure - * + * * Parameters: - * handler - {<OpenLayers.Handler>} - * options - {Object} + * handler - {<OpenLayers.Handler>} + * options - {Object} */ initialize: function(handler, options) { OpenLayers.Control.prototype.initialize.apply(this, [options]); var callbacks = {done: this.measureComplete, point: this.measurePartial}; if (this.immediate){ callbacks.modify = this.measureImmediate; } this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); - // let the handler options override, so old code that passes 'persist' + // 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: deactivate */ deactivate: function() { this.cancelDelay(); @@ -67611,11 +69326,11 @@ this.callbacks.modify = this.measureImmediate; } else { delete this.callbacks.modify; } }, - + /** * Method: updateHandler * * Parameters: * handler - {Function} One of the sketch handler constructors. @@ -67641,11 +69356,11 @@ */ measureComplete: function(geometry) { this.cancelDelay(); this.measure(geometry, "measure"); }, - + /** * Method: measurePartial * Called each time a new point is added to the measurement sketch. * * Parameters: @@ -67672,13 +69387,15 @@ }, /** * Method: measureImmediate * Called each time the measurement sketch is modified. - * - * Parameters: point - {<OpenLayers.Geometry.Point>} The point at the - * mouseposition. feature - {<OpenLayers.Feature.Vector>} The sketch feature. + * + * Parameters: + * point - {<OpenLayers.Geometry.Point>} The point at the mouse position. + * feature - {<OpenLayers.Feature.Vector>} The sketch feature. + * drawing - {Boolean} Indicates whether we're currently drawing. */ measureImmediate : function(point, feature, drawing) { if (drawing && !this.handler.freehandMode(this.handler.evt)) { this.cancelDelay(); this.measure(feature.geometry, "measurepartial"); @@ -67717,11 +69434,11 @@ units: stat[1], order: order, geometry: geometry }); }, - + /** * Method: getBestArea * Based on the <displaySystem> returns the area of a geometry. * * Parameters: @@ -67741,11 +69458,11 @@ break; } } return [area, unit]; }, - + /** * Method: getArea * * Parameters: * geometry - {<OpenLayers.Geometry>} @@ -67768,11 +69485,11 @@ 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: @@ -67826,11 +69543,11 @@ }); /* ====================================================================== OpenLayers/Format/WMC/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -67934,11 +69651,11 @@ }); /* ====================================================================== OpenLayers/Format/WMTSCapabilities/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -68051,11 +69768,10 @@ styles: [], formats: [], dimensions: [], tileMatrixSetLinks: [] }; - layer.layers = []; this.readChildNodes(node, layer); obj.layers.push(layer); }, "Style": function(node, obj) { var style = {}; @@ -68084,16 +69800,43 @@ } else { // TileMatrixSet as string type in schema obj.tileMatrixSet = this.getChildValue(node); } }, + "TileMatrixSetLimits": function(node, obj) { + obj.tileMatrixSetLimits = []; + this.readChildNodes(node, obj); + }, + "TileMatrixLimits": function(node, obj) { + var tileMatrixLimits = {}; + this.readChildNodes(node, tileMatrixLimits); + obj.tileMatrixSetLimits.push(tileMatrixLimits); + }, + "MinTileRow": function(node, obj) { + obj.minTileRow = parseInt(this.getChildValue(node)); + }, + "MaxTileRow": function(node, obj) { + obj.maxTileRow = parseInt(this.getChildValue(node)); + }, + "MinTileCol": function(node, obj) { + obj.minTileCol = parseInt(this.getChildValue(node)); + }, + "MaxTileCol": function(node, obj) { + obj.maxTileCol = parseInt(this.getChildValue(node)); + }, "TileMatrix": function(node, obj) { - var tileMatrix = { - supportedCRS: obj.supportedCRS - }; - this.readChildNodes(node, tileMatrix); - obj.matrixIds.push(tileMatrix); + // node could be child of wmts:TileMatrixSet or wmts:TileMatrixLimits + if (obj.identifier) { + // node is child of wmts:TileMatrixSet + var tileMatrix = { + supportedCRS: obj.supportedCRS + }; + this.readChildNodes(node, tileMatrix); + obj.matrixIds.push(tileMatrix); + } else { + obj.tileMatrix = this.getChildValue(node); + } }, "ScaleDenominator": function(node, obj) { obj.scaleDenominator = parseFloat(this.getChildValue(node)); }, "TopLeftCorner": function(node, obj) { @@ -68142,10 +69885,38 @@ template: node.getAttribute("template"), resourceType: resourceType }; obj.resourceUrls.push(resourceUrl); }, + "LegendURL": function(node, obj) { + obj.legends = obj.legends || []; + var legend = { + format: node.getAttribute("format"), + href: node.getAttribute("xlink:href") + }; + var width = node.getAttribute("width"), + height = node.getAttribute("height"), + minScaleDenominator = node.getAttribute("minScaleDenominator"), + maxScaleDenominator = node.getAttribute("maxScaleDenominator"); + if (width !== null) { + legend.width = parseInt(width); + } + if (height !== null) { + legend.height = parseInt(height); + } + if (minScaleDenominator !== null) { + legend.minScaleDenominator = parseInt(minScaleDenominator); + } + if (maxScaleDenominator !== null) { + legend.maxScaleDenominator = parseInt(maxScaleDenominator); + } + obj.legends.push(legend); + }, + "InfoFormat": function(node, obj) { + obj.infoFormats = obj.infoFormats || []; + obj.infoFormats.push(this.getChildValue(node)); + }, // not used for now, can be added in the future though /*"Themes": function(node, obj) { obj.themes = []; this.readChildNodes(node, obj.themes); }, @@ -68162,15 +69933,10 @@ "ServiceMetadataURL": function(node, obj) { obj.serviceMetadataUrl = {}; obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); // TODO: other attributes of <ServiceMetadataURL> element }, - "LegendURL": function(node, obj) { - obj.legend = {}; - obj.legend.href = node.getAttribute("xlink:href"); - obj.legend.format = node.getAttribute("format"); - }, "Dimension": function(node, obj) { var dimension = {values: []}; this.readChildNodes(node, dimension); obj.dimensions.push(dimension); }, @@ -68189,11 +69955,11 @@ }); /* ====================================================================== OpenLayers/Layer/WorldWind.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -68298,11 +70064,11 @@ }); /* ====================================================================== OpenLayers/Popup/FramedCloud.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -68529,11 +70295,11 @@ }); /* ====================================================================== OpenLayers/Format/SOSCapabilities/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -68931,14 +70697,295 @@ CLASS_NAME: "OpenLayers.Handler.Pinch" }); /* ====================================================================== + OpenLayers/Format/WFST/v2_0_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WFST/v1.js + * @requires OpenLayers/Format/Filter/v2_0_0.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.WFST.v2_0_0 + * A format for creating WFS v2.0.0 transactions. Create a new instance with the + * <OpenLayers.Format.WFST.v2_0_0> constructor. + * + * Inherits from: + * - <OpenLayers.Format.Filter.v2_0_0> + * - <OpenLayers.Format.WFST.v1> + */ +OpenLayers.Format.WFST.v2_0_0 = OpenLayers.Class( + OpenLayers.Format.Filter.v2_0_0, OpenLayers.Format.WFST.v1, { + + /** + * 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/2.0", + gml: "http://www.opengis.net/gml/3.2", + fes: "http://www.opengis.net/fes/2.0" + }, + + /** + * Property: version + * {String} WFS version number. + */ + version: "2.0.0", + + /** + * Property: schemaLocations + * {Object} Properties are namespace aliases, values are schema locations. + */ + schemaLocations: { + "wfs": "http://schemas.opengis.net/wfs/2.0/wfs.xsd" + }, + + /** + * Constructor: OpenLayers.Format.WFST.v2_0_0 + * A class for parsing and generating WFS v2.0.0 transactions. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeNames (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.v2_0_0.prototype.initialize.apply(this, [options]); + OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]); + }, + + /** + * 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). + * first - {Boolean} Should be set to true for the first node read. This + * is usually the readNode call in the read method. Without this being + * set, auto-configured properties will stick on subsequent reads. + * + * Returns: + * {Object} The input object, modified (or a new one if none was provided). + */ + readNode: function(node, obj, first) { + // Not the superclass, only the mixin classes inherit from + // Format.GML.v2. We need this because we don't want to get readNode + // from the superclass's superclass, which is OpenLayers.Format.XML. + return OpenLayers.Format.GML.v3.prototype.readNode.apply(this, arguments); + }, + + /** + * 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({ + "FeatureCollection": function(node, obj) { + obj.numberReturned = parseInt(node.getAttribute( + "numberReturned")); + obj.numberMatched = parseInt(node.getAttribute( + "numberMatched")); + OpenLayers.Format.WFST.v1.prototype.readers["wfs"]["FeatureCollection"].apply( + this, arguments); + }, + "TransactionResponse": function(node, obj) { + obj.insertIds = []; + obj.success = false; + this.readChildNodes(node, obj); + }, + "TransactionSummary": function(node, obj) { + 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]); + }, + "member": function(node, obj) { + this.readChildNodes(node, obj); + }, + "boundedBy": function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + if(container.components && container.components.length > 0) { + obj.bounds = container.components[0]; + } + } + + }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]), + "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"], + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"], + "fes": OpenLayers.Format.Filter.v2_0_0.prototype.readers["fes"] + }, + + /** + * 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({ + "GetFeature": function(options) { + var node = OpenLayers.Format.WFST.v1.prototype.writers["wfs"]["GetFeature"].apply(this, arguments); + options && this.setAttributes(node, { + resultType: options.resultType, + startIndex: options.startIndex, + count: options.count + }); + return node; + }, + "Query": function(options) { + options = OpenLayers.Util.extend({ + featureNS: this.featureNS, + featurePrefix: this.featurePrefix, + featureType: this.featureType, + srsName: this.srsName + }, options); + var prefix = options.featurePrefix; + var node = this.createElementNSPlus("wfs:Query", { + attributes: { + typeNames: (prefix ? prefix + ":" : "") + + options.featureType, + srsName: options.srsName + } + }); + if(options.featureNS) { + node.setAttribute("xmlns:" + prefix, 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("fes:Filter", options.filter, node); + } + return node; + }, + "Update": function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNSPlus("wfs:Update", { + attributes: { + handle: options && options.handle, + typeName: (this.featureNS ? this.featurePrefix + ":" : "") + + this.featureType + } + }); + if(this.featureNS) { + node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + } + + // add in geometry + var modified = feature.modified; + if (this.geometryName !== null && (!modified || modified.geometry !== undefined)) { + this.srsName = this.getSrsName(feature); + this.writeNode( + "Property", {name: this.geometryName, value: feature.geometry}, node + ); + } + + // add in attributes + for(var key in feature.attributes) { + if(feature.attributes[key] !== undefined && + (!modified || !modified.attributes || + (modified.attributes && (key in modified.attributes)))) { + this.writeNode( + "Property", {name: key, value: feature.attributes[key]}, node + ); + } + } + + // add feature id filter + this.writeNode("fes:Filter", new OpenLayers.Filter.FeatureId({ + fids: [feature.fid] + }), node); + + return node; + }, + "Property": function(obj) { + var node = this.createElementNSPlus("wfs:Property"); + this.writeNode("ValueReference", obj.name, node); + if(obj.value !== null) { + this.writeNode("Value", obj.value, node); + } + return node; + }, + "PropertyName": function(obj) { + return this.createElementNSPlus("wfs:PropertyName", { + value: obj.property + }); + }, + "ValueReference": function(name) { + return this.createElementNSPlus("wfs:ValueReference", {value: name}); + }, + "Delete": function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNSPlus("wfs:Delete", { + attributes: { + handle: options && options.handle, + typeName: (this.featureNS ? this.featurePrefix + ":" : "") + + this.featureType + } + }); + if(this.featureNS) { + node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); + } + this.writeNode("fes:Filter", new OpenLayers.Filter.FeatureId({ + fids: [feature.fid] + }), node); + return node; + } + }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]), + "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"], + "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"], + "fes": OpenLayers.Format.Filter.v2_0_0.prototype.writers["fes"] + }, + + CLASS_NAME: "OpenLayers.Format.WFST.v2_0_0" +}); +/* ====================================================================== OpenLayers/Control/NavToolbar.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -68995,11 +71042,11 @@ }); /* ====================================================================== OpenLayers/Layer/OSM.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -69122,11 +71169,11 @@ }); /* ====================================================================== OpenLayers/Strategy/Refresh.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -69203,10 +71250,14 @@ */ deactivate: function() { var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); if(deactivated) { this.stop(); + this.layer.events.un({ + "visibilitychanged": this.reset, + scope: this + }); } return deactivated; }, /** @@ -69260,204 +71311,493 @@ }, CLASS_NAME: "OpenLayers.Strategy.Refresh" }); /* ====================================================================== - OpenLayers/Control/Geolocate.js + OpenLayers/Handler/Hover.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Geometry/Point.js - * @requires OpenLayers/Projection.js + * @requires OpenLayers/Handler.js */ /** - * Class: OpenLayers.Control.Geolocate - * The Geolocate control wraps w3c geolocation API into control that can be - * bound to a map, and generate events on location update - * - * To use this control requires to load the proj4js library if the projection - * of the map is not EPSG:4326 or EPSG:900913. - * + * Class: OpenLayers.Handler.Hover + * The hover handler is to be used to emulate mouseovers on objects + * on the map that aren't DOM elements. For example one can use + * this handler to send WMS/GetFeatureInfo requests as the user + * moves the mouve over the map. + * * Inherits from: - * - <OpenLayers.Control> + * - <OpenLayers.Handler> */ -OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { +OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { - /** - * APIProperty: events - * {<OpenLayers.Events>} Events instance for listeners and triggering - * control specific events. - * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) - * - * Supported event types (in addition to those from <OpenLayers.Control.events>): - * locationupdated - Triggered when browser return a new position. Listeners will - * receive an object with a 'position' property which is the browser.geolocation.position - * native object, as well as a 'point' property which is the location transformed in the - * current map projection. - * locationfailed - Triggered when geolocation has failed - * locationuncapable - Triggered when control is activated on a browser - * which doesn't support geolocation + /** + * APIProperty: delay + * {Integer} - Number of milliseconds between mousemoves before + * the event is considered a hover. Default is 500. */ - + delay: 500, + /** - * Property: geolocation - * {Object} The geolocation engine, as a property to be possibly mocked. + * APIProperty: pixelTolerance + * {Integer} - Maximum number of pixels between mousemoves for + * an event to be considered a hover. Default is null. */ - geolocation: navigator.geolocation, + pixelTolerance: null, /** - * APIProperty: bind - * {Boolean} If true, map center will be set on location update. + * APIProperty: stopMove + * {Boolean} - Stop other listeners from being notified on mousemoves. + * Default is false. */ - bind: true, + stopMove: false, /** - * APIProperty: watch - * {Boolean} If true, position will be update regularly. + * Property: px + * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed + * in pixels. */ - watch: false, + px: null, /** - * APIProperty: geolocationOptions - * {Object} Options to pass to the navigator's geolocation API. See - * <http://dev.w3.org/geo/api/spec-source.html>. No specific - * option is passed to the geolocation API by default. + * Property: timerId + * {Number} - The id of the timer. */ - geolocationOptions: null, - + timerId: null, + /** - * Constructor: OpenLayers.Control.Geolocate - * Create a new control to deal with browser geolocation API + * Constructor: OpenLayers.Handler.Hover + * Construct a hover handler. * + * Parameters: + * control - {<OpenLayers.Control>} The control that initialized this + * handler. The control is assumed to have a valid map property; that + * map is used in the handler's own setMap method. + * callbacks - {Object} An object with keys corresponding to callbacks + * that will be called by the handler. The callbacks should + * expect to receive a single argument, the event. Callbacks for + * 'move', the mouse is moving, and 'pause', the mouse is pausing, + * are supported. + * options - {Object} An optional object whose properties will be set on + * the handler. */ /** - * Method: destroy + * Method: mousemove + * Called when the mouse moves on the map. + * + * Parameters: + * evt - {<OpenLayers.Event>} + * + * Returns: + * {Boolean} Continue propagating this event. */ - destroy: function() { - this.deactivate(); - OpenLayers.Control.prototype.destroy.apply(this, arguments); + mousemove: function(evt) { + if(this.passesTolerance(evt.xy)) { + this.clearTimer(); + this.callback('move', [evt]); + this.px = evt.xy; + // clone the evt so original properties can be accessed even + // if the browser deletes them during the delay + evt = OpenLayers.Util.extend({}, evt); + this.timerId = window.setTimeout( + OpenLayers.Function.bind(this.delayedCall, this, evt), + this.delay + ); + } + return !this.stopMove; }, /** - * Method: activate - * Activates the control. + * Method: mouseout + * Called when the mouse goes out of the map. * + * Parameters: + * evt - {<OpenLayers.Event>} + * * Returns: - * {Boolean} The control was effectively activated. + * {Boolean} Continue propagating this event. */ - activate: function () { - if (!this.geolocation) { - this.events.triggerEvent("locationuncapable"); - return false; + mouseout: function(evt) { + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { + this.clearTimer(); + this.callback('move', [evt]); } - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { - if (this.watch) { - this.watchId = this.geolocation.watchPosition( - OpenLayers.Function.bind(this.geolocate, this), - OpenLayers.Function.bind(this.failure, this), - this.geolocationOptions - ); - } else { - this.getCurrentLocation(); + return true; + }, + + /** + * Method: passesTolerance + * Determine whether the mouse move is within the optional pixel tolerance. + * + * Parameters: + * px - {<OpenLayers.Pixel>} + * + * Returns: + * {Boolean} The mouse move is within the pixel tolerance. + */ + passesTolerance: function(px) { + var passes = true; + if(this.pixelTolerance && this.px) { + var dpx = Math.sqrt( + Math.pow(this.px.x - px.x, 2) + + Math.pow(this.px.y - px.y, 2) + ); + if(dpx < this.pixelTolerance) { + passes = false; } - return true; } - return false; + return passes; }, /** - * Method: deactivate - * Deactivates the control. + * Method: clearTimer + * Clear the timer and set <timerId> to null. + */ + clearTimer: function() { + if(this.timerId != null) { + window.clearTimeout(this.timerId); + this.timerId = null; + } + }, + + /** + * Method: delayedCall + * Triggers pause callback. * + * Parameters: + * evt - {<OpenLayers.Event>} + */ + delayedCall: function(evt) { + this.callback('pause', [evt]); + }, + + /** + * APIMethod: deactivate + * Deactivate the handler. + * * Returns: - * {Boolean} The control was effectively deactivated. + * {Boolean} The handler was successfully deactivated. */ - deactivate: function () { - if (this.active && this.watchId !== null) { - this.geolocation.clearWatch(this.watchId); + deactivate: function() { + var deactivated = false; + if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { + this.clearTimer(); + deactivated = true; } - return OpenLayers.Control.prototype.deactivate.apply( - this, arguments - ); + return deactivated; }, + CLASS_NAME: "OpenLayers.Handler.Hover" +}); +/* ====================================================================== + OpenLayers/Control/ModifyFeature/BySegment.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/BaseTypes.js + * @requires OpenLayers/Control/ModifyFeature.js + * @requires OpenLayers/Geometry.js + * @requires OpenLayers/Handler/Hover.js + */ + +/** + * Class: OpenLayers.Control.ModifyFeature.BySegment + * A mixin for the ModifyFeature control to allow editing of large geometries + * by editing one segment at a time, the segment which is closest to the + * mouse cursor on hover. + * + * To use this is in combination with OpenLayers.Control.ModifyFeature include + * this file in your build and set bySegment to true on the ModifyFeature + * control. Also note this code depends on the rbush library which can be + * found at: https://github.com/mourner/rbush + */ +OpenLayers.Control.ModifyFeature.BySegment = { + /** - * Method: geolocate - * Activates the control. + * APIProperty: hoverTolerance + * {Integer} Number of pixels around the hover location to query the + * spatial index in order to find the closest segment. Defaults to 25. + */ + hoverTolerance: 25, + + /** + * Method: collectVertices + * Collect the vertices from the modifiable feature's geometry and push + * them on to the control's vertices array. + */ + collectVertices: OpenLayers.Function.Void, + + /** + * Method: setMap + * Set the map property for the control and all handlers. * + * Parameters: + * map - {<OpenLayers.Map>} The control's map. */ - geolocate: function (position) { - var center = new OpenLayers.LonLat( - position.coords.longitude, - position.coords.latitude - ).transform( - new OpenLayers.Projection("EPSG:4326"), - this.map.getProjectionObject() - ); - if (this.bind) { - this.map.setCenter(center); + setMap: function(map) { + OpenLayers.Control.ModifyFeature.prototype.setMap.apply(this, arguments); + if (!this.handlers.hover) { + this.handlers.hover = new OpenLayers.Handler.Hover(this, { + move: this.onHoverMove + }); } - this.events.triggerEvent("locationupdated", { - position: position, - point: new OpenLayers.Geometry.Point( - center.lon, center.lat - ) - }); + this.handlers.hover.setMap(map); + this.layer.events.on({ + beforefeaturemodified: this.createSpatialIndex, + afterfeaturemodified: this.deactivateHover, + scope: this + }); }, /** - * APIMethod: getCurrentLocation + * Method: deactivateHover + * Deactivate the hover handler. + */ + deactivateHover: function() { + this.handlers.hover.deactivate(); + }, + + /** + * APIMethod: destroy + * Take care of things that are not handled in superclass. + */ + destroy: function() { + if (this.layer) { + this.layer.events.un({ + beforefeaturemodified: this.createSpatialIndex, + afterfeaturemodified: this.deactivateHover, + scope: this + }); + } + OpenLayers.Control.ModifyFeature.prototype.destroy.apply(this, []); + }, + + /** + * Method: dragStart + * Called by the drag handler before a feature is dragged. This method is + * used to differentiate between points and vertices + * of higher order geometries. * - * Returns: - * {Boolean} Returns true if a event will be fired (successfull - * registration) + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be + * dragged. */ - getCurrentLocation: function() { - if (!this.active || this.watch) { - return false; + dragStart: function(feature) { + OpenLayers.Control.ModifyFeature.prototype.dragStart.apply(this, arguments); + this.vertexGeom = feature.geometry.clone(); + if (this.handlers.drag.stopDown) { + this.handlers.hover.deactivate(); } - this.geolocation.getCurrentPosition( - OpenLayers.Function.bind(this.geolocate, this), - OpenLayers.Function.bind(this.failure, this), - this.geolocationOptions - ); - return true; }, /** - * Method: failure - * method called on browser's geolocation failure + * Method: dragComplete + * Called by the drag handler when the feature dragging is complete. * + * Parameters: + * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. */ - failure: function (error) { - this.events.triggerEvent("locationfailed", {error: error}); + dragComplete: function(vertex) { + this.updateSpatialIndex(vertex); + OpenLayers.Control.ModifyFeature.prototype.dragComplete.apply(this, arguments); + this.handlers.hover.activate(); }, - CLASS_NAME: "OpenLayers.Control.Geolocate" -}); + /** + * Method: onHoverMove + * Move listener of the hover handler. Draws the 2 vertices of the segment + * closest to the mouse cursor, and one virtual vertex in the center of the + * segment. + * + * Parameters: + * evt - {Object} The event object. + */ + onHoverMove: function(evt) { + 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 = []; + } + var pixel = evt.xy; + var llPx = pixel.add(-this.hoverTolerance/2, this.hoverTolerance/2); + var urPx = pixel.add(this.hoverTolerance/2, -this.hoverTolerance/2); + var ll = this.map.getLonLatFromPixel(llPx); + var ur = this.map.getLonLatFromPixel(urPx); + var hits = this.tree.search([ll.lon, ll.lat, ur.lon, ur.lat]); + if (hits.length > 0) { + var center = this.map.getLonLatFromPixel(pixel); + var centerPt = new OpenLayers.Geometry.Point(center.lon, center.lat); + var d = Number.MAX_VALUE; + var closestHit; + for (var i=0, ii = hits.length; i<ii; ++i) { + var hit = hits[i]; + var distance = OpenLayers.Geometry.distanceSquaredToSegment(centerPt, { + x1: hit.point1.x, + x2: hit.point2.x, + y1: hit.point1.y, + y2: hit.point2.y + }).distance; + if (distance < d) { + closestHit = hit; + } + d = distance; + } + var createVertex = function(geom) { + var vertex = new OpenLayers.Feature.Vector(geom); + vertex._sketch = true; + vertex.renderIntent = this.vertexRenderIntent; + this.vertices.push(vertex); + }; + createVertex.call(this, closestHit.point1); + createVertex.call(this, closestHit.point2); + // create virtual vertex + var point = this.createVirtualVertex(closestHit.point1, closestHit.point2); + point._previous = closestHit.point1; + point._next = closestHit.point2; + point._index = -1; + point.geometry.parent = closestHit.point1.parent; + this.virtualVertices.push(point); + } + this.layer.addFeatures(this.vertices, {silent: true}); + this.layer.addFeatures(this.virtualVertices, {silent: true}); + }, + + /** + * Method: createSpatialIndex + * Creates a spatial index for all the segments of the feature's geometry. + * + * Parameters: + * evt - {Object} The event object. + */ + createSpatialIndex: function(evt) { + var feature = evt.feature; + var data = []; + function collectComponentVertices(geometry) { + var i, vertex, component, nextComponent, len; + if (geometry.CLASS_NAME !== "OpenLayers.Geometry.Point") { + var numVert = geometry.components.length; + if (geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { + numVert -= 1; + } + nextComponent = geometry.components[0]; + for (i=1; i<=numVert; ++i) { + component = nextComponent; + nextComponent = geometry.components[i]; + if (component.CLASS_NAME == "OpenLayers.Geometry.Point") { + var bbox = this.createBBOX(component, nextComponent); + bbox.point1 = component; + bbox.point2 = nextComponent; + data.push(bbox); + } else { + collectComponentVertices.call(this, component); + } + } + } + } + collectComponentVertices.call(this, feature.geometry); + this.tree = window.rbush(); + this.tree.load(data); + this.handlers.hover.activate(); + }, + + /** + * Method: createBBOX + * Create an array of 4 points (minx, miny, maxx, maxy) that represents the + * bounding box of the 2 provided points. + * + * Parameters: + * point1 - {<OpenLayers.Geometry.Point>} The first point. + * point2 - {<OpenLayers.Geometry.Point>} The second point. + * + * Returns: {Array(float)} + */ + createBBOX: function(point1, point2) { + return [ + point1.x < point2.x ? point1.x : point2.x, + point1.y < point2.y ? point1.y : point2.y, + point1.x < point2.x ? point2.x : point1.x, + point1.y < point2.y ? point2.y : point1.y + ]; + }, + + /** + * Method: updateSpatialIndex + * Update the spatial index after a (virtual) vertex gets moved. + * + * Parameters: + * vertex - {<OpenLayers.Feature.Vector>} + */ + updateSpatialIndex: function(vertex) { + // this.vertexGeom is the original location of the vertex + var hits = this.tree.search([ + this.vertexGeom.x, + this.vertexGeom.y, + this.vertexGeom.x, + this.vertexGeom.y + ]); + var bbox, i, ii; + // virtual vertex + if (vertex._previous) { + // split segment into 2 and add them to spatial index + bbox = this.createBBOX(vertex._previous, vertex.geometry); + bbox.point1 = vertex._previous; + bbox.point2 = vertex.geometry; + this.tree.insert(bbox); + bbox = this.createBBOX(vertex.geometry, vertex._next); + bbox.point1 = vertex.geometry; + bbox.point2 = vertex._next; + this.tree.insert(bbox); + this.tree.remove(hits[0]); + delete vertex._next; + delete vertex._previous; + } else { // normal vertex + for (i=0, ii=hits.length; i<ii; ++i) { + var hit = hits[i]; + if (this.vertexGeom.equals(hit.point1)) { + bbox = this.createBBOX(vertex.geometry, hit.point2); + bbox.point1 = vertex.geometry; + bbox.point2 = hit.point2; + } else { + bbox = this.createBBOX(vertex.geometry, hit.point1); + bbox.point1 = hit.point1; + bbox.point2 = vertex.geometry; + } + this.tree.insert(bbox); + this.tree.remove(hit); + } + } + this.vertexGeom.destroy(); + this.vertexGeom = null; + } + +}; /* ====================================================================== OpenLayers/Layer/ArcGIS93Rest.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ - /** * @requires OpenLayers/Layer/Grid.js */ /** @@ -69584,11 +71924,11 @@ // 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 imageSize = this.getImageSize(bounds); 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", @@ -69675,198 +72015,14 @@ }, CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" }); /* ====================================================================== - OpenLayers/Handler/Hover.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Handler.js - */ - -/** - * Class: OpenLayers.Handler.Hover - * The hover handler is to be used to emulate mouseovers on objects - * on the map that aren't DOM elements. For example one can use - * this handler to send WMS/GetFeatureInfo requests as the user - * moves the mouve over the map. - * - * Inherits from: - * - <OpenLayers.Handler> - */ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { - - /** - * APIProperty: delay - * {Integer} - Number of milliseconds between mousemoves before - * the event is considered a hover. Default is 500. - */ - delay: 500, - - /** - * APIProperty: pixelTolerance - * {Integer} - Maximum number of pixels between mousemoves for - * an event to be considered a hover. Default is null. - */ - pixelTolerance: null, - - /** - * APIProperty: stopMove - * {Boolean} - Stop other listeners from being notified on mousemoves. - * Default is false. - */ - stopMove: false, - - /** - * Property: px - * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed - * in pixels. - */ - px: null, - - /** - * Property: timerId - * {Number} - The id of the timer. - */ - timerId: null, - - /** - * Constructor: OpenLayers.Handler.Hover - * Construct a hover handler. - * - * Parameters: - * control - {<OpenLayers.Control>} The control that initialized this - * handler. The control is assumed to have a valid map property; that - * map is used in the handler's own setMap method. - * callbacks - {Object} An object with keys corresponding to callbacks - * that will be called by the handler. The callbacks should - * expect to receive a single argument, the event. Callbacks for - * 'move', the mouse is moving, and 'pause', the mouse is pausing, - * are supported. - * options - {Object} An optional object whose properties will be set on - * the handler. - */ - - /** - * Method: mousemove - * Called when the mouse moves on the map. - * - * Parameters: - * evt - {<OpenLayers.Event>} - * - * Returns: - * {Boolean} Continue propagating this event. - */ - mousemove: function(evt) { - if(this.passesTolerance(evt.xy)) { - this.clearTimer(); - this.callback('move', [evt]); - this.px = evt.xy; - // clone the evt so original properties can be accessed even - // if the browser deletes them during the delay - evt = OpenLayers.Util.extend({}, evt); - this.timerId = window.setTimeout( - OpenLayers.Function.bind(this.delayedCall, this, evt), - this.delay - ); - } - return !this.stopMove; - }, - - /** - * Method: mouseout - * Called when the mouse goes out of the map. - * - * Parameters: - * evt - {<OpenLayers.Event>} - * - * Returns: - * {Boolean} Continue propagating this event. - */ - mouseout: function(evt) { - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { - this.clearTimer(); - this.callback('move', [evt]); - } - return true; - }, - - /** - * Method: passesTolerance - * Determine whether the mouse move is within the optional pixel tolerance. - * - * Parameters: - * px - {<OpenLayers.Pixel>} - * - * Returns: - * {Boolean} The mouse move is within the pixel tolerance. - */ - passesTolerance: function(px) { - var passes = true; - if(this.pixelTolerance && this.px) { - var dpx = Math.sqrt( - Math.pow(this.px.x - px.x, 2) + - Math.pow(this.px.y - px.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; - } - }, - - /** - * Method: delayedCall - * Triggers pause callback. - * - * Parameters: - * evt - {<OpenLayers.Event>} - */ - delayedCall: function(evt) { - this.callback('pause', [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(); - deactivated = true; - } - return deactivated; - }, - - CLASS_NAME: "OpenLayers.Handler.Hover" -}); -/* ====================================================================== OpenLayers/Control/GetFeature.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -70463,11 +72619,11 @@ }); /* ====================================================================== OpenLayers/Format/QueryStringFilter.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -70650,11 +72806,11 @@ })(); /* ====================================================================== OpenLayers/Format/WCSCapabilities/v1_1_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -70753,11 +72909,23 @@ } coverageSummary.supportedFormat.push(format); } } }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] + "ows": OpenLayers.Util.applyDefaults({ + // ows puts keywords in a dictionary, which doesn't make a + // lot of sense in this context; we just want a list, so we'll + // override this aspect of the ows parsing. + "Keywords": function(node, serviceIdentification) { + serviceIdentification.keywords = []; + this.readChildNodes(node, serviceIdentification.keywords); + }, + "Keyword": function(node, keywords) { + // Append the keyword to the keywords list + keywords.push(this.getChildValue(node)); + } + }, OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"]) }, CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" }); @@ -70991,14 +73159,210 @@ }, CLASS_NAME: "OpenLayers.Control.MousePosition" }); /* ====================================================================== + OpenLayers/Control/Geolocate.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Geometry/Point.js + * @requires OpenLayers/Projection.js + */ + +/** + * Class: OpenLayers.Control.Geolocate + * The Geolocate control wraps w3c geolocation API into control that can be + * bound to a map, and generate events on location update + * + * To use this control requires to load the proj4js library if the projection + * of the map is not EPSG:4326 or EPSG:900913. + * + * Inherits from: + * - <OpenLayers.Control> + */ +OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: events + * {<OpenLayers.Events>} Events instance for listeners and triggering + * control specific events. + * + * Register a listener for a particular event with the following syntax: + * (code) + * control.events.register(type, obj, listener); + * (end) + * + * Supported event types (in addition to those from <OpenLayers.Control.events>): + * locationupdated - Triggered when browser return a new position. Listeners will + * receive an object with a 'position' property which is the browser.geolocation.position + * native object, as well as a 'point' property which is the location transformed in the + * current map projection. + * locationfailed - Triggered when geolocation has failed + * locationuncapable - Triggered when control is activated on a browser + * which doesn't support geolocation + */ + + /** + * Property: geolocation + * {Object} The geolocation engine, as a property to be possibly mocked. + * This is set lazily to avoid a memory leak in IE9. + */ + geolocation: null, + + /** + * Property: available + * {Boolean} The navigator.geolocation object is available. + */ + available: ('geolocation' in navigator), + + /** + * APIProperty: bind + * {Boolean} If true, map center will be set on location update. + */ + bind: true, + + /** + * APIProperty: watch + * {Boolean} If true, position will be update regularly. + */ + watch: false, + + /** + * APIProperty: geolocationOptions + * {Object} Options to pass to the navigator's geolocation API. See + * <http://dev.w3.org/geo/api/spec-source.html>. No specific + * option is passed to the geolocation API by default. + */ + geolocationOptions: null, + + /** + * Constructor: OpenLayers.Control.Geolocate + * Create a new control to deal with browser geolocation API + * + */ + + /** + * Method: destroy + */ + destroy: function() { + this.deactivate(); + OpenLayers.Control.prototype.destroy.apply(this, arguments); + }, + + /** + * Method: activate + * Activates the control. + * + * Returns: + * {Boolean} The control was effectively activated. + */ + activate: function () { + if (this.available && !this.geolocation) { + // set lazily to avoid IE9 memory leak + this.geolocation = navigator.geolocation; + } + if (!this.geolocation) { + this.events.triggerEvent("locationuncapable"); + return false; + } + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { + if (this.watch) { + this.watchId = this.geolocation.watchPosition( + OpenLayers.Function.bind(this.geolocate, this), + OpenLayers.Function.bind(this.failure, this), + this.geolocationOptions + ); + } else { + this.getCurrentLocation(); + } + return true; + } + return false; + }, + + /** + * Method: deactivate + * Deactivates the control. + * + * Returns: + * {Boolean} The control was effectively deactivated. + */ + deactivate: function () { + if (this.active && this.watchId !== null) { + this.geolocation.clearWatch(this.watchId); + } + return OpenLayers.Control.prototype.deactivate.apply( + this, arguments + ); + }, + + /** + * Method: geolocate + * Activates the control. + * + */ + geolocate: function (position) { + var center = new OpenLayers.LonLat( + position.coords.longitude, + position.coords.latitude + ).transform( + new OpenLayers.Projection("EPSG:4326"), + this.map.getProjectionObject() + ); + if (this.bind) { + this.map.setCenter(center); + } + this.events.triggerEvent("locationupdated", { + position: position, + point: new OpenLayers.Geometry.Point( + center.lon, center.lat + ) + }); + }, + + /** + * APIMethod: getCurrentLocation + * + * Returns: + * {Boolean} Returns true if a event will be fired (successfull + * registration) + */ + getCurrentLocation: function() { + if (!this.active || this.watch) { + return false; + } + this.geolocation.getCurrentPosition( + OpenLayers.Function.bind(this.geolocate, this), + OpenLayers.Function.bind(this.failure, this), + this.geolocationOptions + ); + return true; + }, + + /** + * Method: failure + * method called on browser's geolocation failure + * + */ + failure: function (error) { + this.events.triggerEvent("locationfailed", {error: error}); + }, + + CLASS_NAME: "OpenLayers.Control.Geolocate" +}); +/* ====================================================================== OpenLayers/Tile/UTFGrid.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -71250,11 +73614,11 @@ }); /* ====================================================================== OpenLayers/Control/NavigationHistory.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -71674,598 +74038,62 @@ CLASS_NAME: "OpenLayers.Control.NavigationHistory" }); /* ====================================================================== - OpenLayers/Protocol/HTTP.js + OpenLayers/Protocol/WFS/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Protocol.js - * @requires OpenLayers/Request/XMLHttpRequest.js + * @requires OpenLayers/Protocol/WFS/v1.js + * @requires OpenLayers/Format/WFST/v1_0_0.js */ /** - * if application uses the query string, for example, for BBOX parameters, - * OpenLayers/Format/QueryStringFilter.js should be included in the build config file - */ - -/** - * Class: OpenLayers.Protocol.HTTP - * A basic HTTP protocol for vector layers. Create a new instance with the - * <OpenLayers.Protocol.HTTP> constructor. + * Class: OpenLayers.Protocol.WFS.v1_0_0 + * A WFS v1.0.0 protocol for vector layers. Create a new instance with the + * <OpenLayers.Protocol.WFS.v1_0_0> constructor. * * Inherits from: - * - <OpenLayers.Protocol> + * - <OpenLayers.Protocol.WFS.v1> */ -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, +OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { /** - * 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. + * Property: version + * {String} WFS version number. */ - callback: null, - - /** - * Property: scope - * {Object} Callback execution scope, read-only, set through the - * options passed to the constructor. - */ - scope: null, - - /** - * APIProperty: readWithPOST - * {Boolean} true if read operations are done with POST requests - * instead of GET, defaults to false. - */ - readWithPOST: false, - - /** - * APIProperty: updateWithPOST - * {Boolean} true if update operations are done with POST requests - * defaults to false. - */ - updateWithPOST: false, + version: "1.0.0", /** - * APIProperty: deleteWithPOST - * {Boolean} true if delete operations are done with POST requests - * defaults to false. - * if true, POST data is set to output of format.write(). - */ - deleteWithPOST: false, - - /** - * Property: wildcarded. - * {Boolean} If true percent signs are added around values - * read from LIKE filters, for example if the protocol - * read method is passed a LIKE filter whose property - * is "foo" and whose value is "bar" the string - * "foo__ilike=%bar%" will be sent in the query string; - * defaults to false. - */ - wildcarded: false, - - /** - * APIProperty: srsInBBOX - * {Boolean} Include the SRS identifier in BBOX query string parameter. - * Default is false. If true and the layer has a projection object set, - * any BBOX filter will be serialized with a fifth item identifying the - * projection. E.g. bbox=-1000,-1000,1000,1000,EPSG:900913 - */ - srsInBBOX: false, - - /** - * Constructor: OpenLayers.Protocol.HTTP - * A class for giving layers generic HTTP protocol. + * Constructor: OpenLayers.Protocol.WFS.v1_0_0 + * A class for giving layers WFS v1.0.0 protocol. * * Parameters: * options - {Object} Optional object whose properties will be set on the * instance. * - * Valid options include: - * url - {String} - * headers - {Object} - * params - {Object} URL parameters for GET requests - * format - {<OpenLayers.Format>} - * callback - {Function} - * scope - {Object} + * 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) { - options = options || {}; - this.params = {}; - this.headers = {}; - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); - - if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { - var format = new OpenLayers.Format.QueryStringFilter({ - wildcarded: this.wildcarded, - srsInBBOX: this.srsInBBOX - }); - this.filterToParams = function(filter, params) { - return format.write(filter, params); - }; - } - }, - - /** - * APIMethod: destroy - * Clean up the protocol. - */ - destroy: function() { - this.params = null; - this.headers = null; - OpenLayers.Protocol.prototype.destroy.apply(this); - }, - - /** - * APIMethod: filterToParams - * Optional method to translate an <OpenLayers.Filter> object into an object - * that can be serialized as request query string provided. If a custom - * method is not provided, the filter will be serialized using the - * <OpenLayers.Format.QueryStringFilter> class. - * - * Parameters: - * filter - {<OpenLayers.Filter>} filter to convert. - * params - {Object} The parameters object. - * - * Returns: - * {Object} The resulting parameters object. - */ - - /** - * 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>} Filter to get serialized as a - * query string. - * 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 features received from the server. - */ - read: function(options) { - OpenLayers.Protocol.prototype.read.apply(this, arguments); - options = options || {}; - options.params = OpenLayers.Util.applyDefaults( - options.params, this.options.params); - options = OpenLayers.Util.applyDefaults(options, this.options); - if (options.filter && this.filterToParams) { - options.params = this.filterToParams( - options.filter, options.params - ); - } - var readWithPOST = (options.readWithPOST !== undefined) ? - options.readWithPOST : this.readWithPOST; - var resp = new OpenLayers.Protocol.Response({requestType: "read"}); - if(readWithPOST) { - var headers = options.headers || {}; - headers["Content-Type"] = "application/x-www-form-urlencoded"; - resp.priv = OpenLayers.Request.POST({ - url: options.url, - callback: this.createCallback(this.handleRead, resp, options), - data: OpenLayers.Util.getParameterString(options.params), - headers: headers - }); - } 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) { - options = options || {}; - var url = options.url || - feature.url || - this.options.url + "/" + feature.fid; - options = OpenLayers.Util.applyDefaults(options, this.options); - - var resp = new OpenLayers.Protocol.Response({ - reqFeatures: feature, - requestType: "update" - }); - - var method = this.updateWithPOST ? "POST" : "PUT"; - resp.priv = OpenLayers.Request[method]({ - 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) { - options = options || {}; - var url = options.url || - feature.url || - this.options.url + "/" + feature.fid; - options = OpenLayers.Util.applyDefaults(options, this.options); - - var resp = new OpenLayers.Protocol.Response({ - reqFeatures: feature, - requestType: "delete" - }); - - var method = this.deleteWithPOST ? "POST" : "DELETE"; - var requestOptions = { - url: url, - callback: this.createCallback(this.handleDelete, resp, options), - headers: options.headers - }; - if (this.deleteWithPOST) { - requestOptions.data = this.format.write(feature); - } - resp.priv = OpenLayers.Request[method](requestOptions); - - 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" + + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" }); /* ====================================================================== OpenLayers/Strategy/Cluster.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -72548,11 +74376,11 @@ }); /* ====================================================================== OpenLayers/Strategy/Filter.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -72711,11 +74539,11 @@ }); /* ====================================================================== OpenLayers/Protocol/SOS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -72748,11 +74576,11 @@ }; /* ====================================================================== OpenLayers/Format/GeoRSS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -73161,11 +74989,11 @@ }); /* ====================================================================== OpenLayers/Format/WPSCapabilities.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -73213,11 +75041,11 @@ }); /* ====================================================================== OpenLayers/Format/WPSCapabilities/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -73342,11 +75170,10 @@ * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Util/vendorPrefix.js * @requires OpenLayers/Handler/Pinch.js */ /** * Class: OpenLayers.Control.PinchZoom @@ -73443,43 +75270,29 @@ var containerOrigin = this.map.layerContainerOriginPx; var pinchOrigin = this.pinchOrigin; var current = (this.preserveCenter) ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; - var dx = Math.round((current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); - var dy = Math.round((current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); + var dx = Math.round((containerOrigin.x + current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); + var dy = Math.round((containerOrigin.y + current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); - this.applyTransform( - "translate(" + dx + "px, " + dy + "px) scale(" + scale + ")" - ); + this.map.applyTransform(dx, dy, scale); this.currentCenter = current; }, - + /** - * Method: applyTransform - * Applies the given transform to layers. - */ - applyTransform: function(transform) { - var style = this.map.layerContainerDiv.style; - var transformProperty = OpenLayers.Util.vendorPrefix.style("transform"); - if (transformProperty) { - style[transformProperty] = transform; - } - }, - - /** * Method: pinchDone * * Parameters: * evt - {Event} * start - {Object} pinch data object related to the touchstart event that * started the pinch gesture. * last - {Object} pinch data object related to the last touchmove event * of the pinch gesture. This give us the final scale of the pinch. */ pinchDone: function(evt, start, last) { - this.applyTransform(""); + this.map.applyTransform(); var zoom = this.map.getZoomForResolution(this.map.getResolution() / last.scale, true); if (zoom !== this.map.getZoom() || !this.currentCenter.equals(this.pinchOrigin)) { var resolution = this.map.getResolutionForZoom(zoom); var location = this.map.getLonLatFromPixel(this.pinchOrigin); @@ -73689,21 +75502,277 @@ * * Parameters: * evt - {Event} */ defaultDblClick: function (evt) { - var newCenter = this.map.getLonLatFromViewPortPx(evt.xy); - this.map.setCenter(newCenter, this.map.zoom + 1); + this.map.zoomTo(this.map.zoom + 1, evt.xy); }, CLASS_NAME: "OpenLayers.Control.TouchNavigation" }); /* ====================================================================== + Rico/Color.js + ====================================================================== */ + +/** + * @requires Rico/license.js + * @requires OpenLayers/Console.js + * @requires OpenLayers/BaseTypes/Class.js + * @requires OpenLayers/BaseTypes/Element.js + */ + + +/* + * This file has been edited substantially from the Rico-released version by + * the OpenLayers development team. + */ + +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); + +OpenLayers.Rico = OpenLayers.Rico || {}; +OpenLayers.Rico.Color = OpenLayers.Class({ + + initialize: function(red, green, blue) { + this.rgb = { r: red, g : green, b : blue }; + }, + + setRed: function(r) { + this.rgb.r = r; + }, + + setGreen: function(g) { + this.rgb.g = g; + }, + + setBlue: function(b) { + this.rgb.b = b; + }, + + setHue: function(h) { + + // get an HSB model, and set the new hue... + var hsb = this.asHSB(); + hsb.h = h; + + // convert back to RGB... + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); + }, + + setSaturation: function(s) { + // get an HSB model, and set the new hue... + var hsb = this.asHSB(); + hsb.s = s; + + // convert back to RGB and set values... + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); + }, + + setBrightness: function(b) { + // get an HSB model, and set the new hue... + var hsb = this.asHSB(); + hsb.b = b; + + // convert back to RGB and set values... + this.rgb = OpenLayers.Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b ); + }, + + darken: function(percent) { + var hsb = this.asHSB(); + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0)); + }, + + brighten: function(percent) { + var hsb = this.asHSB(); + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1)); + }, + + blend: function(other) { + this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2); + this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2); + this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2); + }, + + isBright: function() { + var hsb = this.asHSB(); + return this.asHSB().b > 0.5; + }, + + isDark: function() { + return ! this.isBright(); + }, + + asRGB: function() { + return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; + }, + + asHex: function() { + return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); + }, + + asHSB: function() { + return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); + }, + + toString: function() { + return this.asHex(); + } + +}); + +OpenLayers.Rico.Color.createFromHex = function(hexCode) { + if(hexCode.length==4) { + var shortHexCode = hexCode; + var hexCode = '#'; + for(var i=1;i<4;i++) { + hexCode += (shortHexCode.charAt(i) + +shortHexCode.charAt(i)); + } + } + if ( hexCode.indexOf('#') == 0 ) { + hexCode = hexCode.substring(1); + } + var red = hexCode.substring(0,2); + var green = hexCode.substring(2,4); + var blue = hexCode.substring(4,6); + return new OpenLayers.Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) ); +}; + +/** + * Factory method for creating a color from the background of + * an HTML element. + */ +OpenLayers.Rico.Color.createColorFromBackground = function(elem) { + + var actualColor = + OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), + "backgroundColor"); + + if ( actualColor == "transparent" && elem.parentNode ) { + return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); + } + if ( actualColor == null ) { + return new OpenLayers.Rico.Color(255,255,255); + } + if ( actualColor.indexOf("rgb(") == 0 ) { + var colors = actualColor.substring(4, actualColor.length - 1 ); + var colorArray = colors.split(","); + return new OpenLayers.Rico.Color( parseInt( colorArray[0] ), + parseInt( colorArray[1] ), + parseInt( colorArray[2] ) ); + + } + else if ( actualColor.indexOf("#") == 0 ) { + return OpenLayers.Rico.Color.createFromHex(actualColor); + } + else { + return new OpenLayers.Rico.Color(255,255,255); + } +}; + +OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { + + var red = 0; + var green = 0; + var blue = 0; + + if (saturation == 0) { + red = parseInt(brightness * 255.0 + 0.5); + green = red; + blue = red; + } + else { + var h = (hue - Math.floor(hue)) * 6.0; + var f = h - Math.floor(h); + var p = brightness * (1.0 - saturation); + var q = brightness * (1.0 - saturation * f); + var t = brightness * (1.0 - (saturation * (1.0 - f))); + + switch (parseInt(h)) { + case 0: + red = (brightness * 255.0 + 0.5); + green = (t * 255.0 + 0.5); + blue = (p * 255.0 + 0.5); + break; + case 1: + red = (q * 255.0 + 0.5); + green = (brightness * 255.0 + 0.5); + blue = (p * 255.0 + 0.5); + break; + case 2: + red = (p * 255.0 + 0.5); + green = (brightness * 255.0 + 0.5); + blue = (t * 255.0 + 0.5); + break; + case 3: + red = (p * 255.0 + 0.5); + green = (q * 255.0 + 0.5); + blue = (brightness * 255.0 + 0.5); + break; + case 4: + red = (t * 255.0 + 0.5); + green = (p * 255.0 + 0.5); + blue = (brightness * 255.0 + 0.5); + break; + case 5: + red = (brightness * 255.0 + 0.5); + green = (p * 255.0 + 0.5); + blue = (q * 255.0 + 0.5); + break; + } + } + + return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) }; +}; + +OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { + + var hue; + var saturation; + var brightness; + + var cmax = (r > g) ? r : g; + if (b > cmax) { + cmax = b; + } + var cmin = (r < g) ? r : g; + if (b < cmin) { + cmin = b; + } + brightness = cmax / 255.0; + if (cmax != 0) { + saturation = (cmax - cmin)/cmax; + } else { + saturation = 0; + } + if (saturation == 0) { + hue = 0; + } else { + var redc = (cmax - r)/(cmax - cmin); + var greenc = (cmax - g)/(cmax - cmin); + var bluec = (cmax - b)/(cmax - cmin); + + if (r == cmax) { + hue = bluec - greenc; + } else if (g == cmax) { + hue = 2.0 + redc - bluec; + } else { + hue = 4.0 + greenc - redc; + } + hue = hue / 6.0; + if (hue < 0) { + hue = hue + 1.0; + } + } + + return { h : hue, s : saturation, b : brightness }; +}; + +/* ====================================================================== OpenLayers/Style2.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -73815,11 +75884,11 @@ }); /* ====================================================================== OpenLayers/Layer/Boxes.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -73895,11 +75964,11 @@ }); /* ====================================================================== OpenLayers/Format/WFSCapabilities/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -74003,325 +76072,896 @@ "SRS": function(node, obj) { var srs = this.getChildValue(node); if (srs) { obj.srs = srs; } + }, + "LatLongBoundingBox": function(node, obj) { + obj.latLongBoundingBox = [ + parseFloat(node.getAttribute("minx")), + parseFloat(node.getAttribute("miny")), + parseFloat(node.getAttribute("maxx")), + parseFloat(node.getAttribute("maxy")) + ]; } }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) }, CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" }); /* ====================================================================== - OpenLayers/Layer/PointGrid.js + OpenLayers/Format/CSWGetRecords/v2_0_2.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Layer/Vector.js - * @requires OpenLayers/Geometry/Polygon.js + * @requires OpenLayers/Format/XML.js + * @requires OpenLayers/Format/CSWGetRecords.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + * @requires OpenLayers/Format/Filter/v1_1_0.js + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js */ /** - * Class: OpenLayers.Layer.PointGrid - * A point grid layer dynamically generates a regularly spaced grid of point - * features. This is a specialty layer for cases where an application needs - * a regular grid of points. It can be used, for example, in an editing - * environment to snap to a grid. + * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 + * A format for creating CSWGetRecords v2.0.2 transactions. + * Create a new instance with the + * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. * - * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. - * (code) - * // create a grid with points spaced at 10 map units - * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); - * - * // create a grid with different x/y spacing rotated 15 degrees clockwise. - * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); - * (end) - * * Inherits from: - * - <OpenLayers.Layer.Vector> + * - <OpenLayers.Format.XML> */ -OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + csw: "http://www.opengis.net/cat/csw/2.0.2", + dc: "http://purl.org/dc/elements/1.1/", + dct: "http://purl.org/dc/terms/", + gmd: "http://www.isotc211.org/2005/gmd", + geonet: "http://www.fao.org/geonetwork", + ogc: "http://www.opengis.net/ogc", + ows: "http://www.opengis.net/ows", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + * {String} The default prefix (used by Format.XML). + */ + defaultPrefix: "csw", + + /** + * Property: version + * {String} CSW version number. + */ + version: "2.0.2", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/cat/csw/2.0.2 + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd + */ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", /** - * APIProperty: dx - * {Number} Point grid spacing in the x-axis direction (map units). - * Read-only. Use the <setSpacing> method to modify this value. + * APIProperty: requestId + * {String} Value of the requestId attribute of the GetRecords element. */ - dx: null, + requestId: null, /** - * APIProperty: dy - * {Number} Point grid spacing in the y-axis direction (map units). - * Read-only. Use the <setSpacing> method to modify this value. + * APIProperty: resultType + * {String} Value of the resultType attribute of the GetRecords element, + * specifies the result type in the GetRecords response, "hits" is + * the default. */ - dy: null, + resultType: null, /** - * APIProperty: ratio - * {Number} Ratio of the desired grid size to the map viewport size. - * Default is 1.5. Larger ratios mean the grid is recalculated less often - * while panning. The <maxFeatures> setting has precedence when determining - * grid size. Read-only. Use the <setRatio> method to modify this value. + * APIProperty: outputFormat + * {String} Value of the outputFormat attribute of the GetRecords element, + * specifies the format of the GetRecords response, + * "application/xml" is the default. */ - ratio: 1.5, + outputFormat: null, /** - * APIProperty: maxFeatures - * {Number} The maximum number of points to generate in the grid. Default - * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. + * APIProperty: outputSchema + * {String} Value of the outputSchema attribute of the GetRecords element, + * specifies the schema of the GetRecords response. */ - maxFeatures: 250, + outputSchema: null, /** - * APIProperty: rotation - * {Number} Grid rotation (in degrees clockwise from the positive x-axis). - * Default is 0. Read-only. Use the <setRotation> method to modify this - * value. + * APIProperty: startPosition + * {String} Value of the startPosition attribute of the GetRecords element, + * specifies the start position (offset+1) for the GetRecords response, + * 1 is the default. */ - rotation: 0, + startPosition: null, /** - * APIProperty: origin - * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with - * the origin. If not set at construction, the center of the map's maximum - * extent is used. Read-only. Use the <setOrigin> method to modify this - * value. + * APIProperty: maxRecords + * {String} Value of the maxRecords attribute of the GetRecords element, + * specifies the maximum number of records in the GetRecords response, + * 10 is the default. */ - origin: null, + maxRecords: null, /** - * Property: gridBounds - * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional - * rotation applied). + * APIProperty: DistributedSearch + * {String} Value of the csw:DistributedSearch element, used when writing + * a csw:GetRecords document. */ - gridBounds: null, + DistributedSearch: null, /** - * Constructor: OpenLayers.Layer.PointGrid - * Creates a new point grid layer. - * - * Parameters: - * config - {Object} An object containing all configuration properties for - * the layer. The <dx> and <dy> properties are required to be set at - * construction. Any other layer properties may be set in this object. + * APIProperty: ResponseHandler + * {Array({String})} Values of the csw:ResponseHandler elements, used when + * writting a csw:GetRecords document. */ - initialize: function(config) { - config = config || {}; - OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); - }, - - /** - * Method: setMap - * The layer has been added to the map. - * - * Parameters: - * map - {<OpenLayers.Map>} + ResponseHandler: null, + + /** + * APIProperty: Query + * {String} Value of the csw:Query element, used when writing a csw:GetRecords + * document. */ - setMap: function(map) { - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); - map.events.register("moveend", this, this.onMoveEnd); + Query: null, + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) }, /** - * Method: removeMap - * The layer has been removed from the map. + * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 + * A class for parsing and generating CSWGetRecords v2.0.2 transactions. * * Parameters: - * map - {<OpenLayers.Map>} + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties (documented as class properties): + * - requestId + * - resultType + * - outputFormat + * - outputSchema + * - startPosition + * - maxRecords + * - DistributedSearch + * - ResponseHandler + * - Query */ - removeMap: function(map) { - map.events.unregister("moveend", this, this.onMoveEnd); - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); }, + + /** + * APIMethod: read + * Parse the response from a GetRecords request. + */ + 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); + return obj; + }, /** - * APIMethod: setRatio - * Set the grid <ratio> property and update the grid. Can only be called - * after the layer has been added to a map with a center/extent. - * - * Parameters: - * ratio - {Number} + * 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. */ - setRatio: function(ratio) { - this.ratio = ratio; - this.updateGrid(true); + readers: { + "csw": { + "GetRecordsResponse": function(node, obj) { + obj.records = []; + this.readChildNodes(node, obj); + var version = this.getAttributeNS(node, "", 'version'); + if (version != "") { + obj.version = version; + } + }, + "RequestId": function(node, obj) { + obj.RequestId = this.getChildValue(node); + }, + "SearchStatus": function(node, obj) { + obj.SearchStatus = {}; + var timestamp = this.getAttributeNS(node, "", 'timestamp'); + if (timestamp != "") { + obj.SearchStatus.timestamp = timestamp; + } + }, + "SearchResults": function(node, obj) { + this.readChildNodes(node, obj); + var attrs = node.attributes; + var SearchResults = {}; + for(var i=0, len=attrs.length; i<len; ++i) { + if ((attrs[i].name == "numberOfRecordsMatched") || + (attrs[i].name == "numberOfRecordsReturned") || + (attrs[i].name == "nextRecord")) { + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); + } else { + SearchResults[attrs[i].name] = attrs[i].nodeValue; + } + } + obj.SearchResults = SearchResults; + }, + "SummaryRecord": function(node, obj) { + var record = {type: "SummaryRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "BriefRecord": function(node, obj) { + var record = {type: "BriefRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "DCMIRecord": function(node, obj) { + var record = {type: "DCMIRecord"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "Record": function(node, obj) { + var record = {type: "Record"}; + this.readChildNodes(node, record); + obj.records.push(record); + }, + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + obj[name] = this.getChildValue(node); + } + }, + "geonet": { + "info": function(node, obj) { + var gninfo = {}; + this.readChildNodes(node, gninfo); + obj.gninfo = gninfo; + } + }, + "dc": { + // audience, contributor, coverage, creator, date, description, format, + // identifier, language, provenance, publisher, relation, rights, + // rightsHolder, source, subject, title, type, URI + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + if (!(OpenLayers.Util.isArray(obj[name]))) { + obj[name] = []; + } + var dc_element = {}; + var attrs = node.attributes; + for(var i=0, len=attrs.length; i<len; ++i) { + dc_element[attrs[i].name] = attrs[i].nodeValue; + } + dc_element.value = this.getChildValue(node); + if (dc_element.value != "") { + obj[name].push(dc_element); + } + } + }, + "dct": { + // abstract, modified, spatial + "*": function(node, obj) { + var name = node.localName || node.nodeName.split(":").pop(); + if (!(OpenLayers.Util.isArray(obj[name]))) { + obj[name] = []; + } + obj[name].push(this.getChildValue(node)); + } + }, + "ows": OpenLayers.Util.applyDefaults({ + "BoundingBox": function(node, obj) { + if (obj.bounds) { + obj.BoundingBox = [{crs: obj.projection, value: + [ + obj.bounds.left, + obj.bounds.bottom, + obj.bounds.right, + obj.bounds.top + ] + }]; + delete obj.projection; + delete obj.bounds; + } + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( + this, arguments); + } + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) }, /** - * APIMethod: setMaxFeatures - * Set the grid <maxFeatures> property and update the grid. Can only be - * called after the layer has been added to a map with a center/extent. + * Method: write + * Given an configuration js object, write a CSWGetRecords request. * * Parameters: - * maxFeatures - {Number} + * options - {Object} A object mapping the request. + * + * Returns: + * {String} A serialized CSWGetRecords request. */ - setMaxFeatures: function(maxFeatures) { - this.maxFeatures = maxFeatures; - this.updateGrid(true); + write: function(options) { + var node = this.writeNode("csw:GetRecords", options); + node.setAttribute("xmlns:gmd", this.namespaces.gmd); + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); }, /** - * APIMethod: setSpacing - * Set the grid <dx> and <dy> properties and update the grid. If only one - * argument is provided, it will be set as <dx> and <dy>. Can only be - * called after the layer has been added to a map with a center/extent. - * - * Parameters: - * dx - {Number} - * dy - {Number} + * 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. */ - setSpacing: function(dx, dy) { - this.dx = dx; - this.dy = dy || dx; - this.updateGrid(true); + writers: { + "csw": { + "GetRecords": function(options) { + if (!options) { + options = {}; + } + var node = this.createElementNSPlus("csw:GetRecords", { + attributes: { + service: "CSW", + version: this.version, + requestId: options.requestId || this.requestId, + resultType: options.resultType || this.resultType, + outputFormat: options.outputFormat || this.outputFormat, + outputSchema: options.outputSchema || this.outputSchema, + startPosition: options.startPosition || this.startPosition, + maxRecords: options.maxRecords || this.maxRecords + } + }); + if (options.DistributedSearch || this.DistributedSearch) { + this.writeNode( + "csw:DistributedSearch", + options.DistributedSearch || this.DistributedSearch, + node + ); + } + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { + // ResponseHandler must be a non-empty array + for(var i=0, len=ResponseHandler.length; i<len; i++) { + this.writeNode( + "csw:ResponseHandler", + ResponseHandler[i], + node + ); + } + } + this.writeNode("Query", options.Query || this.Query, node); + return node; + }, + "DistributedSearch": function(options) { + var node = this.createElementNSPlus("csw:DistributedSearch", { + attributes: { + hopCount: options.hopCount + } + }); + return node; + }, + "ResponseHandler": function(options) { + var node = this.createElementNSPlus("csw:ResponseHandler", { + value: options.value + }); + return node; + }, + "Query": function(options) { + if (!options) { + options = {}; + } + var node = this.createElementNSPlus("csw:Query", { + attributes: { + typeNames: options.typeNames || "csw:Record" + } + }); + var ElementName = options.ElementName; + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { + // ElementName must be a non-empty array + for(var i=0, len=ElementName.length; i<len; i++) { + this.writeNode( + "csw:ElementName", + ElementName[i], + node + ); + } + } else { + this.writeNode( + "csw:ElementSetName", + options.ElementSetName || {value: 'summary'}, + node + ); + } + if (options.Constraint) { + this.writeNode( + "csw:Constraint", + options.Constraint, + node + ); + } + if (options.SortBy) { + this.writeNode( + "ogc:SortBy", + options.SortBy, + node + ); + } + return node; + }, + "ElementName": function(options) { + var node = this.createElementNSPlus("csw:ElementName", { + value: options.value + }); + return node; + }, + "ElementSetName": function(options) { + var node = this.createElementNSPlus("csw:ElementSetName", { + attributes: { + typeNames: options.typeNames + }, + value: options.value + }); + return node; + }, + "Constraint": function(options) { + var node = this.createElementNSPlus("csw:Constraint", { + attributes: { + version: options.version + } + }); + if (options.Filter) { + var format = new OpenLayers.Format.Filter({ + version: options.version + }); + node.appendChild(format.write(options.Filter)); + } else if (options.CqlText) { + var child = this.createElementNSPlus("CqlText", { + value: options.CqlText.value + }); + node.appendChild(child); + } + return node; + } + }, + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] }, + + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" +}); +/* ====================================================================== + OpenLayers/Control/WMTSGetFeatureInfo.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Handler/Click.js + * @requires OpenLayers/Handler/Hover.js + * @requires OpenLayers/Request.js + * @requires OpenLayers/Format/WMSGetFeatureInfo.js + */ + +/** + * Class: OpenLayers.Control.WMTSGetFeatureInfo + * The WMTSGetFeatureInfo control uses a WMTS query to get information about a + * point on the map. The information may be in a display-friendly format + * such as HTML, or a machine-friendly format such as GML, depending on the + * server's capabilities and the client's configuration. This control + * handles click or hover events, attempts to parse the results using an + * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer + * queried. + * + * Inherits from: + * - <OpenLayers.Control> + */ +OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: hover + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. + * Default is false. + */ + hover: false, /** - * APIMethod: setOrigin - * Set the grid <origin> property and update the grid. Can only be called - * after the layer has been added to a map with a center/extent. + * Property: requestEncoding + * {String} One of "KVP" or "REST". Only KVP encoding is supported at this + * time. + */ + requestEncoding: "KVP", + + /** + * APIProperty: drillDown + * {Boolean} Drill down over all WMTS layers in the map. When + * using drillDown mode, hover is not possible. A getfeatureinfo event + * will be fired for each layer queried. + */ + drillDown: false, + + /** + * APIProperty: maxFeatures + * {Integer} Maximum number of features to return from a WMTS query. This + * sets the feature_count parameter on WMTS GetFeatureInfo + * requests. + */ + maxFeatures: 10, + + /** APIProperty: clickCallback + * {String} The click callback to register in the + * {<OpenLayers.Handler.Click>} object created when the hover + * option is set to false. Default is "click". + */ + clickCallback: "click", + + /** + * Property: layers + * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. + * If omitted, all map WMTS layers will be considered. + */ + layers: null, + + /** + * APIProperty: queryVisible + * {Boolean} Filter out hidden layers when searching the map for layers to + * query. Default is true. + */ + queryVisible: true, + + /** + * Property: infoFormat + * {String} The mimetype to request from the server + */ + infoFormat: 'text/html', + + /** + * Property: vendorParams + * {Object} Additional parameters that will be added to the request, for + * WMTS implementations that support them. This could e.g. look like + * (start code) + * { + * radius: 5 + * } + * (end) + */ + vendorParams: {}, + + /** + * Property: format + * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. + * Default is <OpenLayers.Format.WMSGetFeatureInfo>. + */ + format: null, + + /** + * Property: formatOptions + * {Object} Optional properties to set on the format (if one is not provided + * in the <format> property. + */ + formatOptions: null, + + /** + * APIProperty: handlerOptions + * {Object} Additional options for the handlers used by this control, e.g. + * (start code) + * { + * "click": {delay: 100}, + * "hover": {delay: 300} + * } + * (end) + */ + + /** + * Property: handler + * {Object} Reference to the <OpenLayers.Handler> for this control + */ + handler: null, + + /** + * Property: hoverRequest + * {<OpenLayers.Request>} contains the currently running hover request + * (if any). + */ + hoverRequest: null, + + /** + * APIProperty: events + * {<OpenLayers.Events>} Events instance for listeners and triggering + * control specific events. * - * Parameters: - * origin - {<OpenLayers.LonLat>} + * Register a listener for a particular event with the following syntax: + * (code) + * control.events.register(type, obj, listener); + * (end) + * + * Supported event types (in addition to those from <OpenLayers.Control.events>): + * beforegetfeatureinfo - Triggered before each request is sent. + * The event object has an *xy* property with the position of the + * mouse click or hover event that triggers the request and a *layer* + * property referencing the layer about to be queried. If a listener + * returns false, the request will not be issued. + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. + * The event object has a *text* property with the body of the + * response (String), a *features* property with an array of the + * parsed features, an *xy* property with the position of the mouse + * click or hover event that triggered the request, a *layer* property + * referencing the layer queried and a *request* property with the + * request itself. If drillDown is set to true, one event will be fired + * for each layer queried. + * exception - Triggered when a GetFeatureInfo request fails (with a + * status other than 200) or whenparsing fails. Listeners will receive + * an event with *request*, *xy*, and *layer* properties. In the case + * of a parsing error, the event will also contain an *error* property. */ - setOrigin: function(origin) { - this.origin = origin; - this.updateGrid(true); - }, + /** + * Property: pending + * {Number} The number of pending requests. + */ + pending: 0, + /** - * APIMethod: getOrigin - * Get the grid <origin> property. + * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> * - * Returns: - * {<OpenLayers.LonLat>} The grid origin. + * Parameters: + * options - {Object} */ - getOrigin: function() { - if (!this.origin) { - this.origin = this.map.getExtent().getCenterLonLat(); + initialize: function(options) { + options = options || {}; + options.handlerOptions = options.handlerOptions || {}; + + OpenLayers.Control.prototype.initialize.apply(this, [options]); + + if (!this.format) { + this.format = new OpenLayers.Format.WMSGetFeatureInfo( + options.formatOptions + ); } - return this.origin; + + if (this.drillDown === true) { + this.hover = false; + } + + if (this.hover) { + this.handler = new OpenLayers.Handler.Hover( + this, { + move: this.cancelHover, + pause: this.getInfoForHover + }, + OpenLayers.Util.extend( + this.handlerOptions.hover || {}, {delay: 250} + ) + ); + } else { + var callbacks = {}; + callbacks[this.clickCallback] = this.getInfoForClick; + this.handler = new OpenLayers.Handler.Click( + this, callbacks, this.handlerOptions.click || {} + ); + } }, - + /** - * APIMethod: setRotation - * Set the grid <rotation> property and update the grid. Rotation values - * are in degrees clockwise from the positive x-axis (negative values - * for counter-clockwise rotation). Can only be called after the layer - * has been added to a map with a center/extent. + * Method: getInfoForClick + * Called on click * * Parameters: - * rotation - {Number} Degrees clockwise from the positive x-axis. + * evt - {<OpenLayers.Event>} */ - setRotation: function(rotation) { - this.rotation = rotation; - this.updateGrid(true); + getInfoForClick: function(evt) { + this.request(evt.xy, {}); }, - + /** - * Method: onMoveEnd - * Listener for map "moveend" events. + * Method: getInfoForHover + * Pause callback for the hover handler + * + * Parameters: + * evt - {Object} */ - onMoveEnd: function() { - this.updateGrid(); + getInfoForHover: function(evt) { + this.request(evt.xy, {hover: true}); }, - + /** - * Method: getViewBounds - * Gets the (potentially rotated) view bounds for grid calculations. - * - * Returns: - * {<OpenLayers.Bounds>} + * Method: cancelHover + * Cancel callback for the hover handler */ - getViewBounds: function() { - var bounds = this.map.getExtent(); - if (this.rotation) { - var origin = this.getOrigin(); - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); - var rect = bounds.toGeometry(); - rect.rotate(-this.rotation, rotationOrigin); - bounds = rect.getBounds(); + cancelHover: function() { + if (this.hoverRequest) { + --this.pending; + if (this.pending <= 0) { + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + this.pending = 0; + } + this.hoverRequest.abort(); + this.hoverRequest = null; } - return bounds; }, + + /** + * Method: findLayers + * Internal method to get the layers, independent of whether we are + * inspecting the map or using a client-provided array + */ + findLayers: function() { + var candidates = this.layers || this.map.layers; + var layers = []; + var layer; + for (var i=candidates.length-1; i>=0; --i) { + layer = candidates[i]; + if (layer instanceof OpenLayers.Layer.WMTS && + layer.requestEncoding === this.requestEncoding && + (!this.queryVisible || layer.getVisibility())) { + layers.push(layer); + if (!this.drillDown || this.hover) { + break; + } + } + } + return layers; + }, /** - * Method: updateGrid - * Update the grid. + * Method: buildRequestOptions + * Build an object with the relevant options for the GetFeatureInfo request. * * Parameters: - * force - {Boolean} Update the grid even if the previous bounds are still - * valid. + * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. + * xy - {<OpenLayers.Pixel>} The position on the map where the + * mouse event occurred. */ - updateGrid: function(force) { - if (force || this.invalidBounds()) { - var viewBounds = this.getViewBounds(); - var origin = this.getOrigin(); - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); - var viewBoundsWidth = viewBounds.getWidth(); - var viewBoundsHeight = viewBounds.getHeight(); - var aspectRatio = viewBoundsWidth / viewBoundsHeight; - var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); - var maxWidth = maxHeight * aspectRatio; - var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); - var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); - var center = viewBounds.getCenterLonLat(); - this.gridBounds = new OpenLayers.Bounds( - center.lon - (gridWidth / 2), - center.lat - (gridHeight / 2), - center.lon + (gridWidth / 2), - center.lat + (gridHeight / 2) - ); - var rows = Math.floor(gridHeight / this.dy); - var cols = Math.floor(gridWidth / this.dx); - var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); - var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); - var features = new Array(rows * cols); - var x, y, point; - for (var i=0; i<cols; ++i) { - x = gridLeft + (i * this.dx); - for (var j=0; j<rows; ++j) { - y = gridBottom + (j * this.dy); - point = new OpenLayers.Geometry.Point(x, y); - if (this.rotation) { - point.rotate(this.rotation, rotationOrigin); + buildRequestOptions: function(layer, xy) { + var loc = this.map.getLonLatFromPixel(xy); + var getTileUrl = layer.getURL( + new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) + ); + var params = OpenLayers.Util.getParameters(getTileUrl); + var tileInfo = layer.getTileInfo(loc); + OpenLayers.Util.extend(params, { + service: "WMTS", + version: layer.version, + request: "GetFeatureInfo", + infoFormat: this.infoFormat, + feature_count: this.maxFeatures, + i: tileInfo.i, + j: tileInfo.j + }); + OpenLayers.Util.applyDefaults(params, this.vendorParams); + return { + url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, + params: OpenLayers.Util.upperCaseObject(params), + callback: function(request) { + this.handleResponse(xy, request, layer); + }, + scope: this + }; + }, + + /** + * Method: request + * Sends a GetFeatureInfo request to the WMTS + * + * Parameters: + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event + * occurred. + * options - {Object} additional options for this method. + * + * Valid options: + * - *hover* {Boolean} true if we do the request for the hover handler + */ + request: function(xy, options) { + options = options || {}; + var layers = this.findLayers(); + if (layers.length > 0) { + var issue, layer; + for (var i=0, len=layers.length; i<len; i++) { + layer = layers[i]; + issue = this.events.triggerEvent("beforegetfeatureinfo", { + xy: xy, + layer: layer + }); + if (issue !== false) { + ++this.pending; + var requestOptions = this.buildRequestOptions(layer, xy); + var request = OpenLayers.Request.GET(requestOptions); + if (options.hover === true) { + this.hoverRequest = request; } - features[(i*rows)+j] = new OpenLayers.Feature.Vector(point); } } - this.destroyFeatures(this.features, {silent: true}); - this.addFeatures(features, {silent: true}); + if (this.pending > 0) { + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); + } } }, /** - * Method: invalidBounds - * Determine whether the previously generated point grid is invalid. - * This occurs when the map bounds extends beyond the previously - * generated grid bounds. - * - * Returns: - * {Boolean} + * Method: handleResponse + * Handler for the GetFeatureInfo response. + * + * Parameters: + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event + * occurred. + * request - {XMLHttpRequest} The request object. + * layer - {<OpenLayers.Layer.WMTS>} The queried layer. */ - invalidBounds: function() { - return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); + handleResponse: function(xy, request, layer) { + --this.pending; + if (this.pending <= 0) { + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + this.pending = 0; + } + if (request.status && (request.status < 200 || request.status >= 300)) { + this.events.triggerEvent("exception", { + xy: xy, + request: request, + layer: layer + }); + } else { + var doc = request.responseXML; + if (!doc || !doc.documentElement) { + doc = request.responseText; + } + var features, except; + try { + features = this.format.read(doc); + } catch (error) { + except = true; + this.events.triggerEvent("exception", { + xy: xy, + request: request, + error: error, + layer: layer + }); + } + if (!except) { + this.events.triggerEvent("getfeatureinfo", { + text: request.responseText, + features: features, + request: request, + xy: xy, + layer: layer + }); + } + } }, - CLASS_NAME: "OpenLayers.Layer.PointGrid" - + CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" }); /* ====================================================================== OpenLayers/Layer/Zoomify.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /* @@ -74409,11 +77049,11 @@ // initilize the Zoomify pyramid for given size this.initializeZoomify(size); OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ - name, url, size, {}, options + name, url, {}, options ]); }, /** * Method: initializeZoomify @@ -74507,10 +77147,31 @@ return obj; }, /** + * Method: createBackBuffer + * Create a back buffer. + * + * Returns: + * {DOMElement} The DOM element for the back buffer, undefined if the + * grid isn't initialized yet. + */ + createBackBuffer: function() { + var backBuffer = OpenLayers.Layer.Grid.prototype.createBackBuffer.apply(this, arguments); + if(backBuffer) { + var image; + for (var i=backBuffer.childNodes.length-1; i>=0; --i) { + image = backBuffer.childNodes[i]; + image._w = image.width; + image._h = image.height; + } + } + return backBuffer; + }, + + /** * Method: getURL * * Parameters: * bounds - {<OpenLayers.Bounds>} * @@ -74551,14 +77212,27 @@ var z = this.getZoomForResolution( res ); var w = this.standardTileSize; var h = this.standardTileSize; if (x == this.tierSizeInTiles[z].w -1 ) { var w = this.tierImageSize[z].w % this.standardTileSize; + if (w == 0) { + w = this.standardTileSize; + } } if (y == this.tierSizeInTiles[z].h -1 ) { var h = this.tierImageSize[z].h % this.standardTileSize; + if (h == 0) { + h = this.standardTileSize; + } } + // in jp2 format, dimensions of tiles are ceiled, that means there may be requested part of image (1px usually) above dimension stated in tierImageSize. + if (x == this.tierSizeInTiles[z].w) { + w = Math.ceil(this.size.w / Math.pow(2, this.numberOfTiers - 1 - z) - this.tierImageSize[z].w); + } + if (y == this.tierSizeInTiles[z].h) { + h = Math.ceil(this.size.h / Math.pow(2, this.numberOfTiers - 1 - z) - this.tierImageSize[z].h); + } return (new OpenLayers.Size(w, h)); } else { return this.tileSize; } }, @@ -74581,11 +77255,11 @@ }); /* ====================================================================== OpenLayers/Handler/RegularPolygon.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -75014,11 +77688,11 @@ }); /* ====================================================================== OpenLayers/Layer/MapServer.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -75109,11 +77783,11 @@ 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(); + var imageSize = this.getImageSize(bounds); // make lists, so that literal ','s are used var url = this.getFullRequestString( {mapext: extent, imgext: extent, @@ -75199,11 +77873,11 @@ }); /* ====================================================================== OpenLayers/Renderer/VML.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -76188,11 +78862,11 @@ }; /* ====================================================================== OpenLayers/Control/CacheRead.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -76345,466 +79019,670 @@ }, CLASS_NAME: "OpenLayers.Control.CacheRead" }); /* ====================================================================== - OpenLayers/Protocol/WFS/v1_0_0.js + OpenLayers/Protocol/HTTP.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Protocol/WFS/v1.js - * @requires OpenLayers/Format/WFST/v1_0_0.js + * @requires OpenLayers/Protocol.js + * @requires OpenLayers/Request/XMLHttpRequest.js */ /** - * Class: OpenLayers.Protocol.WFS.v1_0_0 - * A WFS v1.0.0 protocol for vector layers. Create a new instance with the - * <OpenLayers.Protocol.WFS.v1_0_0> constructor. + * if application uses the query string, for example, for BBOX parameters, + * OpenLayers/Format/QueryStringFilter.js should be included in the build config file + */ + +/** + * 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.WFS.v1> + * - <OpenLayers.Protocol> */ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { - +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { + /** - * Property: version - * {String} WFS version number. + * Property: url + * {String} Service URL, read-only, set through the options + * passed to constructor. */ - version: "1.0.0", - + url: null, + /** - * Constructor: OpenLayers.Protocol.WFS.v1_0_0 - * A class for giving layers WFS v1.0.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'. + * Property: headers + * {Object} HTTP request headers, read-only, set through the options + * passed to the constructor, + * Example: {'Content-Type': 'plain/text'} */ - - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" -}); -/* ====================================================================== - OpenLayers/Control/WMTSGetFeatureInfo.js - ====================================================================== */ + headers: null, -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Handler/Click.js - * @requires OpenLayers/Handler/Hover.js - * @requires OpenLayers/Request.js - * @requires OpenLayers/Format/WMSGetFeatureInfo.js - */ - -/** - * Class: OpenLayers.Control.WMTSGetFeatureInfo - * The WMTSGetFeatureInfo control uses a WMTS query to get information about a - * point on the map. The information may be in a display-friendly format - * such as HTML, or a machine-friendly format such as GML, depending on the - * server's capabilities and the client's configuration. This control - * handles click or hover events, attempts to parse the results using an - * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer - * queried. - * - * Inherits from: - * - <OpenLayers.Control> - */ -OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: hover - * {Boolean} Send GetFeatureInfo requests when mouse stops moving. - * Default is false. + /** + * Property: params + * {Object} Parameters of GET requests, read-only, set through the options + * passed to the constructor, + * Example: {'bbox': '5,5,5,5'} */ - hover: false, + params: null, /** - * Property: requestEncoding - * {String} One of "KVP" or "REST". Only KVP encoding is supported at this - * time. + * 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. */ - requestEncoding: "KVP", + callback: null, /** - * APIProperty: drillDown - * {Boolean} Drill down over all WMTS layers in the map. When - * using drillDown mode, hover is not possible. A getfeatureinfo event - * will be fired for each layer queried. + * Property: scope + * {Object} Callback execution scope, read-only, set through the + * options passed to the constructor. */ - drillDown: false, + scope: null, /** - * APIProperty: maxFeatures - * {Integer} Maximum number of features to return from a WMTS query. This - * sets the feature_count parameter on WMTS GetFeatureInfo - * requests. + * APIProperty: readWithPOST + * {Boolean} true if read operations are done with POST requests + * instead of GET, defaults to false. */ - maxFeatures: 10, + readWithPOST: false, - /** APIProperty: clickCallback - * {String} The click callback to register in the - * {<OpenLayers.Handler.Click>} object created when the hover - * option is set to false. Default is "click". + /** + * APIProperty: updateWithPOST + * {Boolean} true if update operations are done with POST requests + * defaults to false. */ - clickCallback: "click", + updateWithPOST: false, /** - * Property: layers - * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. - * If omitted, all map WMTS layers will be considered. + * APIProperty: deleteWithPOST + * {Boolean} true if delete operations are done with POST requests + * defaults to false. + * if true, POST data is set to output of format.write(). */ - layers: null, + deleteWithPOST: false, /** - * APIProperty: queryVisible - * {Boolean} Filter out hidden layers when searching the map for layers to - * query. Default is true. + * Property: wildcarded. + * {Boolean} If true percent signs are added around values + * read from LIKE filters, for example if the protocol + * read method is passed a LIKE filter whose property + * is "foo" and whose value is "bar" the string + * "foo__ilike=%bar%" will be sent in the query string; + * defaults to false. */ - queryVisible: true, + wildcarded: false, /** - * Property: infoFormat - * {String} The mimetype to request from the server + * APIProperty: srsInBBOX + * {Boolean} Include the SRS identifier in BBOX query string parameter. + * Default is false. If true and the layer has a projection object set, + * any BBOX filter will be serialized with a fifth item identifying the + * projection. E.g. bbox=-1000,-1000,1000,1000,EPSG:900913 */ - infoFormat: 'text/html', - + srsInBBOX: false, + /** - * Property: vendorParams - * {Object} Additional parameters that will be added to the request, for - * WMTS implementations that support them. This could e.g. look like - * (start code) - * { - * radius: 5 - * } - * (end) + * 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} URL parameters for GET requests + * format - {<OpenLayers.Format>} + * callback - {Function} + * scope - {Object} */ - vendorParams: {}, + initialize: function(options) { + options = options || {}; + this.params = {}; + this.headers = {}; + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); + + if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { + var format = new OpenLayers.Format.QueryStringFilter({ + wildcarded: this.wildcarded, + srsInBBOX: this.srsInBBOX + }); + this.filterToParams = function(filter, params) { + return format.write(filter, params); + }; + } + }, /** - * Property: format - * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. - * Default is <OpenLayers.Format.WMSGetFeatureInfo>. + * APIMethod: destroy + * Clean up the protocol. */ - format: null, - - /** - * Property: formatOptions - * {Object} Optional properties to set on the format (if one is not provided - * in the <format> property. - */ - formatOptions: null, + destroy: function() { + this.params = null; + this.headers = null; + OpenLayers.Protocol.prototype.destroy.apply(this); + }, /** - * APIProperty: handlerOptions - * {Object} Additional options for the handlers used by this control, e.g. - * (start code) - * { - * "click": {delay: 100}, - * "hover": {delay: 300} - * } - * (end) + * APIMethod: filterToParams + * Optional method to translate an <OpenLayers.Filter> object into an object + * that can be serialized as request query string provided. If a custom + * method is not provided, the filter will be serialized using the + * <OpenLayers.Format.QueryStringFilter> class. + * + * Parameters: + * filter - {<OpenLayers.Filter>} filter to convert. + * params - {Object} The parameters object. + * + * Returns: + * {Object} The resulting parameters object. */ /** - * Property: handler - * {Object} Reference to the <OpenLayers.Handler> for this control + * 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>} Filter to get serialized as a + * query string. + * 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 features received from the server. */ - handler: null, - + read: function(options) { + OpenLayers.Protocol.prototype.read.apply(this, arguments); + options = options || {}; + options.params = OpenLayers.Util.applyDefaults( + options.params, this.options.params); + options = OpenLayers.Util.applyDefaults(options, this.options); + if (options.filter && this.filterToParams) { + options.params = this.filterToParams( + options.filter, options.params + ); + } + var readWithPOST = (options.readWithPOST !== undefined) ? + options.readWithPOST : this.readWithPOST; + var resp = new OpenLayers.Protocol.Response({requestType: "read"}); + if(readWithPOST) { + var headers = options.headers || {}; + headers["Content-Type"] = "application/x-www-form-urlencoded"; + resp.priv = OpenLayers.Request.POST({ + url: options.url, + callback: this.createCallback(this.handleRead, resp, options), + data: OpenLayers.Util.getParameterString(options.params), + headers: headers + }); + } else { + resp.priv = OpenLayers.Request.GET({ + url: options.url, + callback: this.createCallback(this.handleRead, resp, options), + params: options.params, + headers: options.headers + }); + } + return resp; + }, + /** - * Property: hoverRequest - * {<OpenLayers.Request>} contains the currently running hover request - * (if any). + * 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. */ - hoverRequest: null, - - /** - * APIProperty: events - * {<OpenLayers.Events>} Events instance for listeners and triggering - * control specific events. + handleRead: function(resp, options) { + this.handleResponse(resp, options); + }, + + /** + * APIMethod: create + * Construct a request for writing newly created features. * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) + * 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. * - * Supported event types (in addition to those from <OpenLayers.Control.events>): - * beforegetfeatureinfo - Triggered before each request is sent. - * The event object has an *xy* property with the position of the - * mouse click or hover event that triggers the request and a *layer* - * property referencing the layer about to be queried. If a listener - * returns false, the request will not be issued. - * getfeatureinfo - Triggered when a GetFeatureInfo response is received. - * The event object has a *text* property with the body of the - * response (String), a *features* property with an array of the - * parsed features, an *xy* property with the position of the mouse - * click or hover event that triggered the request, a *layer* property - * referencing the layer queried and a *request* property with the - * request itself. If drillDown is set to true, one event will be fired - * for each layer queried. - * exception - Triggered when a GetFeatureInfo request fails (with a - * status other than 200) or whenparsing fails. Listeners will receive - * an event with *request*, *xy*, and *layer* properties. In the case - * of a parsing error, the event will also contain an *error* property. + * 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. */ - - /** - * Property: pending - * {Number} The number of pending requests. + 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. */ - pending: 0, + handleCreate: function(resp, options) { + this.handleResponse(resp, options); + }, /** - * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> + * APIMethod: update + * Construct a request updating modified feature. * * Parameters: - * options - {Object} + * 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. */ - initialize: function(options) { + update: function(feature, options) { options = options || {}; - options.handlerOptions = options.handlerOptions || {}; + var url = options.url || + feature.url || + this.options.url + "/" + feature.fid; + options = OpenLayers.Util.applyDefaults(options, this.options); - OpenLayers.Control.prototype.initialize.apply(this, [options]); - - if (!this.format) { - this.format = new OpenLayers.Format.WMSGetFeatureInfo( - options.formatOptions - ); - } - - if (this.drillDown === true) { - this.hover = false; - } + var resp = new OpenLayers.Protocol.Response({ + reqFeatures: feature, + requestType: "update" + }); - if (this.hover) { - this.handler = new OpenLayers.Handler.Hover( - this, { - move: this.cancelHover, - pause: this.getInfoForHover - }, - OpenLayers.Util.extend( - this.handlerOptions.hover || {}, {delay: 250} - ) - ); - } else { - var callbacks = {}; - callbacks[this.clickCallback] = this.getInfoForClick; - this.handler = new OpenLayers.Handler.Click( - this, callbacks, this.handlerOptions.click || {} - ); - } + var method = this.updateWithPOST ? "POST" : "PUT"; + resp.priv = OpenLayers.Request[method]({ + url: url, + callback: this.createCallback(this.handleUpdate, resp, options), + headers: options.headers, + data: this.format.write(feature) + }); + + return resp; }, /** - * Method: getInfoForClick - * Called on click + * Method: handleUpdate + * Called the the request issued by <update> is complete. May be overridden + * by subclasses. * * Parameters: - * evt - {<OpenLayers.Event>} + * resp - {<OpenLayers.Protocol.Response>} The response object to pass to + * any user callback. + * options - {Object} The user options passed to the update call. */ - getInfoForClick: function(evt) { - this.request(evt.xy, {}); + handleUpdate: function(resp, options) { + this.handleResponse(resp, options); }, - + /** - * Method: getInfoForHover - * Pause callback for the hover handler + * APIMethod: delete + * Construct a request deleting a removed feature. * * Parameters: - * evt - {Object} + * 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. */ - getInfoForHover: function(evt) { - this.request(evt.xy, {hover: true}); + "delete": function(feature, options) { + options = options || {}; + var url = options.url || + feature.url || + this.options.url + "/" + feature.fid; + options = OpenLayers.Util.applyDefaults(options, this.options); + + var resp = new OpenLayers.Protocol.Response({ + reqFeatures: feature, + requestType: "delete" + }); + + var method = this.deleteWithPOST ? "POST" : "DELETE"; + var requestOptions = { + url: url, + callback: this.createCallback(this.handleDelete, resp, options), + headers: options.headers + }; + if (this.deleteWithPOST) { + requestOptions.data = this.format.write(feature); + } + resp.priv = OpenLayers.Request[method](requestOptions); + + return resp; }, /** - * Method: cancelHover - * Cancel callback for the hover handler + * 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. */ - cancelHover: function() { - if (this.hoverRequest) { - --this.pending; - if (this.pending <= 0) { - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); - this.pending = 0; - } - this.hoverRequest.abort(); - this.hoverRequest = null; - } + handleDelete: function(resp, options) { + this.handleResponse(resp, options); }, /** - * Method: findLayers - * Internal method to get the layers, independent of whether we are - * inspecting the map or using a client-provided array + * 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. */ - findLayers: function() { - var candidates = this.layers || this.map.layers; - var layers = []; - var layer; - for (var i=candidates.length-1; i>=0; --i) { - layer = candidates[i]; - if (layer instanceof OpenLayers.Layer.WMTS && - layer.requestEncoding === this.requestEncoding && - (!this.queryVisible || layer.getVisibility())) { - layers.push(layer); - if (!this.drillDown || this.hover) { - break; + 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); } - return layers; }, - + /** - * Method: buildRequestOptions - * Build an object with the relevant options for the GetFeatureInfo request. + * Method: parseFeatures + * Read HTTP response body and return features. * * Parameters: - * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. - * xy - {<OpenLayers.Pixel>} The position on the map where the - * mouse event occurred. + * request - {XMLHttpRequest} The request object + * + * Returns: + * {Array({<OpenLayers.Feature.Vector>})} or + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. */ - buildRequestOptions: function(layer, xy) { - var loc = this.map.getLonLatFromPixel(xy); - var getTileUrl = layer.getURL( - new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) - ); - var params = OpenLayers.Util.getParameters(getTileUrl); - var tileInfo = layer.getTileInfo(loc); - OpenLayers.Util.extend(params, { - service: "WMTS", - version: layer.version, - request: "GetFeatureInfo", - infoFormat: this.infoFormat, - i: tileInfo.i, - j: tileInfo.j - }); - OpenLayers.Util.applyDefaults(params, this.vendorParams); - return { - url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, - params: OpenLayers.Util.upperCaseObject(params), - callback: function(request) { - this.handleResponse(xy, request, layer); - }, - scope: this - }; + 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: request - * Sends a GetFeatureInfo request to the WMTS - * + * APIMethod: commit + * Iterate over each feature and take action based on the feature state. + * Possible actions are create, update and delete. + * * Parameters: - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event - * occurred. - * options - {Object} additional options for this method. - * + * features - {Array({<OpenLayers.Feature.Vector>})} + * options - {Object} Optional object for setting up intermediate commit + * callbacks. + * * Valid options: - * - *hover* {Boolean} true if we do the request for the hover handler + * 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. */ - request: function(xy, options) { - options = options || {}; - var layers = this.findLayers(); - if (layers.length > 0) { - var issue, layer; - for (var i=0, len=layers.length; i<len; i++) { - layer = layers[i]; - issue = this.events.triggerEvent("beforegetfeatureinfo", { - xy: xy, - layer: layer - }); - if (issue !== false) { - ++this.pending; - var requestOptions = this.buildRequestOptions(layer, xy); - var request = OpenLayers.Request.GET(requestOptions); - if (options.hover === true) { - this.hoverRequest = 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); } - if (this.pending > 0) { - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); + } + // 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; }, /** - * Method: handleResponse - * Handler for the GetFeatureInfo response. - * + * 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: - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event - * occurred. - * request - {XMLHttpRequest} The request object. - * layer - {<OpenLayers.Layer.WMTS>} The queried layer. + * response - {<OpenLayers.Protocol.Response>} */ - handleResponse: function(xy, request, layer) { - --this.pending; - if (this.pending <= 0) { - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); - this.pending = 0; + abort: function(response) { + if (response) { + response.priv.abort(); } - if (request.status && (request.status < 200 || request.status >= 300)) { - this.events.triggerEvent("exception", { - xy: xy, - request: request, - layer: layer - }); - } else { - var doc = request.responseXML; - if (!doc || !doc.documentElement) { - doc = request.responseText; - } - var features, except; - try { - features = this.format.read(doc); - } catch (error) { - except = true; - this.events.triggerEvent("exception", { - xy: xy, - request: request, - error: error, - layer: layer + }, + + /** + * 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" +}); +/* ====================================================================== + OpenLayers/Protocol/WFS/v2_0_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Protocol/WFS/v1.js + * @requires OpenLayers/Format/WFST/v2_0_0.js + */ + +/** + * Class: OpenLayers.Protocol.WFS.v2_0_0 + * A WFS v2.0.0 protocol for vector layers. Create a new instance with the + * <OpenLayers.Protocol.WFS.v2_0_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.v2_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { + + /** + * Property: version + * {String} WFS version number. + */ + version: "2.0.0", + + /** + * Constructor: OpenLayers.Protocol.WFS.v2_0_0 + * A class for giving layers WFS v2.0.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'. + * outputFormat - {String} Optional output format to use for WFS GetFeature + * requests. This can be any format advertized by the WFS's + * GetCapabilities response. If set, an appropriate readFormat also + * has to be provided, unless outputFormat is GML3, GML2 or JSON. + * readFormat - {<OpenLayers.Format>} An appropriate format parser if + * outputFormat is none of GML3, GML2 or JSON. + */ + initialize: function(options) { + OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); + if (this.outputFormat && !this.readFormat) { + if (this.outputFormat.toLowerCase() == "gml3") { + this.readFormat = new OpenLayers.Format.GML.v3({ + featureType: this.featureType, + featureNS: this.featureNS, + geometryName: this.geometryName }); + } else if (this.outputFormat.toLowerCase() == "json") { + this.readFormat = new OpenLayers.Format.GeoJSON(); } - if (!except) { - this.events.triggerEvent("getfeatureinfo", { - text: request.responseText, - features: features, - request: request, - xy: xy, - layer: layer - }); - } } }, - - CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" + + CLASS_NAME: "OpenLayers.Protocol.WFS.v2_0_0" }); /* ====================================================================== OpenLayers/Protocol/CSW/v2_0_2.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -76931,11 +79809,11 @@ }); /* ====================================================================== OpenLayers/Control/SLDSelect.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -77502,11 +80380,11 @@ }); /* ====================================================================== OpenLayers/Control/Graticule.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -77880,14 +80758,727 @@ CLASS_NAME: "OpenLayers.Control.Graticule" }); /* ====================================================================== + OpenLayers/Control/DragFeature.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Handler/Drag.js + * @requires OpenLayers/Handler/Feature.js + */ + +/** + * Class: OpenLayers.Control.DragFeature + * The DragFeature control moves a feature with a drag of the mouse. Create a + * new control with the <OpenLayers.Control.DragFeature> constructor. + * + * Inherits From: + * - <OpenLayers.Control> + */ +OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: geometryTypes + * {Array(String)} To restrict dragging to a limited set of geometry types, + * send a list of strings corresponding to the geometry class names. + */ + geometryTypes: null, + + /** + * APIProperty: onStart + * {Function} Define this function if you want to know when a drag starts. + * The function should expect to receive two arguments: the feature + * that is about to be dragged and the pixel location of the mouse. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be + * dragged. + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. + */ + onStart: function(feature, pixel) {}, + + /** + * APIProperty: onDrag + * {Function} Define this function if you want to know about each move of a + * feature. The function should expect to receive two arguments: the + * feature that is being dragged and the pixel location of the mouse. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. + */ + onDrag: function(feature, pixel) {}, + + /** + * APIProperty: onComplete + * {Function} Define this function if you want to know when a feature is + * done dragging. The function should expect to receive two arguments: + * the feature that is being dragged and the pixel location of the + * mouse. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. + */ + onComplete: function(feature, pixel) {}, + + /** + * APIProperty: onEnter + * {Function} Define this function if you want to know when the mouse + * goes over a feature and thereby makes this feature a candidate + * for dragging. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that is ready + * to be dragged. + */ + onEnter: function(feature) {}, + + /** + * APIProperty: onLeave + * {Function} Define this function if you want to know when the mouse + * goes out of the feature that was dragged. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. + */ + onLeave: function(feature) {}, + + /** + * APIProperty: documentDrag + * {Boolean} If set to true, mouse dragging will continue even if the + * mouse cursor leaves the map viewport. Default is false. + */ + documentDrag: false, + + /** + * Property: layer + * {<OpenLayers.Layer.Vector>} + */ + layer: null, + + /** + * Property: feature + * {<OpenLayers.Feature.Vector>} + */ + feature: null, + + /** + * Property: dragCallbacks + * {Object} The functions that are sent to the drag handler for callback. + */ + dragCallbacks: {}, + + /** + * Property: featureCallbacks + * {Object} The functions that are sent to the feature handler for callback. + */ + featureCallbacks: {}, + + /** + * Property: lastPixel + * {<OpenLayers.Pixel>} + */ + lastPixel: null, + + /** + * Constructor: OpenLayers.Control.DragFeature + * Create a new control to drag features. + * + * Parameters: + * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be + * dragged. + * options - {Object} Optional object whose properties will be set on the + * control. + */ + initialize: function(layer, options) { + OpenLayers.Control.prototype.initialize.apply(this, [options]); + this.layer = layer; + this.handlers = { + drag: new OpenLayers.Handler.Drag( + this, OpenLayers.Util.extend({ + down: this.downFeature, + move: this.moveFeature, + up: this.upFeature, + out: this.cancel, + done: this.doneDragging + }, this.dragCallbacks), { + documentDrag: this.documentDrag + } + ), + feature: new OpenLayers.Handler.Feature( + this, this.layer, OpenLayers.Util.extend({ + // 'click' and 'clickout' callback are for the mobile + // support: no 'over' or 'out' in touch based browsers. + click: this.clickFeature, + clickout: this.clickoutFeature, + over: this.overFeature, + out: this.outFeature + }, this.featureCallbacks), + {geometryTypes: this.geometryTypes} + ) + }; + }, + + /** + * Method: clickFeature + * Called when the feature handler detects a click-in on a feature. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + clickFeature: function(feature) { + if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { + this.handlers.drag.dragstart(this.handlers.feature.evt); + // to let the events propagate to the feature handler (click callback) + this.handlers.drag.stopDown = false; + } + }, + + /** + * Method: clickoutFeature + * Called when the feature handler detects a click-out on a feature. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} + */ + clickoutFeature: function(feature) { + if (this.handlers.feature.touch && this.over) { + this.outFeature(feature); + this.handlers.drag.stopDown = true; + } + }, + + /** + * APIMethod: destroy + * Take care of things that are not handled in superclass + */ + destroy: function() { + this.layer = null; + OpenLayers.Control.prototype.destroy.apply(this, []); + }, + + /** + * APIMethod: activate + * Activate the control and the feature handler. + * + * Returns: + * {Boolean} Successfully activated the control and feature handler. + */ + activate: function() { + return (this.handlers.feature.activate() && + OpenLayers.Control.prototype.activate.apply(this, arguments)); + }, + + /** + * APIMethod: deactivate + * Deactivate the control and all handlers. + * + * Returns: + * {Boolean} Successfully deactivated the control. + */ + deactivate: function() { + // the return from the handlers is unimportant in this case + this.handlers.drag.deactivate(); + this.handlers.feature.deactivate(); + this.feature = null; + this.dragging = false; + this.lastPixel = null; + OpenLayers.Element.removeClass( + this.map.viewPortDiv, this.displayClass + "Over" + ); + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); + }, + + /** + * Method: overFeature + * Called when the feature handler detects a mouse-over on a feature. + * This activates the drag handler. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The selected feature. + * + * Returns: + * {Boolean} Successfully activated the drag handler. + */ + overFeature: function(feature) { + var activated = false; + if(!this.handlers.drag.dragging) { + this.feature = feature; + this.handlers.drag.activate(); + activated = true; + this.over = true; + OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); + this.onEnter(feature); + } else { + if(this.feature.id == feature.id) { + this.over = true; + } else { + this.over = false; + } + } + return activated; + }, + + /** + * Method: downFeature + * Called when the drag handler detects a mouse-down. + * + * Parameters: + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. + */ + downFeature: function(pixel) { + this.lastPixel = pixel; + this.onStart(this.feature, pixel); + }, + + /** + * Method: moveFeature + * Called when the drag handler detects a mouse-move. Also calls the + * optional onDrag method. + * + * Parameters: + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. + */ + moveFeature: function(pixel) { + var res = this.map.getResolution(); + this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), + res * (this.lastPixel.y - pixel.y)); + this.layer.drawFeature(this.feature); + this.lastPixel = pixel; + this.onDrag(this.feature, pixel); + }, + + /** + * Method: upFeature + * Called when the drag handler detects a mouse-up. + * + * Parameters: + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. + */ + upFeature: function(pixel) { + if(!this.over) { + this.handlers.drag.deactivate(); + } + }, + + /** + * Method: doneDragging + * Called when the drag handler is done dragging. + * + * Parameters: + * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event + * came from a mouseout, this may not be in the map viewport. + */ + doneDragging: function(pixel) { + this.onComplete(this.feature, pixel); + }, + + /** + * Method: outFeature + * Called when the feature handler detects a mouse-out on a feature. + * + * Parameters: + * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. + */ + outFeature: function(feature) { + if(!this.handlers.drag.dragging) { + this.over = false; + this.handlers.drag.deactivate(); + OpenLayers.Element.removeClass( + this.map.viewPortDiv, this.displayClass + "Over" + ); + this.onLeave(feature); + this.feature = null; + } else { + if(this.feature.id == feature.id) { + this.over = false; + } + } + }, + + /** + * Method: cancel + * Called when the drag handler detects a mouse-out (from the map viewport). + */ + cancel: function() { + this.handlers.drag.deactivate(); + this.over = false; + }, + + /** + * Method: setMap + * Set the map property for the control and all handlers. + * + * Parameters: + * map - {<OpenLayers.Map>} The control's map. + */ + setMap: function(map) { + this.handlers.drag.setMap(map); + this.handlers.feature.setMap(map); + OpenLayers.Control.prototype.setMap.apply(this, arguments); + }, + + CLASS_NAME: "OpenLayers.Control.DragFeature" +}); +/* ====================================================================== + Rico/Corner.js + ====================================================================== */ + +/** + * @requires OpenLayers/Console.js + * @requires Rico/Color.js + */ + + +/* + * 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.Console.warn("OpenLayers.Rico is deprecated"); + +OpenLayers.Rico = OpenLayers.Rico || {}; +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; } +}; +/* ====================================================================== OpenLayers/Layer/UTFGrid.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -77927,11 +81518,11 @@ */ OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { /** * APIProperty: isBaseLayer - * Default is true, as this is designed to be a base tile source. + * Default is false, as UTFGrids are designed to be a transparent overlay layer. */ isBaseLayer: false, /** * APIProperty: projection @@ -77994,10 +81585,16 @@ ); this.tileOptions = OpenLayers.Util.extend({ utfgridResolution: this.utfgridResolution }, this.tileOptions); }, + + /** + * Method: createBackBuffer + * The UTFGrid cannot create a back buffer, so this method is overriden. + */ + createBackBuffer: function() {}, /** * APIMethod: clone * Create a clone of this layer * @@ -78065,21 +81662,22 @@ }); /* ====================================================================== OpenLayers/TileManager.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** - * @requires OpenLayers/Layer/Grid.js * @requires OpenLayers/Util.js * @requires OpenLayers/BaseTypes.js * @requires OpenLayers/BaseTypes/Element.js + * @requires OpenLayers/Layer/Grid.js + * @requires OpenLayers/Tile/Image.js */ /** * Class: OpenLayers.TileManager * Provides queueing of image requests and caching of image elements. @@ -78101,10 +81699,24 @@ * cache for fast reuse. Default is 256. */ cacheSize: 256, /** + * APIProperty: tilesPerFrame + * {Number} Number of queued tiles to load per frame (see <frameDelay>). + * Default is 2. + */ + tilesPerFrame: 2, + + /** + * APIProperty: frameDelay + * {Number} Delay between tile loading frames (see <tilesPerFrame>) in + * milliseconds. Default is 16. + */ + frameDelay: 16, + + /** * APIProperty: moveDelay * {Number} Delay in milliseconds after a map's move event before loading * tiles. Default is 100. */ moveDelay: 100, @@ -78170,11 +81782,11 @@ * * Parameters: * map - {<OpenLayers.Map>} */ addMap: function(map) { - if (this._destroyed) { + if (this._destroyed || !OpenLayers.Layer.Grid) { return; } this.maps.push(map); this.tileQueue[map.id] = []; for (var i=0, ii=map.layers.length; i<ii; ++i) { @@ -78196,11 +81808,11 @@ * * Parameters: * map - {<OpenLayers.Map>} */ removeMap: function(map) { - if (this._destroyed) { + if (this._destroyed || !OpenLayers.Layer.Grid) { return; } window.clearTimeout(this.tileQueueId[map.id]); if (map.layers) { for (var i=0, ii=map.layers.length; i<ii; ++i) { @@ -78228,11 +81840,11 @@ * * Parameters: * evt - {Object} Listener argument */ move: function(evt) { - this.updateTimeout(evt.object, this.moveDelay); + this.updateTimeout(evt.object, this.moveDelay, true); }, /** * Method: zoomEnd * Handles the map's zoomEnd event @@ -78250,11 +81862,11 @@ * * Parameters: * evt - {Object} Listener argument */ changeLayer: function(evt) { - if (evt.property === 'params') { + if (evt.property === 'visibility' || evt.property === 'params') { this.updateTimeout(evt.object, 0); } }, /** @@ -78267,19 +81879,20 @@ addLayer: function(evt) { var layer = evt.layer; if (layer instanceof OpenLayers.Layer.Grid) { layer.events.on({ addtile: this.addTile, + refresh: this.handleLayerRefresh, retile: this.clearTileQueue, scope: this }); var i, j, tile; for (i=layer.grid.length-1; i>=0; --i) { for (j=layer.grid[i].length-1; j>=0; --j) { tile = layer.grid[i][j]; this.addTile({tile: tile}); - if (tile.url) { + if (tile.url && !tile.imgDiv) { this.manageTileCache({object: tile}); } } } } @@ -78297,43 +81910,73 @@ if (layer instanceof OpenLayers.Layer.Grid) { this.clearTileQueue({object: layer}); if (layer.events) { layer.events.un({ addtile: this.addTile, + refresh: this.handleLayerRefresh, retile: this.clearTileQueue, scope: this }); } if (layer.grid) { var i, j, tile; for (i=layer.grid.length-1; i>=0; --i) { for (j=layer.grid[i].length-1; j>=0; --j) { tile = layer.grid[i][j]; this.unloadTile({object: tile}); - if (tile.url) { - this.manageTileCache({object: tile}); - } } } } } }, + + /** + * Method: handleLayerRefresh + * Clears the cache when a redraw is forced on a layer + * + * Parameters: + * evt - {Object} The listener argument + */ + handleLayerRefresh: function(evt) { + var layer = evt.object; + if (layer.grid) { + var i, j, tile; + for (i=layer.grid.length-1; i>=0; --i) { + for (j=layer.grid[i].length-1; j>=0; --j) { + tile = layer.grid[i][j]; + OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); + delete this.tileCache[tile.url]; + } + } + } + }, /** * Method: updateTimeout - * Applies the <moveDelay> or <zoomDelay> to the <drawTilesFromQueue> loop. + * Applies the <moveDelay> or <zoomDelay> to the <drawTilesFromQueue> loop, + * and schedules more queue processing after <frameDelay> if there are still + * tiles in the queue. * * Parameters: * map - {<OpenLayers.Map>} The map to update the timeout for * delay - {Number} The delay to apply + * nice - {Boolean} If true, the timeout function will only be created if + * the tilequeue is not empty. This is used by the move handler to + * avoid impacts on dragging performance. For other events, the tile + * queue may not be populated yet, so we need to set the timer + * regardless of the queue size. */ - updateTimeout: function(map, delay) { + updateTimeout: function(map, delay, nice) { window.clearTimeout(this.tileQueueId[map.id]); - if (this.tileQueue[map.id].length) { + var tileQueue = this.tileQueue[map.id]; + if (!nice || tileQueue.length) { this.tileQueueId[map.id] = window.setTimeout( OpenLayers.Function.bind(function() { this.drawTilesFromQueue(map); + if (tileQueue.length) { + this.updateTimeout(map, this.frameDelay); + } }, this), delay ); } }, @@ -78343,17 +81986,22 @@ * * Parameters: * evt - {Object} The listener argument */ addTile: function(evt) { - evt.tile.events.on({ - beforedraw: this.queueTileDraw, - beforeload: this.manageTileCache, - loadend: this.addToCache, - unload: this.unloadTile, - scope: this - }); + if (evt.tile instanceof OpenLayers.Tile.Image) { + evt.tile.events.on({ + beforedraw: this.queueTileDraw, + beforeload: this.manageTileCache, + loadend: this.addToCache, + unload: this.unloadTile, + scope: this + }); + } else { + // Layer has the wrong tile type, so don't handle it any longer + this.removeLayer({layer: evt.tile.layer}); + } }, /** * Method: unloadTile * Listener for the tile's unload event @@ -78382,13 +82030,20 @@ */ queueTileDraw: function(evt) { var tile = evt.object; var queued = false; var layer = tile.layer; + var url = layer.getURL(tile.bounds); + var img = this.tileCache[url]; + if (img && img.className !== 'olTileImage') { + // cached image no longer valid, e.g. because we're olTileReplacing + delete this.tileCache[url]; + OpenLayers.Util.removeItem(this.tileCacheIndex, url); + img = null; + } // queue only if image with same url not cached already - if (layer.url && (layer.async || - !this.tileCache[layer.getURL(tile.bounds)])) { + if (layer.url && (layer.async || !img)) { // add to queue only if not in queue already var tileQueue = this.tileQueue[layer.map.id]; if (!~OpenLayers.Util.indexOf(tileQueue, tile)) { tileQueue.push(tile); } @@ -78401,12 +82056,15 @@ * Method: drawTilesFromQueue * Draws tiles from the tileQueue, and unqueues the tiles */ drawTilesFromQueue: function(map) { var tileQueue = this.tileQueue[map.id]; - while (tileQueue.length) { + var limit = this.tilesPerFrame; + var animating = map.zoomTween && map.zoomTween.playing; + while (!animating && tileQueue.length && limit) { tileQueue.shift().draw(true); + --limit; } }, /** * Method: manageTileCache @@ -78416,22 +82074,27 @@ * evt - {Object} Listener argument of the tile's beforeload event */ manageTileCache: function(evt) { var tile = evt.object; var img = this.tileCache[tile.url]; - // only use image from cache if it is not on a layer already - if (img && (!img.parentNode || - OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) { - if (tile.layer.backBuffer) { - img.style.opacity = 0; - img.style.visibility = 'hidden'; - } - tile.setImage(img); - // LRU - move tile to the end of the array to mark it as the most - // recently used - OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); - this.tileCacheIndex.push(tile.url); + if (img) { + // if image is on its layer's backbuffer, remove it from backbuffer + if (img.parentNode && + OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer')) { + img.parentNode.removeChild(img); + img.id = null; + } + // only use image from cache if it is not on a layer already + if (!img.parentNode) { + img.style.visibility = 'hidden'; + img.style.opacity = 0; + tile.setImage(img); + // LRU - move tile to the end of the array to mark it as the most + // recently used + OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); + this.tileCacheIndex.push(tile.url); + } } }, /** * Method: addToCache @@ -78488,11 +82151,11 @@ }); /* ====================================================================== OpenLayers/Protocol/Script.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -78869,11 +82532,11 @@ })(); /* ====================================================================== OpenLayers/Control/TransformFeature.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -79497,10 +83160,15 @@ }); /* ====================================================================== OpenLayers/Layer/ArcGISCache.js ====================================================================== */ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + /** * @requires OpenLayers/Layer/XYZ.js */ /** @@ -79976,11 +83644,11 @@ }); /* ====================================================================== OpenLayers/Control/WMSGetFeatureInfo.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -79993,14 +83661,14 @@ */ /** * Class: OpenLayers.Control.WMSGetFeatureInfo * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The - * information may be in a display-friendly format such as HTML, or a machine-friendly format such - * as GML, depending on the server's capabilities and the client's configuration. This control - * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and - * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an + * information may be in a display-friendly format such as HTML, or a machine-friendly format such + * as GML, depending on the server's capabilities and the client's configuration. This control + * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and + * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an * array of features if it successfully read the response. * * Inherits from: * - <OpenLayers.Control> */ @@ -80027,86 +83695,88 @@ * sets the feature_count parameter on WMS GetFeatureInfo * requests. */ maxFeatures: 10, - /** APIProperty: clickCallback - * {String} The click callback to register in the - * {<OpenLayers.Handler.Click>} object created when the hover - * option is set to false. Default is "click". + /** + * APIProperty: clickCallback + * {String} The click callback to register in the + * {<OpenLayers.Handler.Click>} object created when the hover + * option is set to false. Default is "click". */ clickCallback: "click", - - /** APIProperty: output - * {String} Either "features" or "object". When triggering a - * getfeatureinfo request should we pass on an array of features - * or an object with with a "features" property and other properties - * (such as the url of the WMS). Default is "features". + + /** + * APIProperty: output + * {String} Either "features" or "object". When triggering a getfeatureinfo + * request should we pass on an array of features or an object with with + * a "features" property and other properties (such as the url of the + * WMS). Default is "features". */ output: "features", - + /** - * Property: layers + * APIProperty: layers * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info. * If omitted, all map WMS layers with a url that matches this <url> or * <layerUrls> will be considered. */ layers: null, /** - * Property: queryVisible + * APIProperty: queryVisible * {Boolean} If true, filter out hidden layers when searching the map for * layers to query. Default is false. */ queryVisible: false, /** - * Property: url + * APIProperty: url * {String} The URL of the WMS service to use. If not provided, the url * of the first eligible layer will be used. */ url: null, - + /** - * Property: layerUrls + * APIProperty: layerUrls * {Array(String)} Optional list of urls for layers that should be queried. * This can be used when the layer url differs from the url used for * making GetFeatureInfo requests (in the case of a layer using cached * tiles). */ layerUrls: null, /** - * Property: infoFormat - * {String} The mimetype to request from the server. If you are using - * drillDown mode and have multiple servers that do not share a common - * infoFormat, you can override the control's infoFormat by providing an - * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). + * APIProperty: infoFormat + * {String} The mimetype to request from the server. If you are using + * drillDown mode and have multiple servers that do not share a common + * infoFormat, you can override the control's infoFormat by providing an + * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). */ infoFormat: 'text/html', - + /** - * Property: vendorParams + * APIProperty: vendorParams * {Object} Additional parameters that will be added to the request, for - * WMS implementations that support them. This could e.g. look like + * WMS implementations that support them. This could e.g. look like * (start code) * { * radius: 5 * } * (end) */ vendorParams: {}, - + /** - * Property: format + * APIProperty: format * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. * Default is <OpenLayers.Format.WMSGetFeatureInfo>. */ format: null, - + /** - * Property: formatOptions + * APIProperty: formatOptions * {Object} Optional properties to set on the format (if one is not provided * in the <format> property. */ formatOptions: null, @@ -80118,25 +83788,25 @@ * "click": {delay: 100}, * "hover": {delay: 300} * } * (end) */ - + /** * Property: handler * {Object} Reference to the <OpenLayers.Handler> for this control */ handler: null, - + /** * Property: hoverRequest * {<OpenLayers.Request>} contains the currently running hover request * (if any). */ hoverRequest: null, - - /** + + /** * APIProperty: events * {<OpenLayers.Events>} Events instance for listeners and triggering * control specific events. * * Register a listener for a particular event with the following syntax: @@ -80144,11 +83814,11 @@ * control.events.register(type, obj, listener); * (end) * * Supported event types (in addition to those from <OpenLayers.Control.events>): * beforegetfeatureinfo - Triggered before the request is sent. - * The event object has an *xy* property with the position of the + * The event object has an *xy* property with the position of the * mouse click or hover event that triggers the request. * nogetfeatureinfo - no queryable layers were found. * getfeatureinfo - Triggered when a GetFeatureInfo response is received. * The event object has a *text* property with the body of the * response (String), a *features* property with an array of the @@ -80162,24 +83832,24 @@ /** * Constructor: <OpenLayers.Control.WMSGetFeatureInfo> * * Parameters: - * options - {Object} + * options - {Object} */ initialize: function(options) { options = options || {}; options.handlerOptions = options.handlerOptions || {}; OpenLayers.Control.prototype.initialize.apply(this, [options]); - + if(!this.format) { this.format = new OpenLayers.Format.WMSGetFeatureInfo( options.formatOptions ); } - + if(this.drillDown === true) { this.hover = false; } if(this.hover) { @@ -80198,24 +83868,24 @@ this, callbacks, this.handlerOptions.click || {}); } }, /** - * Method: getInfoForClick + * Method: getInfoForClick * Called on click * * Parameters: - * evt - {<OpenLayers.Event>} + * evt - {<OpenLayers.Event>} */ getInfoForClick: function(evt) { this.events.triggerEvent("beforegetfeatureinfo", {xy: evt.xy}); // Set the cursor to "wait" to tell the user we're working on their // click. OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); this.request(evt.xy, {}); }, - + /** * Method: getInfoForHover * Pause callback for the hover handler * * Parameters: @@ -80262,11 +83932,11 @@ } } } return layers; }, - + /** * Method: urlMatches * Test to see if the provided url matches either the control <url> or one * of the <layerUrls>. * @@ -80361,11 +84031,11 @@ /** * Method: getStyleNames * Gets the STYLES parameter for the layer. Make sure the STYLES parameter * matches the LAYERS parameter - * + * * Parameters: * layer - {<OpenLayers.Layer.WMS>} * * Returns: * {Array(String)} The STYLES parameter @@ -80379,26 +84049,26 @@ if (layer.params.STYLES) { styleNames = layer.params.STYLES; } else { if (OpenLayers.Util.isArray(layer.params.LAYERS)) { styleNames = new Array(layer.params.LAYERS.length); - } else { // Assume it's a String - styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); + } else { + styleNames = layer.params.LAYERS.toString().replace(/[^,]/g, ""); } } return styleNames; }, /** * Method: request * Sends a GetFeatureInfo request to the WMS - * + * * Parameters: * clickPosition - {<OpenLayers.Pixel>} The position on the map where the * mouse event occurred. * options - {Object} additional options for this method. - * + * * Valid options: * - *hover* {Boolean} true if we do the request for the hover handler */ request: function(clickPosition, options) { var layers = this.findLayers(); @@ -80406,17 +84076,17 @@ this.events.triggerEvent("nogetfeatureinfo"); // Reset the cursor. OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); return; } - + options = options || {}; if(this.drillDown === false) { var wmsOptions = this.buildWMSOptions(this.url, layers, - clickPosition, layers[0].params.FORMAT); + clickPosition, layers[0].params.FORMAT); var request = OpenLayers.Request.GET(wmsOptions); - + if (options.hover === true) { this.hoverRequest = request; } } else { this._requestCount = 0; @@ -80436,13 +84106,13 @@ } } var layers; for (var url in services) { layers = services[url]; - var wmsOptions = this.buildWMSOptions(url, layers, + var wmsOptions = this.buildWMSOptions(url, layers, clickPosition, layers[0].params.FORMAT); - OpenLayers.Request.GET(wmsOptions); + OpenLayers.Request.GET(wmsOptions); } } }, /** @@ -80466,23 +84136,23 @@ }); // Reset the cursor. OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); }, - + /** * Method: handleResponse * Handler for the GetFeatureInfo response. - * + * * Parameters: * xy - {<OpenLayers.Pixel>} The position on the map where the * mouse event occurred. * request - {XMLHttpRequest} The request object. * url - {String} The url which was used for this request. */ handleResponse: function(xy, request, url) { - + var doc = request.responseXML; if(!doc || !doc.documentElement) { doc = request.responseText; } var features = this.format.read(doc); @@ -80496,11 +84166,11 @@ ); } else { this._features = (this._features || []).concat(features); } if (this._requestCount === this._numRequests) { - this.triggerGetFeatureInfo(request, xy, this._features.concat()); + this.triggerGetFeatureInfo(request, xy, this._features.concat()); delete this._features; delete this._requestCount; delete this._numRequests; } } @@ -80510,11 +84180,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_3_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -80544,11 +84214,11 @@ }); /* ====================================================================== OpenLayers/Format/WFS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -80771,11 +84441,11 @@ }); /* ====================================================================== OpenLayers/Control/UTFGrid.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -81015,11 +84685,11 @@ }); /* ====================================================================== OpenLayers/Format/CQL.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -81471,11 +85141,11 @@ /* ====================================================================== OpenLayers/Control/Split.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -81969,11 +85639,11 @@ }); /* ====================================================================== OpenLayers/Layer/WMTS.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -82235,11 +85905,10 @@ /** * Method: setMap */ setMap: function() { OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); - this.updateMatrixProperties(); }, /** * Method: updateMatrixProperties * Called when map resolution changes to update matrix related properties. @@ -82484,11 +86153,11 @@ }); /* ====================================================================== OpenLayers/Protocol/SOS/v1_0_0.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -82621,11 +86290,11 @@ }); /* ====================================================================== OpenLayers/Layer/KaMapCache.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -82768,11 +86437,11 @@ }); /* ====================================================================== OpenLayers/Layer/TileCache.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ @@ -82912,11 +86581,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_1_1.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -82976,11 +86645,11 @@ }); /* ====================================================================== OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -83062,803 +86731,14 @@ CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" }); /* ====================================================================== - OpenLayers/Control/LayerSwitcher.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Lang.js - * @requires OpenLayers/Console.js - * @requires OpenLayers/Events/buttonclick.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, { - - /** - * APIProperty: roundedCorner - * {Boolean} If true the Rico library is used for rounding the corners - * of the layer switcher div, defaults to false. *Deprecated*. Use - * CSS3's border-radius instead. If this option is set to true the - * Rico/Corner.js script must be loaded in the page, and therefore - * listed in the build profile. - * - */ - roundedCorner: false, - - /** - * APIProperty: roundedCornerColor - * {String} The color of the rounded corners, only applies if roundedCorner - * is true, defaults to "darkblue". - */ - roundedCornerColor: "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(Object)} - */ - baseLayers: null, - - - /** - * Property: dataLbl - * {DOMElement} - */ - dataLbl: null, - - /** - * Property: dataLayersDiv - * {DOMElement} - */ - dataLayersDiv: null, - - /** - * Property: dataLayers - * {Array(Object)} - */ - 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 = []; - - if(this.roundedCorner) { - OpenLayers.Console.warn('roundedCorner option is deprecated'); - } - }, - - /** - * APIMethod: destroy - */ - destroy: function() { - - //clear out layers info and unregister their events - this.clearLayersArray("base"); - this.clearLayersArray("data"); - - this.map.events.un({ - buttonclick: this.onButtonClick, - addlayer: this.redraw, - changelayer: this.redraw, - removelayer: this.redraw, - changebaselayer: this.redraw, - scope: this - }); - this.events.unregister("buttonclick", this, this.onButtonClick); - - 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 - }); - if (this.outsideViewport) { - this.events.attachToElement(this.div); - this.events.register("buttonclick", this, this.onButtonClick); - } else { - this.map.events.register("buttonclick", this, this.onButtonClick); - } - }, - - /** - * 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: onButtonClick - * - * Parameters: - * evt - {Event} - */ - onButtonClick: function(evt) { - var button = evt.buttonElement; - if (button === this.minimizeDiv) { - this.minimizeControl(); - } else if (button === this.maximizeDiv) { - this.maximizeControl(); - } else if (button._layerSwitcher === this.id) { - if (button["for"]) { - button = document.getElementById(button["for"]); - } - if (!button.disabled) { - if (button.type == "radio") { - button.checked = true; - this.map.setBaseLayer(this.map.getLayer(button._layer)); - } else { - button.checked = !button.checked; - this.updateMap(); - } - } - } - }, - - /** - * 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) { - 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) ? this.id + "_baseLayers" : layer.name; - inputElem.type = (baseLayer) ? "radio" : "checkbox"; - inputElem.value = layer.name; - inputElem.checked = checked; - inputElem.defaultChecked = checked; - inputElem.className = "olButton"; - inputElem._layer = layer.id; - inputElem._layerSwitcher = this.id; - - if (!baseLayer && !layer.inRange) { - inputElem.disabled = true; - } - - // create span - var labelSpan = document.createElement("label"); - labelSpan["for"] = inputElem.id; - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); - labelSpan._layer = layer.id; - labelSpan._layerSwitcher = this.id; - if (!baseLayer && !layer.inRange) { - labelSpan.style.color = "gray"; - } - labelSpan.innerHTML = layer.name; - labelSpan.style.verticalAlign = (baseLayer) ? "bottom" - : "baseline"; - // 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: 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) { - - // set the div's width and height to empty values, so - // the div dimensions can be controlled by CSS - this.div.style.width = ""; - 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) { - - // to minimize the control we set its div's width - // and height to 0px, we cannot just set "display" - // to "none" because it would hide the maximize - // div - 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() { - - // layers list div - this.layersDiv = document.createElement("div"); - this.layersDiv.id = this.id + "_layersDiv"; - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); - - this.baseLbl = document.createElement("div"); - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); - - this.baseLayersDiv = document.createElement("div"); - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); - - this.dataLbl = document.createElement("div"); - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); - - this.dataLayersDiv = document.createElement("div"); - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); - - 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); - - if(this.roundedCorner) { - OpenLayers.Rico.Corner.round(this.div, { - corners: "tl bl", - bgColor: "transparent", - color: this.roundedCornerColor, - blend: false - }); - OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75); - } - - // maximize button div - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( - "OpenLayers_Control_MaximizeDiv", - null, - null, - img, - "absolute"); - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); - this.maximizeDiv.style.display = "none"; - - this.div.appendChild(this.maximizeDiv); - - // minimize button div - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( - "OpenLayers_Control_MinimizeDiv", - null, - null, - img, - "absolute"); - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); - this.minimizeDiv.style.display = "none"; - - this.div.appendChild(this.minimizeDiv); - }, - - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" -}); -/* ====================================================================== - OpenLayers/Tile/Image/IFrame.js - ====================================================================== */ - -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Tile/Image.js - */ - -/** - * Constant: OpenLayers.Tile.Image.IFrame - * Mixin for tiles that use form-encoded POST requests to get images from - * remote services. Images will be loaded using HTTP-POST into an IFrame. - * - * This mixin will be applied to <OpenLayers.Tile.Image> instances - * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. - */ -OpenLayers.Tile.Image.IFrame = { - - /** - * Property: useIFrame - * {Boolean} true if we are currently using an IFrame to render POST - * responses, false if we are using an img element to render GET responses. - */ - useIFrame: null, - - /** - * Property: blankImageUrl - * {String} Using a data scheme url is not supported by all browsers, but - * we don't care because we either set it as css backgroundImage, or the - * image's display style is set to "none" when we use it. - */ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", - - /** - * Method: draw - * Set useIFrame in the instance, and operate the image/iframe switch. - * Then call Tile.Image.draw. - * - * Returns: - * {Boolean} - */ - draw: function() { - var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); - if(draw) { - - // this.url isn't set to the currect value yet, so we call getURL - // on the layer and store the result in a local variable - var url = this.layer.getURL(this.bounds); - - var usedIFrame = this.useIFrame; - this.useIFrame = this.maxGetUrlLength !== null && - !this.layer.async && - url.length > this.maxGetUrlLength; - - var fromIFrame = usedIFrame && !this.useIFrame; - var toIFrame = !usedIFrame && this.useIFrame; - - if(fromIFrame || toIFrame) { - - // Switching between GET (image) and POST (iframe). - - // We remove the imgDiv (really either an image or an iframe) - // from the frame and set it to null to make sure initImage - // will call getImage. - - if(this.imgDiv && this.imgDiv.parentNode === this.frame) { - this.frame.removeChild(this.imgDiv); - } - this.imgDiv = null; - - // And if we had an iframe we also remove the event pane. - - if(fromIFrame) { - this.frame.removeChild(this.frame.firstChild); - } - } - } - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); - }, - - /** - * Method: getImage - * Creates the content for the frame on the tile. - */ - getImage: function() { - if (this.useIFrame === true) { - if (!this.frame.childNodes.length) { - var eventPane = document.createElement("div"), - style = eventPane.style; - style.position = "absolute"; - style.width = "100%"; - style.height = "100%"; - style.zIndex = 1; - style.backgroundImage = "url(" + this.blankImageUrl + ")"; - this.frame.appendChild(eventPane); - } - - var id = this.id + '_iFrame', iframe; - if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { - // Older IE versions do not set the name attribute of an iFrame - // properly via DOM manipulation, so we need to do it on our own with - // this hack. - iframe = document.createElement('<iframe name="'+id+'">'); - - // IFrames in older IE versions are not transparent, if you set - // the backgroundColor transparent. This is a workaround to get - // transparent iframes. - iframe.style.backgroundColor = '#FFFFFF'; - iframe.style.filter = 'chroma(color=#FFFFFF)'; - } - else { - iframe = document.createElement('iframe'); - iframe.style.backgroundColor = 'transparent'; - - // iframe.name needs to be an unique id, otherwise it - // could happen that other iframes are overwritten. - iframe.name = id; - } - - // some special properties to avoid scaling the images and scrollbars - // in the iframe - iframe.scrolling = 'no'; - iframe.marginWidth = '0px'; - iframe.marginHeight = '0px'; - iframe.frameBorder = '0'; - - iframe.style.position = "absolute"; - iframe.style.width = "100%"; - iframe.style.height = "100%"; - - if (this.layer.opacity < 1) { - OpenLayers.Util.modifyDOMElement(iframe, null, null, null, - null, null, null, this.layer.opacity); - } - this.frame.appendChild(iframe); - this.imgDiv = iframe; - return iframe; - } else { - return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); - } - }, - - /** - * Method: createRequestForm - * Create the html <form> element with width, height, bbox and all - * parameters specified in the layer params. - * - * Returns: - * {DOMElement} The form element which sends the HTTP-POST request to the - * WMS. - */ - createRequestForm: function() { - // creation of the form element - var form = document.createElement('form'); - form.method = 'POST'; - var cacheId = this.layer.params["_OLSALT"]; - cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); - form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); - form.target = this.id + '_iFrame'; - - // adding all parameters in layer params as hidden fields to the html - // form element - var imageSize = this.layer.getImageSize(), - params = OpenLayers.Util.getParameters(this.url), - field; - - for(var par in params) { - field = document.createElement('input'); - field.type = 'hidden'; - field.name = par; - field.value = params[par]; - form.appendChild(field); - } - - return form; - }, - - /** - * Method: setImgSrc - * Sets the source for the tile image - * - * Parameters: - * url - {String} - */ - setImgSrc: function(url) { - if (this.useIFrame === true) { - if (url) { - var form = this.createRequestForm(); - this.frame.appendChild(form); - form.submit(); - this.frame.removeChild(form); - } else if (this.imgDiv.parentNode === this.frame) { - // we don't reuse iframes to avoid caching issues - this.frame.removeChild(this.imgDiv); - this.imgDiv = null; - } - } else { - OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); - } - }, - - /** - * Method: onImageLoad - * Handler for the image onload event - */ - onImageLoad: function() { - //TODO de-uglify opacity handling - OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); - if (this.useIFrame === true) { - this.imgDiv.style.opacity = 1; - this.frame.style.opacity = this.layer.opacity; - } - }, - - /** - * Method: createBackBuffer - * Override createBackBuffer to do nothing when we use an iframe. Moving an - * iframe from one element to another makes it necessary to reload the iframe - * because its content is lost. So we just give up. - * - * Returns: - * {DOMElement} - */ - createBackBuffer: function() { - var backBuffer; - if(this.useIFrame === false) { - backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); - } - return backBuffer; - } -}; -/* ====================================================================== OpenLayers/Format/Atom.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** @@ -84567,13 +87447,775 @@ }, CLASS_NAME: "OpenLayers.Format.Atom" }); /* ====================================================================== + OpenLayers/Control/LayerSwitcher.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Lang.js + * @requires OpenLayers/Util.js + * @requires OpenLayers/Events/buttonclick.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: 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(Object)} + */ + baseLayers: null, + + + /** + * Property: dataLbl + * {DOMElement} + */ + dataLbl: null, + + /** + * Property: dataLayersDiv + * {DOMElement} + */ + dataLayersDiv: null, + + /** + * Property: dataLayers + * {Array(Object)} + */ + 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() { + + //clear out layers info and unregister their events + this.clearLayersArray("base"); + this.clearLayersArray("data"); + + this.map.events.un({ + buttonclick: this.onButtonClick, + addlayer: this.redraw, + changelayer: this.redraw, + removelayer: this.redraw, + changebaselayer: this.redraw, + scope: this + }); + this.events.unregister("buttonclick", this, this.onButtonClick); + + 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 + }); + if (this.outsideViewport) { + this.events.attachToElement(this.div); + this.events.register("buttonclick", this, this.onButtonClick); + } else { + this.map.events.register("buttonclick", this, this.onButtonClick); + } + }, + + /** + * 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: onButtonClick + * + * Parameters: + * evt - {Event} + */ + onButtonClick: function(evt) { + var button = evt.buttonElement; + if (button === this.minimizeDiv) { + this.minimizeControl(); + } else if (button === this.maximizeDiv) { + this.maximizeControl(); + } else if (button._layerSwitcher === this.id) { + if (button["for"]) { + button = document.getElementById(button["for"]); + } + if (!button.disabled) { + if (button.type == "radio") { + button.checked = true; + this.map.setBaseLayer(this.map.getLayer(button._layer)); + } else { + button.checked = !button.checked; + this.updateMap(); + } + } + } + }, + + /** + * 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) { + 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() { + if ( !this.layerStates.length || + (this.map.layers.length != this.layerStates.length) ) { + return true; + } + + 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) ) { + return true; + } + } + + return false; + }, + + /** + * 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"), + // The input shall have an id attribute so we can use + // labels to interact with them. + inputId = OpenLayers.Util.createUniqueID( + this.id + "_input_" + ); + + inputElem.id = inputId; + inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; + inputElem.type = (baseLayer) ? "radio" : "checkbox"; + inputElem.value = layer.name; + inputElem.checked = checked; + inputElem.defaultChecked = checked; + inputElem.className = "olButton"; + inputElem._layer = layer.id; + inputElem._layerSwitcher = this.id; + + if (!baseLayer && !layer.inRange) { + inputElem.disabled = true; + } + + // create span + var labelSpan = document.createElement("label"); + // this isn't the DOM attribute 'for', but an arbitrary name we + // use to find the appropriate input element in <onButtonClick> + labelSpan["for"] = inputElem.id; + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); + labelSpan._layer = layer.id; + labelSpan._layerSwitcher = this.id; + if (!baseLayer && !layer.inRange) { + labelSpan.style.color = "gray"; + } + labelSpan.innerHTML = layer.name; + labelSpan.style.verticalAlign = (baseLayer) ? "bottom" + : "baseline"; + // 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: 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) { + + // set the div's width and height to empty values, so + // the div dimensions can be controlled by CSS + this.div.style.width = ""; + 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) { + + // to minimize the control we set its div's width + // and height to 0px, we cannot just set "display" + // to "none" because it would hide the maximize + // div + 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() { + + // layers list div + this.layersDiv = document.createElement("div"); + this.layersDiv.id = this.id + "_layersDiv"; + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); + + this.baseLbl = document.createElement("div"); + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); + + this.baseLayersDiv = document.createElement("div"); + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); + + this.dataLbl = document.createElement("div"); + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); + + this.dataLayersDiv = document.createElement("div"); + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); + + 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); + + // maximize button div + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( + "OpenLayers_Control_MaximizeDiv", + null, + null, + img, + "absolute"); + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); + this.maximizeDiv.style.display = "none"; + + this.div.appendChild(this.maximizeDiv); + + // minimize button div + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( + "OpenLayers_Control_MinimizeDiv", + null, + null, + img, + "absolute"); + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); + this.minimizeDiv.style.display = "none"; + + this.div.appendChild(this.minimizeDiv); + }, + + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" +}); +/* ====================================================================== + OpenLayers/Tile/Image/IFrame.js + ====================================================================== */ + +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Tile/Image.js + */ + +/** + * Constant: OpenLayers.Tile.Image.IFrame + * Mixin for tiles that use form-encoded POST requests to get images from + * remote services. Images will be loaded using HTTP-POST into an IFrame. + * + * This mixin will be applied to <OpenLayers.Tile.Image> instances + * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. + */ +OpenLayers.Tile.Image.IFrame = { + + /** + * Property: useIFrame + * {Boolean} true if we are currently using an IFrame to render POST + * responses, false if we are using an img element to render GET responses. + */ + useIFrame: null, + + /** + * Property: blankImageUrl + * {String} Using a data scheme url is not supported by all browsers, but + * we don't care because we either set it as css backgroundImage, or the + * image's display style is set to "none" when we use it. + */ + blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", + + /** + * Method: draw + * Set useIFrame in the instance, and operate the image/iframe switch. + * Then call Tile.Image.draw. + * + * Returns: + * {Boolean} + */ + draw: function() { + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); + if(draw) { + + // this.url isn't set to the currect value yet, so we call getURL + // on the layer and store the result in a local variable + var url = this.layer.getURL(this.bounds); + + var usedIFrame = this.useIFrame; + this.useIFrame = this.maxGetUrlLength !== null && + !this.layer.async && + url.length > this.maxGetUrlLength; + + var fromIFrame = usedIFrame && !this.useIFrame; + var toIFrame = !usedIFrame && this.useIFrame; + + if(fromIFrame || toIFrame) { + + // Switching between GET (image) and POST (iframe). + + // We remove the imgDiv (really either an image or an iframe) + // from the frame and set it to null to make sure initImage + // will call getImage. + + if(this.imgDiv && this.imgDiv.parentNode === this.frame) { + this.frame.removeChild(this.imgDiv); + } + this.imgDiv = null; + + // And if we had an iframe we also remove the event pane. + + if(fromIFrame) { + this.frame.removeChild(this.frame.firstChild); + } + } + } + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); + }, + + /** + * Method: getImage + * Creates the content for the frame on the tile. + */ + getImage: function() { + if (this.useIFrame === true) { + if (!this.frame.childNodes.length) { + var eventPane = document.createElement("div"), + style = eventPane.style; + style.position = "absolute"; + style.width = "100%"; + style.height = "100%"; + style.zIndex = 1; + style.backgroundImage = "url(" + this.blankImageUrl + ")"; + this.frame.appendChild(eventPane); + } + + var id = this.id + '_iFrame', iframe; + if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { + // Older IE versions do not set the name attribute of an iFrame + // properly via DOM manipulation, so we need to do it on our own with + // this hack. + iframe = document.createElement('<iframe name="'+id+'">'); + + // IFrames in older IE versions are not transparent, if you set + // the backgroundColor transparent. This is a workaround to get + // transparent iframes. + iframe.style.backgroundColor = '#FFFFFF'; + iframe.style.filter = 'chroma(color=#FFFFFF)'; + } + else { + iframe = document.createElement('iframe'); + iframe.style.backgroundColor = 'transparent'; + + // iframe.name needs to be an unique id, otherwise it + // could happen that other iframes are overwritten. + iframe.name = id; + } + + // some special properties to avoid scaling the images and scrollbars + // in the iframe + iframe.scrolling = 'no'; + iframe.marginWidth = '0px'; + iframe.marginHeight = '0px'; + iframe.frameBorder = '0'; + + iframe.style.position = "absolute"; + iframe.style.width = "100%"; + iframe.style.height = "100%"; + + if (this.layer.opacity < 1) { + OpenLayers.Util.modifyDOMElement(iframe, null, null, null, + null, null, null, this.layer.opacity); + } + this.frame.appendChild(iframe); + this.imgDiv = iframe; + return iframe; + } else { + return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); + } + }, + + /** + * Method: createRequestForm + * Create the html <form> element with width, height, bbox and all + * parameters specified in the layer params. + * + * Returns: + * {DOMElement} The form element which sends the HTTP-POST request to the + * WMS. + */ + createRequestForm: function() { + // creation of the form element + var form = document.createElement('form'); + form.method = 'POST'; + var cacheId = this.layer.params["_OLSALT"]; + cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); + form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); + form.target = this.id + '_iFrame'; + + // adding all parameters in layer params as hidden fields to the html + // form element + var imageSize = this.layer.getImageSize(), + params = OpenLayers.Util.getParameters(this.url), + field; + + for(var par in params) { + field = document.createElement('input'); + field.type = 'hidden'; + field.name = par; + field.value = params[par]; + form.appendChild(field); + } + + return form; + }, + + /** + * Method: setImgSrc + * Sets the source for the tile image + * + * Parameters: + * url - {String} + */ + setImgSrc: function(url) { + if (this.useIFrame === true) { + if (url) { + var form = this.createRequestForm(); + this.frame.appendChild(form); + form.submit(); + this.frame.removeChild(form); + } else if (this.imgDiv.parentNode === this.frame) { + // we don't reuse iframes to avoid caching issues + this.frame.removeChild(this.imgDiv); + this.imgDiv = null; + } + } else { + OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); + } + }, + + /** + * Method: onImageLoad + * Handler for the image onload event + */ + onImageLoad: function() { + //TODO de-uglify opacity handling + OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); + if (this.useIFrame === true) { + this.imgDiv.style.opacity = 1; + this.frame.style.opacity = this.layer.opacity; + } + }, + + /** + * Method: createBackBuffer + * Override createBackBuffer to do nothing when we use an iframe. Moving an + * iframe from one element to another makes it necessary to reload the iframe + * because its content is lost. So we just give up. + * + * Returns: + * {DOMElement} + */ + createBackBuffer: function() { + var backBuffer; + if(this.useIFrame === false) { + backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); + } + return backBuffer; + } +}; +/* ====================================================================== OpenLayers/Control/KeyboardDefaults.js ====================================================================== */ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /**