{"diffoscope-json-version": 1, "source1": "/srv/reproducible-results/rbuild-debian/r-b-build.mAZFZ7Hu/b1/openlayers_2.13.1+ds2-8_armhf.changes", "source2": "/srv/reproducible-results/rbuild-debian/r-b-build.mAZFZ7Hu/b2/openlayers_2.13.1+ds2-8_armhf.changes", "unified_diff": null, "details": [{"source1": "Files", "source2": "Files", "unified_diff": "@@ -1,2 +1,2 @@\n \n- 842601e2b746cd29de8b587057eb3820 716932 javascript optional libjs-openlayers_2.13.1+ds2-8_all.deb\n+ 66c19e649b9cac5b5f2fb33cb16e5b0c 731100 javascript optional libjs-openlayers_2.13.1+ds2-8_all.deb\n"}, {"source1": "libjs-openlayers_2.13.1+ds2-8_all.deb", "source2": "libjs-openlayers_2.13.1+ds2-8_all.deb", "unified_diff": null, "details": [{"source1": "file list", "source2": "file list", "unified_diff": "@@ -1,3 +1,3 @@\n -rw-r--r-- 0 0 0 4 2020-04-18 18:00:46.000000 debian-binary\n -rw-r--r-- 0 0 0 3684 2020-04-18 18:00:46.000000 control.tar.xz\n--rw-r--r-- 0 0 0 713056 2020-04-18 18:00:46.000000 data.tar.xz\n+-rw-r--r-- 0 0 0 727224 2020-04-18 18:00:46.000000 data.tar.xz\n"}, {"source1": "control.tar.xz", "source2": "control.tar.xz", "unified_diff": null, "details": [{"source1": "control.tar", "source2": "control.tar", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "comments": ["Files differ"], "unified_diff": null}]}]}]}, {"source1": "data.tar.xz", "source2": "data.tar.xz", "unified_diff": null, "details": [{"source1": "data.tar", "source2": "data.tar", "unified_diff": null, "details": [{"source1": "./usr/share/javascript/openlayers/OpenLayers.js", "source2": "./usr/share/javascript/openlayers/OpenLayers.js", "unified_diff": null, "details": [{"source1": "js-beautify {}", "source2": "js-beautify {}", "unified_diff": "@@ -52,14 +52,37 @@\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE \n * POSSIBILITY OF SUCH DAMAGE.\n */\n /* ======================================================================\n+ Rico/license.js\n+ ====================================================================== */\n+\n+/**\n+ * @license Apache 2 \n+ * \n+ * Contains portions of Rico \n+ * \n+ * Copyright 2005 Sabre Airline Solutions \n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\"); you\n+ * may not use this file except in compliance with the License. You\n+ * may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0 \n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n+ * implied. See the License for the specific language governing\n+ * permissions and limitations under the License. \n+ */\n+/* ======================================================================\n OpenLayers/SingleFile.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -136,14 +159,395 @@\n * (code)\n * \n * (end code)\n */\n ImgPath: ''\n };\n /* ======================================================================\n+ OpenLayers/BaseTypes/Class.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+/**\n+ * Constructor: OpenLayers.Class\n+ * Base class used to construct all other classes. Includes support for \n+ * multiple inheritance. \n+ * \n+ * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old \n+ * syntax for creating classes and dealing with inheritance \n+ * will be removed.\n+ * \n+ * To create a new OpenLayers-style class, use the following syntax:\n+ * (code)\n+ * var MyClass = OpenLayers.Class(prototype);\n+ * (end)\n+ *\n+ * To create a new OpenLayers-style class with multiple inheritance, use the\n+ * following syntax:\n+ * (code)\n+ * var MyClass = OpenLayers.Class(Class1, Class2, prototype);\n+ * (end)\n+ * \n+ * Note that instanceof reflection will only reveal Class1 as superclass.\n+ *\n+ */\n+OpenLayers.Class = function() {\n+ var len = arguments.length;\n+ var P = arguments[0];\n+ var F = arguments[len - 1];\n+\n+ var C = typeof F.initialize == \"function\" ?\n+ F.initialize :\n+ function() {\n+ P.prototype.initialize.apply(this, arguments);\n+ };\n+\n+ if (len > 1) {\n+ var newArgs = [C, P].concat(\n+ Array.prototype.slice.call(arguments).slice(1, len - 1), F);\n+ OpenLayers.inherit.apply(null, newArgs);\n+ } else {\n+ C.prototype = F;\n+ }\n+ return C;\n+};\n+\n+/**\n+ * Function: OpenLayers.inherit\n+ *\n+ * Parameters:\n+ * C - {Object} the class that inherits\n+ * P - {Object} the superclass to inherit from\n+ *\n+ * In addition to the mandatory C and P parameters, an arbitrary number of\n+ * objects can be passed, which will extend C.\n+ */\n+OpenLayers.inherit = function(C, P) {\n+ var F = function() {};\n+ F.prototype = P.prototype;\n+ C.prototype = new F;\n+ var i, l, o;\n+ for (i = 2, l = arguments.length; i < l; i++) {\n+ o = arguments[i];\n+ if (typeof o === \"function\") {\n+ o = o.prototype;\n+ }\n+ OpenLayers.Util.extend(C.prototype, o);\n+ }\n+};\n+\n+/**\n+ * APIFunction: extend\n+ * Copy all properties of a source object to a destination object. Modifies\n+ * the passed in destination object. Any properties on the source object\n+ * that are set to undefined will not be (re)set on the destination object.\n+ *\n+ * Parameters:\n+ * destination - {Object} The object that will be modified\n+ * source - {Object} The object with properties to be set on the destination\n+ *\n+ * Returns:\n+ * {Object} The destination object.\n+ */\n+OpenLayers.Util = OpenLayers.Util || {};\n+OpenLayers.Util.extend = function(destination, source) {\n+ destination = destination || {};\n+ if (source) {\n+ for (var property in source) {\n+ var value = source[property];\n+ if (value !== undefined) {\n+ destination[property] = value;\n+ }\n+ }\n+\n+ /**\n+ * IE doesn't include the toString property when iterating over an object's\n+ * properties with the for(property in object) syntax. Explicitly check if\n+ * the source has its own toString property.\n+ */\n+\n+ /*\n+ * FF/Windows < 2.0.0.13 reports \"Illegal operation on WrappedNative\n+ * prototype object\" when calling hawOwnProperty if the source object\n+ * is an instance of window.Event.\n+ */\n+\n+ var sourceIsEvt = typeof window.Event == \"function\" &&\n+ source instanceof window.Event;\n+\n+ if (!sourceIsEvt &&\n+ source.hasOwnProperty && source.hasOwnProperty(\"toString\")) {\n+ destination.toString = source.toString;\n+ }\n+ }\n+ return destination;\n+};\n+/* ======================================================================\n+ OpenLayers/Console.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Namespace: OpenLayers.Console\n+ * The OpenLayers.Console namespace is used for debugging and error logging.\n+ * If the Firebug Lite (../Firebug/firebug.js) is included before this script,\n+ * calls to OpenLayers.Console methods will get redirected to window.console.\n+ * This makes use of the Firebug extension where available and allows for\n+ * cross-browser debugging Firebug style.\n+ *\n+ * Note:\n+ * Note that behavior will differ with the Firebug extention and Firebug Lite.\n+ * Most notably, the Firebug Lite console does not currently allow for\n+ * hyperlinks to code or for clicking on object to explore their properties.\n+ * \n+ */\n+OpenLayers.Console = {\n+ /**\n+ * Create empty functions for all console methods. The real value of these\n+ * properties will be set if Firebug Lite (../Firebug/firebug.js script) is\n+ * included. We explicitly require the Firebug Lite script to trigger\n+ * functionality of the OpenLayers.Console methods.\n+ */\n+\n+ /**\n+ * APIFunction: log\n+ * Log an object in the console. The Firebug Lite console logs string\n+ * representation of objects. Given multiple arguments, they will\n+ * be cast to strings and logged with a space delimiter. If the first\n+ * argument is a string with printf-like formatting, subsequent arguments\n+ * will be used in string substitution. Any additional arguments (beyond\n+ * the number substituted in a format string) will be appended in a space-\n+ * delimited line.\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ log: function() {},\n+\n+ /**\n+ * APIFunction: debug\n+ * Writes a message to the console, including a hyperlink to the line\n+ * where it was called.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ debug: function() {},\n+\n+ /**\n+ * APIFunction: info\n+ * Writes a message to the console with the visual \"info\" icon and color\n+ * coding and a hyperlink to the line where it was called.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ info: function() {},\n+\n+ /**\n+ * APIFunction: warn\n+ * Writes a message to the console with the visual \"warning\" icon and\n+ * color coding and a hyperlink to the line where it was called.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ warn: function() {},\n+\n+ /**\n+ * APIFunction: error\n+ * Writes a message to the console with the visual \"error\" icon and color\n+ * coding and a hyperlink to the line where it was called.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ error: function() {},\n+\n+ /**\n+ * APIFunction: userError\n+ * A single interface for showing error messages to the user. The default\n+ * behavior is a Javascript alert, though this can be overridden by\n+ * reassigning OpenLayers.Console.userError to a different function.\n+ *\n+ * Expects a single error message\n+ * \n+ * Parameters:\n+ * error - {Object}\n+ */\n+ userError: function(error) {\n+ alert(error);\n+ },\n+\n+ /**\n+ * APIFunction: assert\n+ * Tests that an expression is true. If not, it will write a message to\n+ * the console and throw an exception.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ assert: function() {},\n+\n+ /**\n+ * APIFunction: dir\n+ * Prints an interactive listing of all properties of the object. This\n+ * looks identical to the view that you would see in the DOM tab.\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ dir: function() {},\n+\n+ /**\n+ * APIFunction: dirxml\n+ * Prints the XML source tree of an HTML or XML element. This looks\n+ * identical to the view that you would see in the HTML tab. You can click\n+ * on any node to inspect it in the HTML tab.\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ dirxml: function() {},\n+\n+ /**\n+ * APIFunction: trace\n+ * Prints an interactive stack trace of JavaScript execution at the point\n+ * where it is called. The stack trace details the functions on the stack,\n+ * as well as the values that were passed as arguments to each function.\n+ * You can click each function to take you to its source in the Script tab,\n+ * and click each argument value to inspect it in the DOM or HTML tabs.\n+ * \n+ */\n+ trace: function() {},\n+\n+ /**\n+ * APIFunction: group\n+ * Writes a message to the console and opens a nested block to indent all\n+ * future messages sent to the console. Call OpenLayers.Console.groupEnd()\n+ * to close the block.\n+ *\n+ * May be called with multiple arguments as with OpenLayers.Console.log().\n+ * \n+ * Parameters:\n+ * object - {Object}\n+ */\n+ group: function() {},\n+\n+ /**\n+ * APIFunction: groupEnd\n+ * Closes the most recently opened block created by a call to\n+ * OpenLayers.Console.group\n+ */\n+ groupEnd: function() {},\n+\n+ /**\n+ * APIFunction: time\n+ * Creates a new timer under the given name. Call\n+ * OpenLayers.Console.timeEnd(name)\n+ * with the same name to stop the timer and print the time elapsed.\n+ *\n+ * Parameters:\n+ * name - {String}\n+ */\n+ time: function() {},\n+\n+ /**\n+ * APIFunction: timeEnd\n+ * Stops a timer created by a call to OpenLayers.Console.time(name) and\n+ * writes the time elapsed.\n+ *\n+ * Parameters:\n+ * name - {String}\n+ */\n+ timeEnd: function() {},\n+\n+ /**\n+ * APIFunction: profile\n+ * Turns on the JavaScript profiler. The optional argument title would\n+ * contain the text to be printed in the header of the profile report.\n+ *\n+ * This function is not currently implemented in Firebug Lite.\n+ * \n+ * Parameters:\n+ * title - {String} Optional title for the profiler\n+ */\n+ profile: function() {},\n+\n+ /**\n+ * APIFunction: profileEnd\n+ * Turns off the JavaScript profiler and prints its report.\n+ * \n+ * This function is not currently implemented in Firebug Lite.\n+ */\n+ profileEnd: function() {},\n+\n+ /**\n+ * APIFunction: count\n+ * Writes the number of times that the line of code where count was called\n+ * was executed. The optional argument title will print a message in\n+ * addition to the number of the count.\n+ *\n+ * This function is not currently implemented in Firebug Lite.\n+ *\n+ * Parameters:\n+ * title - {String} Optional title to be printed with count\n+ */\n+ count: function() {},\n+\n+ CLASS_NAME: \"OpenLayers.Console\"\n+};\n+\n+/**\n+ * Execute an anonymous function to extend the OpenLayers.Console namespace\n+ * if the firebug.js script is included. This closure is used so that the\n+ * \"scripts\" and \"i\" variables don't pollute the global namespace.\n+ */\n+(function() {\n+ /**\n+ * If Firebug Lite is included (before this script), re-route all\n+ * OpenLayers.Console calls to the console object.\n+ */\n+ var scripts = document.getElementsByTagName(\"script\");\n+ for (var i = 0, len = scripts.length; i < len; ++i) {\n+ if (scripts[i].src.indexOf(\"firebug.js\") != -1) {\n+ if (console) {\n+ OpenLayers.Util.extend(OpenLayers.Console, console);\n+ break;\n+ }\n+ }\n+ }\n+})();\n+/* ======================================================================\n OpenLayers/BaseTypes.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -603,141 +1007,14 @@\n }\n }\n return selected;\n }\n \n };\n /* ======================================================================\n- OpenLayers/BaseTypes/Class.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n-\n-/**\n- * Constructor: OpenLayers.Class\n- * Base class used to construct all other classes. Includes support for \n- * multiple inheritance. \n- * \n- * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old \n- * syntax for creating classes and dealing with inheritance \n- * will be removed.\n- * \n- * To create a new OpenLayers-style class, use the following syntax:\n- * (code)\n- * var MyClass = OpenLayers.Class(prototype);\n- * (end)\n- *\n- * To create a new OpenLayers-style class with multiple inheritance, use the\n- * following syntax:\n- * (code)\n- * var MyClass = OpenLayers.Class(Class1, Class2, prototype);\n- * (end)\n- * \n- * Note that instanceof reflection will only reveal Class1 as superclass.\n- *\n- */\n-OpenLayers.Class = function() {\n- var len = arguments.length;\n- var P = arguments[0];\n- var F = arguments[len - 1];\n-\n- var C = typeof F.initialize == \"function\" ?\n- F.initialize :\n- function() {\n- P.prototype.initialize.apply(this, arguments);\n- };\n-\n- if (len > 1) {\n- var newArgs = [C, P].concat(\n- Array.prototype.slice.call(arguments).slice(1, len - 1), F);\n- OpenLayers.inherit.apply(null, newArgs);\n- } else {\n- C.prototype = F;\n- }\n- return C;\n-};\n-\n-/**\n- * Function: OpenLayers.inherit\n- *\n- * Parameters:\n- * C - {Object} the class that inherits\n- * P - {Object} the superclass to inherit from\n- *\n- * In addition to the mandatory C and P parameters, an arbitrary number of\n- * objects can be passed, which will extend C.\n- */\n-OpenLayers.inherit = function(C, P) {\n- var F = function() {};\n- F.prototype = P.prototype;\n- C.prototype = new F;\n- var i, l, o;\n- for (i = 2, l = arguments.length; i < l; i++) {\n- o = arguments[i];\n- if (typeof o === \"function\") {\n- o = o.prototype;\n- }\n- OpenLayers.Util.extend(C.prototype, o);\n- }\n-};\n-\n-/**\n- * APIFunction: extend\n- * Copy all properties of a source object to a destination object. Modifies\n- * the passed in destination object. Any properties on the source object\n- * that are set to undefined will not be (re)set on the destination object.\n- *\n- * Parameters:\n- * destination - {Object} The object that will be modified\n- * source - {Object} The object with properties to be set on the destination\n- *\n- * Returns:\n- * {Object} The destination object.\n- */\n-OpenLayers.Util = OpenLayers.Util || {};\n-OpenLayers.Util.extend = function(destination, source) {\n- destination = destination || {};\n- if (source) {\n- for (var property in source) {\n- var value = source[property];\n- if (value !== undefined) {\n- destination[property] = value;\n- }\n- }\n-\n- /**\n- * IE doesn't include the toString property when iterating over an object's\n- * properties with the for(property in object) syntax. Explicitly check if\n- * the source has its own toString property.\n- */\n-\n- /*\n- * FF/Windows < 2.0.0.13 reports \"Illegal operation on WrappedNative\n- * prototype object\" when calling hawOwnProperty if the source object\n- * is an instance of window.Event.\n- */\n-\n- var sourceIsEvt = typeof window.Event == \"function\" &&\n- source instanceof window.Event;\n-\n- if (!sourceIsEvt &&\n- source.hasOwnProperty && source.hasOwnProperty(\"toString\")) {\n- destination.toString = source.toString;\n- }\n- }\n- return destination;\n-};\n-/* ======================================================================\n OpenLayers/BaseTypes/Bounds.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -1589,207 +1866,14 @@\n \n opp += (quadrant.charAt(0) == 't') ? 'b' : 't';\n opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';\n \n return opp;\n };\n /* ======================================================================\n- OpenLayers/BaseTypes/Element.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/BaseTypes.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Element\n- */\n-OpenLayers.Element = {\n-\n- /**\n- * APIFunction: visible\n- * \n- * Parameters: \n- * element - {DOMElement}\n- * \n- * Returns:\n- * {Boolean} Is the element visible?\n- */\n- visible: function(element) {\n- return OpenLayers.Util.getElement(element).style.display != 'none';\n- },\n-\n- /**\n- * APIFunction: toggle\n- * Toggle the visibility of element(s) passed in\n- * \n- * Parameters:\n- * element - {DOMElement} Actually user can pass any number of elements\n- */\n- toggle: function() {\n- for (var i = 0, len = arguments.length; i < len; i++) {\n- var element = OpenLayers.Util.getElement(arguments[i]);\n- var display = OpenLayers.Element.visible(element) ? 'none' :\n- '';\n- element.style.display = display;\n- }\n- },\n-\n- /**\n- * APIFunction: remove\n- * Remove the specified element from the DOM.\n- * \n- * Parameters:\n- * element - {DOMElement}\n- */\n- remove: function(element) {\n- element = OpenLayers.Util.getElement(element);\n- element.parentNode.removeChild(element);\n- },\n-\n- /**\n- * APIFunction: getHeight\n- * \n- * Parameters:\n- * element - {DOMElement}\n- * \n- * Returns:\n- * {Integer} The offset height of the element passed in\n- */\n- getHeight: function(element) {\n- element = OpenLayers.Util.getElement(element);\n- return element.offsetHeight;\n- },\n-\n- /**\n- * Function: hasClass\n- * Tests if an element has the given CSS class name.\n- *\n- * Parameters:\n- * element - {DOMElement} A DOM element node.\n- * name - {String} The CSS class name to search for.\n- *\n- * Returns:\n- * {Boolean} The element has the given class name.\n- */\n- hasClass: function(element, name) {\n- var names = element.className;\n- return (!!names && new RegExp(\"(^|\\\\s)\" + name + \"(\\\\s|$)\").test(names));\n- },\n-\n- /**\n- * Function: addClass\n- * Add a CSS class name to an element. Safe where element already has\n- * the class name.\n- *\n- * Parameters:\n- * element - {DOMElement} A DOM element node.\n- * name - {String} The CSS class name to add.\n- *\n- * Returns:\n- * {DOMElement} The element.\n- */\n- addClass: function(element, name) {\n- if (!OpenLayers.Element.hasClass(element, name)) {\n- element.className += (element.className ? \" \" : \"\") + name;\n- }\n- return element;\n- },\n-\n- /**\n- * Function: removeClass\n- * Remove a CSS class name from an element. Safe where element does not\n- * have the class name.\n- *\n- * Parameters:\n- * element - {DOMElement} A DOM element node.\n- * name - {String} The CSS class name to remove.\n- *\n- * Returns:\n- * {DOMElement} The element.\n- */\n- removeClass: function(element, name) {\n- var names = element.className;\n- if (names) {\n- element.className = OpenLayers.String.trim(\n- names.replace(\n- new RegExp(\"(^|\\\\s+)\" + name + \"(\\\\s+|$)\"), \" \"\n- )\n- );\n- }\n- return element;\n- },\n-\n- /**\n- * Function: toggleClass\n- * Remove a CSS class name from an element if it exists. Add the class name\n- * if it doesn't exist.\n- *\n- * Parameters:\n- * element - {DOMElement} A DOM element node.\n- * name - {String} The CSS class name to toggle.\n- *\n- * Returns:\n- * {DOMElement} The element.\n- */\n- toggleClass: function(element, name) {\n- if (OpenLayers.Element.hasClass(element, name)) {\n- OpenLayers.Element.removeClass(element, name);\n- } else {\n- OpenLayers.Element.addClass(element, name);\n- }\n- return element;\n- },\n-\n- /**\n- * APIFunction: getStyle\n- * \n- * Parameters:\n- * element - {DOMElement}\n- * style - {?}\n- * \n- * Returns:\n- * {?}\n- */\n- getStyle: function(element, style) {\n- element = OpenLayers.Util.getElement(element);\n-\n- var value = null;\n- if (element && element.style) {\n- value = element.style[OpenLayers.String.camelize(style)];\n- if (!value) {\n- if (document.defaultView &&\n- document.defaultView.getComputedStyle) {\n-\n- var css = document.defaultView.getComputedStyle(element, null);\n- value = css ? css.getPropertyValue(style) : null;\n- } else if (element.currentStyle) {\n- value = element.currentStyle[OpenLayers.String.camelize(style)];\n- }\n- }\n-\n- var positions = ['left', 'top', 'right', 'bottom'];\n- if (window.opera &&\n- (OpenLayers.Util.indexOf(positions, style) != -1) &&\n- (OpenLayers.Element.getStyle(element, 'position') == 'static')) {\n- value = 'auto';\n- }\n- }\n-\n- return value == 'auto' ? null : value;\n- }\n-\n-};\n-/* ======================================================================\n OpenLayers/BaseTypes/LonLat.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -2243,268 +2327,14 @@\n }\n return equals;\n },\n \n CLASS_NAME: \"OpenLayers.Size\"\n });\n /* ======================================================================\n- OpenLayers/Console.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Console\n- * The OpenLayers.Console namespace is used for debugging and error logging.\n- * If the Firebug Lite (../Firebug/firebug.js) is included before this script,\n- * calls to OpenLayers.Console methods will get redirected to window.console.\n- * This makes use of the Firebug extension where available and allows for\n- * cross-browser debugging Firebug style.\n- *\n- * Note:\n- * Note that behavior will differ with the Firebug extention and Firebug Lite.\n- * Most notably, the Firebug Lite console does not currently allow for\n- * hyperlinks to code or for clicking on object to explore their properties.\n- * \n- */\n-OpenLayers.Console = {\n- /**\n- * Create empty functions for all console methods. The real value of these\n- * properties will be set if Firebug Lite (../Firebug/firebug.js script) is\n- * included. We explicitly require the Firebug Lite script to trigger\n- * functionality of the OpenLayers.Console methods.\n- */\n-\n- /**\n- * APIFunction: log\n- * Log an object in the console. The Firebug Lite console logs string\n- * representation of objects. Given multiple arguments, they will\n- * be cast to strings and logged with a space delimiter. If the first\n- * argument is a string with printf-like formatting, subsequent arguments\n- * will be used in string substitution. Any additional arguments (beyond\n- * the number substituted in a format string) will be appended in a space-\n- * delimited line.\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- log: function() {},\n-\n- /**\n- * APIFunction: debug\n- * Writes a message to the console, including a hyperlink to the line\n- * where it was called.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- debug: function() {},\n-\n- /**\n- * APIFunction: info\n- * Writes a message to the console with the visual \"info\" icon and color\n- * coding and a hyperlink to the line where it was called.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- info: function() {},\n-\n- /**\n- * APIFunction: warn\n- * Writes a message to the console with the visual \"warning\" icon and\n- * color coding and a hyperlink to the line where it was called.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- warn: function() {},\n-\n- /**\n- * APIFunction: error\n- * Writes a message to the console with the visual \"error\" icon and color\n- * coding and a hyperlink to the line where it was called.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- error: function() {},\n-\n- /**\n- * APIFunction: userError\n- * A single interface for showing error messages to the user. The default\n- * behavior is a Javascript alert, though this can be overridden by\n- * reassigning OpenLayers.Console.userError to a different function.\n- *\n- * Expects a single error message\n- * \n- * Parameters:\n- * error - {Object}\n- */\n- userError: function(error) {\n- alert(error);\n- },\n-\n- /**\n- * APIFunction: assert\n- * Tests that an expression is true. If not, it will write a message to\n- * the console and throw an exception.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- assert: function() {},\n-\n- /**\n- * APIFunction: dir\n- * Prints an interactive listing of all properties of the object. This\n- * looks identical to the view that you would see in the DOM tab.\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- dir: function() {},\n-\n- /**\n- * APIFunction: dirxml\n- * Prints the XML source tree of an HTML or XML element. This looks\n- * identical to the view that you would see in the HTML tab. You can click\n- * on any node to inspect it in the HTML tab.\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- dirxml: function() {},\n-\n- /**\n- * APIFunction: trace\n- * Prints an interactive stack trace of JavaScript execution at the point\n- * where it is called. The stack trace details the functions on the stack,\n- * as well as the values that were passed as arguments to each function.\n- * You can click each function to take you to its source in the Script tab,\n- * and click each argument value to inspect it in the DOM or HTML tabs.\n- * \n- */\n- trace: function() {},\n-\n- /**\n- * APIFunction: group\n- * Writes a message to the console and opens a nested block to indent all\n- * future messages sent to the console. Call OpenLayers.Console.groupEnd()\n- * to close the block.\n- *\n- * May be called with multiple arguments as with OpenLayers.Console.log().\n- * \n- * Parameters:\n- * object - {Object}\n- */\n- group: function() {},\n-\n- /**\n- * APIFunction: groupEnd\n- * Closes the most recently opened block created by a call to\n- * OpenLayers.Console.group\n- */\n- groupEnd: function() {},\n-\n- /**\n- * APIFunction: time\n- * Creates a new timer under the given name. Call\n- * OpenLayers.Console.timeEnd(name)\n- * with the same name to stop the timer and print the time elapsed.\n- *\n- * Parameters:\n- * name - {String}\n- */\n- time: function() {},\n-\n- /**\n- * APIFunction: timeEnd\n- * Stops a timer created by a call to OpenLayers.Console.time(name) and\n- * writes the time elapsed.\n- *\n- * Parameters:\n- * name - {String}\n- */\n- timeEnd: function() {},\n-\n- /**\n- * APIFunction: profile\n- * Turns on the JavaScript profiler. The optional argument title would\n- * contain the text to be printed in the header of the profile report.\n- *\n- * This function is not currently implemented in Firebug Lite.\n- * \n- * Parameters:\n- * title - {String} Optional title for the profiler\n- */\n- profile: function() {},\n-\n- /**\n- * APIFunction: profileEnd\n- * Turns off the JavaScript profiler and prints its report.\n- * \n- * This function is not currently implemented in Firebug Lite.\n- */\n- profileEnd: function() {},\n-\n- /**\n- * APIFunction: count\n- * Writes the number of times that the line of code where count was called\n- * was executed. The optional argument title will print a message in\n- * addition to the number of the count.\n- *\n- * This function is not currently implemented in Firebug Lite.\n- *\n- * Parameters:\n- * title - {String} Optional title to be printed with count\n- */\n- count: function() {},\n-\n- CLASS_NAME: \"OpenLayers.Console\"\n-};\n-\n-/**\n- * Execute an anonymous function to extend the OpenLayers.Console namespace\n- * if the firebug.js script is included. This closure is used so that the\n- * \"scripts\" and \"i\" variables don't pollute the global namespace.\n- */\n-(function() {\n- /**\n- * If Firebug Lite is included (before this script), re-route all\n- * OpenLayers.Console calls to the console object.\n- */\n- var scripts = document.getElementsByTagName(\"script\");\n- for (var i = 0, len = scripts.length; i < len; ++i) {\n- if (scripts[i].src.indexOf(\"firebug.js\") != -1) {\n- if (console) {\n- OpenLayers.Util.extend(OpenLayers.Console, console);\n- break;\n- }\n- }\n- }\n-})();\n-/* ======================================================================\n OpenLayers/Lang.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -4426,812 +4256,839 @@\n } else {\n str += coordinate < 0 ? OpenLayers.i18n(\"S\") : OpenLayers.i18n(\"N\");\n }\n return str;\n };\n \n /* ======================================================================\n- OpenLayers/Util/vendorPrefix.js\n+ OpenLayers/BaseTypes/Element.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/SingleFile.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/BaseTypes.js\n */\n \n-OpenLayers.Util = OpenLayers.Util || {};\n /**\n- * Namespace: OpenLayers.Util.vendorPrefix\n- * A collection of utility functions to detect vendor prefixed features\n+ * Namespace: OpenLayers.Element\n */\n-OpenLayers.Util.vendorPrefix = (function() {\n- \"use strict\";\n+OpenLayers.Element = {\n \n- var VENDOR_PREFIXES = [\"\", \"O\", \"ms\", \"Moz\", \"Webkit\"],\n- divStyle = document.createElement(\"div\").style,\n- cssCache = {},\n- jsCache = {};\n+ /**\n+ * APIFunction: visible\n+ * \n+ * Parameters: \n+ * element - {DOMElement}\n+ * \n+ * Returns:\n+ * {Boolean} Is the element visible?\n+ */\n+ visible: function(element) {\n+ return OpenLayers.Util.getElement(element).style.display != 'none';\n+ },\n \n+ /**\n+ * APIFunction: toggle\n+ * Toggle the visibility of element(s) passed in\n+ * \n+ * Parameters:\n+ * element - {DOMElement} Actually user can pass any number of elements\n+ */\n+ toggle: function() {\n+ for (var i = 0, len = arguments.length; i < len; i++) {\n+ var element = OpenLayers.Util.getElement(arguments[i]);\n+ var display = OpenLayers.Element.visible(element) ? 'none' :\n+ '';\n+ element.style.display = display;\n+ }\n+ },\n \n /**\n- * Function: domToCss\n- * Converts a upper camel case DOM style property name to a CSS property\n- * i.e. transformOrigin -> transform-origin\n- * or WebkitTransformOrigin -> -webkit-transform-origin\n- *\n+ * APIFunction: remove\n+ * Remove the specified element from the DOM.\n+ * \n * Parameters:\n- * prefixedDom - {String} The property to convert\n- *\n+ * element - {DOMElement}\n+ */\n+ remove: function(element) {\n+ element = OpenLayers.Util.getElement(element);\n+ element.parentNode.removeChild(element);\n+ },\n+\n+ /**\n+ * APIFunction: getHeight\n+ * \n+ * Parameters:\n+ * element - {DOMElement}\n+ * \n * Returns:\n- * {String} The CSS property\n+ * {Integer} The offset height of the element passed in\n */\n- function domToCss(prefixedDom) {\n- if (!prefixedDom) {\n- return null;\n- }\n- return prefixedDom.\n- replace(/([A-Z])/g, function(c) {\n- return \"-\" + c.toLowerCase();\n- }).\n- replace(/^ms-/, \"-ms-\");\n- }\n+ getHeight: function(element) {\n+ element = OpenLayers.Util.getElement(element);\n+ return element.offsetHeight;\n+ },\n \n /**\n- * APIMethod: css\n- * Detect which property is used for a CSS property\n+ * Function: hasClass\n+ * Tests if an element has the given CSS class name.\n *\n * Parameters:\n- * property - {String} The standard (unprefixed) CSS property name\n+ * element - {DOMElement} A DOM element node.\n+ * name - {String} The CSS class name to search for.\n *\n * Returns:\n- * {String} The standard CSS property, prefixed property or null if not\n- * supported\n+ * {Boolean} The element has the given class name.\n */\n- function css(property) {\n- if (cssCache[property] === undefined) {\n- var domProperty = property.\n- replace(/(-[\\s\\S])/g, function(c) {\n- return c.charAt(1).toUpperCase();\n- });\n- var prefixedDom = style(domProperty);\n- cssCache[property] = domToCss(prefixedDom);\n- }\n- return cssCache[property];\n- }\n+ hasClass: function(element, name) {\n+ var names = element.className;\n+ return (!!names && new RegExp(\"(^|\\\\s)\" + name + \"(\\\\s|$)\").test(names));\n+ },\n \n /**\n- * APIMethod: js\n- * Detect which property is used for a JS property/method\n+ * Function: addClass\n+ * Add a CSS class name to an element. Safe where element already has\n+ * the class name.\n *\n * Parameters:\n- * obj - {Object} The object to test on\n- * property - {String} The standard (unprefixed) JS property name\n+ * element - {DOMElement} A DOM element node.\n+ * name - {String} The CSS class name to add.\n *\n * Returns:\n- * {String} The standard JS property, prefixed property or null if not\n- * supported\n+ * {DOMElement} The element.\n */\n- function js(obj, property) {\n- if (jsCache[property] === undefined) {\n- var tmpProp,\n- i = 0,\n- l = VENDOR_PREFIXES.length,\n- prefix,\n- isStyleObj = (typeof obj.cssText !== \"undefined\");\n-\n- jsCache[property] = null;\n- for (; i < l; i++) {\n- prefix = VENDOR_PREFIXES[i];\n- if (prefix) {\n- if (!isStyleObj) {\n- // js prefix should be lower-case, while style\n- // properties have upper case on first character\n- prefix = prefix.toLowerCase();\n- }\n- tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);\n- } else {\n- tmpProp = property;\n- }\n-\n- if (obj[tmpProp] !== undefined) {\n- jsCache[property] = tmpProp;\n- break;\n- }\n- }\n+ addClass: function(element, name) {\n+ if (!OpenLayers.Element.hasClass(element, name)) {\n+ element.className += (element.className ? \" \" : \"\") + name;\n }\n- return jsCache[property];\n- }\n+ return element;\n+ },\n \n /**\n- * APIMethod: style\n- * Detect which property is used for a DOM style property\n+ * Function: removeClass\n+ * Remove a CSS class name from an element. Safe where element does not\n+ * have the class name.\n *\n * Parameters:\n- * property - {String} The standard (unprefixed) style property name\n+ * element - {DOMElement} A DOM element node.\n+ * name - {String} The CSS class name to remove.\n *\n * Returns:\n- * {String} The standard style property, prefixed property or null if not\n- * supported\n- */\n- function style(property) {\n- return js(divStyle, property);\n- }\n-\n- return {\n- css: css,\n- js: js,\n- style: style,\n-\n- // used for testing\n- cssCache: cssCache,\n- jsCache: jsCache\n- };\n-}());\n-/* ======================================================================\n- OpenLayers/Animation.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- * @requires OpenLayers/Util/vendorPrefix.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Animation\n- * A collection of utility functions for executing methods that repaint a \n- * portion of the browser window. These methods take advantage of the\n- * browser's scheduled repaints where requestAnimationFrame is available.\n- */\n-OpenLayers.Animation = (function(window) {\n-\n- /**\n- * Property: isNative\n- * {Boolean} true if a native requestAnimationFrame function is available\n+ * {DOMElement} The element.\n */\n- var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, \"requestAnimationFrame\");\n- var isNative = !!(requestAnimationFrame);\n+ removeClass: function(element, name) {\n+ var names = element.className;\n+ if (names) {\n+ element.className = OpenLayers.String.trim(\n+ names.replace(\n+ new RegExp(\"(^|\\\\s+)\" + name + \"(\\\\s+|$)\"), \" \"\n+ )\n+ );\n+ }\n+ return element;\n+ },\n \n /**\n- * Function: requestFrame\n- * Schedule a function to be called at the next available animation frame.\n- * Uses the native method where available. Where requestAnimationFrame is\n- * not available, setTimeout will be called with a 16ms delay.\n+ * Function: toggleClass\n+ * Remove a CSS class name from an element if it exists. Add the class name\n+ * if it doesn't exist.\n *\n * Parameters:\n- * callback - {Function} The function to be called at the next animation frame.\n- * element - {DOMElement} Optional element that visually bounds the animation.\n+ * element - {DOMElement} A DOM element node.\n+ * name - {String} The CSS class name to toggle.\n+ *\n+ * Returns:\n+ * {DOMElement} The element.\n */\n- var requestFrame = (function() {\n- var request = window[requestAnimationFrame] ||\n- function(callback, element) {\n- window.setTimeout(callback, 16);\n- };\n- // bind to window to avoid illegal invocation of native function\n- return function(callback, element) {\n- request.apply(window, [callback, element]);\n- };\n- })();\n-\n- // private variables for animation loops\n- var counter = 0;\n- var loops = {};\n+ toggleClass: function(element, name) {\n+ if (OpenLayers.Element.hasClass(element, name)) {\n+ OpenLayers.Element.removeClass(element, name);\n+ } else {\n+ OpenLayers.Element.addClass(element, name);\n+ }\n+ return element;\n+ },\n \n /**\n- * Function: start\n- * Executes a method with in series for some \n- * duration.\n- *\n+ * APIFunction: getStyle\n+ * \n * Parameters:\n- * callback - {Function} The function to be called at the next animation frame.\n- * duration - {Number} Optional duration for the loop. If not provided, the\n- * animation loop will execute indefinitely.\n- * element - {DOMElement} Optional element that visually bounds the animation.\n- *\n+ * element - {DOMElement}\n+ * style - {?}\n+ * \n * Returns:\n- * {Number} Identifier for the animation loop. Used to stop animations with\n- * .\n+ * {?}\n */\n- function start(callback, duration, element) {\n- duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;\n- var id = ++counter;\n- var start = +new Date;\n- loops[id] = function() {\n- if (loops[id] && +new Date - start <= duration) {\n- callback();\n- if (loops[id]) {\n- requestFrame(loops[id], element);\n+ getStyle: function(element, style) {\n+ element = OpenLayers.Util.getElement(element);\n+\n+ var value = null;\n+ if (element && element.style) {\n+ value = element.style[OpenLayers.String.camelize(style)];\n+ if (!value) {\n+ if (document.defaultView &&\n+ document.defaultView.getComputedStyle) {\n+\n+ var css = document.defaultView.getComputedStyle(element, null);\n+ value = css ? css.getPropertyValue(style) : null;\n+ } else if (element.currentStyle) {\n+ value = element.currentStyle[OpenLayers.String.camelize(style)];\n }\n- } else {\n- delete loops[id];\n }\n- };\n- requestFrame(loops[id], element);\n- return id;\n- }\n \n- /**\n- * Function: stop\n- * Terminates an animation loop started with .\n- *\n- * Parameters:\n- * id - {Number} Identifier returned from .\n- */\n- function stop(id) {\n- delete loops[id];\n- }\n+ var positions = ['left', 'top', 'right', 'bottom'];\n+ if (window.opera &&\n+ (OpenLayers.Util.indexOf(positions, style) != -1) &&\n+ (OpenLayers.Element.getStyle(element, 'position') == 'static')) {\n+ value = 'auto';\n+ }\n+ }\n \n- return {\n- isNative: isNative,\n- requestFrame: requestFrame,\n- start: start,\n- stop: stop\n- };\n+ return value == 'auto' ? null : value;\n+ }\n \n-})(window);\n+};\n /* ======================================================================\n- OpenLayers/Kinetic.js\n+ Rico/Color.js\n ====================================================================== */\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n+/** \n+ * @requires Rico/license.js\n+ * @requires OpenLayers/Console.js\n * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Animation.js\n+ * @requires OpenLayers/BaseTypes/Element.js\n */\n \n-OpenLayers.Kinetic = OpenLayers.Class({\n-\n- /**\n- * Property: threshold\n- * In most cases changing the threshold isn't needed.\n- * In px/ms, default to 0.\n- */\n- threshold: 0,\n \n- /**\n- * Property: deceleration\n- * {Float} the deseleration in px/ms\u00b2, default to 0.0035.\n- */\n- deceleration: 0.0035,\n+/*\n+ * This file has been edited substantially from the Rico-released version by\n+ * the OpenLayers development team.\n+ */\n \n- /**\n- * Property: nbPoints\n- * {Integer} the number of points we use to calculate the kinetic\n- * initial values.\n- */\n- nbPoints: 100,\n+OpenLayers.Console.warn(\"OpenLayers.Rico is deprecated\");\n \n- /**\n- * Property: delay\n- * {Float} time to consider to calculate the kinetic initial values.\n- * In ms, default to 200.\n- */\n- delay: 200,\n+OpenLayers.Rico = OpenLayers.Rico || {};\n+OpenLayers.Rico.Color = OpenLayers.Class({\n \n- /**\n- * Property: points\n- * List of points use to calculate the kinetic initial values.\n- */\n- points: undefined,\n+ initialize: function(red, green, blue) {\n+ this.rgb = {\n+ r: red,\n+ g: green,\n+ b: blue\n+ };\n+ },\n \n- /**\n- * Property: timerId\n- * ID of the timer.\n- */\n- timerId: undefined,\n+ setRed: function(r) {\n+ this.rgb.r = r;\n+ },\n \n- /**\n- * Constructor: OpenLayers.Kinetic\n- *\n- * Parameters:\n- * options - {Object}\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n+ setGreen: function(g) {\n+ this.rgb.g = g;\n },\n \n- /**\n- * Method: begin\n- * Begins the dragging.\n- */\n- begin: function() {\n- OpenLayers.Animation.stop(this.timerId);\n- this.timerId = undefined;\n- this.points = [];\n+ setBlue: function(b) {\n+ this.rgb.b = b;\n },\n \n- /**\n- * Method: update\n- * Updates during the dragging.\n- *\n- * Parameters:\n- * xy - {} The new position.\n- */\n- update: function(xy) {\n- this.points.unshift({\n- xy: xy,\n- tick: new Date().getTime()\n- });\n- if (this.points.length > this.nbPoints) {\n- this.points.pop();\n- }\n+ setHue: function(h) {\n+\n+ // get an HSB model, and set the new hue...\n+ var hsb = this.asHSB();\n+ hsb.h = h;\n+\n+ // convert back to RGB...\n+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);\n },\n \n- /**\n- * Method: end\n- * Ends the dragging, start the kinetic.\n- *\n- * Parameters:\n- * xy - {} The last position.\n- *\n- * Returns:\n- * {Object} An object with two properties: \"speed\", and \"theta\". The\n- * \"speed\" and \"theta\" values are to be passed to the move \n- * function when starting the animation.\n- */\n- end: function(xy) {\n- var last, now = new Date().getTime();\n- for (var i = 0, l = this.points.length, point; i < l; i++) {\n- point = this.points[i];\n- if (now - point.tick > this.delay) {\n- break;\n- }\n- last = point;\n- }\n- if (!last) {\n- return;\n- }\n- var time = new Date().getTime() - last.tick;\n- var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) +\n- Math.pow(xy.y - last.xy.y, 2));\n- var speed = dist / time;\n- if (speed == 0 || speed < this.threshold) {\n- return;\n- }\n- var theta = Math.asin((xy.y - last.xy.y) / dist);\n- if (last.xy.x <= xy.x) {\n- theta = Math.PI - theta;\n- }\n- return {\n- speed: speed,\n- theta: theta\n- };\n+ setSaturation: function(s) {\n+ // get an HSB model, and set the new hue...\n+ var hsb = this.asHSB();\n+ hsb.s = s;\n+\n+ // convert back to RGB and set values...\n+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);\n },\n \n- /**\n- * Method: move\n- * Launch the kinetic move pan.\n- *\n- * Parameters:\n- * info - {Object} An object with two properties, \"speed\", and \"theta\".\n- * These values are those returned from the \"end\" call.\n- * callback - {Function} Function called on every step of the animation,\n- * receives x, y (values to pan), end (is the last point).\n- */\n- move: function(info, callback) {\n- var v0 = info.speed;\n- var fx = Math.cos(info.theta);\n- var fy = -Math.sin(info.theta);\n+ setBrightness: function(b) {\n+ // get an HSB model, and set the new hue...\n+ var hsb = this.asHSB();\n+ hsb.b = b;\n \n- var initialTime = new Date().getTime();\n+ // convert back to RGB and set values...\n+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);\n+ },\n \n- var lastX = 0;\n- var lastY = 0;\n+ darken: function(percent) {\n+ var hsb = this.asHSB();\n+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0));\n+ },\n \n- var timerCallback = function() {\n- if (this.timerId == null) {\n- return;\n- }\n+ brighten: function(percent) {\n+ var hsb = this.asHSB();\n+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1));\n+ },\n \n- var t = new Date().getTime() - initialTime;\n+ blend: function(other) {\n+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2);\n+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2);\n+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2);\n+ },\n \n- var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t;\n- var x = p * fx;\n- var y = p * fy;\n+ isBright: function() {\n+ var hsb = this.asHSB();\n+ return this.asHSB().b > 0.5;\n+ },\n \n- var args = {};\n- args.end = false;\n- var v = -this.deceleration * t + v0;\n+ isDark: function() {\n+ return !this.isBright();\n+ },\n \n- if (v <= 0) {\n- OpenLayers.Animation.stop(this.timerId);\n- this.timerId = null;\n- args.end = true;\n- }\n+ asRGB: function() {\n+ return \"rgb(\" + this.rgb.r + \",\" + this.rgb.g + \",\" + this.rgb.b + \")\";\n+ },\n \n- args.x = x - lastX;\n- args.y = y - lastY;\n- lastX = x;\n- lastY = y;\n- callback(args.x, args.y, args.end);\n- };\n+ asHex: function() {\n+ return \"#\" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();\n+ },\n \n- this.timerId = OpenLayers.Animation.start(\n- OpenLayers.Function.bind(timerCallback, this)\n- );\n+ asHSB: function() {\n+ return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);\n },\n \n- CLASS_NAME: \"OpenLayers.Kinetic\"\n+ toString: function() {\n+ return this.asHex();\n+ }\n+\n });\n-/* ======================================================================\n- OpenLayers/Tween.js\n- ====================================================================== */\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+OpenLayers.Rico.Color.createFromHex = function(hexCode) {\n+ if (hexCode.length == 4) {\n+ var shortHexCode = hexCode;\n+ var hexCode = '#';\n+ for (var i = 1; i < 4; i++) {\n+ hexCode += (shortHexCode.charAt(i) +\n+ shortHexCode.charAt(i));\n+ }\n+ }\n+ if (hexCode.indexOf('#') == 0) {\n+ hexCode = hexCode.substring(1);\n+ }\n+ var red = hexCode.substring(0, 2);\n+ var green = hexCode.substring(2, 4);\n+ var blue = hexCode.substring(4, 6);\n+ return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16));\n+};\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Animation.js\n+ * Factory method for creating a color from the background of\n+ * an HTML element.\n */\n+OpenLayers.Rico.Color.createColorFromBackground = function(elem) {\n+\n+ var actualColor =\n+ OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem),\n+ \"backgroundColor\");\n+\n+ if (actualColor == \"transparent\" && elem.parentNode) {\n+ return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode);\n+ }\n+ if (actualColor == null) {\n+ return new OpenLayers.Rico.Color(255, 255, 255);\n+ }\n+ if (actualColor.indexOf(\"rgb(\") == 0) {\n+ var colors = actualColor.substring(4, actualColor.length - 1);\n+ var colorArray = colors.split(\",\");\n+ return new OpenLayers.Rico.Color(parseInt(colorArray[0]),\n+ parseInt(colorArray[1]),\n+ parseInt(colorArray[2]));\n+\n+ } else if (actualColor.indexOf(\"#\") == 0) {\n+ return OpenLayers.Rico.Color.createFromHex(actualColor);\n+ } else {\n+ return new OpenLayers.Rico.Color(255, 255, 255);\n+ }\n+};\n+\n+OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {\n+\n+ var red = 0;\n+ var green = 0;\n+ var blue = 0;\n+\n+ if (saturation == 0) {\n+ red = parseInt(brightness * 255.0 + 0.5);\n+ green = red;\n+ blue = red;\n+ } else {\n+ var h = (hue - Math.floor(hue)) * 6.0;\n+ var f = h - Math.floor(h);\n+ var p = brightness * (1.0 - saturation);\n+ var q = brightness * (1.0 - saturation * f);\n+ var t = brightness * (1.0 - (saturation * (1.0 - f)));\n+\n+ switch (parseInt(h)) {\n+ case 0:\n+ red = (brightness * 255.0 + 0.5);\n+ green = (t * 255.0 + 0.5);\n+ blue = (p * 255.0 + 0.5);\n+ break;\n+ case 1:\n+ red = (q * 255.0 + 0.5);\n+ green = (brightness * 255.0 + 0.5);\n+ blue = (p * 255.0 + 0.5);\n+ break;\n+ case 2:\n+ red = (p * 255.0 + 0.5);\n+ green = (brightness * 255.0 + 0.5);\n+ blue = (t * 255.0 + 0.5);\n+ break;\n+ case 3:\n+ red = (p * 255.0 + 0.5);\n+ green = (q * 255.0 + 0.5);\n+ blue = (brightness * 255.0 + 0.5);\n+ break;\n+ case 4:\n+ red = (t * 255.0 + 0.5);\n+ green = (p * 255.0 + 0.5);\n+ blue = (brightness * 255.0 + 0.5);\n+ break;\n+ case 5:\n+ red = (brightness * 255.0 + 0.5);\n+ green = (p * 255.0 + 0.5);\n+ blue = (q * 255.0 + 0.5);\n+ break;\n+ }\n+ }\n+\n+ return {\n+ r: parseInt(red),\n+ g: parseInt(green),\n+ b: parseInt(blue)\n+ };\n+};\n+\n+OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) {\n+\n+ var hue;\n+ var saturation;\n+ var brightness;\n+\n+ var cmax = (r > g) ? r : g;\n+ if (b > cmax) {\n+ cmax = b;\n+ }\n+ var cmin = (r < g) ? r : g;\n+ if (b < cmin) {\n+ cmin = b;\n+ }\n+ brightness = cmax / 255.0;\n+ if (cmax != 0) {\n+ saturation = (cmax - cmin) / cmax;\n+ } else {\n+ saturation = 0;\n+ }\n+ if (saturation == 0) {\n+ hue = 0;\n+ } else {\n+ var redc = (cmax - r) / (cmax - cmin);\n+ var greenc = (cmax - g) / (cmax - cmin);\n+ var bluec = (cmax - b) / (cmax - cmin);\n+\n+ if (r == cmax) {\n+ hue = bluec - greenc;\n+ } else if (g == cmax) {\n+ hue = 2.0 + redc - bluec;\n+ } else {\n+ hue = 4.0 + greenc - redc;\n+ }\n+ hue = hue / 6.0;\n+ if (hue < 0) {\n+ hue = hue + 1.0;\n+ }\n+ }\n+\n+ return {\n+ h: hue,\n+ s: saturation,\n+ b: brightness\n+ };\n+};\n+\n+/* ======================================================================\n+ Rico/Corner.js\n+ ====================================================================== */\n \n /**\n- * Namespace: OpenLayers.Tween\n+ * @requires OpenLayers/Console.js\n+ * @requires Rico/Color.js\n */\n-OpenLayers.Tween = OpenLayers.Class({\n \n- /**\n- * APIProperty: easing\n- * {(Function)} Easing equation used for the animation\n- * Defaultly set to OpenLayers.Easing.Expo.easeOut\n- */\n- easing: null,\n \n- /**\n- * APIProperty: begin\n- * {Object} Values to start the animation with\n- */\n- begin: null,\n+/*\n+ * This file has been edited substantially from the Rico-released\n+ * version by the OpenLayers development team.\n+ * \n+ * Copyright 2005 Sabre Airline Solutions \n+ * \n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the\n+ * License. You may obtain a copy of the License at\n+ * \n+ * http://www.apache.org/licenses/LICENSE-2.0 \n+ * \n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the * License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or\n+ * implied. See the License for the specific language governing\n+ * permissions * and limitations under the License.\n+ *\n+ */\n \n- /**\n- * APIProperty: finish\n- * {Object} Values to finish the animation with\n- */\n- finish: null,\n+OpenLayers.Console.warn(\"OpenLayers.Rico is deprecated\");\n \n- /**\n- * APIProperty: duration\n- * {int} duration of the tween (number of steps)\n- */\n- duration: null,\n+OpenLayers.Rico = OpenLayers.Rico || {};\n+OpenLayers.Rico.Corner = {\n \n- /**\n- * APIProperty: callbacks\n- * {Object} An object with start, eachStep and done properties whose values\n- * are functions to be call during the animation. They are passed the\n- * current computed value as argument.\n- */\n- callbacks: null,\n+ round: function(e, options) {\n+ e = OpenLayers.Util.getElement(e);\n+ this._setOptions(options);\n \n- /**\n- * Property: time\n- * {int} Step counter\n- */\n- time: null,\n+ var color = this.options.color;\n+ if (this.options.color == \"fromElement\") {\n+ color = this._background(e);\n+ }\n+ var bgColor = this.options.bgColor;\n+ if (this.options.bgColor == \"fromParent\") {\n+ bgColor = this._background(e.offsetParent);\n+ }\n+ this._roundCornersImpl(e, color, bgColor);\n+ },\n \n- /**\n- * APIProperty: minFrameRate\n- * {Number} The minimum framerate for animations in frames per second. After\n- * each step, the time spent in the animation is compared to the calculated\n- * time at this frame rate. If the animation runs longer than the calculated\n- * time, the next step is skipped. Default is 30.\n+ /** This is a helper function to change the background\n+ * color of
that has had Rico rounded corners added.\n+ *\n+ * It seems we cannot just set the background color for the\n+ * outer
so each element used to create the\n+ * corners must have its background color set individually.\n+ *\n+ * @param {DOM} theDiv - A child of the outer
that was\n+ * supplied to the `round` method.\n+ *\n+ * @param {String} newColor - The new background color to use.\n */\n- minFrameRate: null,\n+ changeColor: function(theDiv, newColor) {\n \n- /**\n- * Property: startTime\n- * {Number} The timestamp of the first execution step. Used for skipping\n- * frames\n- */\n- startTime: null,\n+ theDiv.style.backgroundColor = newColor;\n \n- /**\n- * Property: animationId\n- * {int} Loop id returned by OpenLayers.Animation.start\n- */\n- animationId: null,\n+ var spanElements = theDiv.parentNode.getElementsByTagName(\"span\");\n \n- /**\n- * Property: playing\n- * {Boolean} Tells if the easing is currently playing\n- */\n- playing: false,\n+ for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {\n+ spanElements[currIdx].style.backgroundColor = newColor;\n+ }\n+ },\n \n- /** \n- * Constructor: OpenLayers.Tween\n- * Creates a Tween.\n+\n+ /** This is a helper function to change the background\n+ * opacity of
that has had Rico rounded corners added.\n *\n- * Parameters:\n- * easing - {(Function)} easing function method to use\n+ * See changeColor (above) for algorithm explanation\n+ *\n+ * @param {DOM} theDiv A child of the outer
that was\n+ * supplied to the `round` method.\n+ *\n+ * @param {int} newOpacity The new opacity to use (0-1).\n */\n- initialize: function(easing) {\n- this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;\n- },\n+ changeOpacity: function(theDiv, newOpacity) {\n \n- /**\n- * APIMethod: start\n- * Plays the Tween, and calls the callback method on each step\n- * \n- * Parameters:\n- * begin - {Object} values to start the animation with\n- * finish - {Object} values to finish the animation with\n- * duration - {int} duration of the tween (number of steps)\n- * options - {Object} hash of options (callbacks (start, eachStep, done),\n- * minFrameRate)\n- */\n- start: function(begin, finish, duration, options) {\n- this.playing = true;\n- this.begin = begin;\n- this.finish = finish;\n- this.duration = duration;\n- this.callbacks = options.callbacks;\n- this.minFrameRate = options.minFrameRate || 30;\n- this.time = 0;\n- this.startTime = new Date().getTime();\n- OpenLayers.Animation.stop(this.animationId);\n- this.animationId = null;\n- if (this.callbacks && this.callbacks.start) {\n- this.callbacks.start.call(this, this.begin);\n+ var mozillaOpacity = newOpacity;\n+ var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';\n+\n+ theDiv.style.opacity = mozillaOpacity;\n+ theDiv.style.filter = ieOpacity;\n+\n+ var spanElements = theDiv.parentNode.getElementsByTagName(\"span\");\n+\n+ for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {\n+ spanElements[currIdx].style.opacity = mozillaOpacity;\n+ spanElements[currIdx].style.filter = ieOpacity;\n }\n- this.animationId = OpenLayers.Animation.start(\n- OpenLayers.Function.bind(this.play, this)\n- );\n+\n },\n \n- /**\n- * APIMethod: stop\n- * Stops the Tween, and calls the done callback\n- * Doesn't do anything if animation is already finished\n+ /** this function takes care of redoing the rico cornering\n+ * \n+ * you can't just call updateRicoCorners() again and pass it a \n+ * new options string. you have to first remove the divs that \n+ * rico puts on top and below the content div.\n+ *\n+ * @param {DOM} theDiv - A child of the outer
that was\n+ * supplied to the `round` method.\n+ *\n+ * @param {Object} options - list of options\n */\n- stop: function() {\n- if (!this.playing) {\n- return;\n- }\n+ reRound: function(theDiv, options) {\n \n- if (this.callbacks && this.callbacks.done) {\n- this.callbacks.done.call(this, this.finish);\n+ var topRico = theDiv.parentNode.childNodes[0];\n+ //theDiv would be theDiv.parentNode.childNodes[1]\n+ var bottomRico = theDiv.parentNode.childNodes[2];\n+\n+ theDiv.parentNode.removeChild(topRico);\n+ theDiv.parentNode.removeChild(bottomRico);\n+\n+ this.round(theDiv.parentNode, options);\n+ },\n+\n+ _roundCornersImpl: function(e, color, bgColor) {\n+ if (this.options.border) {\n+ this._renderBorder(e, bgColor);\n+ }\n+ if (this._isTopRounded()) {\n+ this._roundTopCorners(e, color, bgColor);\n+ }\n+ if (this._isBottomRounded()) {\n+ this._roundBottomCorners(e, color, bgColor);\n }\n- OpenLayers.Animation.stop(this.animationId);\n- this.animationId = null;\n- this.playing = false;\n },\n \n- /**\n- * Method: play\n- * Calls the appropriate easing method\n- */\n- play: function() {\n- var value = {};\n- for (var i in this.begin) {\n- var b = this.begin[i];\n- var f = this.finish[i];\n- if (b == null || f == null || isNaN(b) || isNaN(f)) {\n- throw new TypeError('invalid value for Tween');\n- }\n+ _renderBorder: function(el, bgColor) {\n+ var borderValue = \"1px solid \" + this._borderColor(bgColor);\n+ var borderL = \"border-left: \" + borderValue;\n+ var borderR = \"border-right: \" + borderValue;\n+ var style = \"style='\" + borderL + \";\" + borderR + \"'\";\n+ el.innerHTML = \"
\" + el.innerHTML + \"
\";\n+ },\n \n- var c = f - b;\n- value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);\n+ _roundTopCorners: function(el, color, bgColor) {\n+ var corner = this._createCorner(bgColor);\n+ for (var i = 0; i < this.options.numSlices; i++) {\n+ corner.appendChild(this._createCornerSlice(color, bgColor, i, \"top\"));\n }\n- this.time++;\n+ el.style.paddingTop = 0;\n+ el.insertBefore(corner, el.firstChild);\n+ },\n \n- if (this.callbacks && this.callbacks.eachStep) {\n- // skip frames if frame rate drops below threshold\n- if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {\n- this.callbacks.eachStep.call(this, value);\n- }\n+ _roundBottomCorners: function(el, color, bgColor) {\n+ var corner = this._createCorner(bgColor);\n+ for (var i = (this.options.numSlices - 1); i >= 0; i--) {\n+ corner.appendChild(this._createCornerSlice(color, bgColor, i, \"bottom\"));\n }\n+ el.style.paddingBottom = 0;\n+ el.appendChild(corner);\n+ },\n \n- if (this.time > this.duration) {\n- this.stop();\n- }\n+ _createCorner: function(bgColor) {\n+ var corner = document.createElement(\"div\");\n+ corner.style.backgroundColor = (this._isTransparent() ? \"transparent\" : bgColor);\n+ return corner;\n },\n \n- /**\n- * Create empty functions for all easing methods.\n- */\n- CLASS_NAME: \"OpenLayers.Tween\"\n-});\n+ _createCornerSlice: function(color, bgColor, n, position) {\n+ var slice = document.createElement(\"span\");\n \n-/**\n- * Namespace: OpenLayers.Easing\n- * \n- * Credits:\n- * Easing Equations by Robert Penner, \n- */\n-OpenLayers.Easing = {\n- /**\n- * Create empty functions for all easing methods.\n- */\n- CLASS_NAME: \"OpenLayers.Easing\"\n-};\n+ var inStyle = slice.style;\n+ inStyle.backgroundColor = color;\n+ inStyle.display = \"block\";\n+ inStyle.height = \"1px\";\n+ inStyle.overflow = \"hidden\";\n+ inStyle.fontSize = \"1px\";\n \n-/**\n- * Namespace: OpenLayers.Easing.Linear\n- */\n-OpenLayers.Easing.Linear = {\n+ var borderColor = this._borderColor(color, bgColor);\n+ if (this.options.border && n == 0) {\n+ inStyle.borderTopStyle = \"solid\";\n+ inStyle.borderTopWidth = \"1px\";\n+ inStyle.borderLeftWidth = \"0px\";\n+ inStyle.borderRightWidth = \"0px\";\n+ inStyle.borderBottomWidth = \"0px\";\n+ inStyle.height = \"0px\"; // assumes css compliant box model\n+ inStyle.borderColor = borderColor;\n+ } else if (borderColor) {\n+ inStyle.borderColor = borderColor;\n+ inStyle.borderStyle = \"solid\";\n+ inStyle.borderWidth = \"0px 1px\";\n+ }\n \n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return c * t / d + b;\n+ if (!this.options.compact && (n == (this.options.numSlices - 1))) {\n+ inStyle.height = \"2px\";\n+ }\n+ this._setMargin(slice, n, position);\n+ this._setBorder(slice, n, position);\n+ return slice;\n },\n \n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return c * t / d + b;\n- },\n+ _setOptions: function(options) {\n+ this.options = {\n+ corners: \"all\",\n+ color: \"fromElement\",\n+ bgColor: \"fromParent\",\n+ blend: true,\n+ border: false,\n+ compact: false\n+ };\n+ OpenLayers.Util.extend(this.options, options || {});\n \n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- return c * t / d + b;\n+ this.options.numSlices = this.options.compact ? 2 : 4;\n+ if (this._isTransparent()) {\n+ this.options.blend = false;\n+ }\n },\n \n- CLASS_NAME: \"OpenLayers.Easing.Linear\"\n-};\n+ _whichSideTop: function() {\n+ if (this._hasString(this.options.corners, \"all\", \"top\")) {\n+ return \"\";\n+ }\n+ if (this.options.corners.indexOf(\"tl\") >= 0 && this.options.corners.indexOf(\"tr\") >= 0) {\n+ return \"\";\n+ }\n+ if (this.options.corners.indexOf(\"tl\") >= 0) {\n+ return \"left\";\n+ } else if (this.options.corners.indexOf(\"tr\") >= 0) {\n+ return \"right\";\n+ }\n+ return \"\";\n+ },\n \n-/**\n- * Namespace: OpenLayers.Easing.Expo\n- */\n-OpenLayers.Easing.Expo = {\n+ _whichSideBottom: function() {\n+ if (this._hasString(this.options.corners, \"all\", \"bottom\")) {\n+ return \"\";\n+ }\n+ if (this.options.corners.indexOf(\"bl\") >= 0 && this.options.corners.indexOf(\"br\") >= 0) {\n+ return \"\";\n+ }\n \n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n+ if (this.options.corners.indexOf(\"bl\") >= 0) {\n+ return \"left\";\n+ } else if (this.options.corners.indexOf(\"br\") >= 0) {\n+ return \"right\";\n+ }\n+ return \"\";\n },\n \n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n+ _borderColor: function(color, bgColor) {\n+ if (color == \"transparent\") {\n+ return bgColor;\n+ } else if (this.options.border) {\n+ return this.options.border;\n+ } else if (this.options.blend) {\n+ return this._blend(bgColor, color);\n+ } else {\n+ return \"\";\n+ }\n },\n \n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- if (t == 0) return b;\n- if (t == d) return b + c;\n- if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n- return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n- },\n \n- CLASS_NAME: \"OpenLayers.Easing.Expo\"\n-};\n+ _setMargin: function(el, n, corners) {\n+ var marginSize = this._marginSize(n);\n+ var whichSide = corners == \"top\" ? this._whichSideTop() : this._whichSideBottom();\n \n-/**\n- * Namespace: OpenLayers.Easing.Quad\n- */\n-OpenLayers.Easing.Quad = {\n+ if (whichSide == \"left\") {\n+ el.style.marginLeft = marginSize + \"px\";\n+ el.style.marginRight = \"0px\";\n+ } else if (whichSide == \"right\") {\n+ el.style.marginRight = marginSize + \"px\";\n+ el.style.marginLeft = \"0px\";\n+ } else {\n+ el.style.marginLeft = marginSize + \"px\";\n+ el.style.marginRight = marginSize + \"px\";\n+ }\n+ },\n \n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return c * (t /= d) * t + b;\n+ _setBorder: function(el, n, corners) {\n+ var borderSize = this._borderSize(n);\n+ var whichSide = corners == \"top\" ? this._whichSideTop() : this._whichSideBottom();\n+ if (whichSide == \"left\") {\n+ el.style.borderLeftWidth = borderSize + \"px\";\n+ el.style.borderRightWidth = \"0px\";\n+ } else if (whichSide == \"right\") {\n+ el.style.borderRightWidth = borderSize + \"px\";\n+ el.style.borderLeftWidth = \"0px\";\n+ } else {\n+ el.style.borderLeftWidth = borderSize + \"px\";\n+ el.style.borderRightWidth = borderSize + \"px\";\n+ }\n+ if (this.options.border != false) {\n+ el.style.borderLeftWidth = borderSize + \"px\";\n+ el.style.borderRightWidth = borderSize + \"px\";\n+ }\n },\n \n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return -c * (t /= d) * (t - 2) + b;\n+ _marginSize: function(n) {\n+ if (this._isTransparent()) {\n+ return 0;\n+ }\n+ var marginSizes = [5, 3, 2, 1];\n+ var blendedMarginSizes = [3, 2, 1, 0];\n+ var compactMarginSizes = [2, 1];\n+ var smBlendedMarginSizes = [1, 0];\n+\n+ if (this.options.compact && this.options.blend) {\n+ return smBlendedMarginSizes[n];\n+ } else if (this.options.compact) {\n+ return compactMarginSizes[n];\n+ } else if (this.options.blend) {\n+ return blendedMarginSizes[n];\n+ } else {\n+ return marginSizes[n];\n+ }\n },\n \n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- if ((t /= d / 2) < 1) return c / 2 * t * t + b;\n- return -c / 2 * ((--t) * (t - 2) - 1) + b;\n+ _borderSize: function(n) {\n+ var transparentBorderSizes = [5, 3, 2, 1];\n+ var blendedBorderSizes = [2, 1, 1, 1];\n+ var compactBorderSizes = [1, 0];\n+ var actualBorderSizes = [0, 2, 0, 0];\n+\n+ if (this.options.compact && (this.options.blend || this._isTransparent())) {\n+ return 1;\n+ } else if (this.options.compact) {\n+ return compactBorderSizes[n];\n+ } else if (this.options.blend) {\n+ return blendedBorderSizes[n];\n+ } else if (this.options.border) {\n+ return actualBorderSizes[n];\n+ } else if (this._isTransparent()) {\n+ return transparentBorderSizes[n];\n+ }\n+ return 0;\n },\n \n- CLASS_NAME: \"OpenLayers.Easing.Quad\"\n+ _hasString: function(str) {\n+ for (var i = 1; i < arguments.length; i++)\n+ if (str.indexOf(arguments[i]) >= 0) {\n+ return true;\n+ } return false;\n+ },\n+ _blend: function(c1, c2) {\n+ var cc1 = OpenLayers.Rico.Color.createFromHex(c1);\n+ cc1.blend(OpenLayers.Rico.Color.createFromHex(c2));\n+ return cc1;\n+ },\n+ _background: function(el) {\n+ try {\n+ return OpenLayers.Rico.Color.createColorFromBackground(el).asHex();\n+ } catch (err) {\n+ return \"#ffffff\";\n+ }\n+ },\n+ _isTransparent: function() {\n+ return this.options.color == \"transparent\";\n+ },\n+ _isTopRounded: function() {\n+ return this._hasString(this.options.corners, \"all\", \"top\", \"tl\", \"tr\");\n+ },\n+ _isBottomRounded: function() {\n+ return this._hasString(this.options.corners, \"all\", \"bottom\", \"bl\", \"br\");\n+ },\n+ _hasSingleTextChild: function(el) {\n+ return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3;\n+ }\n };\n /* ======================================================================\n OpenLayers/Events.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n@@ -6402,876 +6259,4976 @@\n \n OpenLayers.Event.observe(element, 'MSPointerUp', cb);\n },\n \n CLASS_NAME: \"OpenLayers.Events\"\n });\n /* ======================================================================\n- OpenLayers/Projection.js\n+ OpenLayers/Request/XMLHttpRequest.js\n ====================================================================== */\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)\n+//\n+// Licensed under the Apache License, Version 2.0 (the \"License\");\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \"AS IS\" BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Request.js\n */\n \n-/**\n- * Namespace: OpenLayers.Projection\n- * Methods for coordinate transforms between coordinate systems. By default,\n- * OpenLayers ships with the ability to transform coordinates between\n- * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)\n- * coordinate reference systems. See the method for details\n- * on usage.\n- *\n- * Additional transforms may be added by using the \n- * library. If the proj4js library is included, the method \n- * will work between any two coordinate reference systems with proj4js \n- * definitions.\n- *\n- * If the proj4js library is not included, or if you wish to allow transforms\n- * between arbitrary coordinate reference systems, use the \n- * method to register a custom transform method.\n- */\n-OpenLayers.Projection = OpenLayers.Class({\n+(function() {\n \n- /**\n- * Property: proj\n- * {Object} Proj4js.Proj instance.\n- */\n- proj: null,\n+ // Save reference to earlier defined object implementation (if any)\n+ var oXMLHttpRequest = window.XMLHttpRequest;\n \n- /**\n- * Property: projCode\n- * {String}\n- */\n- projCode: null,\n+ // Define on browser type\n+ var bGecko = !!window.controllers,\n+ bIE = window.document.all && !window.opera,\n+ bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);\n \n- /**\n- * Property: titleRegEx\n- * {RegExp} regular expression to strip the title from a proj4js definition\n- */\n- titleRegEx: /\\+title=[^\\+]*/,\n+ // Enables \"XMLHttpRequest()\" call next to \"new XMLHttpReques()\"\n+ function fXMLHttpRequest() {\n+ this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n+ this._listeners = [];\n+ };\n \n- /**\n- * Constructor: OpenLayers.Projection\n- * This class offers several methods for interacting with a wrapped \n- * pro4js projection object. \n- *\n- * Parameters:\n- * projCode - {String} A string identifying the Well Known Identifier for\n- * the projection.\n- * options - {Object} An optional object to set additional properties\n- * on the projection.\n- *\n- * Returns:\n- * {} A projection object.\n- */\n- initialize: function(projCode, options) {\n- OpenLayers.Util.extend(this, options);\n- this.projCode = projCode;\n- if (typeof Proj4js == \"object\") {\n- this.proj = new Proj4js.Proj(projCode);\n+ // Constructor\n+ function cXMLHttpRequest() {\n+ return new fXMLHttpRequest;\n+ };\n+ cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;\n+\n+ // BUGFIX: Firefox with Firebug installed would break pages if not executed\n+ if (bGecko && oXMLHttpRequest.wrapped)\n+ cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;\n+\n+ // Constants\n+ cXMLHttpRequest.UNSENT = 0;\n+ cXMLHttpRequest.OPENED = 1;\n+ cXMLHttpRequest.HEADERS_RECEIVED = 2;\n+ cXMLHttpRequest.LOADING = 3;\n+ cXMLHttpRequest.DONE = 4;\n+\n+ // Public Properties\n+ cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;\n+ cXMLHttpRequest.prototype.responseText = '';\n+ cXMLHttpRequest.prototype.responseXML = null;\n+ cXMLHttpRequest.prototype.status = 0;\n+ cXMLHttpRequest.prototype.statusText = '';\n+\n+ // Priority proposal\n+ cXMLHttpRequest.prototype.priority = \"NORMAL\";\n+\n+ // Instance-level Events Handlers\n+ cXMLHttpRequest.prototype.onreadystatechange = null;\n+\n+ // Class-level Events Handlers\n+ cXMLHttpRequest.onreadystatechange = null;\n+ cXMLHttpRequest.onopen = null;\n+ cXMLHttpRequest.onsend = null;\n+ cXMLHttpRequest.onabort = null;\n+\n+ // Public Methods\n+ cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {\n+ // Delete headers, required when object is reused\n+ delete this._headers;\n+\n+ // When bAsync parameter value is omitted, use true as default\n+ if (arguments.length < 3)\n+ bAsync = true;\n+\n+ // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests\n+ this._async = bAsync;\n+\n+ // Set the onreadystatechange handler\n+ var oRequest = this,\n+ nState = this.readyState,\n+ fOnUnload;\n+\n+ // BUGFIX: IE - memory leak on page unload (inter-page leak)\n+ if (bIE && bAsync) {\n+ fOnUnload = function() {\n+ if (nState != cXMLHttpRequest.DONE) {\n+ fCleanTransport(oRequest);\n+ // Safe to abort here since onreadystatechange handler removed\n+ oRequest.abort();\n+ }\n+ };\n+ window.attachEvent(\"onunload\", fOnUnload);\n }\n- },\n \n- /**\n- * APIMethod: getCode\n- * Get the string SRS code.\n- *\n- * Returns:\n- * {String} The SRS code.\n- */\n- getCode: function() {\n- return this.proj ? this.proj.srsCode : this.projCode;\n- },\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onopen)\n+ cXMLHttpRequest.onopen.apply(this, arguments);\n \n- /**\n- * APIMethod: getUnits\n- * Get the units string for the projection -- returns null if \n- * proj4js is not available.\n- *\n- * Returns:\n- * {String} The units abbreviation.\n- */\n- getUnits: function() {\n- return this.proj ? this.proj.units : null;\n- },\n+ if (arguments.length > 4)\n+ this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n+ else\n+ if (arguments.length > 3)\n+ this._object.open(sMethod, sUrl, bAsync, sUser);\n+ else\n+ this._object.open(sMethod, sUrl, bAsync);\n \n- /**\n- * Method: toString\n- * Convert projection to string (getCode wrapper).\n- *\n- * Returns:\n- * {String} The projection code.\n- */\n- toString: function() {\n- return this.getCode();\n- },\n+ this.readyState = cXMLHttpRequest.OPENED;\n+ fReadyStateChange(this);\n \n- /**\n- * Method: equals\n- * Test equality of two projection instances. Determines equality based\n- * soley on the projection code.\n- *\n- * Returns:\n- * {Boolean} The two projections are equivalent.\n- */\n- equals: function(projection) {\n- var p = projection,\n- equals = false;\n- if (p) {\n- if (!(p instanceof OpenLayers.Projection)) {\n- p = new OpenLayers.Projection(p);\n- }\n- if ((typeof Proj4js == \"object\") && this.proj.defData && p.proj.defData) {\n- equals = this.proj.defData.replace(this.titleRegEx, \"\") ==\n- p.proj.defData.replace(this.titleRegEx, \"\");\n- } else if (p.getCode) {\n- var source = this.getCode(),\n- target = p.getCode();\n- equals = source == target ||\n- !!OpenLayers.Projection.transforms[source] &&\n- OpenLayers.Projection.transforms[source][target] ===\n- OpenLayers.Projection.nullTransform;\n+ this._object.onreadystatechange = function() {\n+ if (bGecko && !bAsync)\n+ return;\n+\n+ // Synchronize state\n+ oRequest.readyState = oRequest._object.readyState;\n+\n+ //\n+ fSynchronizeValues(oRequest);\n+\n+ // BUGFIX: Firefox fires unnecessary DONE when aborting\n+ if (oRequest._aborted) {\n+ // Reset readyState to UNSENT\n+ oRequest.readyState = cXMLHttpRequest.UNSENT;\n+\n+ // Return now\n+ return;\n }\n- }\n- return equals;\n- },\n \n- /* Method: destroy\n- * Destroy projection object.\n- */\n- destroy: function() {\n- delete this.proj;\n- delete this.projCode;\n- },\n+ if (oRequest.readyState == cXMLHttpRequest.DONE) {\n+ // Free up queue\n+ delete oRequest._data;\n+ /* if (bAsync)\n+ fQueue_remove(oRequest);*/\n+ //\n+ fCleanTransport(oRequest);\n+ // Uncomment this block if you need a fix for IE cache\n+ /*\n+ // BUGFIX: IE - cache issue\n+ if (!oRequest._object.getResponseHeader(\"Date\")) {\n+ // Save object to cache\n+ oRequest._cached = oRequest._object;\n \n- CLASS_NAME: \"OpenLayers.Projection\"\n-});\n+ // Instantiate a new transport object\n+ cXMLHttpRequest.call(oRequest);\n \n-/**\n- * Property: transforms\n- * {Object} Transforms is an object, with from properties, each of which may\n- * have a to property. This allows you to define projections without \n- * requiring support for proj4js to be included.\n- *\n- * This object has keys which correspond to a 'source' projection object. The\n- * keys should be strings, corresponding to the projection.getCode() value.\n- * Each source projection object should have a set of destination projection\n- * keys included in the object. \n- * \n- * Each value in the destination object should be a transformation function,\n- * where the function is expected to be passed an object with a .x and a .y\n- * property. The function should return the object, with the .x and .y\n- * transformed according to the transformation function.\n- *\n- * Note - Properties on this object should not be set directly. To add a\n- * transform method to this object, use the method. For an\n- * example of usage, see the OpenLayers.Layer.SphericalMercator file.\n- */\n-OpenLayers.Projection.transforms = {};\n+ // Re-send request\n+ if (sUser) {\n+ if (sPassword)\n+ oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n+ else\n+ oRequest._object.open(sMethod, sUrl, bAsync, sUser);\n+ }\n+ else\n+ oRequest._object.open(sMethod, sUrl, bAsync);\n+ oRequest._object.setRequestHeader(\"If-Modified-Since\", oRequest._cached.getResponseHeader(\"Last-Modified\") || new window.Date(0));\n+ // Copy headers set\n+ if (oRequest._headers)\n+ for (var sHeader in oRequest._headers)\n+ if (typeof oRequest._headers[sHeader] == \"string\") // Some frameworks prototype objects with functions\n+ oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);\n \n-/**\n- * APIProperty: defaults\n- * {Object} Defaults for the SRS codes known to OpenLayers (currently\n- * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,\n- * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,\n- * maxExtent (the validity extent for the SRS) and yx (true if this SRS is\n- * known to have a reverse axis order).\n- */\n-OpenLayers.Projection.defaults = {\n- \"EPSG:4326\": {\n- units: \"degrees\",\n- maxExtent: [-180, -90, 180, 90],\n- yx: true\n- },\n- \"CRS:84\": {\n- units: \"degrees\",\n- maxExtent: [-180, -90, 180, 90]\n- },\n- \"EPSG:900913\": {\n- units: \"m\",\n- maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]\n- }\n-};\n+ oRequest._object.onreadystatechange = function() {\n+ // Synchronize state\n+ oRequest.readyState = oRequest._object.readyState;\n \n-/**\n- * APIMethod: addTransform\n- * Set a custom transform method between two projections. Use this method in\n- * cases where the proj4js lib is not available or where custom projections\n- * need to be handled.\n- *\n- * Parameters:\n- * from - {String} The code for the source projection\n- * to - {String} the code for the destination projection\n- * method - {Function} A function that takes a point as an argument and\n- * transforms that point from the source to the destination projection\n- * in place. The original point should be modified.\n- */\n-OpenLayers.Projection.addTransform = function(from, to, method) {\n- if (method === OpenLayers.Projection.nullTransform) {\n- var defaults = OpenLayers.Projection.defaults[from];\n- if (defaults && !OpenLayers.Projection.defaults[to]) {\n- OpenLayers.Projection.defaults[to] = defaults;\n- }\n- }\n- if (!OpenLayers.Projection.transforms[from]) {\n- OpenLayers.Projection.transforms[from] = {};\n- }\n- OpenLayers.Projection.transforms[from][to] = method;\n-};\n+ if (oRequest._aborted) {\n+ //\n+ oRequest.readyState = cXMLHttpRequest.UNSENT;\n \n-/**\n- * APIMethod: transform\n- * Transform a point coordinate from one projection to another. Note that\n- * the input point is transformed in place.\n- * \n- * Parameters:\n- * point - { | Object} An object with x and y\n- * properties representing coordinates in those dimensions.\n- * source - {OpenLayers.Projection} Source map coordinate system\n- * dest - {OpenLayers.Projection} Destination map coordinate system\n- *\n- * Returns:\n- * point - {object} A transformed coordinate. The original point is modified.\n- */\n-OpenLayers.Projection.transform = function(point, source, dest) {\n- if (source && dest) {\n- if (!(source instanceof OpenLayers.Projection)) {\n- source = new OpenLayers.Projection(source);\n- }\n- if (!(dest instanceof OpenLayers.Projection)) {\n- dest = new OpenLayers.Projection(dest);\n+ // Return\n+ return;\n+ }\n+\n+ if (oRequest.readyState == cXMLHttpRequest.DONE) {\n+ // Clean Object\n+ fCleanTransport(oRequest);\n+\n+ // get cached request\n+ if (oRequest.status == 304)\n+ oRequest._object = oRequest._cached;\n+\n+ //\n+ delete oRequest._cached;\n+\n+ //\n+ fSynchronizeValues(oRequest);\n+\n+ //\n+ fReadyStateChange(oRequest);\n+\n+ // BUGFIX: IE - memory leak in interrupted\n+ if (bIE && bAsync)\n+ window.detachEvent(\"onunload\", fOnUnload);\n+ }\n+ };\n+ oRequest._object.send(null);\n+\n+ // Return now - wait until re-sent request is finished\n+ return;\n+ };\n+ */\n+ // BUGFIX: IE - memory leak in interrupted\n+ if (bIE && bAsync)\n+ window.detachEvent(\"onunload\", fOnUnload);\n+ }\n+\n+ // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice\n+ if (nState != oRequest.readyState)\n+ fReadyStateChange(oRequest);\n+\n+ nState = oRequest.readyState;\n }\n- if (source.proj && dest.proj) {\n- point = Proj4js.transform(source.proj, dest.proj, point);\n- } else {\n- var sourceCode = source.getCode();\n- var destCode = dest.getCode();\n- var transforms = OpenLayers.Projection.transforms;\n- if (transforms[sourceCode] && transforms[sourceCode][destCode]) {\n- transforms[sourceCode][destCode](point);\n+ };\n+\n+ function fXMLHttpRequest_send(oRequest) {\n+ oRequest._object.send(oRequest._data);\n+\n+ // BUGFIX: Gecko - missing readystatechange calls in synchronous requests\n+ if (bGecko && !oRequest._async) {\n+ oRequest.readyState = cXMLHttpRequest.OPENED;\n+\n+ // Synchronize state\n+ fSynchronizeValues(oRequest);\n+\n+ // Simulate missing states\n+ while (oRequest.readyState < cXMLHttpRequest.DONE) {\n+ oRequest.readyState++;\n+ fReadyStateChange(oRequest);\n+ // Check if we are aborted\n+ if (oRequest._aborted)\n+ return;\n }\n }\n- }\n- return point;\n-};\n+ };\n+ cXMLHttpRequest.prototype.send = function(vData) {\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onsend)\n+ cXMLHttpRequest.onsend.apply(this, arguments);\n \n-/**\n- * APIFunction: nullTransform\n- * A null transformation - useful for defining projection aliases when\n- * proj4js is not available:\n- *\n- * (code)\n- * OpenLayers.Projection.addTransform(\"EPSG:3857\", \"EPSG:900913\",\n- * OpenLayers.Projection.nullTransform);\n- * OpenLayers.Projection.addTransform(\"EPSG:900913\", \"EPSG:3857\",\n- * OpenLayers.Projection.nullTransform);\n- * (end)\n- */\n-OpenLayers.Projection.nullTransform = function(point) {\n- return point;\n-};\n+ if (!arguments.length)\n+ vData = null;\n \n-/**\n- * Note: Transforms for web mercator <-> geographic\n- * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.\n- * OpenLayers originally started referring to EPSG:900913 as web mercator.\n- * The EPSG has declared EPSG:3857 to be web mercator.\n- * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as\n- * 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.\n- * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and\n- * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis\n- * order for EPSG:4326. \n- */\n-(function() {\n+ // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required\n+ // BUGFIX: IE - rewrites any custom mime-type to \"text/xml\" in case an XMLNode is sent\n+ // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)\n+ if (vData && vData.nodeType) {\n+ vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;\n+ if (!this._headers[\"Content-Type\"])\n+ this._object.setRequestHeader(\"Content-Type\", \"application/xml\");\n+ }\n \n- var pole = 20037508.34;\n+ this._data = vData;\n+ /*\n+ // Add to queue\n+ if (this._async)\n+ fQueue_add(this);\n+ else*/\n+ fXMLHttpRequest_send(this);\n+ };\n+ cXMLHttpRequest.prototype.abort = function() {\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onabort)\n+ cXMLHttpRequest.onabort.apply(this, arguments);\n \n- function inverseMercator(xy) {\n- xy.x = 180 * xy.x / pole;\n- xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);\n- return xy;\n- }\n+ // BUGFIX: Gecko - unnecessary DONE when aborting\n+ if (this.readyState > cXMLHttpRequest.UNSENT)\n+ this._aborted = true;\n \n- function forwardMercator(xy) {\n- xy.x = xy.x * pole / 180;\n- var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;\n- xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));\n- return xy;\n- }\n+ this._object.abort();\n \n- function map(base, codes) {\n- var add = OpenLayers.Projection.addTransform;\n- var same = OpenLayers.Projection.nullTransform;\n- var i, len, code, other, j;\n- for (i = 0, len = codes.length; i < len; ++i) {\n- code = codes[i];\n- add(base, code, forwardMercator);\n- add(code, base, inverseMercator);\n- for (j = i + 1; j < len; ++j) {\n- other = codes[j];\n- add(code, other, same);\n- add(other, code, same);\n- }\n+ // BUGFIX: IE - memory leak\n+ fCleanTransport(this);\n+\n+ this.readyState = cXMLHttpRequest.UNSENT;\n+\n+ delete this._data;\n+ /* if (this._async)\n+ fQueue_remove(this);*/\n+ };\n+ cXMLHttpRequest.prototype.getAllResponseHeaders = function() {\n+ return this._object.getAllResponseHeaders();\n+ };\n+ cXMLHttpRequest.prototype.getResponseHeader = function(sName) {\n+ return this._object.getResponseHeader(sName);\n+ };\n+ cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {\n+ // BUGFIX: IE - cache issue\n+ if (!this._headers)\n+ this._headers = {};\n+ this._headers[sName] = sValue;\n+\n+ return this._object.setRequestHeader(sName, sValue);\n+ };\n+\n+ // EventTarget interface implementation\n+ cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n+ return;\n+ // Add listener\n+ this._listeners.push([sName, fHandler, bUseCapture]);\n+ };\n+\n+ cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n+ break;\n+ // Remove listener\n+ if (oListener)\n+ this._listeners.splice(nIndex, 1);\n+ };\n+\n+ cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {\n+ var oEventPseudo = {\n+ 'type': oEvent.type,\n+ 'target': this,\n+ 'currentTarget': this,\n+ 'eventPhase': 2,\n+ 'bubbles': oEvent.bubbles,\n+ 'cancelable': oEvent.cancelable,\n+ 'timeStamp': oEvent.timeStamp,\n+ 'stopPropagation': function() {}, // There is no flow\n+ 'preventDefault': function() {}, // There is no default action\n+ 'initEvent': function() {} // Original event object should be initialized\n+ };\n+\n+ // Execute onreadystatechange\n+ if (oEventPseudo.type == \"readystatechange\" && this.onreadystatechange)\n+ (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);\n+\n+ // Execute listeners\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == oEventPseudo.type && !oListener[2])\n+ (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);\n+ };\n+\n+ //\n+ cXMLHttpRequest.prototype.toString = function() {\n+ return '[' + \"object\" + ' ' + \"XMLHttpRequest\" + ']';\n+ };\n+\n+ cXMLHttpRequest.toString = function() {\n+ return '[' + \"XMLHttpRequest\" + ']';\n+ };\n+\n+ // Helper function\n+ function fReadyStateChange(oRequest) {\n+ // Sniffing code\n+ if (cXMLHttpRequest.onreadystatechange)\n+ cXMLHttpRequest.onreadystatechange.apply(oRequest);\n+\n+ // Fake event\n+ oRequest.dispatchEvent({\n+ 'type': \"readystatechange\",\n+ 'bubbles': false,\n+ 'cancelable': false,\n+ 'timeStamp': new Date + 0\n+ });\n+ };\n+\n+ function fGetDocument(oRequest) {\n+ var oDocument = oRequest.responseXML,\n+ sResponse = oRequest.responseText;\n+ // Try parsing responseText\n+ if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader(\"Content-Type\").match(/[^\\/]+\\/[^\\+]+\\+xml/)) {\n+ oDocument = new window.ActiveXObject(\"Microsoft.XMLDOM\");\n+ oDocument.async = false;\n+ oDocument.validateOnParse = false;\n+ oDocument.loadXML(sResponse);\n }\n- }\n+ // Check if there is no error in document\n+ if (oDocument)\n+ if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == \"parsererror\"))\n+ return null;\n+ return oDocument;\n+ };\n \n- // list of equivalent codes for web mercator\n- var mercator = [\"EPSG:900913\", \"EPSG:3857\", \"EPSG:102113\", \"EPSG:102100\"],\n- geographic = [\"CRS:84\", \"urn:ogc:def:crs:EPSG:6.6:4326\", \"EPSG:4326\"],\n- i;\n- for (i = mercator.length - 1; i >= 0; --i) {\n- map(mercator[i], geographic);\n- }\n- for (i = geographic.length - 1; i >= 0; --i) {\n- map(geographic[i], mercator);\n- }\n+ function fSynchronizeValues(oRequest) {\n+ try {\n+ oRequest.responseText = oRequest._object.responseText;\n+ } catch (e) {}\n+ try {\n+ oRequest.responseXML = fGetDocument(oRequest._object);\n+ } catch (e) {}\n+ try {\n+ oRequest.status = oRequest._object.status;\n+ } catch (e) {}\n+ try {\n+ oRequest.statusText = oRequest._object.statusText;\n+ } catch (e) {}\n+ };\n+\n+ function fCleanTransport(oRequest) {\n+ // BUGFIX: IE - memory leak (on-page leak)\n+ oRequest._object.onreadystatechange = new window.Function;\n+ };\n+ /*\n+ // Queue manager\n+ var oQueuePending = {\"CRITICAL\":[],\"HIGH\":[],\"NORMAL\":[],\"LOW\":[],\"LOWEST\":[]},\n+ aQueueRunning = [];\n+ function fQueue_add(oRequest) {\n+ oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : \"NORMAL\"].push(oRequest);\n+ //\n+ setTimeout(fQueue_process);\n+ };\n+\n+ function fQueue_remove(oRequest) {\n+ for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)\n+ if (bFound)\n+ aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];\n+ else\n+ if (aQueueRunning[nIndex] == oRequest)\n+ bFound = true;\n+ if (bFound)\n+ aQueueRunning.length--;\n+ //\n+ setTimeout(fQueue_process);\n+ };\n+\n+ function fQueue_process() {\n+ if (aQueueRunning.length < 6) {\n+ for (var sPriority in oQueuePending) {\n+ if (oQueuePending[sPriority].length) {\n+ var oRequest = oQueuePending[sPriority][0];\n+ oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);\n+ //\n+ aQueueRunning.push(oRequest);\n+ // Send request\n+ fXMLHttpRequest_send(oRequest);\n+ break;\n+ }\n+ }\n+ }\n+ };\n+ */\n+ // Internet Explorer 5.0 (missing apply)\n+ if (!window.Function.prototype.apply) {\n+ window.Function.prototype.apply = function(oRequest, oArguments) {\n+ if (!oArguments)\n+ oArguments = [];\n+ oRequest.__func = this;\n+ oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);\n+ delete oRequest.__func;\n+ };\n+ };\n \n+ // Register new object with window\n+ /**\n+ * Class: OpenLayers.Request.XMLHttpRequest\n+ * Standard-compliant (W3C) cross-browser implementation of the\n+ * XMLHttpRequest object. From\n+ * http://code.google.com/p/xmlhttprequest/.\n+ */\n+ if (!OpenLayers.Request) {\n+ /**\n+ * This allows for OpenLayers/Request.js to be included\n+ * before or after this script.\n+ */\n+ OpenLayers.Request = {};\n+ }\n+ OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;\n })();\n /* ======================================================================\n- OpenLayers/Map.js\n+ OpenLayers/Request.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Util/vendorPrefix.js\n * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Tween.js\n- * @requires OpenLayers/Projection.js\n+ * @requires OpenLayers/Request/XMLHttpRequest.js\n */\n \n /**\n- * Class: OpenLayers.Map\n- * Instances of OpenLayers.Map are interactive maps embedded in a web page.\n- * Create a new map with the constructor.\n- * \n- * On their own maps do not provide much functionality. To extend a map\n- * it's necessary to add controls () and \n- * layers () to the map. \n+ * TODO: deprecate me\n+ * Use OpenLayers.Request.proxy instead.\n */\n-OpenLayers.Map = OpenLayers.Class({\n-\n- /**\n- * Constant: Z_INDEX_BASE\n- * {Object} Base z-indexes for different classes of thing \n- */\n- Z_INDEX_BASE: {\n- BaseLayer: 100,\n- Overlay: 325,\n- Feature: 725,\n- Popup: 750,\n- Control: 1000\n- },\n+OpenLayers.ProxyHost = \"\";\n \n+/**\n+ * Namespace: OpenLayers.Request\n+ * The OpenLayers.Request namespace contains convenience methods for working\n+ * with XMLHttpRequests. These methods work with a cross-browser\n+ * W3C compliant class.\n+ */\n+if (!OpenLayers.Request) {\n /**\n- * APIProperty: events\n- * {}\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * map.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to map.events.object.\n- * element - {DOMElement} A reference to map.events.element.\n- *\n- * Browser events have the following additional properties:\n- * xy - {} The pixel location of the event (relative\n- * to the the map viewport).\n- *\n- * Supported map event types:\n- * preaddlayer - triggered before a layer has been added. The event\n- * object will include a *layer* property that references the layer \n- * to be added. When a listener returns \"false\" the adding will be \n- * aborted.\n- * addlayer - triggered after a layer has been added. The event object\n- * will include a *layer* property that references the added layer.\n- * preremovelayer - triggered before a layer has been removed. The event\n- * object will include a *layer* property that references the layer \n- * to be removed. When a listener returns \"false\" the removal will be \n- * aborted.\n- * removelayer - triggered after a layer has been removed. The event\n- * object will include a *layer* property that references the removed\n- * layer.\n- * changelayer - triggered after a layer name change, order change,\n- * opacity change, params change, visibility change (actual visibility,\n- * not the layer's visibility property) or attribution change (due to\n- * extent change). Listeners will receive an event object with *layer*\n- * and *property* properties. The *layer* property will be a reference\n- * to the changed layer. The *property* property will be a key to the\n- * changed property (name, order, opacity, params, visibility or\n- * attribution).\n- * movestart - triggered after the start of a drag, pan, or zoom. The event\n- * object may include a *zoomChanged* property that tells whether the\n- * zoom has changed.\n- * move - triggered after each drag, pan, or zoom\n- * moveend - triggered after a drag, pan, or zoom completes\n- * zoomend - triggered after a zoom completes\n- * mouseover - triggered after mouseover the map\n- * mouseout - triggered after mouseout the map\n- * mousemove - triggered after mousemove the map\n- * changebaselayer - triggered after the base layer changes\n- * updatesize - triggered after the method was executed\n+ * This allows for OpenLayers/Request/XMLHttpRequest.js to be included\n+ * before or after this script.\n */\n+ OpenLayers.Request = {};\n+}\n+OpenLayers.Util.extend(OpenLayers.Request, {\n \n /**\n- * Property: id\n- * {String} Unique identifier for the map\n+ * Constant: DEFAULT_CONFIG\n+ * {Object} Default configuration for all requests.\n */\n- id: null,\n+ DEFAULT_CONFIG: {\n+ method: \"GET\",\n+ url: window.location.href,\n+ async: true,\n+ user: undefined,\n+ password: undefined,\n+ params: null,\n+ proxy: OpenLayers.ProxyHost,\n+ headers: {},\n+ data: null,\n+ callback: function() {},\n+ success: null,\n+ failure: null,\n+ scope: null\n+ },\n \n /**\n- * Property: fractionalZoom\n- * {Boolean} For a base layer that supports it, allow the map resolution\n- * to be set to a value between one of the values in the resolutions\n- * array. Default is false.\n- *\n- * When fractionalZoom is set to true, it is possible to zoom to\n- * an arbitrary extent. This requires a base layer from a source\n- * that supports requests for arbitrary extents (i.e. not cached\n- * tiles on a regular lattice). This means that fractionalZoom\n- * will not work with commercial layers (Google, Yahoo, VE), layers\n- * using TileCache, or any other pre-cached data sources.\n- *\n- * If you are using fractionalZoom, then you should also use\n- * instead of layer.resolutions[zoom] as the\n- * former works for non-integer zoom levels.\n+ * Constant: URL_SPLIT_REGEX\n */\n- fractionalZoom: false,\n+ URL_SPLIT_REGEX: /([^:]*:)\\/\\/([^:]*:?[^@]*@)?([^:\\/\\?]*):?([^\\/\\?]*)/,\n \n /**\n * APIProperty: events\n * {} An events object that handles all \n- * events on the map\n+ * events on the {} object.\n+ *\n+ * All event listeners will receive an event object with three properties:\n+ * request - {} The request object.\n+ * config - {Object} The config object sent to the specific request method.\n+ * requestUrl - {String} The request url.\n+ * \n+ * Supported event types:\n+ * complete - Triggered when we have a response from the request, if a\n+ * listener returns false, no further response processing will take\n+ * place.\n+ * success - Triggered when the HTTP response has a success code (200-299).\n+ * failure - Triggered when the HTTP response does not have a success code.\n */\n- events: null,\n+ events: new OpenLayers.Events(this),\n \n /**\n- * APIProperty: allOverlays\n- * {Boolean} Allow the map to function with \"overlays\" only. Defaults to\n- * false. If true, the lowest layer in the draw order will act as\n- * the base layer. In addition, if set to true, all layers will\n- * have isBaseLayer set to false when they are added to the map.\n+ * Method: makeSameOrigin\n+ * Using the specified proxy, returns a same origin url of the provided url.\n *\n- * Note:\n- * If you set map.allOverlays to true, then you *cannot* use\n- * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,\n- * the lowest layer in the draw layer is the base layer. So, to change\n- * the base layer, use or to set the layer\n- * index to 0.\n+ * Parameters:\n+ * url - {String} An arbitrary url\n+ * proxy {String|Function} The proxy to use to make the provided url a\n+ * same origin url.\n+ *\n+ * Returns\n+ * {String} the same origin url. If no proxy is provided, the returned url\n+ * will be the same as the provided url.\n */\n- allOverlays: false,\n+ makeSameOrigin: function(url, proxy) {\n+ var sameOrigin = url.indexOf(\"http\") !== 0;\n+ var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);\n+ if (urlParts) {\n+ var location = window.location;\n+ sameOrigin =\n+ urlParts[1] == location.protocol &&\n+ urlParts[3] == location.hostname;\n+ var uPort = urlParts[4],\n+ lPort = location.port;\n+ if (uPort != 80 && uPort != \"\" || lPort != \"80\" && lPort != \"\") {\n+ sameOrigin = sameOrigin && uPort == lPort;\n+ }\n+ }\n+ if (!sameOrigin) {\n+ if (proxy) {\n+ if (typeof proxy == \"function\") {\n+ url = proxy(url);\n+ } else {\n+ url = proxy + encodeURIComponent(url);\n+ }\n+ }\n+ }\n+ return url;\n+ },\n \n /**\n- * APIProperty: div\n- * {DOMElement|String} The element that contains the map (or an id for\n- * that element). If the constructor is called\n- * with two arguments, this should be provided as the first argument.\n- * Alternatively, the map constructor can be called with the options\n- * object as the only argument. In this case (one argument), a\n- * div property may or may not be provided. If the div property\n- * is not provided, the map can be rendered to a container later\n- * using the method.\n- * \n- * Note:\n- * If you are calling after map construction, do not use\n- * auto. Instead, divide your by your\n- * maximum expected dimension.\n+ * APIMethod: issue\n+ * Create a new XMLHttpRequest object, open it, set any headers, bind\n+ * a callback to done state, and send any data. It is recommended that\n+ * you use one , , , , , or .\n+ * This method is only documented to provide detail on the configuration\n+ * options available to all request methods.\n+ *\n+ * Parameters:\n+ * config - {Object} Object containing properties for configuring the\n+ * request. Allowed configuration properties are described below.\n+ * This object is modified and should not be reused.\n+ *\n+ * Allowed config properties:\n+ * method - {String} One of GET, POST, PUT, DELETE, HEAD, or\n+ * OPTIONS. Default is GET.\n+ * url - {String} URL for the request.\n+ * async - {Boolean} Open an asynchronous request. Default is true.\n+ * user - {String} User for relevant authentication scheme. Set\n+ * to null to clear current user.\n+ * password - {String} Password for relevant authentication scheme.\n+ * Set to null to clear current password.\n+ * proxy - {String} Optional proxy. Defaults to\n+ * .\n+ * params - {Object} Any key:value pairs to be appended to the\n+ * url as a query string. Assumes url doesn't already include a query\n+ * string or hash. Typically, this is only appropriate for \n+ * requests where the query string will be appended to the url.\n+ * Parameter values that are arrays will be\n+ * concatenated with a comma (note that this goes against form-encoding)\n+ * as is done with .\n+ * headers - {Object} Object with header:value pairs to be set on\n+ * the request.\n+ * data - {String | Document} Optional data to send with the request.\n+ * Typically, this is only used with and requests.\n+ * Make sure to provide the appropriate \"Content-Type\" header for your\n+ * data. For and requests, the content type defaults to\n+ * \"application-xml\". If your data is a different content type, or\n+ * if you are using a different HTTP method, set the \"Content-Type\"\n+ * header to match your data type.\n+ * callback - {Function} Function to call when request is done.\n+ * To determine if the request failed, check request.status (200\n+ * indicates success).\n+ * success - {Function} Optional function to call if request status is in\n+ * the 200s. This will be called in addition to callback above and\n+ * would typically only be used as an alternative.\n+ * failure - {Function} Optional function to call if request status is not\n+ * in the 200s. This will be called in addition to callback above and\n+ * would typically only be used as an alternative.\n+ * scope - {Object} If callback is a public method on some object,\n+ * set the scope to that object.\n+ *\n+ * Returns:\n+ * {XMLHttpRequest} Request object. To abort the request before a response\n+ * is received, call abort() on the request object.\n */\n- div: null,\n+ issue: function(config) {\n+ // apply default config - proxy host may have changed\n+ var defaultConfig = OpenLayers.Util.extend(\n+ this.DEFAULT_CONFIG, {\n+ proxy: OpenLayers.ProxyHost\n+ }\n+ );\n+ config = config || {};\n+ config.headers = config.headers || {};\n+ config = OpenLayers.Util.applyDefaults(config, defaultConfig);\n+ config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);\n+ // Always set the \"X-Requested-With\" header to signal that this request\n+ // was issued through the XHR-object. Since header keys are case \n+ // insensitive and we want to allow overriding of the \"X-Requested-With\"\n+ // header through the user we cannot use applyDefaults, but have to \n+ // check manually whether we were called with a \"X-Requested-With\"\n+ // header.\n+ var customRequestedWithHeader = false,\n+ headerKey;\n+ for (headerKey in config.headers) {\n+ if (config.headers.hasOwnProperty(headerKey)) {\n+ if (headerKey.toLowerCase() === 'x-requested-with') {\n+ customRequestedWithHeader = true;\n+ }\n+ }\n+ }\n+ if (customRequestedWithHeader === false) {\n+ // we did not have a custom \"X-Requested-With\" header\n+ config.headers['X-Requested-With'] = 'XMLHttpRequest';\n+ }\n \n- /**\n- * Property: dragging\n- * {Boolean} The map is currently being dragged.\n- */\n- dragging: false,\n+ // create request, open, and set headers\n+ var request = new OpenLayers.Request.XMLHttpRequest();\n+ var url = OpenLayers.Util.urlAppend(config.url,\n+ OpenLayers.Util.getParameterString(config.params || {}));\n+ url = OpenLayers.Request.makeSameOrigin(url, config.proxy);\n+ request.open(\n+ config.method, url, config.async, config.user, config.password\n+ );\n+ for (var header in config.headers) {\n+ request.setRequestHeader(header, config.headers[header]);\n+ }\n \n- /**\n- * Property: size\n- * {} Size of the main div (this.div)\n- */\n- size: null,\n+ var events = this.events;\n \n- /**\n- * Property: viewPortDiv\n- * {HTMLDivElement} The element that represents the map viewport\n- */\n- viewPortDiv: null,\n+ // we want to execute runCallbacks with \"this\" as the\n+ // execution scope\n+ var self = this;\n \n- /**\n- * Property: layerContainerOrigin\n- * {} The lonlat at which the later container was\n- * re-initialized (on-zoom)\n- */\n- layerContainerOrigin: null,\n+ request.onreadystatechange = function() {\n+ if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {\n+ var proceed = events.triggerEvent(\n+ \"complete\", {\n+ request: request,\n+ config: config,\n+ requestUrl: url\n+ }\n+ );\n+ if (proceed !== false) {\n+ self.runCallbacks({\n+ request: request,\n+ config: config,\n+ requestUrl: url\n+ });\n+ }\n+ }\n+ };\n \n- /**\n- * Property: layerContainerDiv\n- * {HTMLDivElement} The element that contains the layers.\n- */\n- layerContainerDiv: null,\n+ // send request (optionally with data) and return\n+ // call in a timeout for asynchronous requests so the return is\n+ // available before readyState == 4 for cached docs\n+ if (config.async === false) {\n+ request.send(config.data);\n+ } else {\n+ window.setTimeout(function() {\n+ if (request.readyState !== 0) { // W3C: 0-UNSENT\n+ request.send(config.data);\n+ }\n+ }, 0);\n+ }\n+ return request;\n+ },\n \n /**\n- * APIProperty: layers\n- * {Array()} Ordered list of layers in the map\n+ * Method: runCallbacks\n+ * Calls the complete, success and failure callbacks. Application\n+ * can listen to the \"complete\" event, have the listener \n+ * display a confirm window and always return false, and\n+ * execute OpenLayers.Request.runCallbacks if the user\n+ * hits \"yes\" in the confirm window.\n+ *\n+ * Parameters:\n+ * options - {Object} Hash containing request, config and requestUrl keys\n */\n- layers: null,\n+ runCallbacks: function(options) {\n+ var request = options.request;\n+ var config = options.config;\n+\n+ // bind callbacks to readyState 4 (done)\n+ var complete = (config.scope) ?\n+ OpenLayers.Function.bind(config.callback, config.scope) :\n+ config.callback;\n+\n+ // optional success callback\n+ var success;\n+ if (config.success) {\n+ success = (config.scope) ?\n+ OpenLayers.Function.bind(config.success, config.scope) :\n+ config.success;\n+ }\n+\n+ // optional failure callback\n+ var failure;\n+ if (config.failure) {\n+ failure = (config.scope) ?\n+ OpenLayers.Function.bind(config.failure, config.scope) :\n+ config.failure;\n+ }\n+\n+ if (OpenLayers.Util.createUrlObject(config.url).protocol == \"file:\" &&\n+ request.responseText) {\n+ request.status = 200;\n+ }\n+ complete(request);\n+\n+ if (!request.status || (request.status >= 200 && request.status < 300)) {\n+ this.events.triggerEvent(\"success\", options);\n+ if (success) {\n+ success(request);\n+ }\n+ }\n+ if (request.status && (request.status < 200 || request.status >= 300)) {\n+ this.events.triggerEvent(\"failure\", options);\n+ if (failure) {\n+ failure(request);\n+ }\n+ }\n+ },\n \n /**\n- * APIProperty: controls\n- * {Array()} List of controls associated with the map.\n+ * APIMethod: GET\n+ * Send an HTTP GET request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to GET.\n *\n- * If not provided in the map options at construction, the map will\n- * by default be given the following controls if present in the build:\n- * - or \n- * - or \n- * - \n- * - \n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- controls: null,\n+ GET: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"GET\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n \n /**\n- * Property: popups\n- * {Array()} List of popups associated with the map\n+ * APIMethod: POST\n+ * Send a POST request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to POST and \"Content-Type\" header set to \"application/xml\".\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties. The\n+ * default \"Content-Type\" header will be set to \"application-xml\" if\n+ * none is provided. This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- popups: null,\n+ POST: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"POST\"\n+ });\n+ // set content type to application/xml if it isn't already set\n+ config.headers = config.headers ? config.headers : {};\n+ if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n+ config.headers[\"Content-Type\"] = \"application/xml\";\n+ }\n+ return OpenLayers.Request.issue(config);\n+ },\n \n /**\n- * APIProperty: baseLayer\n- * {} The currently selected base layer. This determines\n- * min/max zoom level, projection, etc.\n+ * APIMethod: PUT\n+ * Send an HTTP PUT request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to PUT and \"Content-Type\" header set to \"application/xml\".\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties. The\n+ * default \"Content-Type\" header will be set to \"application-xml\" if\n+ * none is provided. This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- baseLayer: null,\n+ PUT: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"PUT\"\n+ });\n+ // set content type to application/xml if it isn't already set\n+ config.headers = config.headers ? config.headers : {};\n+ if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n+ config.headers[\"Content-Type\"] = \"application/xml\";\n+ }\n+ return OpenLayers.Request.issue(config);\n+ },\n \n /**\n- * Property: center\n- * {} The current center of the map\n+ * APIMethod: DELETE\n+ * Send an HTTP DELETE request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to DELETE.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- center: null,\n+ DELETE: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"DELETE\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n \n /**\n- * Property: resolution\n- * {Float} The resolution of the map.\n+ * APIMethod: HEAD\n+ * Send an HTTP HEAD request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to HEAD.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- resolution: null,\n+ HEAD: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"HEAD\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n \n /**\n- * Property: zoom\n- * {Integer} The current zoom level of the map\n+ * APIMethod: OPTIONS\n+ * Send an HTTP OPTIONS request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to OPTIONS.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n */\n- zoom: 0,\n+ OPTIONS: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"OPTIONS\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ }\n \n- /**\n- * Property: panRatio\n- * {Float} The ratio of the current extent within\n- * which panning will tween.\n- */\n- panRatio: 1.5,\n+});\n+/* ======================================================================\n+ OpenLayers/Feature.js\n+ ====================================================================== */\n \n- /**\n- * APIProperty: options\n- * {Object} The options object passed to the class constructor. Read-only.\n- */\n- options: null,\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- // Options\n \n- /**\n- * APIProperty: tileSize\n- * {} Set in the map options to override the default tile\n- * size for this map.\n- */\n- tileSize: null,\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ */\n \n- /**\n- * APIProperty: projection\n- * {String} Set in the map options to specify the default projection \n- * for layers added to this map. When using a projection other than EPSG:4326\n- * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),\n- * also set maxExtent, maxResolution or resolutions. Default is \"EPSG:4326\".\n- * Note that the projection of the map is usually determined\n- * by that of the current baseLayer (see and ).\n- */\n- projection: \"EPSG:4326\",\n+/**\n+ * Class: OpenLayers.Feature\n+ * Features are combinations of geography and attributes. The OpenLayers.Feature\n+ * class specifically combines a marker and a lonlat.\n+ */\n+OpenLayers.Feature = OpenLayers.Class({\n \n- /**\n- * APIProperty: units\n- * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', \n- * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.\n- * Only required if both map and layers do not define a projection,\n- * or if they define a projection which does not define units\n+ /** \n+ * Property: layer \n+ * {} \n */\n- units: null,\n+ layer: null,\n \n- /**\n- * APIProperty: resolutions\n- * {Array(Float)} A list of map resolutions (map units per pixel) in \n- * descending order. If this is not set in the layer constructor, it \n- * will be set based on other resolution related properties \n- * (maxExtent, maxResolution, maxScale, etc.).\n+ /** \n+ * Property: id \n+ * {String} \n */\n- resolutions: null,\n+ id: null,\n \n- /**\n- * APIProperty: maxResolution\n- * {Float} Required if you are not displaying the whole world on a tile\n- * with the size specified in .\n+ /** \n+ * Property: lonlat \n+ * {} \n */\n- maxResolution: null,\n+ lonlat: null,\n \n- /**\n- * APIProperty: minResolution\n- * {Float}\n+ /** \n+ * Property: data \n+ * {Object} \n */\n- minResolution: null,\n+ data: null,\n \n- /**\n- * APIProperty: maxScale\n- * {Float}\n+ /** \n+ * Property: marker \n+ * {} \n */\n- maxScale: null,\n+ marker: null,\n \n /**\n- * APIProperty: minScale\n- * {Float}\n+ * APIProperty: popupClass\n+ * {} The class which will be used to instantiate\n+ * a new Popup. Default is .\n */\n- minScale: null,\n+ popupClass: null,\n \n- /**\n- * APIProperty: maxExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The maximum extent for the map.\n- * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults\n- * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there;\n- * else, defaults to null.\n- * To restrict user panning and zooming of the map, use instead.\n- * The value for will change calculations for tile URLs.\n+ /** \n+ * Property: popup \n+ * {} \n */\n- maxExtent: null,\n+ popup: null,\n \n- /**\n- * APIProperty: minExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The minimum extent for the map. Defaults to null.\n+ /** \n+ * Constructor: OpenLayers.Feature\n+ * Constructor for features.\n+ *\n+ * Parameters:\n+ * layer - {} \n+ * lonlat - {} \n+ * data - {Object} \n+ * \n+ * Returns:\n+ * {}\n */\n- minExtent: null,\n+ initialize: function(layer, lonlat, data) {\n+ this.layer = layer;\n+ this.lonlat = lonlat;\n+ this.data = (data != null) ? data : {};\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n \n- /**\n- * APIProperty: restrictedExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * Limit map navigation to this extent where possible.\n- * If a non-null restrictedExtent is set, panning will be restricted\n- * to the given bounds. In addition, zooming to a resolution that\n- * displays more than the restricted extent will center the map\n- * on the restricted extent. If you wish to limit the zoom level\n- * or resolution, use maxResolution.\n+ /** \n+ * Method: destroy\n+ * nullify references to prevent circular references and memory leaks\n */\n- restrictedExtent: null,\n+ destroy: function() {\n \n- /**\n- * APIProperty: numZoomLevels\n- * {Integer} Number of zoom levels for the map. Defaults to 16. Set a\n- * different value in the map options if needed.\n- */\n- numZoomLevels: 16,\n+ //remove the popup from the map\n+ if ((this.layer != null) && (this.layer.map != null)) {\n+ if (this.popup != null) {\n+ this.layer.map.removePopup(this.popup);\n+ }\n+ }\n+ // remove the marker from the layer\n+ if (this.layer != null && this.marker != null) {\n+ this.layer.removeMarker(this.marker);\n+ }\n+\n+ this.layer = null;\n+ this.id = null;\n+ this.lonlat = null;\n+ this.data = null;\n+ if (this.marker != null) {\n+ this.destroyMarker(this.marker);\n+ this.marker = null;\n+ }\n+ if (this.popup != null) {\n+ this.destroyPopup(this.popup);\n+ this.popup = null;\n+ }\n+ },\n \n /**\n- * APIProperty: theme\n- * {String} Relative path to a CSS file from which to load theme styles.\n- * Specify null in the map options (e.g. {theme: null}) if you \n- * want to get cascading style declarations - by putting links to \n- * stylesheets or style declarations directly in your page.\n+ * Method: onScreen\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the feature is currently visible on screen\n+ * (based on its 'lonlat' property)\n */\n- theme: null,\n+ onScreen: function() {\n \n- /** \n- * APIProperty: displayProjection\n- * {} Requires proj4js support for projections other\n- * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by\n- * several controls to display data to user. If this property is set,\n- * it will be set on any control which has a null displayProjection\n- * property at the time the control is added to the map. \n- */\n- displayProjection: null,\n+ var onScreen = false;\n+ if ((this.layer != null) && (this.layer.map != null)) {\n+ var screenBounds = this.layer.map.getExtent();\n+ onScreen = screenBounds.containsLonLat(this.lonlat);\n+ }\n+ return onScreen;\n+ },\n \n- /**\n- * APIProperty: tileManager\n- * {|Object} By default, and if the build contains\n- * TileManager.js, the map will use the TileManager to queue image requests\n- * and to cache tile image elements. To create a map without a TileManager\n- * configure the map with tileManager: null. To create a TileManager with\n- * non-default options, supply the options instead or alternatively supply\n- * an instance of {}.\n- */\n \n /**\n- * APIProperty: fallThrough\n- * {Boolean} Should OpenLayers allow events on the map to fall through to\n- * other elements on the page, or should it swallow them? (#457)\n- * Default is to swallow.\n+ * Method: createMarker\n+ * Based on the data associated with the Feature, create and return a marker object.\n+ *\n+ * Returns: \n+ * {} A Marker Object created from the 'lonlat' and 'icon' properties\n+ * set in this.data. If no 'lonlat' is set, returns null. If no\n+ * 'icon' is set, OpenLayers.Marker() will load the default image.\n+ * \n+ * Note - this.marker is set to return value\n+ * \n */\n- fallThrough: false,\n+ createMarker: function() {\n \n- /**\n- * APIProperty: autoUpdateSize\n- * {Boolean} Should OpenLayers automatically update the size of the map\n- * when the resize event is fired. Default is true.\n- */\n- autoUpdateSize: true,\n+ if (this.lonlat != null) {\n+ this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);\n+ }\n+ return this.marker;\n+ },\n \n /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n+ * Method: destroyMarker\n+ * Destroys marker.\n+ * If user overrides the createMarker() function, s/he should be able\n+ * to also specify an alternative function for destroying it\n */\n- eventListeners: null,\n+ destroyMarker: function() {\n+ this.marker.destroy();\n+ },\n \n /**\n- * Property: panTween\n- * {} Animated panning tween object, see panTo()\n+ * Method: createPopup\n+ * Creates a popup object created from the 'lonlat', 'popupSize',\n+ * and 'popupContentHTML' properties set in this.data. It uses\n+ * this.marker.icon as default anchor. \n+ * \n+ * If no 'lonlat' is set, returns null. \n+ * If no this.marker has been created, no anchor is sent.\n+ *\n+ * Note - the returned popup object is 'owned' by the feature, so you\n+ * cannot use the popup's destroy method to discard the popup.\n+ * Instead, you must use the feature's destroyPopup\n+ * \n+ * Note - this.popup is set to return value\n+ * \n+ * Parameters: \n+ * closeBox - {Boolean} create popup with closebox or not\n+ * \n+ * Returns:\n+ * {} Returns the created popup, which is also set\n+ * as 'popup' property of this feature. Will be of whatever type\n+ * specified by this feature's 'popupClass' property, but must be\n+ * of type .\n+ * \n */\n- panTween: null,\n+ createPopup: function(closeBox) {\n+\n+ if (this.lonlat != null) {\n+ if (!this.popup) {\n+ var anchor = (this.marker) ? this.marker.icon : null;\n+ var popupClass = this.popupClass ?\n+ this.popupClass : OpenLayers.Popup.Anchored;\n+ this.popup = new popupClass(this.id + \"_popup\",\n+ this.lonlat,\n+ this.data.popupSize,\n+ this.data.popupContentHTML,\n+ anchor,\n+ closeBox);\n+ }\n+ if (this.data.overflow != null) {\n+ this.popup.contentDiv.style.overflow = this.data.overflow;\n+ }\n+\n+ this.popup.feature = this;\n+ }\n+ return this.popup;\n+ },\n+\n \n /**\n- * APIProperty: panMethod\n- * {Function} The Easing function to be used for tweening. Default is\n- * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off\n- * animated panning.\n+ * Method: destroyPopup\n+ * Destroys the popup created via createPopup.\n+ *\n+ * As with the marker, if user overrides the createPopup() function, s/he \n+ * should also be able to override the destruction\n */\n- panMethod: OpenLayers.Easing.Expo.easeOut,\n+ destroyPopup: function() {\n+ if (this.popup) {\n+ this.popup.feature = null;\n+ this.popup.destroy();\n+ this.popup = null;\n+ }\n+ },\n \n- /**\n- * Property: panDuration\n- * {Integer} The number of steps to be passed to the\n- * OpenLayers.Tween.start() method when the map is\n- * panned.\n- * Default is 50.\n+ CLASS_NAME: \"OpenLayers.Feature\"\n+});\n+/* ======================================================================\n+ OpenLayers/Feature/Vector.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+// TRASH THIS\n+OpenLayers.State = {\n+ /** states */\n+ UNKNOWN: 'Unknown',\n+ INSERT: 'Insert',\n+ UPDATE: 'Update',\n+ DELETE: 'Delete'\n+};\n+\n+/**\n+ * @requires OpenLayers/Feature.js\n+ * @requires OpenLayers/Util.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Feature.Vector\n+ * Vector features use the OpenLayers.Geometry classes as geometry description.\n+ * They have an 'attributes' property, which is the data object, and a 'style'\n+ * property, the default values of which are defined in the \n+ * objects.\n+ * \n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {\n+\n+ /** \n+ * Property: fid \n+ * {String} \n */\n- panDuration: 50,\n+ fid: null,\n \n- /**\n- * Property: zoomTween\n- * {} Animated zooming tween object, see zoomTo()\n+ /** \n+ * APIProperty: geometry \n+ * {} \n */\n- zoomTween: null,\n+ geometry: null,\n \n- /**\n- * APIProperty: zoomMethod\n- * {Function} The Easing function to be used for tweening. Default is\n- * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off\n- * animated zooming.\n+ /** \n+ * APIProperty: attributes \n+ * {Object} This object holds arbitrary, serializable properties that\n+ * describe the feature.\n */\n- zoomMethod: OpenLayers.Easing.Quad.easeOut,\n+ attributes: null,\n \n /**\n- * Property: zoomDuration\n- * {Integer} The number of steps to be passed to the\n- * OpenLayers.Tween.start() method when the map is zoomed.\n- * Default is 20.\n+ * Property: bounds\n+ * {} The box bounding that feature's geometry, that\n+ * property can be set by an object when\n+ * deserializing the feature, so in most cases it represents an\n+ * information set by the server. \n */\n- zoomDuration: 20,\n+ bounds: null,\n \n- /**\n- * Property: paddingForPopups\n- * {} Outside margin of the popup. Used to prevent \n- * the popup from getting too close to the map border.\n+ /** \n+ * Property: state \n+ * {String} \n */\n- paddingForPopups: null,\n+ state: null,\n \n- /**\n- * Property: layerContainerOriginPx\n- * {Object} Cached object representing the layer container origin (in pixels).\n+ /** \n+ * APIProperty: style \n+ * {Object} \n */\n- layerContainerOriginPx: null,\n+ style: null,\n \n /**\n- * Property: minPx\n- * {Object} An object with a 'x' and 'y' values that is the lower\n- * left of maxExtent in viewport pixel space.\n- * Used to verify in moveByPx that the new location we're moving to\n- * is valid. It is also used in the getLonLatFromViewPortPx function\n- * of Layer.\n+ * APIProperty: url\n+ * {String} If this property is set it will be taken into account by\n+ * {} when upadting or deleting the feature.\n */\n- minPx: null,\n+ url: null,\n \n /**\n- * Property: maxPx\n- * {Object} An object with a 'x' and 'y' values that is the top\n- * right of maxExtent in viewport pixel space.\n- * Used to verify in moveByPx that the new location we're moving to\n- * is valid.\n+ * Property: renderIntent\n+ * {String} rendering intent currently being used\n */\n- maxPx: null,\n+ renderIntent: \"default\",\n \n /**\n- * Constructor: OpenLayers.Map\n- * Constructor for a new OpenLayers.Map instance. There are two possible\n- * ways to call the map constructor. See the examples below.\n- *\n- * Parameters:\n- * div - {DOMElement|String} The element or id of an element in your page\n- * that will contain the map. May be omitted if the
option is\n- * provided or if you intend to call the method later.\n- * options - {Object} Optional object with properties to tag onto the map.\n+ * APIProperty: modified\n+ * {Object} An object with the originals of the geometry and attributes of\n+ * the feature, if they were changed. Currently this property is only read\n+ * by , and written by\n+ * , which sets the geometry property.\n+ * Applications can set the originals of modified attributes in the\n+ * attributes property. Note that applications have to check if this\n+ * object and the attributes property is already created before using it.\n+ * After a change made with ModifyFeature, this object could look like\n *\n- * Valid options (in addition to the listed API properties):\n- * center - {|Array} The default initial center of the map.\n- * If provided as array, the first value is the x coordinate,\n- * and the 2nd value is the y coordinate.\n- * Only specify if is provided.\n- * Note that if an ArgParser/Permalink control is present,\n- * and the querystring contains coordinates, center will be set\n- * by that, and this option will be ignored.\n- * zoom - {Number} The initial zoom level for the map. Only specify if\n- * is provided.\n- * Note that if an ArgParser/Permalink control is present,\n- * and the querystring contains a zoom level, zoom will be set\n- * by that, and this option will be ignored.\n- * extent - {|Array} The initial extent of the map.\n- * If provided as an array, the array should consist of\n- * four values (left, bottom, right, top).\n- * Only specify if
and are not provided.\n- * \n- * Examples:\n * (code)\n- * // create a map with default options in an element with the id \"map1\"\n- * var map = new OpenLayers.Map(\"map1\");\n+ * {\n+ * geometry: >Object\n+ * }\n+ * (end)\n *\n- * // create a map with non-default options in an element with id \"map2\"\n- * var options = {\n- * projection: \"EPSG:3857\",\n- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),\n- * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)\n- * };\n- * var map = new OpenLayers.Map(\"map2\", options);\n+ * When an application has made changes to feature attributes, it could\n+ * have set the attributes to something like this:\n *\n- * // map with non-default options - same as above but with a single argument,\n- * // a restricted extent, and using arrays for bounds and center\n- * var map = new OpenLayers.Map({\n+ * (code)\n+ * {\n+ * attributes: {\n+ * myAttribute: \"original\"\n+ * }\n+ * }\n+ * (end)\n+ *\n+ * Note that only checks for truthy values in\n+ * *modified.geometry* and the attribute names in *modified.attributes*,\n+ * but it is recommended to set the original values (and not just true) as\n+ * attribute value, so applications could use this information to undo\n+ * changes.\n+ */\n+ modified: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Feature.Vector\n+ * Create a vector feature. \n+ * \n+ * Parameters:\n+ * geometry - {} The geometry that this feature\n+ * represents.\n+ * attributes - {Object} An optional object that will be mapped to the\n+ * property. \n+ * style - {Object} An optional style object.\n+ */\n+ initialize: function(geometry, attributes, style) {\n+ OpenLayers.Feature.prototype.initialize.apply(this,\n+ [null, null, attributes]);\n+ this.lonlat = null;\n+ this.geometry = geometry ? geometry : null;\n+ this.state = null;\n+ this.attributes = {};\n+ if (attributes) {\n+ this.attributes = OpenLayers.Util.extend(this.attributes,\n+ attributes);\n+ }\n+ this.style = style ? style : null;\n+ },\n+\n+ /** \n+ * Method: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ if (this.layer) {\n+ this.layer.removeFeatures(this);\n+ this.layer = null;\n+ }\n+\n+ this.geometry = null;\n+ this.modified = null;\n+ OpenLayers.Feature.prototype.destroy.apply(this, arguments);\n+ },\n+\n+ /**\n+ * Method: clone\n+ * Create a clone of this vector feature. Does not set any non-standard\n+ * properties.\n+ *\n+ * Returns:\n+ * {} An exact clone of this vector feature.\n+ */\n+ clone: function() {\n+ return new OpenLayers.Feature.Vector(\n+ this.geometry ? this.geometry.clone() : null,\n+ this.attributes,\n+ this.style);\n+ },\n+\n+ /**\n+ * Method: onScreen\n+ * Determine whether the feature is within the map viewport. This method\n+ * tests for an intersection between the geometry and the viewport\n+ * bounds. If a more effecient but less precise geometry bounds\n+ * intersection is desired, call the method with the boundsOnly\n+ * parameter true.\n+ *\n+ * Parameters:\n+ * boundsOnly - {Boolean} Only test whether a feature's bounds intersects\n+ * the viewport bounds. Default is false. If false, the feature's\n+ * geometry must intersect the viewport for onScreen to return true.\n+ * \n+ * Returns:\n+ * {Boolean} The feature is currently visible on screen (optionally\n+ * based on its bounds if boundsOnly is true).\n+ */\n+ onScreen: function(boundsOnly) {\n+ var onScreen = false;\n+ if (this.layer && this.layer.map) {\n+ var screenBounds = this.layer.map.getExtent();\n+ if (boundsOnly) {\n+ var featureBounds = this.geometry.getBounds();\n+ onScreen = screenBounds.intersectsBounds(featureBounds);\n+ } else {\n+ var screenPoly = screenBounds.toGeometry();\n+ onScreen = screenPoly.intersects(this.geometry);\n+ }\n+ }\n+ return onScreen;\n+ },\n+\n+ /**\n+ * Method: getVisibility\n+ * Determine whether the feature is displayed or not. It may not displayed\n+ * because:\n+ * - its style display property is set to 'none',\n+ * - it doesn't belong to any layer,\n+ * - the styleMap creates a symbolizer with display property set to 'none'\n+ * for it,\n+ * - the layer which it belongs to is not visible.\n+ * \n+ * Returns:\n+ * {Boolean} The feature is currently displayed.\n+ */\n+ getVisibility: function() {\n+ return !(this.style && this.style.display == 'none' ||\n+ !this.layer ||\n+ this.layer && this.layer.styleMap &&\n+ this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||\n+ this.layer && !this.layer.getVisibility());\n+ },\n+\n+ /**\n+ * Method: createMarker\n+ * HACK - we need to decide if all vector features should be able to\n+ * create markers\n+ * \n+ * Returns:\n+ * {} For now just returns null\n+ */\n+ createMarker: function() {\n+ return null;\n+ },\n+\n+ /**\n+ * Method: destroyMarker\n+ * HACK - we need to decide if all vector features should be able to\n+ * delete markers\n+ * \n+ * If user overrides the createMarker() function, s/he should be able\n+ * to also specify an alternative function for destroying it\n+ */\n+ destroyMarker: function() {\n+ // pass\n+ },\n+\n+ /**\n+ * Method: createPopup\n+ * HACK - we need to decide if all vector features should be able to\n+ * create popups\n+ * \n+ * Returns:\n+ * {} For now just returns null\n+ */\n+ createPopup: function() {\n+ return null;\n+ },\n+\n+ /**\n+ * Method: atPoint\n+ * Determins whether the feature intersects with the specified location.\n+ * \n+ * Parameters: \n+ * lonlat - {|Object} OpenLayers.LonLat or an\n+ * object with a 'lon' and 'lat' properties.\n+ * toleranceLon - {float} Optional tolerance in Geometric Coords\n+ * toleranceLat - {float} Optional tolerance in Geographic Coords\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the feature is at the specified location\n+ */\n+ atPoint: function(lonlat, toleranceLon, toleranceLat) {\n+ var atPoint = false;\n+ if (this.geometry) {\n+ atPoint = this.geometry.atPoint(lonlat, toleranceLon,\n+ toleranceLat);\n+ }\n+ return atPoint;\n+ },\n+\n+ /**\n+ * Method: destroyPopup\n+ * HACK - we need to decide if all vector features should be able to\n+ * delete popups\n+ */\n+ destroyPopup: function() {\n+ // pass\n+ },\n+\n+ /**\n+ * Method: move\n+ * Moves the feature and redraws it at its new location\n+ *\n+ * Parameters:\n+ * location - { or } the\n+ * location to which to move the feature.\n+ */\n+ move: function(location) {\n+\n+ if (!this.layer || !this.geometry.move) {\n+ //do nothing if no layer or immoveable geometry\n+ return undefined;\n+ }\n+\n+ var pixel;\n+ if (location.CLASS_NAME == \"OpenLayers.LonLat\") {\n+ pixel = this.layer.getViewPortPxFromLonLat(location);\n+ } else {\n+ pixel = location;\n+ }\n+\n+ var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());\n+ var res = this.layer.map.getResolution();\n+ this.geometry.move(res * (pixel.x - lastPixel.x),\n+ res * (lastPixel.y - pixel.y));\n+ this.layer.drawFeature(this);\n+ return lastPixel;\n+ },\n+\n+ /**\n+ * Method: toState\n+ * Sets the new state\n+ *\n+ * Parameters:\n+ * state - {String} \n+ */\n+ toState: function(state) {\n+ if (state == OpenLayers.State.UPDATE) {\n+ switch (this.state) {\n+ case OpenLayers.State.UNKNOWN:\n+ case OpenLayers.State.DELETE:\n+ this.state = state;\n+ break;\n+ case OpenLayers.State.UPDATE:\n+ case OpenLayers.State.INSERT:\n+ break;\n+ }\n+ } else if (state == OpenLayers.State.INSERT) {\n+ switch (this.state) {\n+ case OpenLayers.State.UNKNOWN:\n+ break;\n+ default:\n+ this.state = state;\n+ break;\n+ }\n+ } else if (state == OpenLayers.State.DELETE) {\n+ switch (this.state) {\n+ case OpenLayers.State.INSERT:\n+ // the feature should be destroyed\n+ break;\n+ case OpenLayers.State.DELETE:\n+ break;\n+ case OpenLayers.State.UNKNOWN:\n+ case OpenLayers.State.UPDATE:\n+ this.state = state;\n+ break;\n+ }\n+ } else if (state == OpenLayers.State.UNKNOWN) {\n+ this.state = state;\n+ }\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Feature.Vector\"\n+});\n+\n+\n+/**\n+ * Constant: OpenLayers.Feature.Vector.style\n+ * OpenLayers features can have a number of style attributes. The 'default' \n+ * style will typically be used if no other style is specified. These\n+ * styles correspond for the most part, to the styling properties defined\n+ * by the SVG standard. \n+ * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties\n+ * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties\n+ *\n+ * Symbolizer properties:\n+ * fill - {Boolean} Set to false if no fill is desired.\n+ * fillColor - {String} Hex fill color. Default is \"#ee9900\".\n+ * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 \n+ * stroke - {Boolean} Set to false if no stroke is desired.\n+ * strokeColor - {String} Hex stroke color. Default is \"#ee9900\".\n+ * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.\n+ * strokeWidth - {Number} Pixel stroke width. Default is 1.\n+ * strokeLinecap - {String} Stroke cap type. Default is \"round\". [butt | round | square]\n+ * strokeDashstyle - {String} Stroke dash style. Default is \"solid\". [dot | dash | dashdot | longdash | longdashdot | solid]\n+ * graphic - {Boolean} Set to false if no graphic is desired.\n+ * pointRadius - {Number} Pixel point radius. Default is 6.\n+ * pointerEvents - {String} Default is \"visiblePainted\".\n+ * cursor - {String} Default is \"\".\n+ * externalGraphic - {String} Url to an external graphic that will be used for rendering points.\n+ * graphicWidth - {Number} Pixel width for sizing an external graphic.\n+ * graphicHeight - {Number} Pixel height for sizing an external graphic.\n+ * graphicOpacity - {Number} Opacity (0-1) for an external graphic.\n+ * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.\n+ * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.\n+ * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).\n+ * graphicZIndex - {Number} The integer z-index value to use in rendering.\n+ * graphicName - {String} Named graphic to use when rendering points. Supported values include \"circle\" (default),\n+ * \"square\", \"star\", \"x\", \"cross\", \"triangle\".\n+ * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead\n+ * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.\n+ * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.\n+ * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.\n+ * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.\n+ * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.\n+ * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.\n+ * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.\n+ * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either\n+ * fillText or mozDrawText to be available.\n+ * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string\n+ * composed of two characters. The first character is for the horizontal alignment, the second for the vertical\n+ * alignment. Valid values for horizontal alignment: \"l\"=left, \"c\"=center, \"r\"=right. Valid values for vertical\n+ * alignment: \"t\"=top, \"m\"=middle, \"b\"=bottom. Example values: \"lt\", \"cm\", \"rb\". Default is \"cm\".\n+ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.\n+ * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.\n+ * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.\n+ * Default is false.\n+ * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.\n+ * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers.\n+ * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.\n+ * fontColor - {String} The font color for the label, to be provided like CSS.\n+ * fontOpacity - {Number} Opacity (0-1) for the label\n+ * fontFamily - {String} The font family for the label, to be provided like in CSS.\n+ * fontSize - {String} The font size for the label, to be provided like in CSS.\n+ * fontStyle - {String} The font style for the label, to be provided like in CSS.\n+ * fontWeight - {String} The font weight for the label, to be provided like in CSS.\n+ * display - {String} Symbolizers will have no effect if display is set to \"none\". All other values have no effect.\n+ */\n+OpenLayers.Feature.Vector.style = {\n+ 'default': {\n+ fillColor: \"#ee9900\",\n+ fillOpacity: 0.4,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"#ee9900\",\n+ strokeOpacity: 1,\n+ strokeWidth: 1,\n+ strokeLinecap: \"round\",\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"inherit\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n+ },\n+ 'select': {\n+ fillColor: \"blue\",\n+ fillOpacity: 0.4,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"blue\",\n+ strokeOpacity: 1,\n+ strokeWidth: 2,\n+ strokeLinecap: \"round\",\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"pointer\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n+\n+ },\n+ 'temporary': {\n+ fillColor: \"#66cccc\",\n+ fillOpacity: 0.2,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"#66cccc\",\n+ strokeOpacity: 1,\n+ strokeLinecap: \"round\",\n+ strokeWidth: 2,\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"inherit\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n+\n+ },\n+ 'delete': {\n+ display: \"none\"\n+ }\n+};\n+/* ======================================================================\n+ OpenLayers/Style.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Style\n+ * This class represents a UserStyle obtained\n+ * from a SLD, containing styling rules.\n+ */\n+OpenLayers.Style = OpenLayers.Class({\n+\n+ /**\n+ * Property: id\n+ * {String} A unique id for this session.\n+ */\n+ id: null,\n+\n+ /**\n+ * APIProperty: name\n+ * {String}\n+ */\n+ name: null,\n+\n+ /**\n+ * Property: title\n+ * {String} Title of this style (set if included in SLD)\n+ */\n+ title: null,\n+\n+ /**\n+ * Property: description\n+ * {String} Description of this style (set if abstract is included in SLD)\n+ */\n+ description: null,\n+\n+ /**\n+ * APIProperty: layerName\n+ * {} name of the layer that this style belongs to, usually\n+ * according to the NamedLayer attribute of an SLD document.\n+ */\n+ layerName: null,\n+\n+ /**\n+ * APIProperty: isDefault\n+ * {Boolean}\n+ */\n+ isDefault: false,\n+\n+ /** \n+ * Property: rules \n+ * {Array()}\n+ */\n+ rules: null,\n+\n+ /**\n+ * APIProperty: context\n+ * {Object} An optional object with properties that symbolizers' property\n+ * values should be evaluated against. If no context is specified,\n+ * feature.attributes will be used\n+ */\n+ context: null,\n+\n+ /**\n+ * Property: defaultStyle\n+ * {Object} hash of style properties to use as default for merging\n+ * rule-based style symbolizers onto. If no rules are defined,\n+ * createSymbolizer will return this style. If is set to\n+ * true, the defaultStyle will only be taken into account if there are\n+ * rules defined.\n+ */\n+ defaultStyle: null,\n+\n+ /**\n+ * Property: defaultsPerSymbolizer\n+ * {Boolean} If set to true, the will extend the symbolizer\n+ * of every rule. Properties of the will also be used to set\n+ * missing symbolizer properties if the symbolizer has stroke, fill or\n+ * graphic set to true. Default is false.\n+ */\n+ defaultsPerSymbolizer: false,\n+\n+ /**\n+ * Property: propertyStyles\n+ * {Hash of Boolean} cache of style properties that need to be parsed for\n+ * propertyNames. Property names are keys, values won't be used.\n+ */\n+ propertyStyles: null,\n+\n+\n+ /** \n+ * Constructor: OpenLayers.Style\n+ * Creates a UserStyle.\n+ *\n+ * Parameters:\n+ * style - {Object} Optional hash of style properties that will be\n+ * used as default style for this style object. This style\n+ * applies if no rules are specified. Symbolizers defined in\n+ * rules will extend this default style.\n+ * options - {Object} An optional object with properties to set on the\n+ * style.\n+ *\n+ * Valid options:\n+ * rules - {Array()} List of rules to be added to the\n+ * style.\n+ * \n+ * Returns:\n+ * {}\n+ */\n+ initialize: function(style, options) {\n+\n+ OpenLayers.Util.extend(this, options);\n+ this.rules = [];\n+ if (options && options.rules) {\n+ this.addRules(options.rules);\n+ }\n+\n+ // use the default style from OpenLayers.Feature.Vector if no style\n+ // was given in the constructor\n+ this.setDefaultStyle(style ||\n+ OpenLayers.Feature.Vector.style[\"default\"]);\n+\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n+\n+ /** \n+ * APIMethod: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ for (var i = 0, len = this.rules.length; i < len; i++) {\n+ this.rules[i].destroy();\n+ this.rules[i] = null;\n+ }\n+ this.rules = null;\n+ this.defaultStyle = null;\n+ },\n+\n+ /**\n+ * Method: createSymbolizer\n+ * creates a style by applying all feature-dependent rules to the base\n+ * style.\n+ * \n+ * Parameters:\n+ * feature - {} feature to evaluate rules for\n+ * \n+ * Returns:\n+ * {Object} symbolizer hash\n+ */\n+ createSymbolizer: function(feature) {\n+ var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(\n+ OpenLayers.Util.extend({}, this.defaultStyle), feature);\n+\n+ var rules = this.rules;\n+\n+ var rule, context;\n+ var elseRules = [];\n+ var appliedRules = false;\n+ for (var i = 0, len = rules.length; i < len; i++) {\n+ rule = rules[i];\n+ // does the rule apply?\n+ var applies = rule.evaluate(feature);\n+\n+ if (applies) {\n+ if (rule instanceof OpenLayers.Rule && rule.elseFilter) {\n+ elseRules.push(rule);\n+ } else {\n+ appliedRules = true;\n+ this.applySymbolizer(rule, style, feature);\n+ }\n+ }\n+ }\n+\n+ // if no other rules apply, apply the rules with else filters\n+ if (appliedRules == false && elseRules.length > 0) {\n+ appliedRules = true;\n+ for (var i = 0, len = elseRules.length; i < len; i++) {\n+ this.applySymbolizer(elseRules[i], style, feature);\n+ }\n+ }\n+\n+ // don't display if there were rules but none applied\n+ if (rules.length > 0 && appliedRules == false) {\n+ style.display = \"none\";\n+ }\n+\n+ if (style.label != null && typeof style.label !== \"string\") {\n+ style.label = String(style.label);\n+ }\n+\n+ return style;\n+ },\n+\n+ /**\n+ * Method: applySymbolizer\n+ *\n+ * Parameters:\n+ * rule - {}\n+ * style - {Object}\n+ * feature - {}\n+ *\n+ * Returns:\n+ * {Object} A style with new symbolizer applied.\n+ */\n+ applySymbolizer: function(rule, style, feature) {\n+ var symbolizerPrefix = feature.geometry ?\n+ this.getSymbolizerPrefix(feature.geometry) :\n+ OpenLayers.Style.SYMBOLIZER_PREFIXES[0];\n+\n+ var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;\n+\n+ if (this.defaultsPerSymbolizer === true) {\n+ var defaults = this.defaultStyle;\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ pointRadius: defaults.pointRadius\n+ });\n+ if (symbolizer.stroke === true || symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ strokeWidth: defaults.strokeWidth,\n+ strokeColor: defaults.strokeColor,\n+ strokeOpacity: defaults.strokeOpacity,\n+ strokeDashstyle: defaults.strokeDashstyle,\n+ strokeLinecap: defaults.strokeLinecap\n+ });\n+ }\n+ if (symbolizer.fill === true || symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ fillColor: defaults.fillColor,\n+ fillOpacity: defaults.fillOpacity\n+ });\n+ }\n+ if (symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ pointRadius: this.defaultStyle.pointRadius,\n+ externalGraphic: this.defaultStyle.externalGraphic,\n+ graphicName: this.defaultStyle.graphicName,\n+ graphicOpacity: this.defaultStyle.graphicOpacity,\n+ graphicWidth: this.defaultStyle.graphicWidth,\n+ graphicHeight: this.defaultStyle.graphicHeight,\n+ graphicXOffset: this.defaultStyle.graphicXOffset,\n+ graphicYOffset: this.defaultStyle.graphicYOffset\n+ });\n+ }\n+ }\n+\n+ // merge the style with the current style\n+ return this.createLiterals(\n+ OpenLayers.Util.extend(style, symbolizer), feature);\n+ },\n+\n+ /**\n+ * Method: createLiterals\n+ * creates literals for all style properties that have an entry in\n+ * .\n+ * \n+ * Parameters:\n+ * style - {Object} style to create literals for. Will be modified\n+ * inline.\n+ * feature - {Object}\n+ * \n+ * Returns:\n+ * {Object} the modified style\n+ */\n+ createLiterals: function(style, feature) {\n+ var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);\n+ OpenLayers.Util.extend(context, this.context);\n+\n+ for (var i in this.propertyStyles) {\n+ style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);\n+ }\n+ return style;\n+ },\n+\n+ /**\n+ * Method: findPropertyStyles\n+ * Looks into all rules for this style and the defaultStyle to collect\n+ * all the style hash property names containing ${...} strings that have\n+ * to be replaced using the createLiteral method before returning them.\n+ * \n+ * Returns:\n+ * {Object} hash of property names that need createLiteral parsing. The\n+ * name of the property is the key, and the value is true;\n+ */\n+ findPropertyStyles: function() {\n+ var propertyStyles = {};\n+\n+ // check the default style\n+ var style = this.defaultStyle;\n+ this.addPropertyStyles(propertyStyles, style);\n+\n+ // walk through all rules to check for properties in their symbolizer\n+ var rules = this.rules;\n+ var symbolizer, value;\n+ for (var i = 0, len = rules.length; i < len; i++) {\n+ symbolizer = rules[i].symbolizer;\n+ for (var key in symbolizer) {\n+ value = symbolizer[key];\n+ if (typeof value == \"object\") {\n+ // symbolizer key is \"Point\", \"Line\" or \"Polygon\"\n+ this.addPropertyStyles(propertyStyles, value);\n+ } else {\n+ // symbolizer is a hash of style properties\n+ this.addPropertyStyles(propertyStyles, symbolizer);\n+ break;\n+ }\n+ }\n+ }\n+ return propertyStyles;\n+ },\n+\n+ /**\n+ * Method: addPropertyStyles\n+ * \n+ * Parameters:\n+ * propertyStyles - {Object} hash to add new property styles to. Will be\n+ * modified inline\n+ * symbolizer - {Object} search this symbolizer for property styles\n+ * \n+ * Returns:\n+ * {Object} propertyStyles hash\n+ */\n+ addPropertyStyles: function(propertyStyles, symbolizer) {\n+ var property;\n+ for (var key in symbolizer) {\n+ property = symbolizer[key];\n+ if (typeof property == \"string\" &&\n+ property.match(/\\$\\{\\w+\\}/)) {\n+ propertyStyles[key] = true;\n+ }\n+ }\n+ return propertyStyles;\n+ },\n+\n+ /**\n+ * APIMethod: addRules\n+ * Adds rules to this style.\n+ * \n+ * Parameters:\n+ * rules - {Array()}\n+ */\n+ addRules: function(rules) {\n+ Array.prototype.push.apply(this.rules, rules);\n+ this.propertyStyles = this.findPropertyStyles();\n+ },\n+\n+ /**\n+ * APIMethod: setDefaultStyle\n+ * Sets the default style for this style object.\n+ * \n+ * Parameters:\n+ * style - {Object} Hash of style properties\n+ */\n+ setDefaultStyle: function(style) {\n+ this.defaultStyle = style;\n+ this.propertyStyles = this.findPropertyStyles();\n+ },\n+\n+ /**\n+ * Method: getSymbolizerPrefix\n+ * Returns the correct symbolizer prefix according to the\n+ * geometry type of the passed geometry\n+ * \n+ * Parameters:\n+ * geometry - {}\n+ * \n+ * Returns:\n+ * {String} key of the according symbolizer\n+ */\n+ getSymbolizerPrefix: function(geometry) {\n+ var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;\n+ for (var i = 0, len = prefixes.length; i < len; i++) {\n+ if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {\n+ return prefixes[i];\n+ }\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: clone\n+ * Clones this style.\n+ * \n+ * Returns:\n+ * {} Clone of this style.\n+ */\n+ clone: function() {\n+ var options = OpenLayers.Util.extend({}, this);\n+ // clone rules\n+ if (this.rules) {\n+ options.rules = [];\n+ for (var i = 0, len = this.rules.length; i < len; ++i) {\n+ options.rules.push(this.rules[i].clone());\n+ }\n+ }\n+ // clone context\n+ options.context = this.context && OpenLayers.Util.extend({}, this.context);\n+ //clone default style\n+ var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);\n+ return new OpenLayers.Style(defaultStyle, options);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Style\"\n+});\n+\n+\n+/**\n+ * Function: createLiteral\n+ * converts a style value holding a combination of PropertyName and Literal\n+ * into a Literal, taking the property values from the passed features.\n+ * \n+ * Parameters:\n+ * value - {String} value to parse. If this string contains a construct like\n+ * \"foo ${bar}\", then \"foo \" will be taken as literal, and \"${bar}\"\n+ * will be replaced by the value of the \"bar\" attribute of the passed\n+ * feature.\n+ * context - {Object} context to take attribute values from\n+ * feature - {} optional feature to pass to\n+ * for evaluating functions in the\n+ * context.\n+ * property - {String} optional, name of the property for which the literal is\n+ * being created for evaluating functions in the context.\n+ * \n+ * Returns:\n+ * {String} the parsed value. In the example of the value parameter above, the\n+ * result would be \"foo valueOfBar\", assuming that the passed feature has an\n+ * attribute named \"bar\" with the value \"valueOfBar\".\n+ */\n+OpenLayers.Style.createLiteral = function(value, context, feature, property) {\n+ if (typeof value == \"string\" && value.indexOf(\"${\") != -1) {\n+ value = OpenLayers.String.format(value, context, [feature, property]);\n+ value = (isNaN(value) || !value) ? value : parseFloat(value);\n+ }\n+ return value;\n+};\n+\n+/**\n+ * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES\n+ * {Array} prefixes of the sld symbolizers. These are the\n+ * same as the main geometry types\n+ */\n+OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',\n+ 'Raster'\n+];\n+/* ======================================================================\n+ OpenLayers/Tile.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Tile \n+ * This is a class designed to designate a single tile, however\n+ * it is explicitly designed to do relatively little. Tiles store \n+ * information about themselves -- such as the URL that they are related\n+ * to, and their size - but do not add themselves to the layer div \n+ * automatically, for example. Create a new tile with the \n+ * constructor, or a subclass. \n+ * \n+ * TBD 3.0 - remove reference to url in above paragraph\n+ * \n+ */\n+OpenLayers.Tile = OpenLayers.Class({\n+\n+ /**\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the tile.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * tile.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types:\n+ * beforedraw - Triggered before the tile is drawn. Used to defer\n+ * drawing to an animation queue. To defer drawing, listeners need\n+ * to return false, which will abort drawing. The queue handler needs\n+ * to call (true) to actually draw the tile.\n+ * loadstart - Triggered when tile loading starts.\n+ * loadend - Triggered when tile loading ends.\n+ * loaderror - Triggered before the loadend event (i.e. when the tile is\n+ * still hidden) if the tile could not be loaded.\n+ * reload - Triggered when an already loading tile is reloaded.\n+ * unload - Triggered before a tile is unloaded.\n+ */\n+ events: null,\n+\n+ /**\n+ * APIProperty: eventListeners\n+ * {Object} If set as an option at construction, the eventListeners\n+ * object will be registered with . Object\n+ * structure must be a listeners object as shown in the example for\n+ * the events.on method.\n+ *\n+ * This options can be set in the ``tileOptions`` option from\n+ * . For example, to be notified of the\n+ * ``loadend`` event of each tiles:\n+ * (code)\n+ * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', {\n+ * tileOptions: {\n+ * eventListeners: {\n+ * 'loadend': function(evt) {\n+ * // do something on loadend\n+ * }\n+ * }\n+ * }\n+ * });\n+ * (end)\n+ */\n+ eventListeners: null,\n+\n+ /**\n+ * Property: id \n+ * {String} null\n+ */\n+ id: null,\n+\n+ /** \n+ * Property: layer \n+ * {} layer the tile is attached to \n+ */\n+ layer: null,\n+\n+ /**\n+ * Property: url\n+ * {String} url of the request.\n+ *\n+ * TBD 3.0 \n+ * Deprecated. The base tile class does not need an url. This should be \n+ * handled in subclasses. Does not belong here.\n+ */\n+ url: null,\n+\n+ /** \n+ * APIProperty: bounds \n+ * {} null\n+ */\n+ bounds: null,\n+\n+ /** \n+ * Property: size \n+ * {} null\n+ */\n+ size: null,\n+\n+ /** \n+ * Property: position \n+ * {} Top Left pixel of the tile\n+ */\n+ position: null,\n+\n+ /**\n+ * Property: isLoading\n+ * {Boolean} Is the tile loading?\n+ */\n+ isLoading: false,\n+\n+ /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.\n+ * there is no need for the base tile class to have a url.\n+ */\n+\n+ /** \n+ * Constructor: OpenLayers.Tile\n+ * Constructor for a new instance.\n+ * \n+ * Parameters:\n+ * layer - {} layer that the tile will go in.\n+ * position - {}\n+ * bounds - {}\n+ * url - {}\n+ * size - {}\n+ * options - {Object}\n+ */\n+ initialize: function(layer, position, bounds, url, size, options) {\n+ this.layer = layer;\n+ this.position = position.clone();\n+ this.setBounds(bounds);\n+ this.url = url;\n+ if (size) {\n+ this.size = size.clone();\n+ }\n+\n+ //give the tile a unique id based on its BBOX.\n+ this.id = OpenLayers.Util.createUniqueID(\"Tile_\");\n+\n+ OpenLayers.Util.extend(this, options);\n+\n+ this.events = new OpenLayers.Events(this);\n+ if (this.eventListeners instanceof Object) {\n+ this.events.on(this.eventListeners);\n+ }\n+ },\n+\n+ /**\n+ * Method: unload\n+ * Call immediately before destroying if you are listening to tile\n+ * events, so that counters are properly handled if tile is still\n+ * loading at destroy-time. Will only fire an event if the tile is\n+ * still loading.\n+ */\n+ unload: function() {\n+ if (this.isLoading) {\n+ this.isLoading = false;\n+ this.events.triggerEvent(\"unload\");\n+ }\n+ },\n+\n+ /** \n+ * APIMethod: destroy\n+ * Nullify references to prevent circular references and memory leaks.\n+ */\n+ destroy: function() {\n+ this.layer = null;\n+ this.bounds = null;\n+ this.size = null;\n+ this.position = null;\n+\n+ if (this.eventListeners) {\n+ this.events.un(this.eventListeners);\n+ }\n+ this.events.destroy();\n+ this.eventListeners = null;\n+ this.events = null;\n+ },\n+\n+ /**\n+ * Method: draw\n+ * Clear whatever is currently in the tile, then return whether or not \n+ * it should actually be re-drawn. This is an example implementation\n+ * that can be overridden by subclasses. The minimum thing to do here\n+ * is to call and return the result from .\n+ *\n+ * Parameters:\n+ * force - {Boolean} If true, the tile will not be cleared and no beforedraw\n+ * event will be fired. This is used for drawing tiles asynchronously\n+ * after drawing has been cancelled by returning false from a beforedraw\n+ * listener.\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the tile should actually be drawn. Returns null\n+ * if a beforedraw listener returned false.\n+ */\n+ draw: function(force) {\n+ if (!force) {\n+ //clear tile's contents and mark as not drawn\n+ this.clear();\n+ }\n+ var draw = this.shouldDraw();\n+ if (draw && !force && this.events.triggerEvent(\"beforedraw\") === false) {\n+ draw = null;\n+ }\n+ return draw;\n+ },\n+\n+ /**\n+ * Method: shouldDraw\n+ * Return whether or not the tile should actually be (re-)drawn. The only\n+ * case where we *wouldn't* want to draw the tile is if the tile is outside\n+ * its layer's maxExtent\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the tile should actually be drawn.\n+ */\n+ shouldDraw: function() {\n+ var withinMaxExtent = false,\n+ maxExtent = this.layer.maxExtent;\n+ if (maxExtent) {\n+ var map = this.layer.map;\n+ var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();\n+ if (this.bounds.intersectsBounds(maxExtent, {\n+ inclusive: false,\n+ worldBounds: worldBounds\n+ })) {\n+ withinMaxExtent = true;\n+ }\n+ }\n+\n+ return withinMaxExtent || this.layer.displayOutsideMaxExtent;\n+ },\n+\n+ /**\n+ * Method: setBounds\n+ * Sets the bounds on this instance\n+ *\n+ * Parameters:\n+ * bounds {}\n+ */\n+ setBounds: function(bounds) {\n+ bounds = bounds.clone();\n+ if (this.layer.map.baseLayer.wrapDateLine) {\n+ var worldExtent = this.layer.map.getMaxExtent(),\n+ tolerance = this.layer.map.getResolution();\n+ bounds = bounds.wrapDateLine(worldExtent, {\n+ leftTolerance: tolerance,\n+ rightTolerance: tolerance\n+ });\n+ }\n+ this.bounds = bounds;\n+ },\n+\n+ /** \n+ * Method: moveTo\n+ * Reposition the tile.\n+ *\n+ * Parameters:\n+ * bounds - {}\n+ * position - {}\n+ * redraw - {Boolean} Call draw method on tile after moving.\n+ * Default is true\n+ */\n+ moveTo: function(bounds, position, redraw) {\n+ if (redraw == null) {\n+ redraw = true;\n+ }\n+\n+ this.setBounds(bounds);\n+ this.position = position.clone();\n+ if (redraw) {\n+ this.draw();\n+ }\n+ },\n+\n+ /** \n+ * Method: clear\n+ * Clear the tile of any bounds/position-related data so that it can \n+ * be reused in a new location.\n+ */\n+ clear: function(draw) {\n+ // to be extended by subclasses\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Tile\"\n+});\n+/* ======================================================================\n+ OpenLayers/Strategy.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Strategy\n+ * Abstract vector layer strategy class. Not to be instantiated directly. Use\n+ * one of the strategy subclasses instead.\n+ */\n+OpenLayers.Strategy = OpenLayers.Class({\n+\n+ /**\n+ * Property: layer\n+ * {} The layer this strategy belongs to.\n+ */\n+ layer: null,\n+\n+ /**\n+ * Property: options\n+ * {Object} Any options sent to the constructor.\n+ */\n+ options: null,\n+\n+ /** \n+ * Property: active \n+ * {Boolean} The control is active.\n+ */\n+ active: null,\n+\n+ /**\n+ * Property: autoActivate\n+ * {Boolean} The creator of the strategy can set autoActivate to false\n+ * to fully control when the protocol is activated and deactivated.\n+ * Defaults to true.\n+ */\n+ autoActivate: true,\n+\n+ /**\n+ * Property: autoDestroy\n+ * {Boolean} The creator of the strategy can set autoDestroy to false\n+ * to fully control when the strategy is destroyed. Defaults to\n+ * true.\n+ */\n+ autoDestroy: true,\n+\n+ /**\n+ * Constructor: OpenLayers.Strategy\n+ * Abstract class for vector strategies. Create instances of a subclass.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.options = options;\n+ // set the active property here, so that user cannot override it\n+ this.active = false;\n+ },\n+\n+ /**\n+ * APIMethod: destroy\n+ * Clean up the strategy.\n+ */\n+ destroy: function() {\n+ this.deactivate();\n+ this.layer = null;\n+ this.options = null;\n+ },\n+\n+ /**\n+ * Method: setLayer\n+ * Called to set the property.\n+ *\n+ * Parameters:\n+ * layer - {}\n+ */\n+ setLayer: function(layer) {\n+ this.layer = layer;\n+ },\n+\n+ /**\n+ * Method: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully activated or false if\n+ * the strategy was already active.\n+ */\n+ activate: function() {\n+ if (!this.active) {\n+ this.active = true;\n+ return true;\n+ }\n+ return false;\n+ },\n+\n+ /**\n+ * Method: deactivate\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully deactivated or false if\n+ * the strategy was already inactive.\n+ */\n+ deactivate: function() {\n+ if (this.active) {\n+ this.active = false;\n+ return true;\n+ }\n+ return false;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Strategy\"\n+});\n+/* ======================================================================\n+ OpenLayers/Handler.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Events.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Handler\n+ * Base class to construct a higher-level handler for event sequences. All\n+ * handlers have activate and deactivate methods. In addition, they have\n+ * methods named like browser events. When a handler is activated, any\n+ * additional methods named like a browser event is registered as a\n+ * listener for the corresponding event. When a handler is deactivated,\n+ * those same methods are unregistered as event listeners.\n+ *\n+ * Handlers also typically have a callbacks object with keys named like\n+ * the abstracted events or event sequences that they are in charge of\n+ * handling. The controls that wrap handlers define the methods that\n+ * correspond to these abstract events - so instead of listening for\n+ * individual browser events, they only listen for the abstract events\n+ * defined by the handler.\n+ * \n+ * Handlers are created by controls, which ultimately have the responsibility\n+ * of making changes to the the state of the application. Handlers\n+ * themselves may make temporary changes, but in general are expected to\n+ * return the application in the same state that they found it.\n+ */\n+OpenLayers.Handler = OpenLayers.Class({\n+\n+ /**\n+ * Property: id\n+ * {String}\n+ */\n+ id: null,\n+\n+ /**\n+ * APIProperty: control\n+ * {}. The control that initialized this handler. The\n+ * control is assumed to have a valid map property - that map is used\n+ * in the handler's own setMap method.\n+ */\n+ control: null,\n+\n+ /**\n+ * Property: map\n+ * {}\n+ */\n+ map: null,\n+\n+ /**\n+ * APIProperty: keyMask\n+ * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler\n+ * constants to construct a keyMask. The keyMask is used by\n+ * . If the keyMask matches the combination of keys\n+ * down on an event, checkModifiers returns true.\n+ *\n+ * Example:\n+ * (code)\n+ * // handler only responds if the Shift key is down\n+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;\n+ *\n+ * // handler only responds if Ctrl-Shift is down\n+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |\n+ * OpenLayers.Handler.MOD_CTRL;\n+ * (end)\n+ */\n+ keyMask: null,\n+\n+ /**\n+ * Property: active\n+ * {Boolean}\n+ */\n+ active: false,\n+\n+ /**\n+ * Property: evt\n+ * {Event} This property references the last event handled by the handler.\n+ * Note that this property is not part of the stable API. Use of the\n+ * evt property should be restricted to controls in the library\n+ * or other applications that are willing to update with changes to\n+ * the OpenLayers code.\n+ */\n+ evt: null,\n+\n+ /**\n+ * Property: touch\n+ * {Boolean} Indicates the support of touch events. When touch events are \n+ * started touch will be true and all mouse related listeners will do \n+ * nothing.\n+ */\n+ touch: false,\n+\n+ /**\n+ * Constructor: OpenLayers.Handler\n+ * Construct a handler.\n+ *\n+ * Parameters:\n+ * control - {} The control that initialized this\n+ * handler. The control is assumed to have a valid map property; that\n+ * map is used in the handler's own setMap method. If a map property\n+ * is present in the options argument it will be used instead.\n+ * callbacks - {Object} An object whose properties correspond to abstracted\n+ * events or sequences of browser events. The values for these\n+ * properties are functions defined by the control that get called by\n+ * the handler.\n+ * options - {Object} An optional object whose properties will be set on\n+ * the handler.\n+ */\n+ initialize: function(control, callbacks, options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.control = control;\n+ this.callbacks = callbacks;\n+\n+ var map = this.map || control.map;\n+ if (map) {\n+ this.setMap(map);\n+ }\n+\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n+\n+ /**\n+ * Method: setMap\n+ */\n+ setMap: function(map) {\n+ this.map = map;\n+ },\n+\n+ /**\n+ * Method: checkModifiers\n+ * Check the keyMask on the handler. If no is set, this always\n+ * returns true. If a is set and it matches the combination\n+ * of keys down on an event, this returns true.\n+ *\n+ * Returns:\n+ * {Boolean} The keyMask matches the keys down on an event.\n+ */\n+ checkModifiers: function(evt) {\n+ if (this.keyMask == null) {\n+ return true;\n+ }\n+ /* calculate the keyboard modifier mask for this event */\n+ var keyModifiers =\n+ (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |\n+ (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |\n+ (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) |\n+ (evt.metaKey ? OpenLayers.Handler.MOD_META : 0);\n+\n+ /* if it differs from the handler object's key mask,\n+ bail out of the event handler */\n+ return (keyModifiers == this.keyMask);\n+ },\n+\n+ /**\n+ * APIMethod: activate\n+ * Turn on the handler. Returns false if the handler was already active.\n+ * \n+ * Returns: \n+ * {Boolean} The handler was activated.\n+ */\n+ activate: function() {\n+ if (this.active) {\n+ return false;\n+ }\n+ // register for event handlers defined on this class.\n+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n+ for (var i = 0, len = events.length; i < len; i++) {\n+ if (this[events[i]]) {\n+ this.register(events[i], this[events[i]]);\n+ }\n+ }\n+ this.active = true;\n+ return true;\n+ },\n+\n+ /**\n+ * APIMethod: deactivate\n+ * Turn off the handler. Returns false if the handler was already inactive.\n+ * \n+ * Returns:\n+ * {Boolean} The handler was deactivated.\n+ */\n+ deactivate: function() {\n+ if (!this.active) {\n+ return false;\n+ }\n+ // unregister event handlers defined on this class.\n+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n+ for (var i = 0, len = events.length; i < len; i++) {\n+ if (this[events[i]]) {\n+ this.unregister(events[i], this[events[i]]);\n+ }\n+ }\n+ this.touch = false;\n+ this.active = false;\n+ return true;\n+ },\n+\n+ /**\n+ * Method: startTouch\n+ * Start touch events, this method must be called by subclasses in \n+ * \"touchstart\" method. When touch events are started will be\n+ * true and all mouse related listeners will do nothing.\n+ */\n+ startTouch: function() {\n+ if (!this.touch) {\n+ this.touch = true;\n+ var events = [\n+ \"mousedown\", \"mouseup\", \"mousemove\", \"click\", \"dblclick\",\n+ \"mouseout\"\n+ ];\n+ for (var i = 0, len = events.length; i < len; i++) {\n+ if (this[events[i]]) {\n+ this.unregister(events[i], this[events[i]]);\n+ }\n+ }\n+ }\n+ },\n+\n+ /**\n+ * Method: callback\n+ * Trigger the control's named callback with the given arguments\n+ *\n+ * Parameters:\n+ * name - {String} The key for the callback that is one of the properties\n+ * of the handler's callbacks object.\n+ * args - {Array(*)} An array of arguments (any type) with which to call \n+ * the callback (defined by the control).\n+ */\n+ callback: function(name, args) {\n+ if (name && this.callbacks[name]) {\n+ this.callbacks[name].apply(this.control, args);\n+ }\n+ },\n+\n+ /**\n+ * Method: register\n+ * register an event on the map\n+ */\n+ register: function(name, method) {\n+ // TODO: deal with registerPriority in 3.0\n+ this.map.events.registerPriority(name, this, method);\n+ this.map.events.registerPriority(name, this, this.setEvent);\n+ },\n+\n+ /**\n+ * Method: unregister\n+ * unregister an event from the map\n+ */\n+ unregister: function(name, method) {\n+ this.map.events.unregister(name, this, method);\n+ this.map.events.unregister(name, this, this.setEvent);\n+ },\n+\n+ /**\n+ * Method: setEvent\n+ * With each registered browser event, the handler sets its own evt\n+ * property. This property can be accessed by controls if needed\n+ * to get more information about the event that the handler is\n+ * processing.\n+ *\n+ * This allows modifier keys on the event to be checked (alt, shift, ctrl,\n+ * and meta cannot be checked with the keyboard handler). For a\n+ * control to determine which modifier keys are associated with the\n+ * event that a handler is currently processing, it should access\n+ * (code)handler.evt.altKey || handler.evt.shiftKey ||\n+ * handler.evt.ctrlKey || handler.evt.metaKey(end).\n+ *\n+ * Parameters:\n+ * evt - {Event} The browser event.\n+ */\n+ setEvent: function(evt) {\n+ this.evt = evt;\n+ return true;\n+ },\n+\n+ /**\n+ * Method: destroy\n+ * Deconstruct the handler.\n+ */\n+ destroy: function() {\n+ // unregister event listeners\n+ this.deactivate();\n+ // eliminate circular references\n+ this.control = this.map = null;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Handler\"\n+});\n+\n+/**\n+ * Constant: OpenLayers.Handler.MOD_NONE\n+ * If set as the , returns false if any key is down.\n+ */\n+OpenLayers.Handler.MOD_NONE = 0;\n+\n+/**\n+ * Constant: OpenLayers.Handler.MOD_SHIFT\n+ * If set as the , returns false if Shift is down.\n+ */\n+OpenLayers.Handler.MOD_SHIFT = 1;\n+\n+/**\n+ * Constant: OpenLayers.Handler.MOD_CTRL\n+ * If set as the , returns false if Ctrl is down.\n+ */\n+OpenLayers.Handler.MOD_CTRL = 2;\n+\n+/**\n+ * Constant: OpenLayers.Handler.MOD_ALT\n+ * If set as the , returns false if Alt is down.\n+ */\n+OpenLayers.Handler.MOD_ALT = 4;\n+\n+/**\n+ * Constant: OpenLayers.Handler.MOD_META\n+ * If set as the , returns false if Cmd is down.\n+ */\n+OpenLayers.Handler.MOD_META = 8;\n+\n+\n+/* ======================================================================\n+ OpenLayers/Protocol.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Protocol\n+ * Abstract vector layer protocol class. Not to be instantiated directly. Use\n+ * one of the protocol subclasses instead.\n+ */\n+OpenLayers.Protocol = OpenLayers.Class({\n+\n+ /**\n+ * Property: format\n+ * {} The format used by this protocol.\n+ */\n+ format: null,\n+\n+ /**\n+ * Property: options\n+ * {Object} Any options sent to the constructor.\n+ */\n+ options: null,\n+\n+ /**\n+ * Property: autoDestroy\n+ * {Boolean} The creator of the protocol can set autoDestroy to false\n+ * to fully control when the protocol is destroyed. Defaults to\n+ * true.\n+ */\n+ autoDestroy: true,\n+\n+ /**\n+ * Property: defaultFilter\n+ * {} Optional default filter to read requests\n+ */\n+ defaultFilter: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Protocol\n+ * Abstract class for vector protocols. Create instances of a subclass.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n+ */\n+ initialize: function(options) {\n+ options = options || {};\n+ OpenLayers.Util.extend(this, options);\n+ this.options = options;\n+ },\n+\n+ /**\n+ * Method: mergeWithDefaultFilter\n+ * Merge filter passed to the read method with the default one\n+ *\n+ * Parameters:\n+ * filter - {}\n+ */\n+ mergeWithDefaultFilter: function(filter) {\n+ var merged;\n+ if (filter && this.defaultFilter) {\n+ merged = new OpenLayers.Filter.Logical({\n+ type: OpenLayers.Filter.Logical.AND,\n+ filters: [this.defaultFilter, filter]\n+ });\n+ } else {\n+ merged = filter || this.defaultFilter || undefined;\n+ }\n+ return merged;\n+ },\n+\n+ /**\n+ * APIMethod: destroy\n+ * Clean up the protocol.\n+ */\n+ destroy: function() {\n+ this.options = null;\n+ this.format = null;\n+ },\n+\n+ /**\n+ * APIMethod: read\n+ * Construct a request for reading new features.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object for configuring the request.\n+ *\n+ * Returns:\n+ * {} An \n+ * object, the same object will be passed to the callback function passed\n+ * if one exists in the options object.\n+ */\n+ read: function(options) {\n+ options = options || {};\n+ options.filter = this.mergeWithDefaultFilter(options.filter);\n+ },\n+\n+\n+ /**\n+ * APIMethod: create\n+ * Construct a request for writing newly created features.\n+ *\n+ * Parameters:\n+ * features - {Array({})} or\n+ * {}\n+ * options - {Object} Optional object for configuring the request.\n+ *\n+ * Returns:\n+ * {} An \n+ * object, the same object will be passed to the callback function passed\n+ * if one exists in the options object.\n+ */\n+ create: function() {},\n+\n+ /**\n+ * APIMethod: update\n+ * Construct a request updating modified features.\n+ *\n+ * Parameters:\n+ * features - {Array({})} or\n+ * {}\n+ * options - {Object} Optional object for configuring the request.\n+ *\n+ * Returns:\n+ * {} An \n+ * object, the same object will be passed to the callback function passed\n+ * if one exists in the options object.\n+ */\n+ update: function() {},\n+\n+ /**\n+ * APIMethod: delete\n+ * Construct a request deleting a removed feature.\n+ *\n+ * Parameters:\n+ * feature - {}\n+ * options - {Object} Optional object for configuring the request.\n+ *\n+ * Returns:\n+ * {} An \n+ * object, the same object will be passed to the callback function passed\n+ * if one exists in the options object.\n+ */\n+ \"delete\": function() {},\n+\n+ /**\n+ * APIMethod: commit\n+ * Go over the features and for each take action\n+ * based on the feature state. Possible actions are create,\n+ * update and delete.\n+ *\n+ * Parameters:\n+ * features - {Array({})}\n+ * options - {Object} Object whose possible keys are \"create\", \"update\",\n+ * \"delete\", \"callback\" and \"scope\", the values referenced by the\n+ * first three are objects as passed to the \"create\", \"update\", and\n+ * \"delete\" methods, the value referenced by the \"callback\" key is\n+ * a function which is called when the commit operation is complete\n+ * using the scope referenced by the \"scope\" key.\n+ *\n+ * Returns:\n+ * {Array({})} An array of\n+ * objects.\n+ */\n+ commit: function() {},\n+\n+ /**\n+ * Method: abort\n+ * Abort an ongoing request.\n+ *\n+ * Parameters:\n+ * response - {}\n+ */\n+ abort: function(response) {},\n+\n+ /**\n+ * Method: createCallback\n+ * Returns a function that applies the given public method with resp and\n+ * options arguments.\n+ *\n+ * Parameters:\n+ * method - {Function} The method to be applied by the callback.\n+ * response - {} The protocol response object.\n+ * options - {Object} Options sent to the protocol method\n+ */\n+ createCallback: function(method, response, options) {\n+ return OpenLayers.Function.bind(function() {\n+ method.apply(this, [response, options]);\n+ }, this);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Protocol\"\n+});\n+\n+/**\n+ * Class: OpenLayers.Protocol.Response\n+ * Protocols return Response objects to their users.\n+ */\n+OpenLayers.Protocol.Response = OpenLayers.Class({\n+ /**\n+ * Property: code\n+ * {Number} - OpenLayers.Protocol.Response.SUCCESS or\n+ * OpenLayers.Protocol.Response.FAILURE\n+ */\n+ code: null,\n+\n+ /**\n+ * Property: requestType\n+ * {String} The type of request this response corresponds to. Either\n+ * \"create\", \"read\", \"update\" or \"delete\".\n+ */\n+ requestType: null,\n+\n+ /**\n+ * Property: last\n+ * {Boolean} - true if this is the last response expected in a commit,\n+ * false otherwise, defaults to true.\n+ */\n+ last: true,\n+\n+ /**\n+ * Property: features\n+ * {Array({})} or {}\n+ * The features returned in the response by the server. Depending on the \n+ * protocol's read payload, either features or data will be populated.\n+ */\n+ features: null,\n+\n+ /**\n+ * Property: data\n+ * {Object}\n+ * The data returned in the response by the server. Depending on the \n+ * protocol's read payload, either features or data will be populated.\n+ */\n+ data: null,\n+\n+ /**\n+ * Property: reqFeatures\n+ * {Array({})} or {}\n+ * The features provided by the user and placed in the request by the\n+ * protocol.\n+ */\n+ reqFeatures: null,\n+\n+ /**\n+ * Property: priv\n+ */\n+ priv: null,\n+\n+ /**\n+ * Property: error\n+ * {Object} The error object in case a service exception was encountered.\n+ */\n+ error: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Protocol.Response\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ },\n+\n+ /**\n+ * Method: success\n+ *\n+ * Returns:\n+ * {Boolean} - true on success, false otherwise\n+ */\n+ success: function() {\n+ return this.code > 0;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Protocol.Response\"\n+});\n+\n+OpenLayers.Protocol.Response.SUCCESS = 1;\n+OpenLayers.Protocol.Response.FAILURE = 0;\n+/* ======================================================================\n+ OpenLayers/StyleMap.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Style.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.StyleMap\n+ */\n+OpenLayers.StyleMap = OpenLayers.Class({\n+\n+ /**\n+ * Property: styles\n+ * {Object} Hash of {}, keyed by names of well known\n+ * rendering intents (e.g. \"default\", \"temporary\", \"select\", \"delete\").\n+ */\n+ styles: null,\n+\n+ /**\n+ * Property: extendDefault\n+ * {Boolean} if true, every render intent will extend the symbolizers\n+ * specified for the \"default\" intent at rendering time. Otherwise, every\n+ * rendering intent will be treated as a completely independent style.\n+ */\n+ extendDefault: true,\n+\n+ /**\n+ * Constructor: OpenLayers.StyleMap\n+ * \n+ * Parameters:\n+ * style - {Object} Optional. Either a style hash, or a style object, or\n+ * a hash of style objects (style hashes) keyed by rendering\n+ * intent. If just one style hash or style object is passed,\n+ * this will be used for all known render intents (default,\n+ * select, temporary)\n+ * options - {Object} optional hash of additional options for this\n+ * instance\n+ */\n+ initialize: function(style, options) {\n+ this.styles = {\n+ \"default\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"default\"]),\n+ \"select\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"select\"]),\n+ \"temporary\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"temporary\"]),\n+ \"delete\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"delete\"])\n+ };\n+\n+ // take whatever the user passed as style parameter and convert it\n+ // into parts of stylemap.\n+ if (style instanceof OpenLayers.Style) {\n+ // user passed a style object\n+ this.styles[\"default\"] = style;\n+ this.styles[\"select\"] = style;\n+ this.styles[\"temporary\"] = style;\n+ this.styles[\"delete\"] = style;\n+ } else if (typeof style == \"object\") {\n+ for (var key in style) {\n+ if (style[key] instanceof OpenLayers.Style) {\n+ // user passed a hash of style objects\n+ this.styles[key] = style[key];\n+ } else if (typeof style[key] == \"object\") {\n+ // user passsed a hash of style hashes\n+ this.styles[key] = new OpenLayers.Style(style[key]);\n+ } else {\n+ // user passed a style hash (i.e. symbolizer)\n+ this.styles[\"default\"] = new OpenLayers.Style(style);\n+ this.styles[\"select\"] = new OpenLayers.Style(style);\n+ this.styles[\"temporary\"] = new OpenLayers.Style(style);\n+ this.styles[\"delete\"] = new OpenLayers.Style(style);\n+ break;\n+ }\n+ }\n+ }\n+ OpenLayers.Util.extend(this, options);\n+ },\n+\n+ /**\n+ * Method: destroy\n+ */\n+ destroy: function() {\n+ for (var key in this.styles) {\n+ this.styles[key].destroy();\n+ }\n+ this.styles = null;\n+ },\n+\n+ /**\n+ * Method: createSymbolizer\n+ * Creates the symbolizer for a feature for a render intent.\n+ * \n+ * Parameters:\n+ * feature - {} The feature to evaluate the rules\n+ * of the intended style against.\n+ * intent - {String} The intent determines the symbolizer that will be\n+ * used to draw the feature. Well known intents are \"default\"\n+ * (for just drawing the features), \"select\" (for selected\n+ * features) and \"temporary\" (for drawing features).\n+ * \n+ * Returns:\n+ * {Object} symbolizer hash\n+ */\n+ createSymbolizer: function(feature, intent) {\n+ if (!feature) {\n+ feature = new OpenLayers.Feature.Vector();\n+ }\n+ if (!this.styles[intent]) {\n+ intent = \"default\";\n+ }\n+ feature.renderIntent = intent;\n+ var defaultSymbolizer = {};\n+ if (this.extendDefault && intent != \"default\") {\n+ defaultSymbolizer = this.styles[\"default\"].createSymbolizer(feature);\n+ }\n+ return OpenLayers.Util.extend(defaultSymbolizer,\n+ this.styles[intent].createSymbolizer(feature));\n+ },\n+\n+ /**\n+ * Method: addUniqueValueRules\n+ * Convenience method to create comparison rules for unique values of a\n+ * property. The rules will be added to the style object for a specified\n+ * rendering intent. This method is a shortcut for creating something like\n+ * the \"unique value legends\" familiar from well known desktop GIS systems\n+ * \n+ * Parameters:\n+ * renderIntent - {String} rendering intent to add the rules to\n+ * property - {String} values of feature attributes to create the\n+ * rules for\n+ * symbolizers - {Object} Hash of symbolizers, keyed by the desired\n+ * property values \n+ * context - {Object} An optional object with properties that\n+ * symbolizers' property values should be evaluated\n+ * against. If no context is specified, feature.attributes\n+ * will be used\n+ */\n+ addUniqueValueRules: function(renderIntent, property, symbolizers, context) {\n+ var rules = [];\n+ for (var value in symbolizers) {\n+ rules.push(new OpenLayers.Rule({\n+ symbolizer: symbolizers[value],\n+ context: context,\n+ filter: new OpenLayers.Filter.Comparison({\n+ type: OpenLayers.Filter.Comparison.EQUAL_TO,\n+ property: property,\n+ value: value\n+ })\n+ }));\n+ }\n+ this.styles[renderIntent].addRules(rules);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.StyleMap\"\n+});\n+/* ======================================================================\n+ OpenLayers/Spherical.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+/**\n+ * Namespace: Spherical\n+ * The OpenLayers.Spherical namespace includes utility functions for\n+ * calculations on the basis of a spherical earth (ignoring ellipsoidal\n+ * effects), which is accurate enough for most purposes.\n+ *\n+ * Relevant links:\n+ * * http://www.movable-type.co.uk/scripts/latlong.html\n+ * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical\n+ */\n+\n+OpenLayers.Spherical = OpenLayers.Spherical || {};\n+\n+OpenLayers.Spherical.DEFAULT_RADIUS = 6378137;\n+\n+/**\n+ * APIFunction: computeDistanceBetween\n+ * Computes the distance between two LonLats.\n+ *\n+ * Parameters:\n+ * from - {} or {Object} Starting point. A LonLat or\n+ * a JavaScript literal with lon lat properties.\n+ * to - {} or {Object} Ending point. A LonLat or a\n+ * JavaScript literal with lon lat properties.\n+ * radius - {Float} The radius. Optional. Defaults to 6378137 meters.\n+ *\n+ * Returns:\n+ * {Float} The distance in meters.\n+ */\n+OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) {\n+ var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS;\n+ var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360);\n+ var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360);\n+ var a = sinHalfDeltaLat * sinHalfDeltaLat +\n+ sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180);\n+ return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n+};\n+\n+\n+/**\n+ * APIFunction: computeHeading\n+ * Computes the heading from one LonLat to another LonLat.\n+ *\n+ * Parameters:\n+ * from - {} or {Object} Starting point. A LonLat or\n+ * a JavaScript literal with lon lat properties.\n+ * to - {} or {Object} Ending point. A LonLat or a\n+ * JavaScript literal with lon lat properties.\n+ *\n+ * Returns:\n+ * {Float} The heading in degrees.\n+ */\n+OpenLayers.Spherical.computeHeading = function(from, to) {\n+ var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180);\n+ var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) -\n+ Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180);\n+ return 180 * Math.atan2(y, x) / Math.PI;\n+};\n+/* ======================================================================\n+ OpenLayers/Filter.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Style.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Filter\n+ * This class represents an OGC Filter.\n+ */\n+OpenLayers.Filter = OpenLayers.Class({\n+\n+ /** \n+ * Constructor: OpenLayers.Filter\n+ * This class represents a generic filter.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n+ * \n+ * Returns:\n+ * {}\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ },\n+\n+ /** \n+ * APIMethod: destroy\n+ * Remove reference to anything added.\n+ */\n+ destroy: function() {},\n+\n+ /**\n+ * APIMethod: evaluate\n+ * Evaluates this filter in a specific context. Instances or subclasses\n+ * are supposed to override this method.\n+ * \n+ * Parameters:\n+ * context - {Object} Context to use in evaluating the filter. If a vector\n+ * feature is provided, the feature.attributes will be used as context.\n+ * \n+ * Returns:\n+ * {Boolean} The filter applies.\n+ */\n+ evaluate: function(context) {\n+ return true;\n+ },\n+\n+ /**\n+ * APIMethod: clone\n+ * Clones this filter. Should be implemented by subclasses.\n+ * \n+ * Returns:\n+ * {} Clone of this filter.\n+ */\n+ clone: function() {\n+ return null;\n+ },\n+\n+ /**\n+ * APIMethod: toString\n+ *\n+ * Returns:\n+ * {String} Include in your build to get a CQL\n+ * representation of the filter returned. Otherwise \"[Object object]\"\n+ * will be returned.\n+ */\n+ toString: function() {\n+ var string;\n+ if (OpenLayers.Format && OpenLayers.Format.CQL) {\n+ string = OpenLayers.Format.CQL.prototype.write(this);\n+ } else {\n+ string = Object.prototype.toString.call(this);\n+ }\n+ return string;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Filter\"\n+});\n+/* ======================================================================\n+ OpenLayers/Util/vendorPrefix.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+OpenLayers.Util = OpenLayers.Util || {};\n+/**\n+ * Namespace: OpenLayers.Util.vendorPrefix\n+ * A collection of utility functions to detect vendor prefixed features\n+ */\n+OpenLayers.Util.vendorPrefix = (function() {\n+ \"use strict\";\n+\n+ var VENDOR_PREFIXES = [\"\", \"O\", \"ms\", \"Moz\", \"Webkit\"],\n+ divStyle = document.createElement(\"div\").style,\n+ cssCache = {},\n+ jsCache = {};\n+\n+\n+ /**\n+ * Function: domToCss\n+ * Converts a upper camel case DOM style property name to a CSS property\n+ * i.e. transformOrigin -> transform-origin\n+ * or WebkitTransformOrigin -> -webkit-transform-origin\n+ *\n+ * Parameters:\n+ * prefixedDom - {String} The property to convert\n+ *\n+ * Returns:\n+ * {String} The CSS property\n+ */\n+ function domToCss(prefixedDom) {\n+ if (!prefixedDom) {\n+ return null;\n+ }\n+ return prefixedDom.\n+ replace(/([A-Z])/g, function(c) {\n+ return \"-\" + c.toLowerCase();\n+ }).\n+ replace(/^ms-/, \"-ms-\");\n+ }\n+\n+ /**\n+ * APIMethod: css\n+ * Detect which property is used for a CSS property\n+ *\n+ * Parameters:\n+ * property - {String} The standard (unprefixed) CSS property name\n+ *\n+ * Returns:\n+ * {String} The standard CSS property, prefixed property or null if not\n+ * supported\n+ */\n+ function css(property) {\n+ if (cssCache[property] === undefined) {\n+ var domProperty = property.\n+ replace(/(-[\\s\\S])/g, function(c) {\n+ return c.charAt(1).toUpperCase();\n+ });\n+ var prefixedDom = style(domProperty);\n+ cssCache[property] = domToCss(prefixedDom);\n+ }\n+ return cssCache[property];\n+ }\n+\n+ /**\n+ * APIMethod: js\n+ * Detect which property is used for a JS property/method\n+ *\n+ * Parameters:\n+ * obj - {Object} The object to test on\n+ * property - {String} The standard (unprefixed) JS property name\n+ *\n+ * Returns:\n+ * {String} The standard JS property, prefixed property or null if not\n+ * supported\n+ */\n+ function js(obj, property) {\n+ if (jsCache[property] === undefined) {\n+ var tmpProp,\n+ i = 0,\n+ l = VENDOR_PREFIXES.length,\n+ prefix,\n+ isStyleObj = (typeof obj.cssText !== \"undefined\");\n+\n+ jsCache[property] = null;\n+ for (; i < l; i++) {\n+ prefix = VENDOR_PREFIXES[i];\n+ if (prefix) {\n+ if (!isStyleObj) {\n+ // js prefix should be lower-case, while style\n+ // properties have upper case on first character\n+ prefix = prefix.toLowerCase();\n+ }\n+ tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);\n+ } else {\n+ tmpProp = property;\n+ }\n+\n+ if (obj[tmpProp] !== undefined) {\n+ jsCache[property] = tmpProp;\n+ break;\n+ }\n+ }\n+ }\n+ return jsCache[property];\n+ }\n+\n+ /**\n+ * APIMethod: style\n+ * Detect which property is used for a DOM style property\n+ *\n+ * Parameters:\n+ * property - {String} The standard (unprefixed) style property name\n+ *\n+ * Returns:\n+ * {String} The standard style property, prefixed property or null if not\n+ * supported\n+ */\n+ function style(property) {\n+ return js(divStyle, property);\n+ }\n+\n+ return {\n+ css: css,\n+ js: js,\n+ style: style,\n+\n+ // used for testing\n+ cssCache: cssCache,\n+ jsCache: jsCache\n+ };\n+}());\n+/* ======================================================================\n+ OpenLayers/Animation.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ * @requires OpenLayers/Util/vendorPrefix.js\n+ */\n+\n+/**\n+ * Namespace: OpenLayers.Animation\n+ * A collection of utility functions for executing methods that repaint a \n+ * portion of the browser window. These methods take advantage of the\n+ * browser's scheduled repaints where requestAnimationFrame is available.\n+ */\n+OpenLayers.Animation = (function(window) {\n+\n+ /**\n+ * Property: isNative\n+ * {Boolean} true if a native requestAnimationFrame function is available\n+ */\n+ var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, \"requestAnimationFrame\");\n+ var isNative = !!(requestAnimationFrame);\n+\n+ /**\n+ * Function: requestFrame\n+ * Schedule a function to be called at the next available animation frame.\n+ * Uses the native method where available. Where requestAnimationFrame is\n+ * not available, setTimeout will be called with a 16ms delay.\n+ *\n+ * Parameters:\n+ * callback - {Function} The function to be called at the next animation frame.\n+ * element - {DOMElement} Optional element that visually bounds the animation.\n+ */\n+ var requestFrame = (function() {\n+ var request = window[requestAnimationFrame] ||\n+ function(callback, element) {\n+ window.setTimeout(callback, 16);\n+ };\n+ // bind to window to avoid illegal invocation of native function\n+ return function(callback, element) {\n+ request.apply(window, [callback, element]);\n+ };\n+ })();\n+\n+ // private variables for animation loops\n+ var counter = 0;\n+ var loops = {};\n+\n+ /**\n+ * Function: start\n+ * Executes a method with in series for some \n+ * duration.\n+ *\n+ * Parameters:\n+ * callback - {Function} The function to be called at the next animation frame.\n+ * duration - {Number} Optional duration for the loop. If not provided, the\n+ * animation loop will execute indefinitely.\n+ * element - {DOMElement} Optional element that visually bounds the animation.\n+ *\n+ * Returns:\n+ * {Number} Identifier for the animation loop. Used to stop animations with\n+ * .\n+ */\n+ function start(callback, duration, element) {\n+ duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;\n+ var id = ++counter;\n+ var start = +new Date;\n+ loops[id] = function() {\n+ if (loops[id] && +new Date - start <= duration) {\n+ callback();\n+ if (loops[id]) {\n+ requestFrame(loops[id], element);\n+ }\n+ } else {\n+ delete loops[id];\n+ }\n+ };\n+ requestFrame(loops[id], element);\n+ return id;\n+ }\n+\n+ /**\n+ * Function: stop\n+ * Terminates an animation loop started with .\n+ *\n+ * Parameters:\n+ * id - {Number} Identifier returned from .\n+ */\n+ function stop(id) {\n+ delete loops[id];\n+ }\n+\n+ return {\n+ isNative: isNative,\n+ requestFrame: requestFrame,\n+ start: start,\n+ stop: stop\n+ };\n+\n+})(window);\n+/* ======================================================================\n+ OpenLayers/Tween.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Animation.js\n+ */\n+\n+/**\n+ * Namespace: OpenLayers.Tween\n+ */\n+OpenLayers.Tween = OpenLayers.Class({\n+\n+ /**\n+ * APIProperty: easing\n+ * {(Function)} Easing equation used for the animation\n+ * Defaultly set to OpenLayers.Easing.Expo.easeOut\n+ */\n+ easing: null,\n+\n+ /**\n+ * APIProperty: begin\n+ * {Object} Values to start the animation with\n+ */\n+ begin: null,\n+\n+ /**\n+ * APIProperty: finish\n+ * {Object} Values to finish the animation with\n+ */\n+ finish: null,\n+\n+ /**\n+ * APIProperty: duration\n+ * {int} duration of the tween (number of steps)\n+ */\n+ duration: null,\n+\n+ /**\n+ * APIProperty: callbacks\n+ * {Object} An object with start, eachStep and done properties whose values\n+ * are functions to be call during the animation. They are passed the\n+ * current computed value as argument.\n+ */\n+ callbacks: null,\n+\n+ /**\n+ * Property: time\n+ * {int} Step counter\n+ */\n+ time: null,\n+\n+ /**\n+ * APIProperty: minFrameRate\n+ * {Number} The minimum framerate for animations in frames per second. After\n+ * each step, the time spent in the animation is compared to the calculated\n+ * time at this frame rate. If the animation runs longer than the calculated\n+ * time, the next step is skipped. Default is 30.\n+ */\n+ minFrameRate: null,\n+\n+ /**\n+ * Property: startTime\n+ * {Number} The timestamp of the first execution step. Used for skipping\n+ * frames\n+ */\n+ startTime: null,\n+\n+ /**\n+ * Property: animationId\n+ * {int} Loop id returned by OpenLayers.Animation.start\n+ */\n+ animationId: null,\n+\n+ /**\n+ * Property: playing\n+ * {Boolean} Tells if the easing is currently playing\n+ */\n+ playing: false,\n+\n+ /** \n+ * Constructor: OpenLayers.Tween\n+ * Creates a Tween.\n+ *\n+ * Parameters:\n+ * easing - {(Function)} easing function method to use\n+ */\n+ initialize: function(easing) {\n+ this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;\n+ },\n+\n+ /**\n+ * APIMethod: start\n+ * Plays the Tween, and calls the callback method on each step\n+ * \n+ * Parameters:\n+ * begin - {Object} values to start the animation with\n+ * finish - {Object} values to finish the animation with\n+ * duration - {int} duration of the tween (number of steps)\n+ * options - {Object} hash of options (callbacks (start, eachStep, done),\n+ * minFrameRate)\n+ */\n+ start: function(begin, finish, duration, options) {\n+ this.playing = true;\n+ this.begin = begin;\n+ this.finish = finish;\n+ this.duration = duration;\n+ this.callbacks = options.callbacks;\n+ this.minFrameRate = options.minFrameRate || 30;\n+ this.time = 0;\n+ this.startTime = new Date().getTime();\n+ OpenLayers.Animation.stop(this.animationId);\n+ this.animationId = null;\n+ if (this.callbacks && this.callbacks.start) {\n+ this.callbacks.start.call(this, this.begin);\n+ }\n+ this.animationId = OpenLayers.Animation.start(\n+ OpenLayers.Function.bind(this.play, this)\n+ );\n+ },\n+\n+ /**\n+ * APIMethod: stop\n+ * Stops the Tween, and calls the done callback\n+ * Doesn't do anything if animation is already finished\n+ */\n+ stop: function() {\n+ if (!this.playing) {\n+ return;\n+ }\n+\n+ if (this.callbacks && this.callbacks.done) {\n+ this.callbacks.done.call(this, this.finish);\n+ }\n+ OpenLayers.Animation.stop(this.animationId);\n+ this.animationId = null;\n+ this.playing = false;\n+ },\n+\n+ /**\n+ * Method: play\n+ * Calls the appropriate easing method\n+ */\n+ play: function() {\n+ var value = {};\n+ for (var i in this.begin) {\n+ var b = this.begin[i];\n+ var f = this.finish[i];\n+ if (b == null || f == null || isNaN(b) || isNaN(f)) {\n+ throw new TypeError('invalid value for Tween');\n+ }\n+\n+ var c = f - b;\n+ value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);\n+ }\n+ this.time++;\n+\n+ if (this.callbacks && this.callbacks.eachStep) {\n+ // skip frames if frame rate drops below threshold\n+ if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {\n+ this.callbacks.eachStep.call(this, value);\n+ }\n+ }\n+\n+ if (this.time > this.duration) {\n+ this.stop();\n+ }\n+ },\n+\n+ /**\n+ * Create empty functions for all easing methods.\n+ */\n+ CLASS_NAME: \"OpenLayers.Tween\"\n+});\n+\n+/**\n+ * Namespace: OpenLayers.Easing\n+ * \n+ * Credits:\n+ * Easing Equations by Robert Penner, \n+ */\n+OpenLayers.Easing = {\n+ /**\n+ * Create empty functions for all easing methods.\n+ */\n+ CLASS_NAME: \"OpenLayers.Easing\"\n+};\n+\n+/**\n+ * Namespace: OpenLayers.Easing.Linear\n+ */\n+OpenLayers.Easing.Linear = {\n+\n+ /**\n+ * Function: easeIn\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeIn: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n+\n+ /**\n+ * Function: easeOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeOut: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n+\n+ /**\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeInOut: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Easing.Linear\"\n+};\n+\n+/**\n+ * Namespace: OpenLayers.Easing.Expo\n+ */\n+OpenLayers.Easing.Expo = {\n+\n+ /**\n+ * Function: easeIn\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeIn: function(t, b, c, d) {\n+ return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n+ },\n+\n+ /**\n+ * Function: easeOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeOut: function(t, b, c, d) {\n+ return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n+ },\n+\n+ /**\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeInOut: function(t, b, c, d) {\n+ if (t == 0) return b;\n+ if (t == d) return b + c;\n+ if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n+ return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Easing.Expo\"\n+};\n+\n+/**\n+ * Namespace: OpenLayers.Easing.Quad\n+ */\n+OpenLayers.Easing.Quad = {\n+\n+ /**\n+ * Function: easeIn\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeIn: function(t, b, c, d) {\n+ return c * (t /= d) * t + b;\n+ },\n+\n+ /**\n+ * Function: easeOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeOut: function(t, b, c, d) {\n+ return -c * (t /= d) * (t - 2) + b;\n+ },\n+\n+ /**\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n+ */\n+ easeInOut: function(t, b, c, d) {\n+ if ((t /= d / 2) < 1) return c / 2 * t * t + b;\n+ return -c / 2 * ((--t) * (t - 2) - 1) + b;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Easing.Quad\"\n+};\n+/* ======================================================================\n+ OpenLayers/Projection.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ */\n+\n+/**\n+ * Namespace: OpenLayers.Projection\n+ * Methods for coordinate transforms between coordinate systems. By default,\n+ * OpenLayers ships with the ability to transform coordinates between\n+ * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)\n+ * coordinate reference systems. See the method for details\n+ * on usage.\n+ *\n+ * Additional transforms may be added by using the \n+ * library. If the proj4js library is included, the method \n+ * will work between any two coordinate reference systems with proj4js \n+ * definitions.\n+ *\n+ * If the proj4js library is not included, or if you wish to allow transforms\n+ * between arbitrary coordinate reference systems, use the \n+ * method to register a custom transform method.\n+ */\n+OpenLayers.Projection = OpenLayers.Class({\n+\n+ /**\n+ * Property: proj\n+ * {Object} Proj4js.Proj instance.\n+ */\n+ proj: null,\n+\n+ /**\n+ * Property: projCode\n+ * {String}\n+ */\n+ projCode: null,\n+\n+ /**\n+ * Property: titleRegEx\n+ * {RegExp} regular expression to strip the title from a proj4js definition\n+ */\n+ titleRegEx: /\\+title=[^\\+]*/,\n+\n+ /**\n+ * Constructor: OpenLayers.Projection\n+ * This class offers several methods for interacting with a wrapped \n+ * pro4js projection object. \n+ *\n+ * Parameters:\n+ * projCode - {String} A string identifying the Well Known Identifier for\n+ * the projection.\n+ * options - {Object} An optional object to set additional properties\n+ * on the projection.\n+ *\n+ * Returns:\n+ * {} A projection object.\n+ */\n+ initialize: function(projCode, options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.projCode = projCode;\n+ if (typeof Proj4js == \"object\") {\n+ this.proj = new Proj4js.Proj(projCode);\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: getCode\n+ * Get the string SRS code.\n+ *\n+ * Returns:\n+ * {String} The SRS code.\n+ */\n+ getCode: function() {\n+ return this.proj ? this.proj.srsCode : this.projCode;\n+ },\n+\n+ /**\n+ * APIMethod: getUnits\n+ * Get the units string for the projection -- returns null if \n+ * proj4js is not available.\n+ *\n+ * Returns:\n+ * {String} The units abbreviation.\n+ */\n+ getUnits: function() {\n+ return this.proj ? this.proj.units : null;\n+ },\n+\n+ /**\n+ * Method: toString\n+ * Convert projection to string (getCode wrapper).\n+ *\n+ * Returns:\n+ * {String} The projection code.\n+ */\n+ toString: function() {\n+ return this.getCode();\n+ },\n+\n+ /**\n+ * Method: equals\n+ * Test equality of two projection instances. Determines equality based\n+ * soley on the projection code.\n+ *\n+ * Returns:\n+ * {Boolean} The two projections are equivalent.\n+ */\n+ equals: function(projection) {\n+ var p = projection,\n+ equals = false;\n+ if (p) {\n+ if (!(p instanceof OpenLayers.Projection)) {\n+ p = new OpenLayers.Projection(p);\n+ }\n+ if ((typeof Proj4js == \"object\") && this.proj.defData && p.proj.defData) {\n+ equals = this.proj.defData.replace(this.titleRegEx, \"\") ==\n+ p.proj.defData.replace(this.titleRegEx, \"\");\n+ } else if (p.getCode) {\n+ var source = this.getCode(),\n+ target = p.getCode();\n+ equals = source == target ||\n+ !!OpenLayers.Projection.transforms[source] &&\n+ OpenLayers.Projection.transforms[source][target] ===\n+ OpenLayers.Projection.nullTransform;\n+ }\n+ }\n+ return equals;\n+ },\n+\n+ /* Method: destroy\n+ * Destroy projection object.\n+ */\n+ destroy: function() {\n+ delete this.proj;\n+ delete this.projCode;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Projection\"\n+});\n+\n+/**\n+ * Property: transforms\n+ * {Object} Transforms is an object, with from properties, each of which may\n+ * have a to property. This allows you to define projections without \n+ * requiring support for proj4js to be included.\n+ *\n+ * This object has keys which correspond to a 'source' projection object. The\n+ * keys should be strings, corresponding to the projection.getCode() value.\n+ * Each source projection object should have a set of destination projection\n+ * keys included in the object. \n+ * \n+ * Each value in the destination object should be a transformation function,\n+ * where the function is expected to be passed an object with a .x and a .y\n+ * property. The function should return the object, with the .x and .y\n+ * transformed according to the transformation function.\n+ *\n+ * Note - Properties on this object should not be set directly. To add a\n+ * transform method to this object, use the method. For an\n+ * example of usage, see the OpenLayers.Layer.SphericalMercator file.\n+ */\n+OpenLayers.Projection.transforms = {};\n+\n+/**\n+ * APIProperty: defaults\n+ * {Object} Defaults for the SRS codes known to OpenLayers (currently\n+ * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,\n+ * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,\n+ * maxExtent (the validity extent for the SRS) and yx (true if this SRS is\n+ * known to have a reverse axis order).\n+ */\n+OpenLayers.Projection.defaults = {\n+ \"EPSG:4326\": {\n+ units: \"degrees\",\n+ maxExtent: [-180, -90, 180, 90],\n+ yx: true\n+ },\n+ \"CRS:84\": {\n+ units: \"degrees\",\n+ maxExtent: [-180, -90, 180, 90]\n+ },\n+ \"EPSG:900913\": {\n+ units: \"m\",\n+ maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]\n+ }\n+};\n+\n+/**\n+ * APIMethod: addTransform\n+ * Set a custom transform method between two projections. Use this method in\n+ * cases where the proj4js lib is not available or where custom projections\n+ * need to be handled.\n+ *\n+ * Parameters:\n+ * from - {String} The code for the source projection\n+ * to - {String} the code for the destination projection\n+ * method - {Function} A function that takes a point as an argument and\n+ * transforms that point from the source to the destination projection\n+ * in place. The original point should be modified.\n+ */\n+OpenLayers.Projection.addTransform = function(from, to, method) {\n+ if (method === OpenLayers.Projection.nullTransform) {\n+ var defaults = OpenLayers.Projection.defaults[from];\n+ if (defaults && !OpenLayers.Projection.defaults[to]) {\n+ OpenLayers.Projection.defaults[to] = defaults;\n+ }\n+ }\n+ if (!OpenLayers.Projection.transforms[from]) {\n+ OpenLayers.Projection.transforms[from] = {};\n+ }\n+ OpenLayers.Projection.transforms[from][to] = method;\n+};\n+\n+/**\n+ * APIMethod: transform\n+ * Transform a point coordinate from one projection to another. Note that\n+ * the input point is transformed in place.\n+ * \n+ * Parameters:\n+ * point - { | Object} An object with x and y\n+ * properties representing coordinates in those dimensions.\n+ * source - {OpenLayers.Projection} Source map coordinate system\n+ * dest - {OpenLayers.Projection} Destination map coordinate system\n+ *\n+ * Returns:\n+ * point - {object} A transformed coordinate. The original point is modified.\n+ */\n+OpenLayers.Projection.transform = function(point, source, dest) {\n+ if (source && dest) {\n+ if (!(source instanceof OpenLayers.Projection)) {\n+ source = new OpenLayers.Projection(source);\n+ }\n+ if (!(dest instanceof OpenLayers.Projection)) {\n+ dest = new OpenLayers.Projection(dest);\n+ }\n+ if (source.proj && dest.proj) {\n+ point = Proj4js.transform(source.proj, dest.proj, point);\n+ } else {\n+ var sourceCode = source.getCode();\n+ var destCode = dest.getCode();\n+ var transforms = OpenLayers.Projection.transforms;\n+ if (transforms[sourceCode] && transforms[sourceCode][destCode]) {\n+ transforms[sourceCode][destCode](point);\n+ }\n+ }\n+ }\n+ return point;\n+};\n+\n+/**\n+ * APIFunction: nullTransform\n+ * A null transformation - useful for defining projection aliases when\n+ * proj4js is not available:\n+ *\n+ * (code)\n+ * OpenLayers.Projection.addTransform(\"EPSG:3857\", \"EPSG:900913\",\n+ * OpenLayers.Projection.nullTransform);\n+ * OpenLayers.Projection.addTransform(\"EPSG:900913\", \"EPSG:3857\",\n+ * OpenLayers.Projection.nullTransform);\n+ * (end)\n+ */\n+OpenLayers.Projection.nullTransform = function(point) {\n+ return point;\n+};\n+\n+/**\n+ * Note: Transforms for web mercator <-> geographic\n+ * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.\n+ * OpenLayers originally started referring to EPSG:900913 as web mercator.\n+ * The EPSG has declared EPSG:3857 to be web mercator.\n+ * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as\n+ * 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.\n+ * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and\n+ * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis\n+ * order for EPSG:4326. \n+ */\n+(function() {\n+\n+ var pole = 20037508.34;\n+\n+ function inverseMercator(xy) {\n+ xy.x = 180 * xy.x / pole;\n+ xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);\n+ return xy;\n+ }\n+\n+ function forwardMercator(xy) {\n+ xy.x = xy.x * pole / 180;\n+ var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;\n+ xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));\n+ return xy;\n+ }\n+\n+ function map(base, codes) {\n+ var add = OpenLayers.Projection.addTransform;\n+ var same = OpenLayers.Projection.nullTransform;\n+ var i, len, code, other, j;\n+ for (i = 0, len = codes.length; i < len; ++i) {\n+ code = codes[i];\n+ add(base, code, forwardMercator);\n+ add(code, base, inverseMercator);\n+ for (j = i + 1; j < len; ++j) {\n+ other = codes[j];\n+ add(code, other, same);\n+ add(other, code, same);\n+ }\n+ }\n+ }\n+\n+ // list of equivalent codes for web mercator\n+ var mercator = [\"EPSG:900913\", \"EPSG:3857\", \"EPSG:102113\", \"EPSG:102100\"],\n+ geographic = [\"CRS:84\", \"urn:ogc:def:crs:EPSG:6.6:4326\", \"EPSG:4326\"],\n+ i;\n+ for (i = mercator.length - 1; i >= 0; --i) {\n+ map(mercator[i], geographic);\n+ }\n+ for (i = geographic.length - 1; i >= 0; --i) {\n+ map(geographic[i], mercator);\n+ }\n+\n+})();\n+/* ======================================================================\n+ OpenLayers/Map.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Util/vendorPrefix.js\n+ * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Tween.js\n+ * @requires OpenLayers/Projection.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Map\n+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.\n+ * Create a new map with the constructor.\n+ * \n+ * On their own maps do not provide much functionality. To extend a map\n+ * it's necessary to add controls () and \n+ * layers () to the map. \n+ */\n+OpenLayers.Map = OpenLayers.Class({\n+\n+ /**\n+ * Constant: Z_INDEX_BASE\n+ * {Object} Base z-indexes for different classes of thing \n+ */\n+ Z_INDEX_BASE: {\n+ BaseLayer: 100,\n+ Overlay: 325,\n+ Feature: 725,\n+ Popup: 750,\n+ Control: 1000\n+ },\n+\n+ /**\n+ * APIProperty: events\n+ * {}\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * map.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Listeners will be called with a reference to an event object. The\n+ * properties of this event depends on exactly what happened.\n+ *\n+ * All event objects have at least the following properties:\n+ * object - {Object} A reference to map.events.object.\n+ * element - {DOMElement} A reference to map.events.element.\n+ *\n+ * Browser events have the following additional properties:\n+ * xy - {} The pixel location of the event (relative\n+ * to the the map viewport).\n+ *\n+ * Supported map event types:\n+ * preaddlayer - triggered before a layer has been added. The event\n+ * object will include a *layer* property that references the layer \n+ * to be added. When a listener returns \"false\" the adding will be \n+ * aborted.\n+ * addlayer - triggered after a layer has been added. The event object\n+ * will include a *layer* property that references the added layer.\n+ * preremovelayer - triggered before a layer has been removed. The event\n+ * object will include a *layer* property that references the layer \n+ * to be removed. When a listener returns \"false\" the removal will be \n+ * aborted.\n+ * removelayer - triggered after a layer has been removed. The event\n+ * object will include a *layer* property that references the removed\n+ * layer.\n+ * changelayer - triggered after a layer name change, order change,\n+ * opacity change, params change, visibility change (actual visibility,\n+ * not the layer's visibility property) or attribution change (due to\n+ * extent change). Listeners will receive an event object with *layer*\n+ * and *property* properties. The *layer* property will be a reference\n+ * to the changed layer. The *property* property will be a key to the\n+ * changed property (name, order, opacity, params, visibility or\n+ * attribution).\n+ * movestart - triggered after the start of a drag, pan, or zoom. The event\n+ * object may include a *zoomChanged* property that tells whether the\n+ * zoom has changed.\n+ * move - triggered after each drag, pan, or zoom\n+ * moveend - triggered after a drag, pan, or zoom completes\n+ * zoomend - triggered after a zoom completes\n+ * mouseover - triggered after mouseover the map\n+ * mouseout - triggered after mouseout the map\n+ * mousemove - triggered after mousemove the map\n+ * changebaselayer - triggered after the base layer changes\n+ * updatesize - triggered after the method was executed\n+ */\n+\n+ /**\n+ * Property: id\n+ * {String} Unique identifier for the map\n+ */\n+ id: null,\n+\n+ /**\n+ * Property: fractionalZoom\n+ * {Boolean} For a base layer that supports it, allow the map resolution\n+ * to be set to a value between one of the values in the resolutions\n+ * array. Default is false.\n+ *\n+ * When fractionalZoom is set to true, it is possible to zoom to\n+ * an arbitrary extent. This requires a base layer from a source\n+ * that supports requests for arbitrary extents (i.e. not cached\n+ * tiles on a regular lattice). This means that fractionalZoom\n+ * will not work with commercial layers (Google, Yahoo, VE), layers\n+ * using TileCache, or any other pre-cached data sources.\n+ *\n+ * If you are using fractionalZoom, then you should also use\n+ * instead of layer.resolutions[zoom] as the\n+ * former works for non-integer zoom levels.\n+ */\n+ fractionalZoom: false,\n+\n+ /**\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the map\n+ */\n+ events: null,\n+\n+ /**\n+ * APIProperty: allOverlays\n+ * {Boolean} Allow the map to function with \"overlays\" only. Defaults to\n+ * false. If true, the lowest layer in the draw order will act as\n+ * the base layer. In addition, if set to true, all layers will\n+ * have isBaseLayer set to false when they are added to the map.\n+ *\n+ * Note:\n+ * If you set map.allOverlays to true, then you *cannot* use\n+ * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,\n+ * the lowest layer in the draw layer is the base layer. So, to change\n+ * the base layer, use or to set the layer\n+ * index to 0.\n+ */\n+ allOverlays: false,\n+\n+ /**\n+ * APIProperty: div\n+ * {DOMElement|String} The element that contains the map (or an id for\n+ * that element). If the constructor is called\n+ * with two arguments, this should be provided as the first argument.\n+ * Alternatively, the map constructor can be called with the options\n+ * object as the only argument. In this case (one argument), a\n+ * div property may or may not be provided. If the div property\n+ * is not provided, the map can be rendered to a container later\n+ * using the method.\n+ * \n+ * Note:\n+ * If you are calling after map construction, do not use\n+ * auto. Instead, divide your by your\n+ * maximum expected dimension.\n+ */\n+ div: null,\n+\n+ /**\n+ * Property: dragging\n+ * {Boolean} The map is currently being dragged.\n+ */\n+ dragging: false,\n+\n+ /**\n+ * Property: size\n+ * {} Size of the main div (this.div)\n+ */\n+ size: null,\n+\n+ /**\n+ * Property: viewPortDiv\n+ * {HTMLDivElement} The element that represents the map viewport\n+ */\n+ viewPortDiv: null,\n+\n+ /**\n+ * Property: layerContainerOrigin\n+ * {} The lonlat at which the later container was\n+ * re-initialized (on-zoom)\n+ */\n+ layerContainerOrigin: null,\n+\n+ /**\n+ * Property: layerContainerDiv\n+ * {HTMLDivElement} The element that contains the layers.\n+ */\n+ layerContainerDiv: null,\n+\n+ /**\n+ * APIProperty: layers\n+ * {Array()} Ordered list of layers in the map\n+ */\n+ layers: null,\n+\n+ /**\n+ * APIProperty: controls\n+ * {Array()} List of controls associated with the map.\n+ *\n+ * If not provided in the map options at construction, the map will\n+ * by default be given the following controls if present in the build:\n+ * - or \n+ * - or \n+ * - \n+ * - \n+ */\n+ controls: null,\n+\n+ /**\n+ * Property: popups\n+ * {Array()} List of popups associated with the map\n+ */\n+ popups: null,\n+\n+ /**\n+ * APIProperty: baseLayer\n+ * {} The currently selected base layer. This determines\n+ * min/max zoom level, projection, etc.\n+ */\n+ baseLayer: null,\n+\n+ /**\n+ * Property: center\n+ * {} The current center of the map\n+ */\n+ center: null,\n+\n+ /**\n+ * Property: resolution\n+ * {Float} The resolution of the map.\n+ */\n+ resolution: null,\n+\n+ /**\n+ * Property: zoom\n+ * {Integer} The current zoom level of the map\n+ */\n+ zoom: 0,\n+\n+ /**\n+ * Property: panRatio\n+ * {Float} The ratio of the current extent within\n+ * which panning will tween.\n+ */\n+ panRatio: 1.5,\n+\n+ /**\n+ * APIProperty: options\n+ * {Object} The options object passed to the class constructor. Read-only.\n+ */\n+ options: null,\n+\n+ // Options\n+\n+ /**\n+ * APIProperty: tileSize\n+ * {} Set in the map options to override the default tile\n+ * size for this map.\n+ */\n+ tileSize: null,\n+\n+ /**\n+ * APIProperty: projection\n+ * {String} Set in the map options to specify the default projection \n+ * for layers added to this map. When using a projection other than EPSG:4326\n+ * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),\n+ * also set maxExtent, maxResolution or resolutions. Default is \"EPSG:4326\".\n+ * Note that the projection of the map is usually determined\n+ * by that of the current baseLayer (see and ).\n+ */\n+ projection: \"EPSG:4326\",\n+\n+ /**\n+ * APIProperty: units\n+ * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', \n+ * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.\n+ * Only required if both map and layers do not define a projection,\n+ * or if they define a projection which does not define units\n+ */\n+ units: null,\n+\n+ /**\n+ * APIProperty: resolutions\n+ * {Array(Float)} A list of map resolutions (map units per pixel) in \n+ * descending order. If this is not set in the layer constructor, it \n+ * will be set based on other resolution related properties \n+ * (maxExtent, maxResolution, maxScale, etc.).\n+ */\n+ resolutions: null,\n+\n+ /**\n+ * APIProperty: maxResolution\n+ * {Float} Required if you are not displaying the whole world on a tile\n+ * with the size specified in .\n+ */\n+ maxResolution: null,\n+\n+ /**\n+ * APIProperty: minResolution\n+ * {Float}\n+ */\n+ minResolution: null,\n+\n+ /**\n+ * APIProperty: maxScale\n+ * {Float}\n+ */\n+ maxScale: null,\n+\n+ /**\n+ * APIProperty: minScale\n+ * {Float}\n+ */\n+ minScale: null,\n+\n+ /**\n+ * APIProperty: maxExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The maximum extent for the map.\n+ * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults\n+ * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there;\n+ * else, defaults to null.\n+ * To restrict user panning and zooming of the map, use instead.\n+ * The value for will change calculations for tile URLs.\n+ */\n+ maxExtent: null,\n+\n+ /**\n+ * APIProperty: minExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The minimum extent for the map. Defaults to null.\n+ */\n+ minExtent: null,\n+\n+ /**\n+ * APIProperty: restrictedExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * Limit map navigation to this extent where possible.\n+ * If a non-null restrictedExtent is set, panning will be restricted\n+ * to the given bounds. In addition, zooming to a resolution that\n+ * displays more than the restricted extent will center the map\n+ * on the restricted extent. If you wish to limit the zoom level\n+ * or resolution, use maxResolution.\n+ */\n+ restrictedExtent: null,\n+\n+ /**\n+ * APIProperty: numZoomLevels\n+ * {Integer} Number of zoom levels for the map. Defaults to 16. Set a\n+ * different value in the map options if needed.\n+ */\n+ numZoomLevels: 16,\n+\n+ /**\n+ * APIProperty: theme\n+ * {String} Relative path to a CSS file from which to load theme styles.\n+ * Specify null in the map options (e.g. {theme: null}) if you \n+ * want to get cascading style declarations - by putting links to \n+ * stylesheets or style declarations directly in your page.\n+ */\n+ theme: null,\n+\n+ /** \n+ * APIProperty: displayProjection\n+ * {} Requires proj4js support for projections other\n+ * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by\n+ * several controls to display data to user. If this property is set,\n+ * it will be set on any control which has a null displayProjection\n+ * property at the time the control is added to the map. \n+ */\n+ displayProjection: null,\n+\n+ /**\n+ * APIProperty: tileManager\n+ * {|Object} By default, and if the build contains\n+ * TileManager.js, the map will use the TileManager to queue image requests\n+ * and to cache tile image elements. To create a map without a TileManager\n+ * configure the map with tileManager: null. To create a TileManager with\n+ * non-default options, supply the options instead or alternatively supply\n+ * an instance of {}.\n+ */\n+\n+ /**\n+ * APIProperty: fallThrough\n+ * {Boolean} Should OpenLayers allow events on the map to fall through to\n+ * other elements on the page, or should it swallow them? (#457)\n+ * Default is to swallow.\n+ */\n+ fallThrough: false,\n+\n+ /**\n+ * APIProperty: autoUpdateSize\n+ * {Boolean} Should OpenLayers automatically update the size of the map\n+ * when the resize event is fired. Default is true.\n+ */\n+ autoUpdateSize: true,\n+\n+ /**\n+ * APIProperty: eventListeners\n+ * {Object} If set as an option at construction, the eventListeners\n+ * object will be registered with . Object\n+ * structure must be a listeners object as shown in the example for\n+ * the events.on method.\n+ */\n+ eventListeners: null,\n+\n+ /**\n+ * Property: panTween\n+ * {} Animated panning tween object, see panTo()\n+ */\n+ panTween: null,\n+\n+ /**\n+ * APIProperty: panMethod\n+ * {Function} The Easing function to be used for tweening. Default is\n+ * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off\n+ * animated panning.\n+ */\n+ panMethod: OpenLayers.Easing.Expo.easeOut,\n+\n+ /**\n+ * Property: panDuration\n+ * {Integer} The number of steps to be passed to the\n+ * OpenLayers.Tween.start() method when the map is\n+ * panned.\n+ * Default is 50.\n+ */\n+ panDuration: 50,\n+\n+ /**\n+ * Property: zoomTween\n+ * {} Animated zooming tween object, see zoomTo()\n+ */\n+ zoomTween: null,\n+\n+ /**\n+ * APIProperty: zoomMethod\n+ * {Function} The Easing function to be used for tweening. Default is\n+ * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off\n+ * animated zooming.\n+ */\n+ zoomMethod: OpenLayers.Easing.Quad.easeOut,\n+\n+ /**\n+ * Property: zoomDuration\n+ * {Integer} The number of steps to be passed to the\n+ * OpenLayers.Tween.start() method when the map is zoomed.\n+ * Default is 20.\n+ */\n+ zoomDuration: 20,\n+\n+ /**\n+ * Property: paddingForPopups\n+ * {} Outside margin of the popup. Used to prevent \n+ * the popup from getting too close to the map border.\n+ */\n+ paddingForPopups: null,\n+\n+ /**\n+ * Property: layerContainerOriginPx\n+ * {Object} Cached object representing the layer container origin (in pixels).\n+ */\n+ layerContainerOriginPx: null,\n+\n+ /**\n+ * Property: minPx\n+ * {Object} An object with a 'x' and 'y' values that is the lower\n+ * left of maxExtent in viewport pixel space.\n+ * Used to verify in moveByPx that the new location we're moving to\n+ * is valid. It is also used in the getLonLatFromViewPortPx function\n+ * of Layer.\n+ */\n+ minPx: null,\n+\n+ /**\n+ * Property: maxPx\n+ * {Object} An object with a 'x' and 'y' values that is the top\n+ * right of maxExtent in viewport pixel space.\n+ * Used to verify in moveByPx that the new location we're moving to\n+ * is valid.\n+ */\n+ maxPx: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Map\n+ * Constructor for a new OpenLayers.Map instance. There are two possible\n+ * ways to call the map constructor. See the examples below.\n+ *\n+ * Parameters:\n+ * div - {DOMElement|String} The element or id of an element in your page\n+ * that will contain the map. May be omitted if the
option is\n+ * provided or if you intend to call the method later.\n+ * options - {Object} Optional object with properties to tag onto the map.\n+ *\n+ * Valid options (in addition to the listed API properties):\n+ * center - {|Array} The default initial center of the map.\n+ * If provided as array, the first value is the x coordinate,\n+ * and the 2nd value is the y coordinate.\n+ * Only specify if is provided.\n+ * Note that if an ArgParser/Permalink control is present,\n+ * and the querystring contains coordinates, center will be set\n+ * by that, and this option will be ignored.\n+ * zoom - {Number} The initial zoom level for the map. Only specify if\n+ * is provided.\n+ * Note that if an ArgParser/Permalink control is present,\n+ * and the querystring contains a zoom level, zoom will be set\n+ * by that, and this option will be ignored.\n+ * extent - {|Array} The initial extent of the map.\n+ * If provided as an array, the array should consist of\n+ * four values (left, bottom, right, top).\n+ * Only specify if
and are not provided.\n+ * \n+ * Examples:\n+ * (code)\n+ * // create a map with default options in an element with the id \"map1\"\n+ * var map = new OpenLayers.Map(\"map1\");\n+ *\n+ * // create a map with non-default options in an element with id \"map2\"\n+ * var options = {\n+ * projection: \"EPSG:3857\",\n+ * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),\n+ * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)\n+ * };\n+ * var map = new OpenLayers.Map(\"map2\", options);\n+ *\n+ * // map with non-default options - same as above but with a single argument,\n+ * // a restricted extent, and using arrays for bounds and center\n+ * var map = new OpenLayers.Map({\n * div: \"map_id\",\n * projection: \"EPSG:3857\",\n * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],\n * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],\n * center: [-12356463.476333, 5621521.4854095]\n * });\n *\n@@ -9645,1311 +13602,516 @@\n OpenLayers.Map.TILE_WIDTH = 256;\n /**\n * Constant: TILE_HEIGHT\n * {Integer} 256 Default tile height (unless otherwise specified)\n */\n OpenLayers.Map.TILE_HEIGHT = 256;\n /* ======================================================================\n- OpenLayers/Request/XMLHttpRequest.js\n+ OpenLayers/Icon.js\n ====================================================================== */\n \n-// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)\n-//\n-// Licensed under the Apache License, Version 2.0 (the \"License\");\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-//\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \"AS IS\" BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n /**\n- * @requires OpenLayers/Request.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n */\n \n-(function() {\n-\n- // Save reference to earlier defined object implementation (if any)\n- var oXMLHttpRequest = window.XMLHttpRequest;\n-\n- // Define on browser type\n- var bGecko = !!window.controllers,\n- bIE = window.document.all && !window.opera,\n- bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);\n-\n- // Enables \"XMLHttpRequest()\" call next to \"new XMLHttpReques()\"\n- function fXMLHttpRequest() {\n- this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n- this._listeners = [];\n- };\n+/**\n+ * Class: OpenLayers.Icon\n+ * \n+ * The icon represents a graphical icon on the screen. Typically used in\n+ * conjunction with a to represent markers on a screen.\n+ *\n+ * An icon has a url, size and position. It also contains an offset which \n+ * allows the center point to be represented correctly. This can be\n+ * provided either as a fixed offset or a function provided to calculate\n+ * the desired offset. \n+ * \n+ */\n+OpenLayers.Icon = OpenLayers.Class({\n \n- // Constructor\n- function cXMLHttpRequest() {\n- return new fXMLHttpRequest;\n- };\n- cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;\n+ /** \n+ * Property: url \n+ * {String} image url\n+ */\n+ url: null,\n \n- // BUGFIX: Firefox with Firebug installed would break pages if not executed\n- if (bGecko && oXMLHttpRequest.wrapped)\n- cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;\n+ /** \n+ * Property: size \n+ * {|Object} An OpenLayers.Size or\n+ * an object with a 'w' and 'h' properties.\n+ */\n+ size: null,\n \n- // Constants\n- cXMLHttpRequest.UNSENT = 0;\n- cXMLHttpRequest.OPENED = 1;\n- cXMLHttpRequest.HEADERS_RECEIVED = 2;\n- cXMLHttpRequest.LOADING = 3;\n- cXMLHttpRequest.DONE = 4;\n+ /** \n+ * Property: offset \n+ * {|Object} distance in pixels to offset the\n+ * image when being rendered. An OpenLayers.Pixel or an object\n+ * with a 'x' and 'y' properties.\n+ */\n+ offset: null,\n \n- // Public Properties\n- cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;\n- cXMLHttpRequest.prototype.responseText = '';\n- cXMLHttpRequest.prototype.responseXML = null;\n- cXMLHttpRequest.prototype.status = 0;\n- cXMLHttpRequest.prototype.statusText = '';\n+ /** \n+ * Property: calculateOffset \n+ * {Function} Function to calculate the offset (based on the size)\n+ */\n+ calculateOffset: null,\n \n- // Priority proposal\n- cXMLHttpRequest.prototype.priority = \"NORMAL\";\n+ /** \n+ * Property: imageDiv \n+ * {DOMElement} \n+ */\n+ imageDiv: null,\n \n- // Instance-level Events Handlers\n- cXMLHttpRequest.prototype.onreadystatechange = null;\n+ /** \n+ * Property: px \n+ * {|Object} An OpenLayers.Pixel or an object\n+ * with a 'x' and 'y' properties.\n+ */\n+ px: null,\n \n- // Class-level Events Handlers\n- cXMLHttpRequest.onreadystatechange = null;\n- cXMLHttpRequest.onopen = null;\n- cXMLHttpRequest.onsend = null;\n- cXMLHttpRequest.onabort = null;\n+ /** \n+ * Constructor: OpenLayers.Icon\n+ * Creates an icon, which is an image tag in a div. \n+ *\n+ * url - {String} \n+ * size - {|Object} An OpenLayers.Size or an\n+ * object with a 'w' and 'h'\n+ * properties.\n+ * offset - {|Object} An OpenLayers.Pixel or an\n+ * object with a 'x' and 'y'\n+ * properties.\n+ * calculateOffset - {Function} \n+ */\n+ initialize: function(url, size, offset, calculateOffset) {\n+ this.url = url;\n+ this.size = size || {\n+ w: 20,\n+ h: 20\n+ };\n+ this.offset = offset || {\n+ x: -(this.size.w / 2),\n+ y: -(this.size.h / 2)\n+ };\n+ this.calculateOffset = calculateOffset;\n \n- // Public Methods\n- cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {\n- // Delete headers, required when object is reused\n- delete this._headers;\n+ var id = OpenLayers.Util.createUniqueID(\"OL_Icon_\");\n+ this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);\n+ },\n \n- // When bAsync parameter value is omitted, use true as default\n- if (arguments.length < 3)\n- bAsync = true;\n+ /** \n+ * Method: destroy\n+ * Nullify references and remove event listeners to prevent circular \n+ * references and memory leaks\n+ */\n+ destroy: function() {\n+ // erase any drawn elements\n+ this.erase();\n \n- // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests\n- this._async = bAsync;\n+ OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);\n+ this.imageDiv.innerHTML = \"\";\n+ this.imageDiv = null;\n+ },\n \n- // Set the onreadystatechange handler\n- var oRequest = this,\n- nState = this.readyState,\n- fOnUnload;\n+ /** \n+ * Method: clone\n+ * \n+ * Returns:\n+ * {} A fresh copy of the icon.\n+ */\n+ clone: function() {\n+ return new OpenLayers.Icon(this.url,\n+ this.size,\n+ this.offset,\n+ this.calculateOffset);\n+ },\n \n- // BUGFIX: IE - memory leak on page unload (inter-page leak)\n- if (bIE && bAsync) {\n- fOnUnload = function() {\n- if (nState != cXMLHttpRequest.DONE) {\n- fCleanTransport(oRequest);\n- // Safe to abort here since onreadystatechange handler removed\n- oRequest.abort();\n- }\n- };\n- window.attachEvent(\"onunload\", fOnUnload);\n+ /**\n+ * Method: setSize\n+ * \n+ * Parameters:\n+ * size - {|Object} An OpenLayers.Size or\n+ * an object with a 'w' and 'h' properties.\n+ */\n+ setSize: function(size) {\n+ if (size != null) {\n+ this.size = size;\n }\n+ this.draw();\n+ },\n \n- // Add method sniffer\n- if (cXMLHttpRequest.onopen)\n- cXMLHttpRequest.onopen.apply(this, arguments);\n-\n- if (arguments.length > 4)\n- this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n- else\n- if (arguments.length > 3)\n- this._object.open(sMethod, sUrl, bAsync, sUser);\n- else\n- this._object.open(sMethod, sUrl, bAsync);\n+ /**\n+ * Method: setUrl\n+ * \n+ * Parameters:\n+ * url - {String} \n+ */\n+ setUrl: function(url) {\n+ if (url != null) {\n+ this.url = url;\n+ }\n+ this.draw();\n+ },\n \n- this.readyState = cXMLHttpRequest.OPENED;\n- fReadyStateChange(this);\n+ /** \n+ * Method: draw\n+ * Move the div to the given pixel.\n+ * \n+ * Parameters:\n+ * px - {|Object} An OpenLayers.Pixel or an\n+ * object with a 'x' and 'y' properties.\n+ * \n+ * Returns:\n+ * {DOMElement} A new DOM Image of this icon set at the location passed-in\n+ */\n+ draw: function(px) {\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,\n+ null,\n+ null,\n+ this.size,\n+ this.url,\n+ \"absolute\");\n+ this.moveTo(px);\n+ return this.imageDiv;\n+ },\n \n- this._object.onreadystatechange = function() {\n- if (bGecko && !bAsync)\n- return;\n+ /** \n+ * Method: erase\n+ * Erase the underlying image element.\n+ */\n+ erase: function() {\n+ if (this.imageDiv != null && this.imageDiv.parentNode != null) {\n+ OpenLayers.Element.remove(this.imageDiv);\n+ }\n+ },\n \n- // Synchronize state\n- oRequest.readyState = oRequest._object.readyState;\n+ /** \n+ * Method: setOpacity\n+ * Change the icon's opacity\n+ *\n+ * Parameters:\n+ * opacity - {float} \n+ */\n+ setOpacity: function(opacity) {\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,\n+ null, null, null, null, opacity);\n \n- //\n- fSynchronizeValues(oRequest);\n+ },\n \n- // BUGFIX: Firefox fires unnecessary DONE when aborting\n- if (oRequest._aborted) {\n- // Reset readyState to UNSENT\n- oRequest.readyState = cXMLHttpRequest.UNSENT;\n+ /**\n+ * Method: moveTo\n+ * move icon to passed in px.\n+ *\n+ * Parameters:\n+ * px - {|Object} the pixel position to move to.\n+ * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n+ */\n+ moveTo: function(px) {\n+ //if no px passed in, use stored location\n+ if (px != null) {\n+ this.px = px;\n+ }\n \n- // Return now\n- return;\n+ if (this.imageDiv != null) {\n+ if (this.px == null) {\n+ this.display(false);\n+ } else {\n+ if (this.calculateOffset) {\n+ this.offset = this.calculateOffset(this.size);\n+ }\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {\n+ x: this.px.x + this.offset.x,\n+ y: this.px.y + this.offset.y\n+ });\n }\n+ }\n+ },\n \n- if (oRequest.readyState == cXMLHttpRequest.DONE) {\n- // Free up queue\n- delete oRequest._data;\n- /* if (bAsync)\n- fQueue_remove(oRequest);*/\n- //\n- fCleanTransport(oRequest);\n- // Uncomment this block if you need a fix for IE cache\n- /*\n- // BUGFIX: IE - cache issue\n- if (!oRequest._object.getResponseHeader(\"Date\")) {\n- // Save object to cache\n- oRequest._cached = oRequest._object;\n-\n- // Instantiate a new transport object\n- cXMLHttpRequest.call(oRequest);\n-\n- // Re-send request\n- if (sUser) {\n- if (sPassword)\n- oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n- else\n- oRequest._object.open(sMethod, sUrl, bAsync, sUser);\n- }\n- else\n- oRequest._object.open(sMethod, sUrl, bAsync);\n- oRequest._object.setRequestHeader(\"If-Modified-Since\", oRequest._cached.getResponseHeader(\"Last-Modified\") || new window.Date(0));\n- // Copy headers set\n- if (oRequest._headers)\n- for (var sHeader in oRequest._headers)\n- if (typeof oRequest._headers[sHeader] == \"string\") // Some frameworks prototype objects with functions\n- oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);\n+ /** \n+ * Method: display\n+ * Hide or show the icon\n+ *\n+ * Parameters:\n+ * display - {Boolean} \n+ */\n+ display: function(display) {\n+ this.imageDiv.style.display = (display) ? \"\" : \"none\";\n+ },\n \n- oRequest._object.onreadystatechange = function() {\n- // Synchronize state\n- oRequest.readyState = oRequest._object.readyState;\n \n- if (oRequest._aborted) {\n- //\n- oRequest.readyState = cXMLHttpRequest.UNSENT;\n+ /**\n+ * APIMethod: isDrawn\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the icon is drawn.\n+ */\n+ isDrawn: function() {\n+ // nodeType 11 for ie, whose nodes *always* have a parentNode\n+ // (of type document fragment)\n+ var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&\n+ (this.imageDiv.parentNode.nodeType != 11));\n \n- // Return\n- return;\n- }\n+ return isDrawn;\n+ },\n \n- if (oRequest.readyState == cXMLHttpRequest.DONE) {\n- // Clean Object\n- fCleanTransport(oRequest);\n+ CLASS_NAME: \"OpenLayers.Icon\"\n+});\n+/* ======================================================================\n+ OpenLayers/Marker.js\n+ ====================================================================== */\n \n- // get cached request\n- if (oRequest.status == 304)\n- oRequest._object = oRequest._cached;\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- //\n- delete oRequest._cached;\n \n- //\n- fSynchronizeValues(oRequest);\n-\n- //\n- fReadyStateChange(oRequest);\n-\n- // BUGFIX: IE - memory leak in interrupted\n- if (bIE && bAsync)\n- window.detachEvent(\"onunload\", fOnUnload);\n- }\n- };\n- oRequest._object.send(null);\n-\n- // Return now - wait until re-sent request is finished\n- return;\n- };\n- */\n- // BUGFIX: IE - memory leak in interrupted\n- if (bIE && bAsync)\n- window.detachEvent(\"onunload\", fOnUnload);\n- }\n-\n- // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice\n- if (nState != oRequest.readyState)\n- fReadyStateChange(oRequest);\n-\n- nState = oRequest.readyState;\n- }\n- };\n-\n- function fXMLHttpRequest_send(oRequest) {\n- oRequest._object.send(oRequest._data);\n-\n- // BUGFIX: Gecko - missing readystatechange calls in synchronous requests\n- if (bGecko && !oRequest._async) {\n- oRequest.readyState = cXMLHttpRequest.OPENED;\n-\n- // Synchronize state\n- fSynchronizeValues(oRequest);\n-\n- // Simulate missing states\n- while (oRequest.readyState < cXMLHttpRequest.DONE) {\n- oRequest.readyState++;\n- fReadyStateChange(oRequest);\n- // Check if we are aborted\n- if (oRequest._aborted)\n- return;\n- }\n- }\n- };\n- cXMLHttpRequest.prototype.send = function(vData) {\n- // Add method sniffer\n- if (cXMLHttpRequest.onsend)\n- cXMLHttpRequest.onsend.apply(this, arguments);\n-\n- if (!arguments.length)\n- vData = null;\n-\n- // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required\n- // BUGFIX: IE - rewrites any custom mime-type to \"text/xml\" in case an XMLNode is sent\n- // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)\n- if (vData && vData.nodeType) {\n- vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;\n- if (!this._headers[\"Content-Type\"])\n- this._object.setRequestHeader(\"Content-Type\", \"application/xml\");\n- }\n-\n- this._data = vData;\n- /*\n- // Add to queue\n- if (this._async)\n- fQueue_add(this);\n- else*/\n- fXMLHttpRequest_send(this);\n- };\n- cXMLHttpRequest.prototype.abort = function() {\n- // Add method sniffer\n- if (cXMLHttpRequest.onabort)\n- cXMLHttpRequest.onabort.apply(this, arguments);\n-\n- // BUGFIX: Gecko - unnecessary DONE when aborting\n- if (this.readyState > cXMLHttpRequest.UNSENT)\n- this._aborted = true;\n-\n- this._object.abort();\n-\n- // BUGFIX: IE - memory leak\n- fCleanTransport(this);\n-\n- this.readyState = cXMLHttpRequest.UNSENT;\n-\n- delete this._data;\n- /* if (this._async)\n- fQueue_remove(this);*/\n- };\n- cXMLHttpRequest.prototype.getAllResponseHeaders = function() {\n- return this._object.getAllResponseHeaders();\n- };\n- cXMLHttpRequest.prototype.getResponseHeader = function(sName) {\n- return this._object.getResponseHeader(sName);\n- };\n- cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {\n- // BUGFIX: IE - cache issue\n- if (!this._headers)\n- this._headers = {};\n- this._headers[sName] = sValue;\n-\n- return this._object.setRequestHeader(sName, sValue);\n- };\n-\n- // EventTarget interface implementation\n- cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n- return;\n- // Add listener\n- this._listeners.push([sName, fHandler, bUseCapture]);\n- };\n-\n- cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n- break;\n- // Remove listener\n- if (oListener)\n- this._listeners.splice(nIndex, 1);\n- };\n-\n- cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {\n- var oEventPseudo = {\n- 'type': oEvent.type,\n- 'target': this,\n- 'currentTarget': this,\n- 'eventPhase': 2,\n- 'bubbles': oEvent.bubbles,\n- 'cancelable': oEvent.cancelable,\n- 'timeStamp': oEvent.timeStamp,\n- 'stopPropagation': function() {}, // There is no flow\n- 'preventDefault': function() {}, // There is no default action\n- 'initEvent': function() {} // Original event object should be initialized\n- };\n-\n- // Execute onreadystatechange\n- if (oEventPseudo.type == \"readystatechange\" && this.onreadystatechange)\n- (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);\n-\n- // Execute listeners\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == oEventPseudo.type && !oListener[2])\n- (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);\n- };\n-\n- //\n- cXMLHttpRequest.prototype.toString = function() {\n- return '[' + \"object\" + ' ' + \"XMLHttpRequest\" + ']';\n- };\n-\n- cXMLHttpRequest.toString = function() {\n- return '[' + \"XMLHttpRequest\" + ']';\n- };\n-\n- // Helper function\n- function fReadyStateChange(oRequest) {\n- // Sniffing code\n- if (cXMLHttpRequest.onreadystatechange)\n- cXMLHttpRequest.onreadystatechange.apply(oRequest);\n-\n- // Fake event\n- oRequest.dispatchEvent({\n- 'type': \"readystatechange\",\n- 'bubbles': false,\n- 'cancelable': false,\n- 'timeStamp': new Date + 0\n- });\n- };\n-\n- function fGetDocument(oRequest) {\n- var oDocument = oRequest.responseXML,\n- sResponse = oRequest.responseText;\n- // Try parsing responseText\n- if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader(\"Content-Type\").match(/[^\\/]+\\/[^\\+]+\\+xml/)) {\n- oDocument = new window.ActiveXObject(\"Microsoft.XMLDOM\");\n- oDocument.async = false;\n- oDocument.validateOnParse = false;\n- oDocument.loadXML(sResponse);\n- }\n- // Check if there is no error in document\n- if (oDocument)\n- if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == \"parsererror\"))\n- return null;\n- return oDocument;\n- };\n-\n- function fSynchronizeValues(oRequest) {\n- try {\n- oRequest.responseText = oRequest._object.responseText;\n- } catch (e) {}\n- try {\n- oRequest.responseXML = fGetDocument(oRequest._object);\n- } catch (e) {}\n- try {\n- oRequest.status = oRequest._object.status;\n- } catch (e) {}\n- try {\n- oRequest.statusText = oRequest._object.statusText;\n- } catch (e) {}\n- };\n-\n- function fCleanTransport(oRequest) {\n- // BUGFIX: IE - memory leak (on-page leak)\n- oRequest._object.onreadystatechange = new window.Function;\n- };\n- /*\n- // Queue manager\n- var oQueuePending = {\"CRITICAL\":[],\"HIGH\":[],\"NORMAL\":[],\"LOW\":[],\"LOWEST\":[]},\n- aQueueRunning = [];\n- function fQueue_add(oRequest) {\n- oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : \"NORMAL\"].push(oRequest);\n- //\n- setTimeout(fQueue_process);\n- };\n-\n- function fQueue_remove(oRequest) {\n- for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)\n- if (bFound)\n- aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];\n- else\n- if (aQueueRunning[nIndex] == oRequest)\n- bFound = true;\n- if (bFound)\n- aQueueRunning.length--;\n- //\n- setTimeout(fQueue_process);\n- };\n-\n- function fQueue_process() {\n- if (aQueueRunning.length < 6) {\n- for (var sPriority in oQueuePending) {\n- if (oQueuePending[sPriority].length) {\n- var oRequest = oQueuePending[sPriority][0];\n- oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);\n- //\n- aQueueRunning.push(oRequest);\n- // Send request\n- fXMLHttpRequest_send(oRequest);\n- break;\n- }\n- }\n- }\n- };\n- */\n- // Internet Explorer 5.0 (missing apply)\n- if (!window.Function.prototype.apply) {\n- window.Function.prototype.apply = function(oRequest, oArguments) {\n- if (!oArguments)\n- oArguments = [];\n- oRequest.__func = this;\n- oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);\n- delete oRequest.__func;\n- };\n- };\n-\n- // Register new object with window\n- /**\n- * Class: OpenLayers.Request.XMLHttpRequest\n- * Standard-compliant (W3C) cross-browser implementation of the\n- * XMLHttpRequest object. From\n- * http://code.google.com/p/xmlhttprequest/.\n- */\n- if (!OpenLayers.Request) {\n- /**\n- * This allows for OpenLayers/Request.js to be included\n- * before or after this script.\n- */\n- OpenLayers.Request = {};\n- }\n- OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;\n-})();\n-/* ======================================================================\n- OpenLayers/Request.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Request/XMLHttpRequest.js\n- */\n-\n-/**\n- * TODO: deprecate me\n- * Use OpenLayers.Request.proxy instead.\n- */\n-OpenLayers.ProxyHost = \"\";\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Icon.js\n+ */\n \n /**\n- * Namespace: OpenLayers.Request\n- * The OpenLayers.Request namespace contains convenience methods for working\n- * with XMLHttpRequests. These methods work with a cross-browser\n- * W3C compliant class.\n+ * Class: OpenLayers.Marker\n+ * Instances of OpenLayers.Marker are a combination of a \n+ * and an . \n+ *\n+ * Markers are generally added to a special layer called\n+ * .\n+ *\n+ * Example:\n+ * (code)\n+ * var markers = new OpenLayers.Layer.Markers( \"Markers\" );\n+ * map.addLayer(markers);\n+ *\n+ * var size = new OpenLayers.Size(21,25);\n+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);\n+ * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);\n+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));\n+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));\n+ *\n+ * (end)\n+ *\n+ * Note that if you pass an icon into the Marker constructor, it will take\n+ * that icon and use it. This means that you should not share icons between\n+ * markers -- you use them once, but you should clone() for any additional\n+ * markers using that same icon.\n */\n-if (!OpenLayers.Request) {\n- /**\n- * This allows for OpenLayers/Request/XMLHttpRequest.js to be included\n- * before or after this script.\n- */\n- OpenLayers.Request = {};\n-}\n-OpenLayers.Util.extend(OpenLayers.Request, {\n+OpenLayers.Marker = OpenLayers.Class({\n \n- /**\n- * Constant: DEFAULT_CONFIG\n- * {Object} Default configuration for all requests.\n+ /** \n+ * Property: icon \n+ * {} The icon used by this marker.\n */\n- DEFAULT_CONFIG: {\n- method: \"GET\",\n- url: window.location.href,\n- async: true,\n- user: undefined,\n- password: undefined,\n- params: null,\n- proxy: OpenLayers.ProxyHost,\n- headers: {},\n- data: null,\n- callback: function() {},\n- success: null,\n- failure: null,\n- scope: null\n- },\n+ icon: null,\n \n- /**\n- * Constant: URL_SPLIT_REGEX\n+ /** \n+ * Property: lonlat \n+ * {} location of object\n */\n- URL_SPLIT_REGEX: /([^:]*:)\\/\\/([^:]*:?[^@]*@)?([^:\\/\\?]*):?([^\\/\\?]*)/,\n+ lonlat: null,\n \n- /**\n- * APIProperty: events\n- * {} An events object that handles all \n- * events on the {} object.\n- *\n- * All event listeners will receive an event object with three properties:\n- * request - {} The request object.\n- * config - {Object} The config object sent to the specific request method.\n- * requestUrl - {String} The request url.\n- * \n- * Supported event types:\n- * complete - Triggered when we have a response from the request, if a\n- * listener returns false, no further response processing will take\n- * place.\n- * success - Triggered when the HTTP response has a success code (200-299).\n- * failure - Triggered when the HTTP response does not have a success code.\n+ /** \n+ * Property: events \n+ * {} the event handler.\n */\n- events: new OpenLayers.Events(this),\n+ events: null,\n \n- /**\n- * Method: makeSameOrigin\n- * Using the specified proxy, returns a same origin url of the provided url.\n- *\n- * Parameters:\n- * url - {String} An arbitrary url\n- * proxy {String|Function} The proxy to use to make the provided url a\n- * same origin url.\n- *\n- * Returns\n- * {String} the same origin url. If no proxy is provided, the returned url\n- * will be the same as the provided url.\n+ /** \n+ * Property: map \n+ * {} the map this marker is attached to\n */\n- makeSameOrigin: function(url, proxy) {\n- var sameOrigin = url.indexOf(\"http\") !== 0;\n- var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);\n- if (urlParts) {\n- var location = window.location;\n- sameOrigin =\n- urlParts[1] == location.protocol &&\n- urlParts[3] == location.hostname;\n- var uPort = urlParts[4],\n- lPort = location.port;\n- if (uPort != 80 && uPort != \"\" || lPort != \"80\" && lPort != \"\") {\n- sameOrigin = sameOrigin && uPort == lPort;\n- }\n- }\n- if (!sameOrigin) {\n- if (proxy) {\n- if (typeof proxy == \"function\") {\n- url = proxy(url);\n- } else {\n- url = proxy + encodeURIComponent(url);\n- }\n- }\n- }\n- return url;\n- },\n+ map: null,\n \n- /**\n- * APIMethod: issue\n- * Create a new XMLHttpRequest object, open it, set any headers, bind\n- * a callback to done state, and send any data. It is recommended that\n- * you use one , , , , , or .\n- * This method is only documented to provide detail on the configuration\n- * options available to all request methods.\n+ /** \n+ * Constructor: OpenLayers.Marker\n *\n * Parameters:\n- * config - {Object} Object containing properties for configuring the\n- * request. Allowed configuration properties are described below.\n- * This object is modified and should not be reused.\n- *\n- * Allowed config properties:\n- * method - {String} One of GET, POST, PUT, DELETE, HEAD, or\n- * OPTIONS. Default is GET.\n- * url - {String} URL for the request.\n- * async - {Boolean} Open an asynchronous request. Default is true.\n- * user - {String} User for relevant authentication scheme. Set\n- * to null to clear current user.\n- * password - {String} Password for relevant authentication scheme.\n- * Set to null to clear current password.\n- * proxy - {String} Optional proxy. Defaults to\n- * .\n- * params - {Object} Any key:value pairs to be appended to the\n- * url as a query string. Assumes url doesn't already include a query\n- * string or hash. Typically, this is only appropriate for \n- * requests where the query string will be appended to the url.\n- * Parameter values that are arrays will be\n- * concatenated with a comma (note that this goes against form-encoding)\n- * as is done with .\n- * headers - {Object} Object with header:value pairs to be set on\n- * the request.\n- * data - {String | Document} Optional data to send with the request.\n- * Typically, this is only used with and requests.\n- * Make sure to provide the appropriate \"Content-Type\" header for your\n- * data. For and requests, the content type defaults to\n- * \"application-xml\". If your data is a different content type, or\n- * if you are using a different HTTP method, set the \"Content-Type\"\n- * header to match your data type.\n- * callback - {Function} Function to call when request is done.\n- * To determine if the request failed, check request.status (200\n- * indicates success).\n- * success - {Function} Optional function to call if request status is in\n- * the 200s. This will be called in addition to callback above and\n- * would typically only be used as an alternative.\n- * failure - {Function} Optional function to call if request status is not\n- * in the 200s. This will be called in addition to callback above and\n- * would typically only be used as an alternative.\n- * scope - {Object} If callback is a public method on some object,\n- * set the scope to that object.\n- *\n- * Returns:\n- * {XMLHttpRequest} Request object. To abort the request before a response\n- * is received, call abort() on the request object.\n+ * lonlat - {} the position of this marker\n+ * icon - {} the icon for this marker\n */\n- issue: function(config) {\n- // apply default config - proxy host may have changed\n- var defaultConfig = OpenLayers.Util.extend(\n- this.DEFAULT_CONFIG, {\n- proxy: OpenLayers.ProxyHost\n- }\n- );\n- config = config || {};\n- config.headers = config.headers || {};\n- config = OpenLayers.Util.applyDefaults(config, defaultConfig);\n- config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);\n- // Always set the \"X-Requested-With\" header to signal that this request\n- // was issued through the XHR-object. Since header keys are case \n- // insensitive and we want to allow overriding of the \"X-Requested-With\"\n- // header through the user we cannot use applyDefaults, but have to \n- // check manually whether we were called with a \"X-Requested-With\"\n- // header.\n- var customRequestedWithHeader = false,\n- headerKey;\n- for (headerKey in config.headers) {\n- if (config.headers.hasOwnProperty(headerKey)) {\n- if (headerKey.toLowerCase() === 'x-requested-with') {\n- customRequestedWithHeader = true;\n- }\n- }\n- }\n- if (customRequestedWithHeader === false) {\n- // we did not have a custom \"X-Requested-With\" header\n- config.headers['X-Requested-With'] = 'XMLHttpRequest';\n- }\n-\n- // create request, open, and set headers\n- var request = new OpenLayers.Request.XMLHttpRequest();\n- var url = OpenLayers.Util.urlAppend(config.url,\n- OpenLayers.Util.getParameterString(config.params || {}));\n- url = OpenLayers.Request.makeSameOrigin(url, config.proxy);\n- request.open(\n- config.method, url, config.async, config.user, config.password\n- );\n- for (var header in config.headers) {\n- request.setRequestHeader(header, config.headers[header]);\n- }\n-\n- var events = this.events;\n-\n- // we want to execute runCallbacks with \"this\" as the\n- // execution scope\n- var self = this;\n-\n- request.onreadystatechange = function() {\n- if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {\n- var proceed = events.triggerEvent(\n- \"complete\", {\n- request: request,\n- config: config,\n- requestUrl: url\n- }\n- );\n- if (proceed !== false) {\n- self.runCallbacks({\n- request: request,\n- config: config,\n- requestUrl: url\n- });\n- }\n- }\n- };\n+ initialize: function(lonlat, icon) {\n+ this.lonlat = lonlat;\n \n- // send request (optionally with data) and return\n- // call in a timeout for asynchronous requests so the return is\n- // available before readyState == 4 for cached docs\n- if (config.async === false) {\n- request.send(config.data);\n+ var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();\n+ if (this.icon == null) {\n+ this.icon = newIcon;\n } else {\n- window.setTimeout(function() {\n- if (request.readyState !== 0) { // W3C: 0-UNSENT\n- request.send(config.data);\n- }\n- }, 0);\n+ this.icon.url = newIcon.url;\n+ this.icon.size = newIcon.size;\n+ this.icon.offset = newIcon.offset;\n+ this.icon.calculateOffset = newIcon.calculateOffset;\n }\n- return request;\n+ this.events = new OpenLayers.Events(this, this.icon.imageDiv);\n },\n \n /**\n- * Method: runCallbacks\n- * Calls the complete, success and failure callbacks. Application\n- * can listen to the \"complete\" event, have the listener \n- * display a confirm window and always return false, and\n- * execute OpenLayers.Request.runCallbacks if the user\n- * hits \"yes\" in the confirm window.\n- *\n- * Parameters:\n- * options - {Object} Hash containing request, config and requestUrl keys\n+ * APIMethod: destroy\n+ * Destroy the marker. You must first remove the marker from any \n+ * layer which it has been added to, or you will get buggy behavior.\n+ * (This can not be done within the marker since the marker does not\n+ * know which layer it is attached to.)\n */\n- runCallbacks: function(options) {\n- var request = options.request;\n- var config = options.config;\n-\n- // bind callbacks to readyState 4 (done)\n- var complete = (config.scope) ?\n- OpenLayers.Function.bind(config.callback, config.scope) :\n- config.callback;\n-\n- // optional success callback\n- var success;\n- if (config.success) {\n- success = (config.scope) ?\n- OpenLayers.Function.bind(config.success, config.scope) :\n- config.success;\n- }\n+ destroy: function() {\n+ // erase any drawn features\n+ this.erase();\n \n- // optional failure callback\n- var failure;\n- if (config.failure) {\n- failure = (config.scope) ?\n- OpenLayers.Function.bind(config.failure, config.scope) :\n- config.failure;\n- }\n+ this.map = null;\n \n- if (OpenLayers.Util.createUrlObject(config.url).protocol == \"file:\" &&\n- request.responseText) {\n- request.status = 200;\n- }\n- complete(request);\n+ this.events.destroy();\n+ this.events = null;\n \n- if (!request.status || (request.status >= 200 && request.status < 300)) {\n- this.events.triggerEvent(\"success\", options);\n- if (success) {\n- success(request);\n- }\n- }\n- if (request.status && (request.status < 200 || request.status >= 300)) {\n- this.events.triggerEvent(\"failure\", options);\n- if (failure) {\n- failure(request);\n- }\n+ if (this.icon != null) {\n+ this.icon.destroy();\n+ this.icon = null;\n }\n },\n \n- /**\n- * APIMethod: GET\n- * Send an HTTP GET request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to GET.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n+ /** \n+ * Method: draw\n+ * Calls draw on the icon, and returns that output.\n * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- GET: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"GET\"\n- });\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: POST\n- * Send a POST request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to POST and \"Content-Type\" header set to \"application/xml\".\n- *\n * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties. The\n- * default \"Content-Type\" header will be set to \"application-xml\" if\n- * none is provided. This object is modified and should not be reused.\n+ * px - {}\n * \n * Returns:\n- * {XMLHttpRequest} Request object.\n+ * {DOMElement} A new DOM Image with this marker's icon set at the \n+ * location passed-in\n */\n- POST: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"POST\"\n- });\n- // set content type to application/xml if it isn't already set\n- config.headers = config.headers ? config.headers : {};\n- if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n- config.headers[\"Content-Type\"] = \"application/xml\";\n- }\n- return OpenLayers.Request.issue(config);\n+ draw: function(px) {\n+ return this.icon.draw(px);\n },\n \n- /**\n- * APIMethod: PUT\n- * Send an HTTP PUT request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to PUT and \"Content-Type\" header set to \"application/xml\".\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties. The\n- * default \"Content-Type\" header will be set to \"application-xml\" if\n- * none is provided. This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n+ /** \n+ * Method: erase\n+ * Erases any drawn elements for this marker.\n */\n- PUT: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"PUT\"\n- });\n- // set content type to application/xml if it isn't already set\n- config.headers = config.headers ? config.headers : {};\n- if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n- config.headers[\"Content-Type\"] = \"application/xml\";\n+ erase: function() {\n+ if (this.icon != null) {\n+ this.icon.erase();\n }\n- return OpenLayers.Request.issue(config);\n },\n \n /**\n- * APIMethod: DELETE\n- * Send an HTTP DELETE request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to DELETE.\n+ * Method: moveTo\n+ * Move the marker to the new location.\n *\n * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n+ * px - {|Object} the pixel position to move to.\n+ * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n */\n- DELETE: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"DELETE\"\n- });\n- return OpenLayers.Request.issue(config);\n+ moveTo: function(px) {\n+ if ((px != null) && (this.icon != null)) {\n+ this.icon.moveTo(px);\n+ }\n+ this.lonlat = this.map.getLonLatFromLayerPx(px);\n },\n \n /**\n- * APIMethod: HEAD\n- * Send an HTTP HEAD request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to HEAD.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n+ * APIMethod: isDrawn\n * \n * Returns:\n- * {XMLHttpRequest} Request object.\n+ * {Boolean} Whether or not the marker is drawn.\n */\n- HEAD: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"HEAD\"\n- });\n- return OpenLayers.Request.issue(config);\n+ isDrawn: function() {\n+ var isDrawn = (this.icon && this.icon.isDrawn());\n+ return isDrawn;\n },\n \n /**\n- * APIMethod: OPTIONS\n- * Send an HTTP OPTIONS request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to OPTIONS.\n+ * Method: onScreen\n *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- OPTIONS: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"OPTIONS\"\n- });\n- return OpenLayers.Request.issue(config);\n- }\n-\n-});\n-/* ======================================================================\n- OpenLayers/Control.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Control\n- * Controls affect the display or behavior of the map. They allow everything\n- * from panning and zooming to displaying a scale indicator. Controls by \n- * default are added to the map they are contained within however it is\n- * possible to add a control to an external div by passing the div in the\n- * options parameter.\n- * \n- * Example:\n- * The following example shows how to add many of the common controls\n- * to a map.\n- * \n- * > var map = new OpenLayers.Map('map', { controls: [] });\n- * >\n- * > map.addControl(new OpenLayers.Control.PanZoomBar());\n- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));\n- * > map.addControl(new OpenLayers.Control.Permalink());\n- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));\n- * > map.addControl(new OpenLayers.Control.MousePosition());\n- * > map.addControl(new OpenLayers.Control.OverviewMap());\n- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());\n- *\n- * The next code fragment is a quick example of how to intercept \n- * shift-mouse click to display the extent of the bounding box\n- * dragged out by the user. Usually controls are not created\n- * in exactly this manner. See the source for a more complete \n- * example:\n- *\n- * > var control = new OpenLayers.Control();\n- * > OpenLayers.Util.extend(control, {\n- * > draw: function () {\n- * > // this Handler.Box will intercept the shift-mousedown\n- * > // before Control.MouseDefault gets to see it\n- * > this.box = new OpenLayers.Handler.Box( control, \n- * > {\"done\": this.notice},\n- * > {keyMask: OpenLayers.Handler.MOD_SHIFT});\n- * > this.box.activate();\n- * > },\n- * >\n- * > notice: function (bounds) {\n- * > OpenLayers.Console.userError(bounds);\n- * > }\n- * > }); \n- * > map.addControl(control);\n- * \n- */\n-OpenLayers.Control = OpenLayers.Class({\n-\n- /** \n- * Property: id \n- * {String} \n- */\n- id: null,\n-\n- /** \n- * Property: map \n- * {} this gets set in the addControl() function in\n- * OpenLayers.Map \n- */\n- map: null,\n-\n- /** \n- * APIProperty: div \n- * {DOMElement} The element that contains the control, if not present the \n- * control is placed inside the map.\n- */\n- div: null,\n-\n- /** \n- * APIProperty: type \n- * {Number} Controls can have a 'type'. The type determines the type of\n- * interactions which are possible with them when they are placed in an\n- * . \n- */\n- type: null,\n-\n- /** \n- * Property: allowSelection\n- * {Boolean} By default, controls do not allow selection, because\n- * it may interfere with map dragging. If this is true, OpenLayers\n- * will not prevent selection of the control.\n- * Default is false.\n- */\n- allowSelection: false,\n-\n- /** \n- * Property: displayClass \n- * {string} This property is used for CSS related to the drawing of the\n- * Control. \n- */\n- displayClass: \"\",\n-\n- /**\n- * APIProperty: title \n- * {string} This property is used for showing a tooltip over the \n- * Control. \n- */\n- title: \"\",\n-\n- /**\n- * APIProperty: autoActivate\n- * {Boolean} Activate the control when it is added to a map. Default is\n- * false.\n- */\n- autoActivate: false,\n-\n- /** \n- * APIProperty: active \n- * {Boolean} The control is active (read-only). Use and \n- * to change control state.\n- */\n- active: null,\n-\n- /**\n- * Property: handlerOptions\n- * {Object} Used to set non-default properties on the control's handler\n- */\n- handlerOptions: null,\n-\n- /** \n- * Property: handler \n- * {} null\n- */\n- handler: null,\n-\n- /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n- */\n- eventListeners: null,\n-\n- /** \n- * APIProperty: events\n- * {} Events instance for listeners and triggering\n- * control specific events.\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * control.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to control.events.object (a reference\n- * to the control).\n- * element - {DOMElement} A reference to control.events.element (which\n- * will be null unless documented otherwise).\n- *\n- * Supported map event types:\n- * activate - Triggered when activated.\n- * deactivate - Triggered when deactivated.\n- */\n- events: null,\n-\n- /**\n- * Constructor: OpenLayers.Control\n- * Create an OpenLayers Control. The options passed as a parameter\n- * directly extend the control. For example passing the following:\n- * \n- * > var control = new OpenLayers.Control({div: myDiv});\n- *\n- * Overrides the default div attribute value of null.\n- * \n- * Parameters:\n- * options - {Object} \n- */\n- initialize: function(options) {\n- // We do this before the extend so that instances can override\n- // className in options.\n- this.displayClass =\n- this.CLASS_NAME.replace(\"OpenLayers.\", \"ol\").replace(/\\./g, \"\");\n-\n- OpenLayers.Util.extend(this, options);\n-\n- this.events = new OpenLayers.Events(this);\n- if (this.eventListeners instanceof Object) {\n- this.events.on(this.eventListeners);\n- }\n- if (this.id == null) {\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- }\n- },\n-\n- /**\n- * Method: destroy\n- * The destroy method is used to perform any clean up before the control\n- * is dereferenced. Typically this is where event listeners are removed\n- * to prevent memory leaks.\n+ * {Boolean} Whether or not the marker is currently visible on screen.\n */\n- destroy: function() {\n- if (this.events) {\n- if (this.eventListeners) {\n- this.events.un(this.eventListeners);\n- }\n- this.events.destroy();\n- this.events = null;\n- }\n- this.eventListeners = null;\n+ onScreen: function() {\n \n- // eliminate circular references\n- if (this.handler) {\n- this.handler.destroy();\n- this.handler = null;\n- }\n- if (this.handlers) {\n- for (var key in this.handlers) {\n- if (this.handlers.hasOwnProperty(key) &&\n- typeof this.handlers[key].destroy == \"function\") {\n- this.handlers[key].destroy();\n- }\n- }\n- this.handlers = null;\n- }\n+ var onScreen = false;\n if (this.map) {\n- this.map.removeControl(this);\n- this.map = null;\n- }\n- this.div = null;\n- },\n-\n- /** \n- * Method: setMap\n- * Set the map property for the control. This is done through an accessor\n- * so that subclasses can override this and take special action once \n- * they have their map variable set. \n- *\n- * Parameters:\n- * map - {} \n- */\n- setMap: function(map) {\n- this.map = map;\n- if (this.handler) {\n- this.handler.setMap(map);\n+ var screenBounds = this.map.getExtent();\n+ onScreen = screenBounds.containsLonLat(this.lonlat);\n }\n+ return onScreen;\n },\n \n /**\n- * Method: draw\n- * The draw method is called when the control is ready to be displayed\n- * on the page. If a div has not been created one is created. Controls\n- * with a visual component will almost always want to override this method \n- * to customize the look of control. \n+ * Method: inflate\n+ * Englarges the markers icon by the specified ratio.\n *\n * Parameters:\n- * px - {} The top-left pixel position of the control\n- * or null.\n- *\n- * Returns:\n- * {DOMElement} A reference to the DIV DOMElement containing the control\n+ * inflate - {float} the ratio to enlarge the marker by (passing 2\n+ * will double the size).\n */\n- draw: function(px) {\n- if (this.div == null) {\n- this.div = OpenLayers.Util.createDiv(this.id);\n- this.div.className = this.displayClass;\n- if (!this.allowSelection) {\n- this.div.className += \" olControlNoSelect\";\n- this.div.setAttribute(\"unselectable\", \"on\", 0);\n- this.div.onselectstart = OpenLayers.Function.False;\n- }\n- if (this.title != \"\") {\n- this.div.title = this.title;\n- }\n- }\n- if (px != null) {\n- this.position = px.clone();\n+ inflate: function(inflate) {\n+ if (this.icon) {\n+ this.icon.setSize({\n+ w: this.icon.size.w * inflate,\n+ h: this.icon.size.h * inflate\n+ });\n }\n- this.moveTo(this.position);\n- return this.div;\n },\n \n- /**\n- * Method: moveTo\n- * Sets the left and top style attributes to the passed in pixel \n- * coordinates.\n- *\n+ /** \n+ * Method: setOpacity\n+ * Change the opacity of the marker by changin the opacity of \n+ * its icon\n+ * \n * Parameters:\n- * px - {}\n+ * opacity - {float} Specified as fraction (0.4, etc)\n */\n- moveTo: function(px) {\n- if ((px != null) && (this.div != null)) {\n- this.div.style.left = px.x + \"px\";\n- this.div.style.top = px.y + \"px\";\n- }\n+ setOpacity: function(opacity) {\n+ this.icon.setOpacity(opacity);\n },\n \n /**\n- * APIMethod: activate\n- * Explicitly activates a control and it's associated\n- * handler if one has been set. Controls can be\n- * deactivated by calling the deactivate() method.\n+ * Method: setUrl\n+ * Change URL of the Icon Image.\n * \n- * Returns:\n- * {Boolean} True if the control was successfully activated or\n- * false if the control was already active.\n+ * url - {String} \n */\n- activate: function() {\n- if (this.active) {\n- return false;\n- }\n- if (this.handler) {\n- this.handler.activate();\n- }\n- this.active = true;\n- if (this.map) {\n- OpenLayers.Element.addClass(\n- this.map.viewPortDiv,\n- this.displayClass.replace(/ /g, \"\") + \"Active\"\n- );\n- }\n- this.events.triggerEvent(\"activate\");\n- return true;\n+ setUrl: function(url) {\n+ this.icon.setUrl(url);\n },\n \n- /**\n- * APIMethod: deactivate\n- * Deactivates a control and it's associated handler if any. The exact\n- * effect of this depends on the control itself.\n+ /** \n+ * Method: display\n+ * Hide or show the icon\n * \n- * Returns:\n- * {Boolean} True if the control was effectively deactivated or false\n- * if the control was already inactive.\n+ * display - {Boolean} \n */\n- deactivate: function() {\n- if (this.active) {\n- if (this.handler) {\n- this.handler.deactivate();\n- }\n- this.active = false;\n- if (this.map) {\n- OpenLayers.Element.removeClass(\n- this.map.viewPortDiv,\n- this.displayClass.replace(/ /g, \"\") + \"Active\"\n- );\n- }\n- this.events.triggerEvent(\"deactivate\");\n- return true;\n- }\n- return false;\n+ display: function(display) {\n+ this.icon.display(display);\n },\n \n- CLASS_NAME: \"OpenLayers.Control\"\n+ CLASS_NAME: \"OpenLayers.Marker\"\n });\n \n-/**\n- * Constant: OpenLayers.Control.TYPE_BUTTON\n- */\n-OpenLayers.Control.TYPE_BUTTON = 1;\n \n /**\n- * Constant: OpenLayers.Control.TYPE_TOGGLE\n+ * Function: defaultIcon\n+ * Creates a default .\n+ * \n+ * Returns:\n+ * {} A default OpenLayers.Icon to use for a marker\n */\n-OpenLayers.Control.TYPE_TOGGLE = 2;\n+OpenLayers.Marker.defaultIcon = function() {\n+ return new OpenLayers.Icon(OpenLayers.Util.getImageLocation(\"marker.png\"), {\n+ w: 21,\n+ h: 25\n+ }, {\n+ x: -10.5,\n+ y: -25\n+ });\n+};\n+\n \n-/**\n- * Constant: OpenLayers.Control.TYPE_TOOL\n- */\n-OpenLayers.Control.TYPE_TOOL = 3;\n /* ======================================================================\n OpenLayers/Geometry.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n@@ -11449,757 +14611,14 @@\n distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2),\n x: x,\n y: y,\n along: along\n };\n };\n /* ======================================================================\n- OpenLayers/Feature.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- */\n-\n-/**\n- * Class: OpenLayers.Feature\n- * Features are combinations of geography and attributes. The OpenLayers.Feature\n- * class specifically combines a marker and a lonlat.\n- */\n-OpenLayers.Feature = OpenLayers.Class({\n-\n- /** \n- * Property: layer \n- * {} \n- */\n- layer: null,\n-\n- /** \n- * Property: id \n- * {String} \n- */\n- id: null,\n-\n- /** \n- * Property: lonlat \n- * {} \n- */\n- lonlat: null,\n-\n- /** \n- * Property: data \n- * {Object} \n- */\n- data: null,\n-\n- /** \n- * Property: marker \n- * {} \n- */\n- marker: null,\n-\n- /**\n- * APIProperty: popupClass\n- * {} The class which will be used to instantiate\n- * a new Popup. Default is .\n- */\n- popupClass: null,\n-\n- /** \n- * Property: popup \n- * {} \n- */\n- popup: null,\n-\n- /** \n- * Constructor: OpenLayers.Feature\n- * Constructor for features.\n- *\n- * Parameters:\n- * layer - {} \n- * lonlat - {} \n- * data - {Object} \n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(layer, lonlat, data) {\n- this.layer = layer;\n- this.lonlat = lonlat;\n- this.data = (data != null) ? data : {};\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n-\n- //remove the popup from the map\n- if ((this.layer != null) && (this.layer.map != null)) {\n- if (this.popup != null) {\n- this.layer.map.removePopup(this.popup);\n- }\n- }\n- // remove the marker from the layer\n- if (this.layer != null && this.marker != null) {\n- this.layer.removeMarker(this.marker);\n- }\n-\n- this.layer = null;\n- this.id = null;\n- this.lonlat = null;\n- this.data = null;\n- if (this.marker != null) {\n- this.destroyMarker(this.marker);\n- this.marker = null;\n- }\n- if (this.popup != null) {\n- this.destroyPopup(this.popup);\n- this.popup = null;\n- }\n- },\n-\n- /**\n- * Method: onScreen\n- * \n- * Returns:\n- * {Boolean} Whether or not the feature is currently visible on screen\n- * (based on its 'lonlat' property)\n- */\n- onScreen: function() {\n-\n- var onScreen = false;\n- if ((this.layer != null) && (this.layer.map != null)) {\n- var screenBounds = this.layer.map.getExtent();\n- onScreen = screenBounds.containsLonLat(this.lonlat);\n- }\n- return onScreen;\n- },\n-\n-\n- /**\n- * Method: createMarker\n- * Based on the data associated with the Feature, create and return a marker object.\n- *\n- * Returns: \n- * {} A Marker Object created from the 'lonlat' and 'icon' properties\n- * set in this.data. If no 'lonlat' is set, returns null. If no\n- * 'icon' is set, OpenLayers.Marker() will load the default image.\n- * \n- * Note - this.marker is set to return value\n- * \n- */\n- createMarker: function() {\n-\n- if (this.lonlat != null) {\n- this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);\n- }\n- return this.marker;\n- },\n-\n- /**\n- * Method: destroyMarker\n- * Destroys marker.\n- * If user overrides the createMarker() function, s/he should be able\n- * to also specify an alternative function for destroying it\n- */\n- destroyMarker: function() {\n- this.marker.destroy();\n- },\n-\n- /**\n- * Method: createPopup\n- * Creates a popup object created from the 'lonlat', 'popupSize',\n- * and 'popupContentHTML' properties set in this.data. It uses\n- * this.marker.icon as default anchor. \n- * \n- * If no 'lonlat' is set, returns null. \n- * If no this.marker has been created, no anchor is sent.\n- *\n- * Note - the returned popup object is 'owned' by the feature, so you\n- * cannot use the popup's destroy method to discard the popup.\n- * Instead, you must use the feature's destroyPopup\n- * \n- * Note - this.popup is set to return value\n- * \n- * Parameters: \n- * closeBox - {Boolean} create popup with closebox or not\n- * \n- * Returns:\n- * {} Returns the created popup, which is also set\n- * as 'popup' property of this feature. Will be of whatever type\n- * specified by this feature's 'popupClass' property, but must be\n- * of type .\n- * \n- */\n- createPopup: function(closeBox) {\n-\n- if (this.lonlat != null) {\n- if (!this.popup) {\n- var anchor = (this.marker) ? this.marker.icon : null;\n- var popupClass = this.popupClass ?\n- this.popupClass : OpenLayers.Popup.Anchored;\n- this.popup = new popupClass(this.id + \"_popup\",\n- this.lonlat,\n- this.data.popupSize,\n- this.data.popupContentHTML,\n- anchor,\n- closeBox);\n- }\n- if (this.data.overflow != null) {\n- this.popup.contentDiv.style.overflow = this.data.overflow;\n- }\n-\n- this.popup.feature = this;\n- }\n- return this.popup;\n- },\n-\n-\n- /**\n- * Method: destroyPopup\n- * Destroys the popup created via createPopup.\n- *\n- * As with the marker, if user overrides the createPopup() function, s/he \n- * should also be able to override the destruction\n- */\n- destroyPopup: function() {\n- if (this.popup) {\n- this.popup.feature = null;\n- this.popup.destroy();\n- this.popup = null;\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Feature\"\n-});\n-/* ======================================================================\n- OpenLayers/Feature/Vector.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-// TRASH THIS\n-OpenLayers.State = {\n- /** states */\n- UNKNOWN: 'Unknown',\n- INSERT: 'Insert',\n- UPDATE: 'Update',\n- DELETE: 'Delete'\n-};\n-\n-/**\n- * @requires OpenLayers/Feature.js\n- * @requires OpenLayers/Util.js\n- */\n-\n-/**\n- * Class: OpenLayers.Feature.Vector\n- * Vector features use the OpenLayers.Geometry classes as geometry description.\n- * They have an 'attributes' property, which is the data object, and a 'style'\n- * property, the default values of which are defined in the \n- * objects.\n- * \n- * Inherits from:\n- * - \n- */\n-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {\n-\n- /** \n- * Property: fid \n- * {String} \n- */\n- fid: null,\n-\n- /** \n- * APIProperty: geometry \n- * {} \n- */\n- geometry: null,\n-\n- /** \n- * APIProperty: attributes \n- * {Object} This object holds arbitrary, serializable properties that\n- * describe the feature.\n- */\n- attributes: null,\n-\n- /**\n- * Property: bounds\n- * {} The box bounding that feature's geometry, that\n- * property can be set by an object when\n- * deserializing the feature, so in most cases it represents an\n- * information set by the server. \n- */\n- bounds: null,\n-\n- /** \n- * Property: state \n- * {String} \n- */\n- state: null,\n-\n- /** \n- * APIProperty: style \n- * {Object} \n- */\n- style: null,\n-\n- /**\n- * APIProperty: url\n- * {String} If this property is set it will be taken into account by\n- * {} when upadting or deleting the feature.\n- */\n- url: null,\n-\n- /**\n- * Property: renderIntent\n- * {String} rendering intent currently being used\n- */\n- renderIntent: \"default\",\n-\n- /**\n- * APIProperty: modified\n- * {Object} An object with the originals of the geometry and attributes of\n- * the feature, if they were changed. Currently this property is only read\n- * by , and written by\n- * , which sets the geometry property.\n- * Applications can set the originals of modified attributes in the\n- * attributes property. Note that applications have to check if this\n- * object and the attributes property is already created before using it.\n- * After a change made with ModifyFeature, this object could look like\n- *\n- * (code)\n- * {\n- * geometry: >Object\n- * }\n- * (end)\n- *\n- * When an application has made changes to feature attributes, it could\n- * have set the attributes to something like this:\n- *\n- * (code)\n- * {\n- * attributes: {\n- * myAttribute: \"original\"\n- * }\n- * }\n- * (end)\n- *\n- * Note that only checks for truthy values in\n- * *modified.geometry* and the attribute names in *modified.attributes*,\n- * but it is recommended to set the original values (and not just true) as\n- * attribute value, so applications could use this information to undo\n- * changes.\n- */\n- modified: null,\n-\n- /** \n- * Constructor: OpenLayers.Feature.Vector\n- * Create a vector feature. \n- * \n- * Parameters:\n- * geometry - {} The geometry that this feature\n- * represents.\n- * attributes - {Object} An optional object that will be mapped to the\n- * property. \n- * style - {Object} An optional style object.\n- */\n- initialize: function(geometry, attributes, style) {\n- OpenLayers.Feature.prototype.initialize.apply(this,\n- [null, null, attributes]);\n- this.lonlat = null;\n- this.geometry = geometry ? geometry : null;\n- this.state = null;\n- this.attributes = {};\n- if (attributes) {\n- this.attributes = OpenLayers.Util.extend(this.attributes,\n- attributes);\n- }\n- this.style = style ? style : null;\n- },\n-\n- /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- if (this.layer) {\n- this.layer.removeFeatures(this);\n- this.layer = null;\n- }\n-\n- this.geometry = null;\n- this.modified = null;\n- OpenLayers.Feature.prototype.destroy.apply(this, arguments);\n- },\n-\n- /**\n- * Method: clone\n- * Create a clone of this vector feature. Does not set any non-standard\n- * properties.\n- *\n- * Returns:\n- * {} An exact clone of this vector feature.\n- */\n- clone: function() {\n- return new OpenLayers.Feature.Vector(\n- this.geometry ? this.geometry.clone() : null,\n- this.attributes,\n- this.style);\n- },\n-\n- /**\n- * Method: onScreen\n- * Determine whether the feature is within the map viewport. This method\n- * tests for an intersection between the geometry and the viewport\n- * bounds. If a more effecient but less precise geometry bounds\n- * intersection is desired, call the method with the boundsOnly\n- * parameter true.\n- *\n- * Parameters:\n- * boundsOnly - {Boolean} Only test whether a feature's bounds intersects\n- * the viewport bounds. Default is false. If false, the feature's\n- * geometry must intersect the viewport for onScreen to return true.\n- * \n- * Returns:\n- * {Boolean} The feature is currently visible on screen (optionally\n- * based on its bounds if boundsOnly is true).\n- */\n- onScreen: function(boundsOnly) {\n- var onScreen = false;\n- if (this.layer && this.layer.map) {\n- var screenBounds = this.layer.map.getExtent();\n- if (boundsOnly) {\n- var featureBounds = this.geometry.getBounds();\n- onScreen = screenBounds.intersectsBounds(featureBounds);\n- } else {\n- var screenPoly = screenBounds.toGeometry();\n- onScreen = screenPoly.intersects(this.geometry);\n- }\n- }\n- return onScreen;\n- },\n-\n- /**\n- * Method: getVisibility\n- * Determine whether the feature is displayed or not. It may not displayed\n- * because:\n- * - its style display property is set to 'none',\n- * - it doesn't belong to any layer,\n- * - the styleMap creates a symbolizer with display property set to 'none'\n- * for it,\n- * - the layer which it belongs to is not visible.\n- * \n- * Returns:\n- * {Boolean} The feature is currently displayed.\n- */\n- getVisibility: function() {\n- return !(this.style && this.style.display == 'none' ||\n- !this.layer ||\n- this.layer && this.layer.styleMap &&\n- this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||\n- this.layer && !this.layer.getVisibility());\n- },\n-\n- /**\n- * Method: createMarker\n- * HACK - we need to decide if all vector features should be able to\n- * create markers\n- * \n- * Returns:\n- * {} For now just returns null\n- */\n- createMarker: function() {\n- return null;\n- },\n-\n- /**\n- * Method: destroyMarker\n- * HACK - we need to decide if all vector features should be able to\n- * delete markers\n- * \n- * If user overrides the createMarker() function, s/he should be able\n- * to also specify an alternative function for destroying it\n- */\n- destroyMarker: function() {\n- // pass\n- },\n-\n- /**\n- * Method: createPopup\n- * HACK - we need to decide if all vector features should be able to\n- * create popups\n- * \n- * Returns:\n- * {} For now just returns null\n- */\n- createPopup: function() {\n- return null;\n- },\n-\n- /**\n- * Method: atPoint\n- * Determins whether the feature intersects with the specified location.\n- * \n- * Parameters: \n- * lonlat - {|Object} OpenLayers.LonLat or an\n- * object with a 'lon' and 'lat' properties.\n- * toleranceLon - {float} Optional tolerance in Geometric Coords\n- * toleranceLat - {float} Optional tolerance in Geographic Coords\n- * \n- * Returns:\n- * {Boolean} Whether or not the feature is at the specified location\n- */\n- atPoint: function(lonlat, toleranceLon, toleranceLat) {\n- var atPoint = false;\n- if (this.geometry) {\n- atPoint = this.geometry.atPoint(lonlat, toleranceLon,\n- toleranceLat);\n- }\n- return atPoint;\n- },\n-\n- /**\n- * Method: destroyPopup\n- * HACK - we need to decide if all vector features should be able to\n- * delete popups\n- */\n- destroyPopup: function() {\n- // pass\n- },\n-\n- /**\n- * Method: move\n- * Moves the feature and redraws it at its new location\n- *\n- * Parameters:\n- * location - { or } the\n- * location to which to move the feature.\n- */\n- move: function(location) {\n-\n- if (!this.layer || !this.geometry.move) {\n- //do nothing if no layer or immoveable geometry\n- return undefined;\n- }\n-\n- var pixel;\n- if (location.CLASS_NAME == \"OpenLayers.LonLat\") {\n- pixel = this.layer.getViewPortPxFromLonLat(location);\n- } else {\n- pixel = location;\n- }\n-\n- var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());\n- var res = this.layer.map.getResolution();\n- this.geometry.move(res * (pixel.x - lastPixel.x),\n- res * (lastPixel.y - pixel.y));\n- this.layer.drawFeature(this);\n- return lastPixel;\n- },\n-\n- /**\n- * Method: toState\n- * Sets the new state\n- *\n- * Parameters:\n- * state - {String} \n- */\n- toState: function(state) {\n- if (state == OpenLayers.State.UPDATE) {\n- switch (this.state) {\n- case OpenLayers.State.UNKNOWN:\n- case OpenLayers.State.DELETE:\n- this.state = state;\n- break;\n- case OpenLayers.State.UPDATE:\n- case OpenLayers.State.INSERT:\n- break;\n- }\n- } else if (state == OpenLayers.State.INSERT) {\n- switch (this.state) {\n- case OpenLayers.State.UNKNOWN:\n- break;\n- default:\n- this.state = state;\n- break;\n- }\n- } else if (state == OpenLayers.State.DELETE) {\n- switch (this.state) {\n- case OpenLayers.State.INSERT:\n- // the feature should be destroyed\n- break;\n- case OpenLayers.State.DELETE:\n- break;\n- case OpenLayers.State.UNKNOWN:\n- case OpenLayers.State.UPDATE:\n- this.state = state;\n- break;\n- }\n- } else if (state == OpenLayers.State.UNKNOWN) {\n- this.state = state;\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Feature.Vector\"\n-});\n-\n-\n-/**\n- * Constant: OpenLayers.Feature.Vector.style\n- * OpenLayers features can have a number of style attributes. The 'default' \n- * style will typically be used if no other style is specified. These\n- * styles correspond for the most part, to the styling properties defined\n- * by the SVG standard. \n- * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties\n- * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties\n- *\n- * Symbolizer properties:\n- * fill - {Boolean} Set to false if no fill is desired.\n- * fillColor - {String} Hex fill color. Default is \"#ee9900\".\n- * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 \n- * stroke - {Boolean} Set to false if no stroke is desired.\n- * strokeColor - {String} Hex stroke color. Default is \"#ee9900\".\n- * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.\n- * strokeWidth - {Number} Pixel stroke width. Default is 1.\n- * strokeLinecap - {String} Stroke cap type. Default is \"round\". [butt | round | square]\n- * strokeDashstyle - {String} Stroke dash style. Default is \"solid\". [dot | dash | dashdot | longdash | longdashdot | solid]\n- * graphic - {Boolean} Set to false if no graphic is desired.\n- * pointRadius - {Number} Pixel point radius. Default is 6.\n- * pointerEvents - {String} Default is \"visiblePainted\".\n- * cursor - {String} Default is \"\".\n- * externalGraphic - {String} Url to an external graphic that will be used for rendering points.\n- * graphicWidth - {Number} Pixel width for sizing an external graphic.\n- * graphicHeight - {Number} Pixel height for sizing an external graphic.\n- * graphicOpacity - {Number} Opacity (0-1) for an external graphic.\n- * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.\n- * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.\n- * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).\n- * graphicZIndex - {Number} The integer z-index value to use in rendering.\n- * graphicName - {String} Named graphic to use when rendering points. Supported values include \"circle\" (default),\n- * \"square\", \"star\", \"x\", \"cross\", \"triangle\".\n- * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead\n- * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.\n- * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.\n- * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.\n- * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.\n- * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.\n- * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.\n- * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.\n- * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either\n- * fillText or mozDrawText to be available.\n- * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string\n- * composed of two characters. The first character is for the horizontal alignment, the second for the vertical\n- * alignment. Valid values for horizontal alignment: \"l\"=left, \"c\"=center, \"r\"=right. Valid values for vertical\n- * alignment: \"t\"=top, \"m\"=middle, \"b\"=bottom. Example values: \"lt\", \"cm\", \"rb\". Default is \"cm\".\n- * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.\n- * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.\n- * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.\n- * Default is false.\n- * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.\n- * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers.\n- * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.\n- * fontColor - {String} The font color for the label, to be provided like CSS.\n- * fontOpacity - {Number} Opacity (0-1) for the label\n- * fontFamily - {String} The font family for the label, to be provided like in CSS.\n- * fontSize - {String} The font size for the label, to be provided like in CSS.\n- * fontStyle - {String} The font style for the label, to be provided like in CSS.\n- * fontWeight - {String} The font weight for the label, to be provided like in CSS.\n- * display - {String} Symbolizers will have no effect if display is set to \"none\". All other values have no effect.\n- */\n-OpenLayers.Feature.Vector.style = {\n- 'default': {\n- fillColor: \"#ee9900\",\n- fillOpacity: 0.4,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"#ee9900\",\n- strokeOpacity: 1,\n- strokeWidth: 1,\n- strokeLinecap: \"round\",\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"inherit\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n- },\n- 'select': {\n- fillColor: \"blue\",\n- fillOpacity: 0.4,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"blue\",\n- strokeOpacity: 1,\n- strokeWidth: 2,\n- strokeLinecap: \"round\",\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"pointer\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n-\n- },\n- 'temporary': {\n- fillColor: \"#66cccc\",\n- fillOpacity: 0.2,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"#66cccc\",\n- strokeOpacity: 1,\n- strokeLinecap: \"round\",\n- strokeWidth: 2,\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"inherit\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n-\n- },\n- 'delete': {\n- display: \"none\"\n- }\n-};\n-/* ======================================================================\n OpenLayers/Format.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -18560,557 +20979,14 @@\n * Constant: OpenLayers.Format.WFST.DEFAULTS\n * {Object} Default properties for the WFST format.\n */\n OpenLayers.Format.WFST.DEFAULTS = {\n \"version\": \"1.0.0\"\n };\n /* ======================================================================\n- OpenLayers/Style.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Feature/Vector.js\n- */\n-\n-/**\n- * Class: OpenLayers.Style\n- * This class represents a UserStyle obtained\n- * from a SLD, containing styling rules.\n- */\n-OpenLayers.Style = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String} A unique id for this session.\n- */\n- id: null,\n-\n- /**\n- * APIProperty: name\n- * {String}\n- */\n- name: null,\n-\n- /**\n- * Property: title\n- * {String} Title of this style (set if included in SLD)\n- */\n- title: null,\n-\n- /**\n- * Property: description\n- * {String} Description of this style (set if abstract is included in SLD)\n- */\n- description: null,\n-\n- /**\n- * APIProperty: layerName\n- * {} name of the layer that this style belongs to, usually\n- * according to the NamedLayer attribute of an SLD document.\n- */\n- layerName: null,\n-\n- /**\n- * APIProperty: isDefault\n- * {Boolean}\n- */\n- isDefault: false,\n-\n- /** \n- * Property: rules \n- * {Array()}\n- */\n- rules: null,\n-\n- /**\n- * APIProperty: context\n- * {Object} An optional object with properties that symbolizers' property\n- * values should be evaluated against. If no context is specified,\n- * feature.attributes will be used\n- */\n- context: null,\n-\n- /**\n- * Property: defaultStyle\n- * {Object} hash of style properties to use as default for merging\n- * rule-based style symbolizers onto. If no rules are defined,\n- * createSymbolizer will return this style. If is set to\n- * true, the defaultStyle will only be taken into account if there are\n- * rules defined.\n- */\n- defaultStyle: null,\n-\n- /**\n- * Property: defaultsPerSymbolizer\n- * {Boolean} If set to true, the will extend the symbolizer\n- * of every rule. Properties of the will also be used to set\n- * missing symbolizer properties if the symbolizer has stroke, fill or\n- * graphic set to true. Default is false.\n- */\n- defaultsPerSymbolizer: false,\n-\n- /**\n- * Property: propertyStyles\n- * {Hash of Boolean} cache of style properties that need to be parsed for\n- * propertyNames. Property names are keys, values won't be used.\n- */\n- propertyStyles: null,\n-\n-\n- /** \n- * Constructor: OpenLayers.Style\n- * Creates a UserStyle.\n- *\n- * Parameters:\n- * style - {Object} Optional hash of style properties that will be\n- * used as default style for this style object. This style\n- * applies if no rules are specified. Symbolizers defined in\n- * rules will extend this default style.\n- * options - {Object} An optional object with properties to set on the\n- * style.\n- *\n- * Valid options:\n- * rules - {Array()} List of rules to be added to the\n- * style.\n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(style, options) {\n-\n- OpenLayers.Util.extend(this, options);\n- this.rules = [];\n- if (options && options.rules) {\n- this.addRules(options.rules);\n- }\n-\n- // use the default style from OpenLayers.Feature.Vector if no style\n- // was given in the constructor\n- this.setDefaultStyle(style ||\n- OpenLayers.Feature.Vector.style[\"default\"]);\n-\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i = 0, len = this.rules.length; i < len; i++) {\n- this.rules[i].destroy();\n- this.rules[i] = null;\n- }\n- this.rules = null;\n- this.defaultStyle = null;\n- },\n-\n- /**\n- * Method: createSymbolizer\n- * creates a style by applying all feature-dependent rules to the base\n- * style.\n- * \n- * Parameters:\n- * feature - {} feature to evaluate rules for\n- * \n- * Returns:\n- * {Object} symbolizer hash\n- */\n- createSymbolizer: function(feature) {\n- var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(\n- OpenLayers.Util.extend({}, this.defaultStyle), feature);\n-\n- var rules = this.rules;\n-\n- var rule, context;\n- var elseRules = [];\n- var appliedRules = false;\n- for (var i = 0, len = rules.length; i < len; i++) {\n- rule = rules[i];\n- // does the rule apply?\n- var applies = rule.evaluate(feature);\n-\n- if (applies) {\n- if (rule instanceof OpenLayers.Rule && rule.elseFilter) {\n- elseRules.push(rule);\n- } else {\n- appliedRules = true;\n- this.applySymbolizer(rule, style, feature);\n- }\n- }\n- }\n-\n- // if no other rules apply, apply the rules with else filters\n- if (appliedRules == false && elseRules.length > 0) {\n- appliedRules = true;\n- for (var i = 0, len = elseRules.length; i < len; i++) {\n- this.applySymbolizer(elseRules[i], style, feature);\n- }\n- }\n-\n- // don't display if there were rules but none applied\n- if (rules.length > 0 && appliedRules == false) {\n- style.display = \"none\";\n- }\n-\n- if (style.label != null && typeof style.label !== \"string\") {\n- style.label = String(style.label);\n- }\n-\n- return style;\n- },\n-\n- /**\n- * Method: applySymbolizer\n- *\n- * Parameters:\n- * rule - {}\n- * style - {Object}\n- * feature - {}\n- *\n- * Returns:\n- * {Object} A style with new symbolizer applied.\n- */\n- applySymbolizer: function(rule, style, feature) {\n- var symbolizerPrefix = feature.geometry ?\n- this.getSymbolizerPrefix(feature.geometry) :\n- OpenLayers.Style.SYMBOLIZER_PREFIXES[0];\n-\n- var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;\n-\n- if (this.defaultsPerSymbolizer === true) {\n- var defaults = this.defaultStyle;\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- pointRadius: defaults.pointRadius\n- });\n- if (symbolizer.stroke === true || symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- strokeWidth: defaults.strokeWidth,\n- strokeColor: defaults.strokeColor,\n- strokeOpacity: defaults.strokeOpacity,\n- strokeDashstyle: defaults.strokeDashstyle,\n- strokeLinecap: defaults.strokeLinecap\n- });\n- }\n- if (symbolizer.fill === true || symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- fillColor: defaults.fillColor,\n- fillOpacity: defaults.fillOpacity\n- });\n- }\n- if (symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- pointRadius: this.defaultStyle.pointRadius,\n- externalGraphic: this.defaultStyle.externalGraphic,\n- graphicName: this.defaultStyle.graphicName,\n- graphicOpacity: this.defaultStyle.graphicOpacity,\n- graphicWidth: this.defaultStyle.graphicWidth,\n- graphicHeight: this.defaultStyle.graphicHeight,\n- graphicXOffset: this.defaultStyle.graphicXOffset,\n- graphicYOffset: this.defaultStyle.graphicYOffset\n- });\n- }\n- }\n-\n- // merge the style with the current style\n- return this.createLiterals(\n- OpenLayers.Util.extend(style, symbolizer), feature);\n- },\n-\n- /**\n- * Method: createLiterals\n- * creates literals for all style properties that have an entry in\n- * .\n- * \n- * Parameters:\n- * style - {Object} style to create literals for. Will be modified\n- * inline.\n- * feature - {Object}\n- * \n- * Returns:\n- * {Object} the modified style\n- */\n- createLiterals: function(style, feature) {\n- var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);\n- OpenLayers.Util.extend(context, this.context);\n-\n- for (var i in this.propertyStyles) {\n- style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);\n- }\n- return style;\n- },\n-\n- /**\n- * Method: findPropertyStyles\n- * Looks into all rules for this style and the defaultStyle to collect\n- * all the style hash property names containing ${...} strings that have\n- * to be replaced using the createLiteral method before returning them.\n- * \n- * Returns:\n- * {Object} hash of property names that need createLiteral parsing. The\n- * name of the property is the key, and the value is true;\n- */\n- findPropertyStyles: function() {\n- var propertyStyles = {};\n-\n- // check the default style\n- var style = this.defaultStyle;\n- this.addPropertyStyles(propertyStyles, style);\n-\n- // walk through all rules to check for properties in their symbolizer\n- var rules = this.rules;\n- var symbolizer, value;\n- for (var i = 0, len = rules.length; i < len; i++) {\n- symbolizer = rules[i].symbolizer;\n- for (var key in symbolizer) {\n- value = symbolizer[key];\n- if (typeof value == \"object\") {\n- // symbolizer key is \"Point\", \"Line\" or \"Polygon\"\n- this.addPropertyStyles(propertyStyles, value);\n- } else {\n- // symbolizer is a hash of style properties\n- this.addPropertyStyles(propertyStyles, symbolizer);\n- break;\n- }\n- }\n- }\n- return propertyStyles;\n- },\n-\n- /**\n- * Method: addPropertyStyles\n- * \n- * Parameters:\n- * propertyStyles - {Object} hash to add new property styles to. Will be\n- * modified inline\n- * symbolizer - {Object} search this symbolizer for property styles\n- * \n- * Returns:\n- * {Object} propertyStyles hash\n- */\n- addPropertyStyles: function(propertyStyles, symbolizer) {\n- var property;\n- for (var key in symbolizer) {\n- property = symbolizer[key];\n- if (typeof property == \"string\" &&\n- property.match(/\\$\\{\\w+\\}/)) {\n- propertyStyles[key] = true;\n- }\n- }\n- return propertyStyles;\n- },\n-\n- /**\n- * APIMethod: addRules\n- * Adds rules to this style.\n- * \n- * Parameters:\n- * rules - {Array()}\n- */\n- addRules: function(rules) {\n- Array.prototype.push.apply(this.rules, rules);\n- this.propertyStyles = this.findPropertyStyles();\n- },\n-\n- /**\n- * APIMethod: setDefaultStyle\n- * Sets the default style for this style object.\n- * \n- * Parameters:\n- * style - {Object} Hash of style properties\n- */\n- setDefaultStyle: function(style) {\n- this.defaultStyle = style;\n- this.propertyStyles = this.findPropertyStyles();\n- },\n-\n- /**\n- * Method: getSymbolizerPrefix\n- * Returns the correct symbolizer prefix according to the\n- * geometry type of the passed geometry\n- * \n- * Parameters:\n- * geometry - {}\n- * \n- * Returns:\n- * {String} key of the according symbolizer\n- */\n- getSymbolizerPrefix: function(geometry) {\n- var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;\n- for (var i = 0, len = prefixes.length; i < len; i++) {\n- if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {\n- return prefixes[i];\n- }\n- }\n- },\n-\n- /**\n- * APIMethod: clone\n- * Clones this style.\n- * \n- * Returns:\n- * {} Clone of this style.\n- */\n- clone: function() {\n- var options = OpenLayers.Util.extend({}, this);\n- // clone rules\n- if (this.rules) {\n- options.rules = [];\n- for (var i = 0, len = this.rules.length; i < len; ++i) {\n- options.rules.push(this.rules[i].clone());\n- }\n- }\n- // clone context\n- options.context = this.context && OpenLayers.Util.extend({}, this.context);\n- //clone default style\n- var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);\n- return new OpenLayers.Style(defaultStyle, options);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Style\"\n-});\n-\n-\n-/**\n- * Function: createLiteral\n- * converts a style value holding a combination of PropertyName and Literal\n- * into a Literal, taking the property values from the passed features.\n- * \n- * Parameters:\n- * value - {String} value to parse. If this string contains a construct like\n- * \"foo ${bar}\", then \"foo \" will be taken as literal, and \"${bar}\"\n- * will be replaced by the value of the \"bar\" attribute of the passed\n- * feature.\n- * context - {Object} context to take attribute values from\n- * feature - {} optional feature to pass to\n- * for evaluating functions in the\n- * context.\n- * property - {String} optional, name of the property for which the literal is\n- * being created for evaluating functions in the context.\n- * \n- * Returns:\n- * {String} the parsed value. In the example of the value parameter above, the\n- * result would be \"foo valueOfBar\", assuming that the passed feature has an\n- * attribute named \"bar\" with the value \"valueOfBar\".\n- */\n-OpenLayers.Style.createLiteral = function(value, context, feature, property) {\n- if (typeof value == \"string\" && value.indexOf(\"${\") != -1) {\n- value = OpenLayers.String.format(value, context, [feature, property]);\n- value = (isNaN(value) || !value) ? value : parseFloat(value);\n- }\n- return value;\n-};\n-\n-/**\n- * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES\n- * {Array} prefixes of the sld symbolizers. These are the\n- * same as the main geometry types\n- */\n-OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',\n- 'Raster'\n-];\n-/* ======================================================================\n- OpenLayers/Filter.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Style.js\n- */\n-\n-/**\n- * Class: OpenLayers.Filter\n- * This class represents an OGC Filter.\n- */\n-OpenLayers.Filter = OpenLayers.Class({\n-\n- /** \n- * Constructor: OpenLayers.Filter\n- * This class represents a generic filter.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- },\n-\n- /** \n- * APIMethod: destroy\n- * Remove reference to anything added.\n- */\n- destroy: function() {},\n-\n- /**\n- * APIMethod: evaluate\n- * Evaluates this filter in a specific context. Instances or subclasses\n- * are supposed to override this method.\n- * \n- * Parameters:\n- * context - {Object} Context to use in evaluating the filter. If a vector\n- * feature is provided, the feature.attributes will be used as context.\n- * \n- * Returns:\n- * {Boolean} The filter applies.\n- */\n- evaluate: function(context) {\n- return true;\n- },\n-\n- /**\n- * APIMethod: clone\n- * Clones this filter. Should be implemented by subclasses.\n- * \n- * Returns:\n- * {} Clone of this filter.\n- */\n- clone: function() {\n- return null;\n- },\n-\n- /**\n- * APIMethod: toString\n- *\n- * Returns:\n- * {String} Include in your build to get a CQL\n- * representation of the filter returned. Otherwise \"[Object object]\"\n- * will be returned.\n- */\n- toString: function() {\n- var string;\n- if (OpenLayers.Format && OpenLayers.Format.CQL) {\n- string = OpenLayers.Format.CQL.prototype.write(this);\n- } else {\n- string = Object.prototype.toString.call(this);\n- }\n- return string;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Filter\"\n-});\n-/* ======================================================================\n OpenLayers/Filter/Spatial.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -24416,974 +26292,1463 @@\n OpenLayers.Util.extend(this, options);\n },\n \n CLASS_NAME: \"OpenLayers.WPSProcess.ChainLink\"\n \n });\n /* ======================================================================\n- OpenLayers/Format/WPSDescribeProcess.js\n+ OpenLayers/Popup.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Format/XML.js\n- * @requires OpenLayers/Format/OWSCommon/v1_1_0.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n */\n \n+\n /**\n- * Class: OpenLayers.Format.WPSDescribeProcess\n- * Read WPS DescribeProcess responses. \n+ * Class: OpenLayers.Popup\n+ * A popup is a small div that can opened and closed on the map.\n+ * Typically opened in response to clicking on a marker. \n+ * See . Popup's don't require their own\n+ * layer and are added the the map using the \n+ * method.\n *\n- * Inherits from:\n- * - \n+ * Example:\n+ * (code)\n+ * popup = new OpenLayers.Popup(\"chicken\", \n+ * new OpenLayers.LonLat(5,40),\n+ * new OpenLayers.Size(200,200),\n+ * \"example popup\",\n+ * true);\n+ * \n+ * map.addPopup(popup);\n+ * (end)\n */\n-OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(\n- OpenLayers.Format.XML, {\n+OpenLayers.Popup = OpenLayers.Class({\n \n- /**\n- * Constant: VERSION\n- * {String} 1.0.0\n- */\n- VERSION: \"1.0.0\",\n+ /** \n+ * Property: events \n+ * {} custom event manager \n+ */\n+ events: null,\n \n- /**\n- * Property: namespaces\n- * {Object} Mapping of namespace aliases to namespace URIs.\n- */\n- namespaces: {\n- wps: \"http://www.opengis.net/wps/1.0.0\",\n- ows: \"http://www.opengis.net/ows/1.1\",\n- xsi: \"http://www.w3.org/2001/XMLSchema-instance\"\n- },\n+ /** Property: id\n+ * {String} the unique identifier assigned to this popup.\n+ */\n+ id: \"\",\n \n- /**\n- * Property: schemaLocation\n- * {String} Schema location\n- */\n- schemaLocation: \"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\",\n+ /** \n+ * Property: lonlat \n+ * {} the position of this popup on the map\n+ */\n+ lonlat: null,\n \n- /**\n- * Property: defaultPrefix\n- */\n- defaultPrefix: \"wps\",\n+ /** \n+ * Property: div \n+ * {DOMElement} the div that contains this popup.\n+ */\n+ div: null,\n \n- /**\n- * Property: regExes\n- * Compiled regular expressions for manipulating strings.\n- */\n- regExes: {\n- trimSpace: (/^\\s*|\\s*$/g),\n- removeSpace: (/\\s*/g),\n- splitSpace: (/\\s+/),\n- trimComma: (/\\s*,\\s*/g)\n- },\n+ /** \n+ * Property: contentSize \n+ * {} the width and height of the content.\n+ */\n+ contentSize: null,\n \n- /**\n- * Constructor: OpenLayers.Format.WPSDescribeProcess\n- *\n- * Parameters:\n- * options - {Object} An optional object whose properties will be set on\n- * this instance.\n- */\n+ /** \n+ * Property: size \n+ * {} the width and height of the popup.\n+ */\n+ size: null,\n \n- /**\n- * APIMethod: read\n- * Parse a WPS DescribeProcess and return an object with its information.\n- * \n- * Parameters: \n- * data - {String} or {DOMElement} data to read/parse.\n- *\n- * Returns:\n- * {Object}\n- */\n- read: function(data) {\n- if (typeof data == \"string\") {\n- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n- }\n- if (data && data.nodeType == 9) {\n- data = data.documentElement;\n- }\n- var info = {};\n- this.readNode(data, info);\n- return info;\n- },\n+ /** \n+ * Property: contentHTML \n+ * {String} An HTML string for this popup to display.\n+ */\n+ contentHTML: null,\n \n- /**\n- * Property: readers\n- * Contains public functions, grouped by namespace prefix, that will\n- * be applied when a namespaced node is found matching the function\n- * name. The function will be applied in the scope of this parser\n- * with two arguments: the node being read and a context object passed\n- * from the parent.\n- */\n- readers: {\n- \"wps\": {\n- \"ProcessDescriptions\": function(node, obj) {\n- obj.processDescriptions = {};\n- this.readChildNodes(node, obj.processDescriptions);\n- },\n- \"ProcessDescription\": function(node, processDescriptions) {\n- var processVersion = this.getAttributeNS(node, this.namespaces.wps, \"processVersion\");\n- var processDescription = {\n- processVersion: processVersion,\n- statusSupported: (node.getAttribute(\"statusSupported\") === \"true\"),\n- storeSupported: (node.getAttribute(\"storeSupported\") === \"true\")\n- };\n- this.readChildNodes(node, processDescription);\n- processDescriptions[processDescription.identifier] = processDescription;\n- },\n- \"DataInputs\": function(node, processDescription) {\n- processDescription.dataInputs = [];\n- this.readChildNodes(node, processDescription.dataInputs);\n- },\n- \"ProcessOutputs\": function(node, processDescription) {\n- processDescription.processOutputs = [];\n- this.readChildNodes(node, processDescription.processOutputs);\n- },\n- \"Output\": function(node, processOutputs) {\n- var output = {};\n- this.readChildNodes(node, output);\n- processOutputs.push(output);\n- },\n- \"ComplexOutput\": function(node, output) {\n- output.complexOutput = {};\n- this.readChildNodes(node, output.complexOutput);\n- },\n- \"LiteralOutput\": function(node, output) {\n- output.literalOutput = {};\n- this.readChildNodes(node, output.literalOutput);\n- },\n- \"Input\": function(node, dataInputs) {\n- var input = {\n- maxOccurs: parseInt(node.getAttribute(\"maxOccurs\")),\n- minOccurs: parseInt(node.getAttribute(\"minOccurs\"))\n- };\n- this.readChildNodes(node, input);\n- dataInputs.push(input);\n- },\n- \"BoundingBoxData\": function(node, input) {\n- input.boundingBoxData = {};\n- this.readChildNodes(node, input.boundingBoxData);\n- },\n- \"CRS\": function(node, obj) {\n- if (!obj.CRSs) {\n- obj.CRSs = {};\n- }\n- obj.CRSs[this.getChildValue(node)] = true;\n- },\n- \"LiteralData\": function(node, input) {\n- input.literalData = {};\n- this.readChildNodes(node, input.literalData);\n- },\n- \"ComplexData\": function(node, input) {\n- input.complexData = {};\n- this.readChildNodes(node, input.complexData);\n- },\n- \"Default\": function(node, complexData) {\n- complexData[\"default\"] = {};\n- this.readChildNodes(node, complexData[\"default\"]);\n- },\n- \"Supported\": function(node, complexData) {\n- complexData[\"supported\"] = {};\n- this.readChildNodes(node, complexData[\"supported\"]);\n- },\n- \"Format\": function(node, obj) {\n- var format = {};\n- this.readChildNodes(node, format);\n- if (!obj.formats) {\n- obj.formats = {};\n- }\n- obj.formats[format.mimeType] = true;\n- },\n- \"MimeType\": function(node, format) {\n- format.mimeType = this.getChildValue(node);\n- }\n- },\n- \"ows\": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers[\"ows\"]\n- },\n+ /** \n+ * Property: backgroundColor \n+ * {String} the background color used by the popup.\n+ */\n+ backgroundColor: \"\",\n \n- CLASS_NAME: \"OpenLayers.Format.WPSDescribeProcess\"\n+ /** \n+ * Property: opacity \n+ * {float} the opacity of this popup (between 0.0 and 1.0)\n+ */\n+ opacity: \"\",\n \n- });\n-/* ======================================================================\n- OpenLayers/WPSClient.js\n- ====================================================================== */\n+ /** \n+ * Property: border \n+ * {String} the border size of the popup. (eg 2px)\n+ */\n+ border: \"\",\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ /** \n+ * Property: contentDiv \n+ * {DOMElement} a reference to the element that holds the content of\n+ * the div.\n+ */\n+ contentDiv: null,\n \n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n+ /** \n+ * Property: groupDiv \n+ * {DOMElement} First and only child of 'div'. The group Div contains the\n+ * 'contentDiv' and the 'closeDiv'.\n+ */\n+ groupDiv: null,\n \n-/**\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/WPSProcess.js\n- * @requires OpenLayers/Format/WPSDescribeProcess.js\n- * @requires OpenLayers/Request.js\n- */\n+ /** \n+ * Property: closeDiv\n+ * {DOMElement} the optional closer image\n+ */\n+ closeDiv: null,\n \n-/**\n- * Class: OpenLayers.WPSClient\n- * High level API for interaction with Web Processing Services (WPS).\n- * An instance is used to create \n- * instances for servers known to the WPSClient. The WPSClient also caches\n- * DescribeProcess responses to reduce the number of requests sent to servers\n- * when processes are created.\n- */\n-OpenLayers.WPSClient = OpenLayers.Class({\n+ /** \n+ * APIProperty: autoSize\n+ * {Boolean} Resize the popup to auto-fit the contents.\n+ * Default is false.\n+ */\n+ autoSize: false,\n \n /**\n- * Property: servers\n- * {Object} Service metadata, keyed by a local identifier.\n- *\n- * Properties:\n- * url - {String} the url of the server\n- * version - {String} WPS version of the server\n- * processDescription - {Object} Cache of raw DescribeProcess\n- * responses, keyed by process identifier.\n+ * APIProperty: minSize\n+ * {} Minimum size allowed for the popup's contents.\n */\n- servers: null,\n+ minSize: null,\n \n /**\n- * Property: version\n- * {String} The default WPS version to use if none is configured. Default\n- * is '1.0.0'.\n+ * APIProperty: maxSize\n+ * {} Maximum size allowed for the popup's contents.\n */\n- version: '1.0.0',\n+ maxSize: null,\n \n- /**\n- * Property: lazy\n- * {Boolean} Should the DescribeProcess be deferred until a process is\n- * fully configured? Default is false.\n+ /** \n+ * Property: displayClass\n+ * {String} The CSS class of the popup.\n */\n- lazy: false,\n+ displayClass: \"olPopup\",\n \n- /**\n- * Property: events\n- * {}\n- *\n- * Supported event types:\n- * describeprocess - Fires when the process description is available.\n- * Listeners receive an object with a 'raw' property holding the raw\n- * DescribeProcess response, and an 'identifier' property holding the\n- * process identifier of the described process.\n+ /** \n+ * Property: contentDisplayClass\n+ * {String} The CSS class of the popup content div.\n */\n- events: null,\n+ contentDisplayClass: \"olPopupContent\",\n \n- /**\n- * Constructor: OpenLayers.WPSClient\n- *\n- * Parameters:\n- * options - {Object} Object whose properties will be set on the instance.\n- *\n- * Avaliable options:\n- * servers - {Object} Mandatory. Service metadata, keyed by a local\n- * identifier. Can either be a string with the service url or an\n- * object literal with additional metadata:\n- *\n- * (code)\n- * servers: {\n- * local: '/geoserver/wps'\n- * }, {\n- * opengeo: {\n- * url: 'http://demo.opengeo.org/geoserver/wps',\n- * version: '1.0.0'\n- * }\n- * }\n- * (end)\n- *\n- * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be\n- * requested until a process is fully configured. Default is false.\n+ /** \n+ * Property: padding \n+ * {int or } An extra opportunity to specify internal \n+ * padding of the content div inside the popup. This was originally\n+ * confused with the css padding as specified in style.css's \n+ * 'olPopupContent' class. We would like to get rid of this altogether,\n+ * except that it does come in handy for the framed and anchoredbubble\n+ * popups, who need to maintain yet another barrier between their \n+ * content and the outer border of the popup itself. \n+ * \n+ * Note that in order to not break API, we must continue to support \n+ * this property being set as an integer. Really, though, we'd like to \n+ * have this specified as a Bounds object so that user can specify\n+ * distinct left, top, right, bottom paddings. With the 3.0 release\n+ * we can make this only a bounds.\n */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.events = new OpenLayers.Events(this);\n- this.servers = {};\n- for (var s in options.servers) {\n- this.servers[s] = typeof options.servers[s] == 'string' ? {\n- url: options.servers[s],\n- version: this.version,\n- processDescription: {}\n- } : options.servers[s];\n- }\n- },\n+ padding: 0,\n \n- /**\n- * APIMethod: execute\n- * Shortcut to execute a process with a single function call. This is\n- * equivalent to using and then calling execute on the\n- * process.\n- *\n- * Parameters:\n- * options - {Object} Options for the execute operation.\n- *\n- * Available options:\n- * server - {String} Mandatory. One of the local identifiers of the\n- * configured servers.\n- * process - {String} Mandatory. A process identifier known to the\n- * server.\n- * inputs - {Object} The inputs for the process, keyed by input identifier.\n- * For spatial data inputs, the value of an input is usually an\n- * , an or an array of\n- * geometries or features.\n- * output - {String} The identifier of an output to parse. Optional. If not\n- * provided, the first output will be parsed.\n- * success - {Function} Callback to call when the process is complete.\n- * This function is called with an outputs object as argument, which\n- * will have a property with the identifier of the requested output\n- * (e.g. 'result'). For processes that generate spatial output, the\n- * value will either be a single or an\n- * array of features.\n- * scope - {Object} Optional scope for the success callback.\n+ /** \n+ * Property: disableFirefoxOverflowHack\n+ * {Boolean} The hack for overflow in Firefox causes all elements \n+ * to be re-drawn, which causes Flash elements to be \n+ * re-initialized, which is troublesome.\n+ * With this property the hack can be disabled.\n */\n- execute: function(options) {\n- var process = this.getProcess(options.server, options.process);\n- process.execute({\n- inputs: options.inputs,\n- success: options.success,\n- scope: options.scope\n- });\n- },\n+ disableFirefoxOverflowHack: false,\n \n /**\n- * APIMethod: getProcess\n- * Creates an .\n- *\n- * Parameters:\n- * serverID - {String} Local identifier from the servers that this instance\n- * was constructed with.\n- * processID - {String} Process identifier known to the server.\n- *\n- * Returns:\n- * {}\n+ * Method: fixPadding\n+ * To be removed in 3.0, this function merely helps us to deal with the \n+ * case where the user may have set an integer value for padding, \n+ * instead of an object.\n */\n- getProcess: function(serverID, processID) {\n- var process = new OpenLayers.WPSProcess({\n- client: this,\n- server: serverID,\n- identifier: processID\n- });\n- if (!this.lazy) {\n- process.describe();\n+ fixPadding: function() {\n+ if (typeof this.padding == \"number\") {\n+ this.padding = new OpenLayers.Bounds(\n+ this.padding, this.padding, this.padding, this.padding\n+ );\n }\n- return process;\n },\n \n /**\n- * Method: describeProcess\n- *\n- * Parameters:\n- * serverID - {String} Identifier of the server\n- * processID - {String} Identifier of the requested process\n- * callback - {Function} Callback to call when the description is available\n- * scope - {Object} Optional execution scope for the callback function\n+ * APIProperty: panMapIfOutOfView\n+ * {Boolean} When drawn, pan map such that the entire popup is visible in\n+ * the current viewport (if necessary).\n+ * Default is false.\n */\n- describeProcess: function(serverID, processID, callback, scope) {\n- var server = this.servers[serverID];\n- if (!server.processDescription[processID]) {\n- if (!(processID in server.processDescription)) {\n- // set to null so we know a describeFeature request is pending\n- server.processDescription[processID] = null;\n- OpenLayers.Request.GET({\n- url: server.url,\n- params: {\n- SERVICE: 'WPS',\n- VERSION: server.version,\n- REQUEST: 'DescribeProcess',\n- IDENTIFIER: processID\n- },\n- success: function(response) {\n- server.processDescription[processID] = response.responseText;\n- this.events.triggerEvent('describeprocess', {\n- identifier: processID,\n- raw: response.responseText\n- });\n- },\n- scope: this\n- });\n- } else {\n- // pending request\n- this.events.register('describeprocess', this, function describe(evt) {\n- if (evt.identifier === processID) {\n- this.events.unregister('describeprocess', this, describe);\n- callback.call(scope, evt.raw);\n- }\n- });\n- }\n- } else {\n- window.setTimeout(function() {\n- callback.call(scope, server.processDescription[processID]);\n- }, 0);\n- }\n- },\n+ panMapIfOutOfView: false,\n \n /**\n- * Method: destroy\n+ * APIProperty: keepInMap \n+ * {Boolean} If panMapIfOutOfView is false, and this property is true, \n+ * contrain the popup such that it always fits in the available map\n+ * space. By default, this is not set on the base class. If you are\n+ * creating popups that are near map edges and not allowing pannning,\n+ * and especially if you have a popup which has a\n+ * fixedRelativePosition, setting this to false may be a smart thing to\n+ * do. Subclasses may want to override this setting.\n+ * \n+ * Default is false.\n */\n- destroy: function() {\n- this.events.destroy();\n- this.events = null;\n- this.servers = null;\n- },\n-\n- CLASS_NAME: 'OpenLayers.WPSClient'\n-\n-});\n-/* ======================================================================\n- OpenLayers/Icon.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Icon\n- * \n- * The icon represents a graphical icon on the screen. Typically used in\n- * conjunction with a to represent markers on a screen.\n- *\n- * An icon has a url, size and position. It also contains an offset which \n- * allows the center point to be represented correctly. This can be\n- * provided either as a fixed offset or a function provided to calculate\n- * the desired offset. \n- * \n- */\n-OpenLayers.Icon = OpenLayers.Class({\n+ keepInMap: false,\n \n- /** \n- * Property: url \n- * {String} image url\n+ /**\n+ * APIProperty: closeOnMove\n+ * {Boolean} When map pans, close the popup.\n+ * Default is false.\n */\n- url: null,\n+ closeOnMove: false,\n \n /** \n- * Property: size \n- * {|Object} An OpenLayers.Size or\n- * an object with a 'w' and 'h' properties.\n+ * Property: map \n+ * {} this gets set in Map.js when the popup is added to the map\n */\n- size: null,\n+ map: null,\n \n /** \n- * Property: offset \n- * {|Object} distance in pixels to offset the\n- * image when being rendered. An OpenLayers.Pixel or an object\n- * with a 'x' and 'y' properties.\n+ * Constructor: OpenLayers.Popup\n+ * Create a popup.\n+ * \n+ * Parameters: \n+ * id - {String} a unqiue identifier for this popup. If null is passed\n+ * an identifier will be automatically generated. \n+ * lonlat - {} The position on the map the popup will\n+ * be shown.\n+ * contentSize - {} The size of the content.\n+ * contentHTML - {String} An HTML string to display inside the \n+ * popup.\n+ * closeBox - {Boolean} Whether to display a close box inside\n+ * the popup.\n+ * closeBoxCallback - {Function} Function to be called on closeBox click.\n */\n- offset: null,\n+ initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {\n+ if (id == null) {\n+ id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ }\n \n- /** \n- * Property: calculateOffset \n- * {Function} Function to calculate the offset (based on the size)\n- */\n- calculateOffset: null,\n+ this.id = id;\n+ this.lonlat = lonlat;\n \n- /** \n- * Property: imageDiv \n- * {DOMElement} \n- */\n- imageDiv: null,\n+ this.contentSize = (contentSize != null) ? contentSize :\n+ new OpenLayers.Size(\n+ OpenLayers.Popup.WIDTH,\n+ OpenLayers.Popup.HEIGHT);\n+ if (contentHTML != null) {\n+ this.contentHTML = contentHTML;\n+ }\n+ this.backgroundColor = OpenLayers.Popup.COLOR;\n+ this.opacity = OpenLayers.Popup.OPACITY;\n+ this.border = OpenLayers.Popup.BORDER;\n \n- /** \n- * Property: px \n- * {|Object} An OpenLayers.Pixel or an object\n- * with a 'x' and 'y' properties.\n- */\n- px: null,\n+ this.div = OpenLayers.Util.createDiv(this.id, null, null,\n+ null, null, null, \"hidden\");\n+ this.div.className = this.displayClass;\n \n- /** \n- * Constructor: OpenLayers.Icon\n- * Creates an icon, which is an image tag in a div. \n- *\n- * url - {String} \n- * size - {|Object} An OpenLayers.Size or an\n- * object with a 'w' and 'h'\n- * properties.\n- * offset - {|Object} An OpenLayers.Pixel or an\n- * object with a 'x' and 'y'\n- * properties.\n- * calculateOffset - {Function} \n- */\n- initialize: function(url, size, offset, calculateOffset) {\n- this.url = url;\n- this.size = size || {\n- w: 20,\n- h: 20\n- };\n- this.offset = offset || {\n- x: -(this.size.w / 2),\n- y: -(this.size.h / 2)\n- };\n- this.calculateOffset = calculateOffset;\n+ var groupDivId = this.id + \"_GroupDiv\";\n+ this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,\n+ null, \"relative\", null,\n+ \"hidden\");\n \n- var id = OpenLayers.Util.createUniqueID(\"OL_Icon_\");\n- this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);\n+ var id = this.div.id + \"_contentDiv\";\n+ this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),\n+ null, \"relative\");\n+ this.contentDiv.className = this.contentDisplayClass;\n+ this.groupDiv.appendChild(this.contentDiv);\n+ this.div.appendChild(this.groupDiv);\n+\n+ if (closeBox) {\n+ this.addCloseBox(closeBoxCallback);\n+ }\n+\n+ this.registerEvents();\n },\n \n /** \n * Method: destroy\n- * Nullify references and remove event listeners to prevent circular \n- * references and memory leaks\n+ * nullify references to prevent circular references and memory leaks\n */\n destroy: function() {\n- // erase any drawn elements\n- this.erase();\n \n- OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);\n- this.imageDiv.innerHTML = \"\";\n- this.imageDiv = null;\n+ this.id = null;\n+ this.lonlat = null;\n+ this.size = null;\n+ this.contentHTML = null;\n+\n+ this.backgroundColor = null;\n+ this.opacity = null;\n+ this.border = null;\n+\n+ if (this.closeOnMove && this.map) {\n+ this.map.events.unregister(\"movestart\", this, this.hide);\n+ }\n+\n+ this.events.destroy();\n+ this.events = null;\n+\n+ if (this.closeDiv) {\n+ OpenLayers.Event.stopObservingElement(this.closeDiv);\n+ this.groupDiv.removeChild(this.closeDiv);\n+ }\n+ this.closeDiv = null;\n+\n+ this.div.removeChild(this.groupDiv);\n+ this.groupDiv = null;\n+\n+ if (this.map != null) {\n+ this.map.removePopup(this);\n+ }\n+ this.map = null;\n+ this.div = null;\n+\n+ this.autoSize = null;\n+ this.minSize = null;\n+ this.maxSize = null;\n+ this.padding = null;\n+ this.panMapIfOutOfView = null;\n },\n \n /** \n- * Method: clone\n+ * Method: draw\n+ * Constructs the elements that make up the popup.\n+ *\n+ * Parameters:\n+ * px - {} the position the popup in pixels.\n * \n * Returns:\n- * {} A fresh copy of the icon.\n+ * {DOMElement} Reference to a div that contains the drawn popup\n */\n- clone: function() {\n- return new OpenLayers.Icon(this.url,\n- this.size,\n- this.offset,\n- this.calculateOffset);\n+ draw: function(px) {\n+ if (px == null) {\n+ if ((this.lonlat != null) && (this.map != null)) {\n+ px = this.map.getLayerPxFromLonLat(this.lonlat);\n+ }\n+ }\n+\n+ // this assumes that this.map already exists, which is okay because \n+ // this.draw is only called once the popup has been added to the map.\n+ if (this.closeOnMove) {\n+ this.map.events.register(\"movestart\", this, this.hide);\n+ }\n+\n+ //listen to movestart, moveend to disable overflow (FF bug)\n+ if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') {\n+ this.map.events.register(\"movestart\", this, function() {\n+ var style = document.defaultView.getComputedStyle(\n+ this.contentDiv, null\n+ );\n+ var currentOverflow = style.getPropertyValue(\"overflow\");\n+ if (currentOverflow != \"hidden\") {\n+ this.contentDiv._oldOverflow = currentOverflow;\n+ this.contentDiv.style.overflow = \"hidden\";\n+ }\n+ });\n+ this.map.events.register(\"moveend\", this, function() {\n+ var oldOverflow = this.contentDiv._oldOverflow;\n+ if (oldOverflow) {\n+ this.contentDiv.style.overflow = oldOverflow;\n+ this.contentDiv._oldOverflow = null;\n+ }\n+ });\n+ }\n+\n+ this.moveTo(px);\n+ if (!this.autoSize && !this.size) {\n+ this.setSize(this.contentSize);\n+ }\n+ this.setBackgroundColor();\n+ this.setOpacity();\n+ this.setBorder();\n+ this.setContentHTML();\n+\n+ if (this.panMapIfOutOfView) {\n+ this.panIntoView();\n+ }\n+\n+ return this.div;\n },\n \n- /**\n- * Method: setSize\n- * \n- * Parameters:\n- * size - {|Object} An OpenLayers.Size or\n- * an object with a 'w' and 'h' properties.\n+ /** \n+ * Method: updatePosition\n+ * if the popup has a lonlat and its map members set, \n+ * then have it move itself to its proper position\n */\n- setSize: function(size) {\n- if (size != null) {\n- this.size = size;\n+ updatePosition: function() {\n+ if ((this.lonlat) && (this.map)) {\n+ var px = this.map.getLayerPxFromLonLat(this.lonlat);\n+ if (px) {\n+ this.moveTo(px);\n+ }\n }\n- this.draw();\n },\n \n /**\n- * Method: setUrl\n+ * Method: moveTo\n * \n * Parameters:\n- * url - {String} \n+ * px - {} the top and left position of the popup div. \n */\n- setUrl: function(url) {\n- if (url != null) {\n- this.url = url;\n+ moveTo: function(px) {\n+ if ((px != null) && (this.div != null)) {\n+ this.div.style.left = px.x + \"px\";\n+ this.div.style.top = px.y + \"px\";\n }\n- this.draw();\n },\n \n- /** \n- * Method: draw\n- * Move the div to the given pixel.\n- * \n- * Parameters:\n- * px - {|Object} An OpenLayers.Pixel or an\n- * object with a 'x' and 'y' properties.\n- * \n- * Returns:\n- * {DOMElement} A new DOM Image of this icon set at the location passed-in\n+ /**\n+ * Method: visible\n+ *\n+ * Returns: \n+ * {Boolean} Boolean indicating whether or not the popup is visible\n */\n- draw: function(px) {\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,\n- null,\n- null,\n- this.size,\n- this.url,\n- \"absolute\");\n- this.moveTo(px);\n- return this.imageDiv;\n+ visible: function() {\n+ return OpenLayers.Element.visible(this.div);\n },\n \n- /** \n- * Method: erase\n- * Erase the underlying image element.\n+ /**\n+ * Method: toggle\n+ * Toggles visibility of the popup.\n */\n- erase: function() {\n- if (this.imageDiv != null && this.imageDiv.parentNode != null) {\n- OpenLayers.Element.remove(this.imageDiv);\n+ toggle: function() {\n+ if (this.visible()) {\n+ this.hide();\n+ } else {\n+ this.show();\n }\n },\n \n- /** \n- * Method: setOpacity\n- * Change the icon's opacity\n- *\n- * Parameters:\n- * opacity - {float} \n+ /**\n+ * Method: show\n+ * Makes the popup visible.\n */\n- setOpacity: function(opacity) {\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,\n- null, null, null, null, opacity);\n+ show: function() {\n+ this.div.style.display = '';\n \n+ if (this.panMapIfOutOfView) {\n+ this.panIntoView();\n+ }\n },\n \n /**\n- * Method: moveTo\n- * move icon to passed in px.\n+ * Method: hide\n+ * Makes the popup invisible.\n+ */\n+ hide: function() {\n+ this.div.style.display = 'none';\n+ },\n+\n+ /**\n+ * Method: setSize\n+ * Used to adjust the size of the popup. \n *\n * Parameters:\n- * px - {|Object} the pixel position to move to.\n- * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n+ * contentSize - {} the new size for the popup's \n+ * contents div (in pixels).\n */\n- moveTo: function(px) {\n- //if no px passed in, use stored location\n- if (px != null) {\n- this.px = px;\n+ setSize: function(contentSize) {\n+ this.size = contentSize.clone();\n+\n+ // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n+ // must add that to the desired \"size\". \n+ var contentDivPadding = this.getContentDivPadding();\n+ var wPadding = contentDivPadding.left + contentDivPadding.right;\n+ var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n+\n+ // take into account the popup's 'padding' property\n+ this.fixPadding();\n+ wPadding += this.padding.left + this.padding.right;\n+ hPadding += this.padding.top + this.padding.bottom;\n+\n+ // make extra space for the close div\n+ if (this.closeDiv) {\n+ var closeDivWidth = parseInt(this.closeDiv.style.width);\n+ wPadding += closeDivWidth + contentDivPadding.right;\n }\n \n- if (this.imageDiv != null) {\n- if (this.px == null) {\n- this.display(false);\n- } else {\n- if (this.calculateOffset) {\n- this.offset = this.calculateOffset(this.size);\n- }\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {\n- x: this.px.x + this.offset.x,\n- y: this.px.y + this.offset.y\n- });\n- }\n+ //increase size of the main popup div to take into account the \n+ // users's desired padding and close div. \n+ this.size.w += wPadding;\n+ this.size.h += hPadding;\n+\n+ //now if our browser is IE, we need to actually make the contents \n+ // div itself bigger to take its own padding into effect. this makes \n+ // me want to shoot someone, but so it goes.\n+ if (OpenLayers.BROWSER_NAME == \"msie\") {\n+ this.contentSize.w +=\n+ contentDivPadding.left + contentDivPadding.right;\n+ this.contentSize.h +=\n+ contentDivPadding.bottom + contentDivPadding.top;\n }\n- },\n \n- /** \n- * Method: display\n- * Hide or show the icon\n- *\n- * Parameters:\n- * display - {Boolean} \n- */\n- display: function(display) {\n- this.imageDiv.style.display = (display) ? \"\" : \"none\";\n+ if (this.div != null) {\n+ this.div.style.width = this.size.w + \"px\";\n+ this.div.style.height = this.size.h + \"px\";\n+ }\n+ if (this.contentDiv != null) {\n+ this.contentDiv.style.width = contentSize.w + \"px\";\n+ this.contentDiv.style.height = contentSize.h + \"px\";\n+ }\n },\n \n-\n /**\n- * APIMethod: isDrawn\n- * \n- * Returns:\n- * {Boolean} Whether or not the icon is drawn.\n+ * APIMethod: updateSize\n+ * Auto size the popup so that it precisely fits its contents (as \n+ * determined by this.contentDiv.innerHTML). Popup size will, of\n+ * course, be limited by the available space on the current map\n */\n- isDrawn: function() {\n- // nodeType 11 for ie, whose nodes *always* have a parentNode\n- // (of type document fragment)\n- var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&\n- (this.imageDiv.parentNode.nodeType != 11));\n+ updateSize: function() {\n \n- return isDrawn;\n- },\n+ // determine actual render dimensions of the contents by putting its\n+ // contents into a fake contentDiv (for the CSS) and then measuring it\n+ var preparedHTML = \"
\" +\n+ this.contentDiv.innerHTML +\n+ \"
\";\n \n- CLASS_NAME: \"OpenLayers.Icon\"\n-});\n-/* ======================================================================\n- OpenLayers/Protocol.js\n- ====================================================================== */\n+ var containerElement = (this.map) ? this.map.div : document.body;\n+ var realSize = OpenLayers.Util.getRenderedDimensions(\n+ preparedHTML, null, {\n+ displayClass: this.displayClass,\n+ containerElement: containerElement\n+ }\n+ );\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ // is the \"real\" size of the div is safe to display in our map?\n+ var safeSize = this.getSafeContentSize(realSize);\n \n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n+ var newSize = null;\n+ if (safeSize.equals(realSize)) {\n+ //real size of content is small enough to fit on the map, \n+ // so we use real size.\n+ newSize = realSize;\n \n-/**\n- * Class: OpenLayers.Protocol\n- * Abstract vector layer protocol class. Not to be instantiated directly. Use\n- * one of the protocol subclasses instead.\n- */\n-OpenLayers.Protocol = OpenLayers.Class({\n+ } else {\n \n- /**\n- * Property: format\n- * {} The format used by this protocol.\n- */\n- format: null,\n+ // make a new 'size' object with the clipped dimensions \n+ // set or null if not clipped.\n+ var fixedSize = {\n+ w: (safeSize.w < realSize.w) ? safeSize.w : null,\n+ h: (safeSize.h < realSize.h) ? safeSize.h : null\n+ };\n \n- /**\n- * Property: options\n- * {Object} Any options sent to the constructor.\n- */\n- options: null,\n+ if (fixedSize.w && fixedSize.h) {\n+ //content is too big in both directions, so we will use \n+ // max popup size (safeSize), knowing well that it will \n+ // overflow both ways. \n+ newSize = safeSize;\n+ } else {\n+ //content is clipped in only one direction, so we need to \n+ // run getRenderedDimensions() again with a fixed dimension\n+ var clippedSize = OpenLayers.Util.getRenderedDimensions(\n+ preparedHTML, fixedSize, {\n+ displayClass: this.contentDisplayClass,\n+ containerElement: containerElement\n+ }\n+ );\n \n- /**\n- * Property: autoDestroy\n- * {Boolean} The creator of the protocol can set autoDestroy to false\n- * to fully control when the protocol is destroyed. Defaults to\n- * true.\n- */\n- autoDestroy: true,\n+ //if the clipped size is still the same as the safeSize, \n+ // that means that our content must be fixed in the \n+ // offending direction. If overflow is 'auto', this means \n+ // we are going to have a scrollbar for sure, so we must \n+ // adjust for that.\n+ //\n+ var currentOverflow = OpenLayers.Element.getStyle(\n+ this.contentDiv, \"overflow\"\n+ );\n+ if ((currentOverflow != \"hidden\") &&\n+ (clippedSize.equals(safeSize))) {\n+ var scrollBar = OpenLayers.Util.getScrollbarWidth();\n+ if (fixedSize.w) {\n+ clippedSize.h += scrollBar;\n+ } else {\n+ clippedSize.w += scrollBar;\n+ }\n+ }\n \n- /**\n- * Property: defaultFilter\n- * {} Optional default filter to read requests\n- */\n- defaultFilter: null,\n+ newSize = this.getSafeContentSize(clippedSize);\n+ }\n+ }\n+ this.setSize(newSize);\n+ },\n \n /**\n- * Constructor: OpenLayers.Protocol\n- * Abstract class for vector protocols. Create instances of a subclass.\n+ * Method: setBackgroundColor\n+ * Sets the background color of the popup.\n *\n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * color - {String} the background color. eg \"#FFBBBB\"\n */\n- initialize: function(options) {\n- options = options || {};\n- OpenLayers.Util.extend(this, options);\n- this.options = options;\n+ setBackgroundColor: function(color) {\n+ if (color != undefined) {\n+ this.backgroundColor = color;\n+ }\n+\n+ if (this.div != null) {\n+ this.div.style.backgroundColor = this.backgroundColor;\n+ }\n },\n \n /**\n- * Method: mergeWithDefaultFilter\n- * Merge filter passed to the read method with the default one\n- *\n+ * Method: setOpacity\n+ * Sets the opacity of the popup.\n+ * \n * Parameters:\n- * filter - {}\n+ * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). \n */\n- mergeWithDefaultFilter: function(filter) {\n- var merged;\n- if (filter && this.defaultFilter) {\n- merged = new OpenLayers.Filter.Logical({\n- type: OpenLayers.Filter.Logical.AND,\n- filters: [this.defaultFilter, filter]\n- });\n- } else {\n- merged = filter || this.defaultFilter || undefined;\n+ setOpacity: function(opacity) {\n+ if (opacity != undefined) {\n+ this.opacity = opacity;\n }\n- return merged;\n- },\n \n- /**\n- * APIMethod: destroy\n- * Clean up the protocol.\n- */\n- destroy: function() {\n- this.options = null;\n- this.format = null;\n+ if (this.div != null) {\n+ // for Mozilla and Safari\n+ this.div.style.opacity = this.opacity;\n+\n+ // for IE\n+ this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')';\n+ }\n },\n \n /**\n- * APIMethod: read\n- * Construct a request for reading new features.\n+ * Method: setBorder\n+ * Sets the border style of the popup.\n *\n * Parameters:\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n+ * border - {String} The border style value. eg 2px \n */\n- read: function(options) {\n- options = options || {};\n- options.filter = this.mergeWithDefaultFilter(options.filter);\n- },\n+ setBorder: function(border) {\n+ if (border != undefined) {\n+ this.border = border;\n+ }\n \n+ if (this.div != null) {\n+ this.div.style.border = this.border;\n+ }\n+ },\n \n /**\n- * APIMethod: create\n- * Construct a request for writing newly created features.\n+ * Method: setContentHTML\n+ * Allows the user to set the HTML content of the popup.\n *\n * Parameters:\n- * features - {Array({})} or\n- * {}\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n+ * contentHTML - {String} HTML for the div.\n */\n- create: function() {},\n+ setContentHTML: function(contentHTML) {\n+\n+ if (contentHTML != null) {\n+ this.contentHTML = contentHTML;\n+ }\n+\n+ if ((this.contentDiv != null) &&\n+ (this.contentHTML != null) &&\n+ (this.contentHTML != this.contentDiv.innerHTML)) {\n+\n+ this.contentDiv.innerHTML = this.contentHTML;\n+\n+ if (this.autoSize) {\n+\n+ //if popup has images, listen for when they finish\n+ // loading and resize accordingly\n+ this.registerImageListeners();\n+\n+ //auto size the popup to its current contents\n+ this.updateSize();\n+ }\n+ }\n+\n+ },\n \n /**\n- * APIMethod: update\n- * Construct a request updating modified features.\n- *\n- * Parameters:\n- * features - {Array({})} or\n- * {}\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n+ * Method: registerImageListeners\n+ * Called when an image contained by the popup loaded. this function\n+ * updates the popup size, then unregisters the image load listener.\n */\n- update: function() {},\n+ registerImageListeners: function() {\n+\n+ // As the images load, this function will call updateSize() to \n+ // resize the popup to fit the content div (which presumably is now\n+ // bigger than when the image was not loaded).\n+ // \n+ // If the 'panMapIfOutOfView' property is set, we will pan the newly\n+ // resized popup back into view.\n+ // \n+ // Note that this function, when called, will have 'popup' and \n+ // 'img' properties in the context.\n+ //\n+ var onImgLoad = function() {\n+ if (this.popup.id === null) { // this.popup has been destroyed!\n+ return;\n+ }\n+ this.popup.updateSize();\n+\n+ if (this.popup.visible() && this.popup.panMapIfOutOfView) {\n+ this.popup.panIntoView();\n+ }\n+\n+ OpenLayers.Event.stopObserving(\n+ this.img, \"load\", this.img._onImgLoad\n+ );\n+\n+ };\n+\n+ //cycle through the images and if their size is 0x0, that means that \n+ // they haven't been loaded yet, so we attach the listener, which \n+ // will fire when the images finish loading and will resize the \n+ // popup accordingly to its new size.\n+ var images = this.contentDiv.getElementsByTagName(\"img\");\n+ for (var i = 0, len = images.length; i < len; i++) {\n+ var img = images[i];\n+ if (img.width == 0 || img.height == 0) {\n+\n+ var context = {\n+ 'popup': this,\n+ 'img': img\n+ };\n+\n+ //expando this function to the image itself before registering\n+ // it. This way we can easily and properly unregister it.\n+ img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);\n+\n+ OpenLayers.Event.observe(img, 'load', img._onImgLoad);\n+ }\n+ }\n+ },\n \n /**\n- * APIMethod: delete\n- * Construct a request deleting a removed feature.\n- *\n+ * APIMethod: getSafeContentSize\n+ * \n * Parameters:\n- * feature - {}\n- * options - {Object} Optional object for configuring the request.\n- *\n+ * size - {} Desired size to make the popup.\n+ * \n * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n+ * {} A size to make the popup which is neither smaller\n+ * than the specified minimum size, nor bigger than the maximum \n+ * size (which is calculated relative to the size of the viewport).\n */\n- \"delete\": function() {},\n+ getSafeContentSize: function(size) {\n+\n+ var safeContentSize = size.clone();\n+\n+ // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n+ // must add that to the desired \"size\". \n+ var contentDivPadding = this.getContentDivPadding();\n+ var wPadding = contentDivPadding.left + contentDivPadding.right;\n+ var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n+\n+ // take into account the popup's 'padding' property\n+ this.fixPadding();\n+ wPadding += this.padding.left + this.padding.right;\n+ hPadding += this.padding.top + this.padding.bottom;\n+\n+ if (this.closeDiv) {\n+ var closeDivWidth = parseInt(this.closeDiv.style.width);\n+ wPadding += closeDivWidth + contentDivPadding.right;\n+ }\n+\n+ // prevent the popup from being smaller than a specified minimal size\n+ if (this.minSize) {\n+ safeContentSize.w = Math.max(safeContentSize.w,\n+ (this.minSize.w - wPadding));\n+ safeContentSize.h = Math.max(safeContentSize.h,\n+ (this.minSize.h - hPadding));\n+ }\n+\n+ // prevent the popup from being bigger than a specified maximum size\n+ if (this.maxSize) {\n+ safeContentSize.w = Math.min(safeContentSize.w,\n+ (this.maxSize.w - wPadding));\n+ safeContentSize.h = Math.min(safeContentSize.h,\n+ (this.maxSize.h - hPadding));\n+ }\n+\n+ //make sure the desired size to set doesn't result in a popup that \n+ // is bigger than the map's viewport.\n+ //\n+ if (this.map && this.map.size) {\n+\n+ var extraX = 0,\n+ extraY = 0;\n+ if (this.keepInMap && !this.panMapIfOutOfView) {\n+ var px = this.map.getPixelFromLonLat(this.lonlat);\n+ switch (this.relativePosition) {\n+ case \"tr\":\n+ extraX = px.x;\n+ extraY = this.map.size.h - px.y;\n+ break;\n+ case \"tl\":\n+ extraX = this.map.size.w - px.x;\n+ extraY = this.map.size.h - px.y;\n+ break;\n+ case \"bl\":\n+ extraX = this.map.size.w - px.x;\n+ extraY = px.y;\n+ break;\n+ case \"br\":\n+ extraX = px.x;\n+ extraY = px.y;\n+ break;\n+ default:\n+ extraX = px.x;\n+ extraY = this.map.size.h - px.y;\n+ break;\n+ }\n+ }\n+\n+ var maxY = this.map.size.h -\n+ this.map.paddingForPopups.top -\n+ this.map.paddingForPopups.bottom -\n+ hPadding - extraY;\n+\n+ var maxX = this.map.size.w -\n+ this.map.paddingForPopups.left -\n+ this.map.paddingForPopups.right -\n+ wPadding - extraX;\n+\n+ safeContentSize.w = Math.min(safeContentSize.w, maxX);\n+ safeContentSize.h = Math.min(safeContentSize.h, maxY);\n+ }\n+\n+ return safeContentSize;\n+ },\n \n /**\n- * APIMethod: commit\n- * Go over the features and for each take action\n- * based on the feature state. Possible actions are create,\n- * update and delete.\n+ * Method: getContentDivPadding\n+ * Glorious, oh glorious hack in order to determine the css 'padding' of \n+ * the contentDiv. IE/Opera return null here unless we actually add the \n+ * popup's main 'div' element (which contains contentDiv) to the DOM. \n+ * So we make it invisible and then add it to the document temporarily. \n *\n- * Parameters:\n- * features - {Array({})}\n- * options - {Object} Object whose possible keys are \"create\", \"update\",\n- * \"delete\", \"callback\" and \"scope\", the values referenced by the\n- * first three are objects as passed to the \"create\", \"update\", and\n- * \"delete\" methods, the value referenced by the \"callback\" key is\n- * a function which is called when the commit operation is complete\n- * using the scope referenced by the \"scope\" key.\n+ * Once we've taken the padding readings we need, we then remove it \n+ * from the DOM (it will actually get added to the DOM in \n+ * Map.js's addPopup)\n *\n * Returns:\n- * {Array({})} An array of\n- * objects.\n+ * {}\n */\n- commit: function() {},\n+ getContentDivPadding: function() {\n \n- /**\n- * Method: abort\n- * Abort an ongoing request.\n- *\n- * Parameters:\n- * response - {}\n- */\n- abort: function(response) {},\n+ //use cached value if we have it\n+ var contentDivPadding = this._contentDivPadding;\n+ if (!contentDivPadding) {\n+\n+ if (this.div.parentNode == null) {\n+ //make the div invisible and add it to the page \n+ this.div.style.display = \"none\";\n+ document.body.appendChild(this.div);\n+ }\n+\n+ //read the padding settings from css, put them in an OL.Bounds \n+ contentDivPadding = new OpenLayers.Bounds(\n+ OpenLayers.Element.getStyle(this.contentDiv, \"padding-left\"),\n+ OpenLayers.Element.getStyle(this.contentDiv, \"padding-bottom\"),\n+ OpenLayers.Element.getStyle(this.contentDiv, \"padding-right\"),\n+ OpenLayers.Element.getStyle(this.contentDiv, \"padding-top\")\n+ );\n+\n+ //cache the value\n+ this._contentDivPadding = contentDivPadding;\n+\n+ if (this.div.parentNode == document.body) {\n+ //remove the div from the page and make it visible again\n+ document.body.removeChild(this.div);\n+ this.div.style.display = \"\";\n+ }\n+ }\n+ return contentDivPadding;\n+ },\n \n /**\n- * Method: createCallback\n- * Returns a function that applies the given public method with resp and\n- * options arguments.\n- *\n+ * Method: addCloseBox\n+ * \n * Parameters:\n- * method - {Function} The method to be applied by the callback.\n- * response - {} The protocol response object.\n- * options - {Object} Options sent to the protocol method\n+ * callback - {Function} The callback to be called when the close button\n+ * is clicked.\n */\n- createCallback: function(method, response, options) {\n- return OpenLayers.Function.bind(function() {\n- method.apply(this, [response, options]);\n- }, this);\n- },\n+ addCloseBox: function(callback) {\n \n- CLASS_NAME: \"OpenLayers.Protocol\"\n-});\n+ this.closeDiv = OpenLayers.Util.createDiv(\n+ this.id + \"_close\", null, {\n+ w: 17,\n+ h: 17\n+ }\n+ );\n+ this.closeDiv.className = \"olPopupCloseBox\";\n \n-/**\n- * Class: OpenLayers.Protocol.Response\n- * Protocols return Response objects to their users.\n- */\n-OpenLayers.Protocol.Response = OpenLayers.Class({\n- /**\n- * Property: code\n- * {Number} - OpenLayers.Protocol.Response.SUCCESS or\n- * OpenLayers.Protocol.Response.FAILURE\n- */\n- code: null,\n+ // use the content div's css padding to determine if we should\n+ // padd the close div\n+ var contentDivPadding = this.getContentDivPadding();\n \n- /**\n- * Property: requestType\n- * {String} The type of request this response corresponds to. Either\n- * \"create\", \"read\", \"update\" or \"delete\".\n- */\n- requestType: null,\n+ this.closeDiv.style.right = contentDivPadding.right + \"px\";\n+ this.closeDiv.style.top = contentDivPadding.top + \"px\";\n+ this.groupDiv.appendChild(this.closeDiv);\n+\n+ var closePopup = callback || function(e) {\n+ this.hide();\n+ OpenLayers.Event.stop(e);\n+ };\n+ OpenLayers.Event.observe(this.closeDiv, \"touchend\",\n+ OpenLayers.Function.bindAsEventListener(closePopup, this));\n+ OpenLayers.Event.observe(this.closeDiv, \"click\",\n+ OpenLayers.Function.bindAsEventListener(closePopup, this));\n+ },\n \n /**\n- * Property: last\n- * {Boolean} - true if this is the last response expected in a commit,\n- * false otherwise, defaults to true.\n+ * Method: panIntoView\n+ * Pans the map such that the popup is totaly viewable (if necessary)\n */\n- last: true,\n+ panIntoView: function() {\n \n- /**\n- * Property: features\n- * {Array({})} or {}\n- * The features returned in the response by the server. Depending on the \n- * protocol's read payload, either features or data will be populated.\n+ var mapSize = this.map.getSize();\n+\n+ //start with the top left corner of the popup, in px, \n+ // relative to the viewport\n+ var origTL = this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(\n+ parseInt(this.div.style.left),\n+ parseInt(this.div.style.top)\n+ ));\n+ var newTL = origTL.clone();\n+\n+ //new left (compare to margins, using this.size to calculate right)\n+ if (origTL.x < this.map.paddingForPopups.left) {\n+ newTL.x = this.map.paddingForPopups.left;\n+ } else\n+ if ((origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {\n+ newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;\n+ }\n+\n+ //new top (compare to margins, using this.size to calculate bottom)\n+ if (origTL.y < this.map.paddingForPopups.top) {\n+ newTL.y = this.map.paddingForPopups.top;\n+ } else\n+ if ((origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {\n+ newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;\n+ }\n+\n+ var dx = origTL.x - newTL.x;\n+ var dy = origTL.y - newTL.y;\n+\n+ this.map.pan(dx, dy);\n+ },\n+\n+ /** \n+ * Method: registerEvents\n+ * Registers events on the popup.\n+ *\n+ * Do this in a separate function so that subclasses can \n+ * choose to override it if they wish to deal differently\n+ * with mouse events\n+ * \n+ * Note in the following handler functions that some special\n+ * care is needed to deal correctly with mousing and popups. \n+ * \n+ * Because the user might select the zoom-rectangle option and\n+ * then drag it over a popup, we need a safe way to allow the\n+ * mousemove and mouseup events to pass through the popup when\n+ * they are initiated from outside. The same procedure is needed for\n+ * touchmove and touchend events.\n+ * \n+ * Otherwise, we want to essentially kill the event propagation\n+ * for all other events, though we have to do so carefully, \n+ * without disabling basic html functionality, like clicking on \n+ * hyperlinks or drag-selecting text.\n */\n- features: null,\n+ registerEvents: function() {\n+ this.events = new OpenLayers.Events(this, this.div, null, true);\n \n- /**\n- * Property: data\n- * {Object}\n- * The data returned in the response by the server. Depending on the \n- * protocol's read payload, either features or data will be populated.\n+ function onTouchstart(evt) {\n+ OpenLayers.Event.stop(evt, true);\n+ }\n+ this.events.on({\n+ \"mousedown\": this.onmousedown,\n+ \"mousemove\": this.onmousemove,\n+ \"mouseup\": this.onmouseup,\n+ \"click\": this.onclick,\n+ \"mouseout\": this.onmouseout,\n+ \"dblclick\": this.ondblclick,\n+ \"touchstart\": onTouchstart,\n+ scope: this\n+ });\n+\n+ },\n+\n+ /** \n+ * Method: onmousedown \n+ * When mouse goes down within the popup, make a note of\n+ * it locally, and then do not propagate the mousedown \n+ * (but do so safely so that user can select text inside)\n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- data: null,\n+ onmousedown: function(evt) {\n+ this.mousedown = true;\n+ OpenLayers.Event.stop(evt, true);\n+ },\n \n- /**\n- * Property: reqFeatures\n- * {Array({})} or {}\n- * The features provided by the user and placed in the request by the\n- * protocol.\n+ /** \n+ * Method: onmousemove\n+ * If the drag was started within the popup, then \n+ * do not propagate the mousemove (but do so safely\n+ * so that user can select text inside)\n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- reqFeatures: null,\n+ onmousemove: function(evt) {\n+ if (this.mousedown) {\n+ OpenLayers.Event.stop(evt, true);\n+ }\n+ },\n \n- /**\n- * Property: priv\n+ /** \n+ * Method: onmouseup\n+ * When mouse comes up within the popup, after going down \n+ * in it, reset the flag, and then (once again) do not \n+ * propagate the event, but do so safely so that user can \n+ * select text inside\n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- priv: null,\n+ onmouseup: function(evt) {\n+ if (this.mousedown) {\n+ this.mousedown = false;\n+ OpenLayers.Event.stop(evt, true);\n+ }\n+ },\n \n /**\n- * Property: error\n- * {Object} The error object in case a service exception was encountered.\n+ * Method: onclick\n+ * Ignore clicks, but allowing default browser handling\n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- error: null,\n+ onclick: function(evt) {\n+ OpenLayers.Event.stop(evt, true);\n+ },\n \n- /**\n- * Constructor: OpenLayers.Protocol.Response\n- *\n+ /** \n+ * Method: onmouseout\n+ * When mouse goes out of the popup set the flag to false so that\n+ * if they let go and then drag back in, we won't be confused.\n+ * \n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * evt - {Event} \n */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n+ onmouseout: function(evt) {\n+ this.mousedown = false;\n },\n \n- /**\n- * Method: success\n- *\n- * Returns:\n- * {Boolean} - true on success, false otherwise\n+ /** \n+ * Method: ondblclick\n+ * Ignore double-clicks, but allowing default browser handling\n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- success: function() {\n- return this.code > 0;\n+ ondblclick: function(evt) {\n+ OpenLayers.Event.stop(evt, true);\n },\n \n- CLASS_NAME: \"OpenLayers.Protocol.Response\"\n+ CLASS_NAME: \"OpenLayers.Popup\"\n });\n \n-OpenLayers.Protocol.Response.SUCCESS = 1;\n-OpenLayers.Protocol.Response.FAILURE = 0;\n+OpenLayers.Popup.WIDTH = 200;\n+OpenLayers.Popup.HEIGHT = 200;\n+OpenLayers.Popup.COLOR = \"white\";\n+OpenLayers.Popup.OPACITY = 1;\n+OpenLayers.Popup.BORDER = \"0px\";\n /* ======================================================================\n- OpenLayers/Renderer.js\n+ OpenLayers/Control.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control\n+ * Controls affect the display or behavior of the map. They allow everything\n+ * from panning and zooming to displaying a scale indicator. Controls by \n+ * default are added to the map they are contained within however it is\n+ * possible to add a control to an external div by passing the div in the\n+ * options parameter.\n+ * \n+ * Example:\n+ * The following example shows how to add many of the common controls\n+ * to a map.\n+ * \n+ * > var map = new OpenLayers.Map('map', { controls: [] });\n+ * >\n+ * > map.addControl(new OpenLayers.Control.PanZoomBar());\n+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));\n+ * > map.addControl(new OpenLayers.Control.Permalink());\n+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));\n+ * > map.addControl(new OpenLayers.Control.MousePosition());\n+ * > map.addControl(new OpenLayers.Control.OverviewMap());\n+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());\n+ *\n+ * The next code fragment is a quick example of how to intercept \n+ * shift-mouse click to display the extent of the bounding box\n+ * dragged out by the user. Usually controls are not created\n+ * in exactly this manner. See the source for a more complete \n+ * example:\n+ *\n+ * > var control = new OpenLayers.Control();\n+ * > OpenLayers.Util.extend(control, {\n+ * > draw: function () {\n+ * > // this Handler.Box will intercept the shift-mousedown\n+ * > // before Control.MouseDefault gets to see it\n+ * > this.box = new OpenLayers.Handler.Box( control, \n+ * > {\"done\": this.notice},\n+ * > {keyMask: OpenLayers.Handler.MOD_SHIFT});\n+ * > this.box.activate();\n+ * > },\n+ * >\n+ * > notice: function (bounds) {\n+ * > OpenLayers.Console.userError(bounds);\n+ * > }\n+ * > }); \n+ * > map.addControl(control);\n+ * \n+ */\n+OpenLayers.Control = OpenLayers.Class({\n+\n+ /** \n+ * Property: id \n+ * {String} \n+ */\n+ id: null,\n+\n+ /** \n+ * Property: map \n+ * {} this gets set in the addControl() function in\n+ * OpenLayers.Map \n+ */\n+ map: null,\n+\n+ /** \n+ * APIProperty: div \n+ * {DOMElement} The element that contains the control, if not present the \n+ * control is placed inside the map.\n+ */\n+ div: null,\n+\n+ /** \n+ * APIProperty: type \n+ * {Number} Controls can have a 'type'. The type determines the type of\n+ * interactions which are possible with them when they are placed in an\n+ * . \n+ */\n+ type: null,\n+\n+ /** \n+ * Property: allowSelection\n+ * {Boolean} By default, controls do not allow selection, because\n+ * it may interfere with map dragging. If this is true, OpenLayers\n+ * will not prevent selection of the control.\n+ * Default is false.\n+ */\n+ allowSelection: false,\n+\n+ /** \n+ * Property: displayClass \n+ * {string} This property is used for CSS related to the drawing of the\n+ * Control. \n+ */\n+ displayClass: \"\",\n+\n+ /**\n+ * APIProperty: title \n+ * {string} This property is used for showing a tooltip over the \n+ * Control. \n+ */\n+ title: \"\",\n+\n+ /**\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * false.\n+ */\n+ autoActivate: false,\n+\n+ /** \n+ * APIProperty: active \n+ * {Boolean} The control is active (read-only). Use and \n+ * to change control state.\n+ */\n+ active: null,\n+\n+ /**\n+ * Property: handlerOptions\n+ * {Object} Used to set non-default properties on the control's handler\n+ */\n+ handlerOptions: null,\n+\n+ /** \n+ * Property: handler \n+ * {} null\n+ */\n+ handler: null,\n+\n+ /**\n+ * APIProperty: eventListeners\n+ * {Object} If set as an option at construction, the eventListeners\n+ * object will be registered with . Object\n+ * structure must be a listeners object as shown in the example for\n+ * the events.on method.\n+ */\n+ eventListeners: null,\n+\n+ /** \n+ * APIProperty: events\n+ * {} Events instance for listeners and triggering\n+ * control specific events.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * control.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Listeners will be called with a reference to an event object. The\n+ * properties of this event depends on exactly what happened.\n+ *\n+ * All event objects have at least the following properties:\n+ * object - {Object} A reference to control.events.object (a reference\n+ * to the control).\n+ * element - {DOMElement} A reference to control.events.element (which\n+ * will be null unless documented otherwise).\n+ *\n+ * Supported map event types:\n+ * activate - Triggered when activated.\n+ * deactivate - Triggered when deactivated.\n+ */\n+ events: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Control\n+ * Create an OpenLayers Control. The options passed as a parameter\n+ * directly extend the control. For example passing the following:\n+ * \n+ * > var control = new OpenLayers.Control({div: myDiv});\n+ *\n+ * Overrides the default div attribute value of null.\n+ * \n+ * Parameters:\n+ * options - {Object} \n+ */\n+ initialize: function(options) {\n+ // We do this before the extend so that instances can override\n+ // className in options.\n+ this.displayClass =\n+ this.CLASS_NAME.replace(\"OpenLayers.\", \"ol\").replace(/\\./g, \"\");\n+\n+ OpenLayers.Util.extend(this, options);\n+\n+ this.events = new OpenLayers.Events(this);\n+ if (this.eventListeners instanceof Object) {\n+ this.events.on(this.eventListeners);\n+ }\n+ if (this.id == null) {\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ }\n+ },\n+\n+ /**\n+ * Method: destroy\n+ * The destroy method is used to perform any clean up before the control\n+ * is dereferenced. Typically this is where event listeners are removed\n+ * to prevent memory leaks.\n+ */\n+ destroy: function() {\n+ if (this.events) {\n+ if (this.eventListeners) {\n+ this.events.un(this.eventListeners);\n+ }\n+ this.events.destroy();\n+ this.events = null;\n+ }\n+ this.eventListeners = null;\n+\n+ // eliminate circular references\n+ if (this.handler) {\n+ this.handler.destroy();\n+ this.handler = null;\n+ }\n+ if (this.handlers) {\n+ for (var key in this.handlers) {\n+ if (this.handlers.hasOwnProperty(key) &&\n+ typeof this.handlers[key].destroy == \"function\") {\n+ this.handlers[key].destroy();\n+ }\n+ }\n+ this.handlers = null;\n+ }\n+ if (this.map) {\n+ this.map.removeControl(this);\n+ this.map = null;\n+ }\n+ this.div = null;\n+ },\n+\n+ /** \n+ * Method: setMap\n+ * Set the map property for the control. This is done through an accessor\n+ * so that subclasses can override this and take special action once \n+ * they have their map variable set. \n+ *\n+ * Parameters:\n+ * map - {} \n+ */\n+ setMap: function(map) {\n+ this.map = map;\n+ if (this.handler) {\n+ this.handler.setMap(map);\n+ }\n+ },\n+\n+ /**\n+ * Method: draw\n+ * The draw method is called when the control is ready to be displayed\n+ * on the page. If a div has not been created one is created. Controls\n+ * with a visual component will almost always want to override this method \n+ * to customize the look of control. \n+ *\n+ * Parameters:\n+ * px - {} The top-left pixel position of the control\n+ * or null.\n+ *\n+ * Returns:\n+ * {DOMElement} A reference to the DIV DOMElement containing the control\n+ */\n+ draw: function(px) {\n+ if (this.div == null) {\n+ this.div = OpenLayers.Util.createDiv(this.id);\n+ this.div.className = this.displayClass;\n+ if (!this.allowSelection) {\n+ this.div.className += \" olControlNoSelect\";\n+ this.div.setAttribute(\"unselectable\", \"on\", 0);\n+ this.div.onselectstart = OpenLayers.Function.False;\n+ }\n+ if (this.title != \"\") {\n+ this.div.title = this.title;\n+ }\n+ }\n+ if (px != null) {\n+ this.position = px.clone();\n+ }\n+ this.moveTo(this.position);\n+ return this.div;\n+ },\n+\n+ /**\n+ * Method: moveTo\n+ * Sets the left and top style attributes to the passed in pixel \n+ * coordinates.\n+ *\n+ * Parameters:\n+ * px - {}\n+ */\n+ moveTo: function(px) {\n+ if ((px != null) && (this.div != null)) {\n+ this.div.style.left = px.x + \"px\";\n+ this.div.style.top = px.y + \"px\";\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: activate\n+ * Explicitly activates a control and it's associated\n+ * handler if one has been set. Controls can be\n+ * deactivated by calling the deactivate() method.\n+ * \n+ * Returns:\n+ * {Boolean} True if the control was successfully activated or\n+ * false if the control was already active.\n+ */\n+ activate: function() {\n+ if (this.active) {\n+ return false;\n+ }\n+ if (this.handler) {\n+ this.handler.activate();\n+ }\n+ this.active = true;\n+ if (this.map) {\n+ OpenLayers.Element.addClass(\n+ this.map.viewPortDiv,\n+ this.displayClass.replace(/ /g, \"\") + \"Active\"\n+ );\n+ }\n+ this.events.triggerEvent(\"activate\");\n+ return true;\n+ },\n+\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivates a control and it's associated handler if any. The exact\n+ * effect of this depends on the control itself.\n+ * \n+ * Returns:\n+ * {Boolean} True if the control was effectively deactivated or false\n+ * if the control was already inactive.\n+ */\n+ deactivate: function() {\n+ if (this.active) {\n+ if (this.handler) {\n+ this.handler.deactivate();\n+ }\n+ this.active = false;\n+ if (this.map) {\n+ OpenLayers.Element.removeClass(\n+ this.map.viewPortDiv,\n+ this.displayClass.replace(/ /g, \"\") + \"Active\"\n+ );\n+ }\n+ this.events.triggerEvent(\"deactivate\");\n+ return true;\n+ }\n+ return false;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control\"\n+});\n+\n+/**\n+ * Constant: OpenLayers.Control.TYPE_BUTTON\n+ */\n+OpenLayers.Control.TYPE_BUTTON = 1;\n+\n+/**\n+ * Constant: OpenLayers.Control.TYPE_TOGGLE\n+ */\n+OpenLayers.Control.TYPE_TOGGLE = 2;\n+\n+/**\n+ * Constant: OpenLayers.Control.TYPE_TOOL\n+ */\n+OpenLayers.Control.TYPE_TOOL = 3;\n+/* ======================================================================\n+ OpenLayers/Renderer.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n@@ -25817,14 +28182,917 @@\n 4, 0\n ],\n \"x\": [0, 0, 25, 0, 50, 35, 75, 0, 100, 0, 65, 50, 100, 100, 75, 100, 50, 65, 25, 100, 0, 100, 35, 50, 0, 0],\n \"square\": [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],\n \"triangle\": [0, 10, 10, 10, 5, 0, 0, 10]\n };\n /* ======================================================================\n+ OpenLayers/Symbolizer.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer\n+ * Base class representing a symbolizer used for feature rendering.\n+ */\n+OpenLayers.Symbolizer = OpenLayers.Class({\n+\n+\n+ /**\n+ * APIProperty: zIndex\n+ * {Number} The zIndex determines the rendering order for a symbolizer.\n+ * Symbolizers with larger zIndex values are rendered over symbolizers\n+ * with smaller zIndex values. Default is 0.\n+ */\n+ zIndex: 0,\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer\n+ * Instances of this class are not useful. See one of the subclasses.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Util.extend(this, config);\n+ },\n+\n+ /** \n+ * APIMethod: clone\n+ * Create a copy of this symbolizer.\n+ *\n+ * Returns a symbolizer of the same type with the same properties.\n+ */\n+ clone: function() {\n+ var Type = eval(this.CLASS_NAME);\n+ return new Type(OpenLayers.Util.extend({}, this));\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer\"\n+\n+});\n+\n+/* ======================================================================\n+ OpenLayers/Rule.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Style.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Rule\n+ * This class represents an SLD Rule, as being used for rule-based SLD styling.\n+ */\n+OpenLayers.Rule = OpenLayers.Class({\n+\n+ /**\n+ * Property: id\n+ * {String} A unique id for this session.\n+ */\n+ id: null,\n+\n+ /**\n+ * APIProperty: name\n+ * {String} name of this rule\n+ */\n+ name: null,\n+\n+ /**\n+ * Property: title\n+ * {String} Title of this rule (set if included in SLD)\n+ */\n+ title: null,\n+\n+ /**\n+ * Property: description\n+ * {String} Description of this rule (set if abstract is included in SLD)\n+ */\n+ description: null,\n+\n+ /**\n+ * Property: context\n+ * {Object} An optional object with properties that the rule should be\n+ * evaluated against. If no context is specified, feature.attributes will\n+ * be used.\n+ */\n+ context: null,\n+\n+ /**\n+ * Property: filter\n+ * {} Optional filter for the rule.\n+ */\n+ filter: null,\n+\n+ /**\n+ * Property: elseFilter\n+ * {Boolean} Determines whether this rule is only to be applied only if\n+ * no other rules match (ElseFilter according to the SLD specification). \n+ * Default is false. For instances of OpenLayers.Rule, if elseFilter is\n+ * false, the rule will always apply. For subclasses, the else property is \n+ * ignored.\n+ */\n+ elseFilter: false,\n+\n+ /**\n+ * Property: symbolizer\n+ * {Object} Symbolizer or hash of symbolizers for this rule. If hash of\n+ * symbolizers, keys are one or more of [\"Point\", \"Line\", \"Polygon\"]. The\n+ * latter if useful if it is required to style e.g. vertices of a line\n+ * with a point symbolizer. Note, however, that this is not implemented\n+ * yet in OpenLayers, but it is the way how symbolizers are defined in\n+ * SLD.\n+ */\n+ symbolizer: null,\n+\n+ /**\n+ * Property: symbolizers\n+ * {Array} Collection of symbolizers associated with this rule. If \n+ * provided at construction, the symbolizers array has precedence\n+ * over the deprecated symbolizer property. Note that multiple \n+ * symbolizers are not currently supported by the vector renderers.\n+ * Rules with multiple symbolizers are currently only useful for\n+ * maintaining elements in an SLD document.\n+ */\n+ symbolizers: null,\n+\n+ /**\n+ * APIProperty: minScaleDenominator\n+ * {Number} or {String} minimum scale at which to draw the feature.\n+ * In the case of a String, this can be a combination of text and\n+ * propertyNames in the form \"literal ${propertyName}\"\n+ */\n+ minScaleDenominator: null,\n+\n+ /**\n+ * APIProperty: maxScaleDenominator\n+ * {Number} or {String} maximum scale at which to draw the feature.\n+ * In the case of a String, this can be a combination of text and\n+ * propertyNames in the form \"literal ${propertyName}\"\n+ */\n+ maxScaleDenominator: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Rule\n+ * Creates a Rule.\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object with properties to set on the\n+ * rule\n+ * \n+ * Returns:\n+ * {}\n+ */\n+ initialize: function(options) {\n+ this.symbolizer = {};\n+ OpenLayers.Util.extend(this, options);\n+ if (this.symbolizers) {\n+ delete this.symbolizer;\n+ }\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n+\n+ /** \n+ * APIMethod: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ for (var i in this.symbolizer) {\n+ this.symbolizer[i] = null;\n+ }\n+ this.symbolizer = null;\n+ delete this.symbolizers;\n+ },\n+\n+ /**\n+ * APIMethod: evaluate\n+ * evaluates this rule for a specific feature\n+ * \n+ * Parameters:\n+ * feature - {} feature to apply the rule to.\n+ * \n+ * Returns:\n+ * {Boolean} true if the rule applies, false if it does not.\n+ * This rule is the default rule and always returns true.\n+ */\n+ evaluate: function(feature) {\n+ var context = this.getContext(feature);\n+ var applies = true;\n+\n+ if (this.minScaleDenominator || this.maxScaleDenominator) {\n+ var scale = feature.layer.map.getScale();\n+ }\n+\n+ // check if within minScale/maxScale bounds\n+ if (this.minScaleDenominator) {\n+ applies = scale >= OpenLayers.Style.createLiteral(\n+ this.minScaleDenominator, context);\n+ }\n+ if (applies && this.maxScaleDenominator) {\n+ applies = scale < OpenLayers.Style.createLiteral(\n+ this.maxScaleDenominator, context);\n+ }\n+\n+ // check if optional filter applies\n+ if (applies && this.filter) {\n+ // feature id filters get the feature, others get the context\n+ if (this.filter.CLASS_NAME == \"OpenLayers.Filter.FeatureId\") {\n+ applies = this.filter.evaluate(feature);\n+ } else {\n+ applies = this.filter.evaluate(context);\n+ }\n+ }\n+\n+ return applies;\n+ },\n+\n+ /**\n+ * Method: getContext\n+ * Gets the context for evaluating this rule\n+ * \n+ * Paramters:\n+ * feature - {} feature to take the context from if\n+ * none is specified.\n+ */\n+ getContext: function(feature) {\n+ var context = this.context;\n+ if (!context) {\n+ context = feature.attributes || feature.data;\n+ }\n+ if (typeof this.context == \"function\") {\n+ context = this.context(feature);\n+ }\n+ return context;\n+ },\n+\n+ /**\n+ * APIMethod: clone\n+ * Clones this rule.\n+ * \n+ * Returns:\n+ * {} Clone of this rule.\n+ */\n+ clone: function() {\n+ var options = OpenLayers.Util.extend({}, this);\n+ if (this.symbolizers) {\n+ // clone symbolizers\n+ var len = this.symbolizers.length;\n+ options.symbolizers = new Array(len);\n+ for (var i = 0; i < len; ++i) {\n+ options.symbolizers[i] = this.symbolizers[i].clone();\n+ }\n+ } else {\n+ // clone symbolizer\n+ options.symbolizer = {};\n+ var value, type;\n+ for (var key in this.symbolizer) {\n+ value = this.symbolizer[key];\n+ type = typeof value;\n+ if (type === \"object\") {\n+ options.symbolizer[key] = OpenLayers.Util.extend({}, value);\n+ } else if (type === \"string\") {\n+ options.symbolizer[key] = value;\n+ }\n+ }\n+ }\n+ // clone filter\n+ options.filter = this.filter && this.filter.clone();\n+ // clone context\n+ options.context = this.context && OpenLayers.Util.extend({}, this.context);\n+ return new OpenLayers.Rule(options);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Rule\"\n+});\n+/* ======================================================================\n+ OpenLayers/Format/WPSDescribeProcess.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Format/XML.js\n+ * @requires OpenLayers/Format/OWSCommon/v1_1_0.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Format.WPSDescribeProcess\n+ * Read WPS DescribeProcess responses. \n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(\n+ OpenLayers.Format.XML, {\n+\n+ /**\n+ * Constant: VERSION\n+ * {String} 1.0.0\n+ */\n+ VERSION: \"1.0.0\",\n+\n+ /**\n+ * Property: namespaces\n+ * {Object} Mapping of namespace aliases to namespace URIs.\n+ */\n+ namespaces: {\n+ wps: \"http://www.opengis.net/wps/1.0.0\",\n+ ows: \"http://www.opengis.net/ows/1.1\",\n+ xsi: \"http://www.w3.org/2001/XMLSchema-instance\"\n+ },\n+\n+ /**\n+ * Property: schemaLocation\n+ * {String} Schema location\n+ */\n+ schemaLocation: \"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\",\n+\n+ /**\n+ * Property: defaultPrefix\n+ */\n+ defaultPrefix: \"wps\",\n+\n+ /**\n+ * Property: regExes\n+ * Compiled regular expressions for manipulating strings.\n+ */\n+ regExes: {\n+ trimSpace: (/^\\s*|\\s*$/g),\n+ removeSpace: (/\\s*/g),\n+ splitSpace: (/\\s+/),\n+ trimComma: (/\\s*,\\s*/g)\n+ },\n+\n+ /**\n+ * Constructor: OpenLayers.Format.WPSDescribeProcess\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be set on\n+ * this instance.\n+ */\n+\n+ /**\n+ * APIMethod: read\n+ * Parse a WPS DescribeProcess and return an object with its information.\n+ * \n+ * Parameters: \n+ * data - {String} or {DOMElement} data to read/parse.\n+ *\n+ * Returns:\n+ * {Object}\n+ */\n+ read: function(data) {\n+ if (typeof data == \"string\") {\n+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n+ }\n+ if (data && data.nodeType == 9) {\n+ data = data.documentElement;\n+ }\n+ var info = {};\n+ this.readNode(data, info);\n+ return info;\n+ },\n+\n+ /**\n+ * Property: readers\n+ * Contains public functions, grouped by namespace prefix, that will\n+ * be applied when a namespaced node is found matching the function\n+ * name. The function will be applied in the scope of this parser\n+ * with two arguments: the node being read and a context object passed\n+ * from the parent.\n+ */\n+ readers: {\n+ \"wps\": {\n+ \"ProcessDescriptions\": function(node, obj) {\n+ obj.processDescriptions = {};\n+ this.readChildNodes(node, obj.processDescriptions);\n+ },\n+ \"ProcessDescription\": function(node, processDescriptions) {\n+ var processVersion = this.getAttributeNS(node, this.namespaces.wps, \"processVersion\");\n+ var processDescription = {\n+ processVersion: processVersion,\n+ statusSupported: (node.getAttribute(\"statusSupported\") === \"true\"),\n+ storeSupported: (node.getAttribute(\"storeSupported\") === \"true\")\n+ };\n+ this.readChildNodes(node, processDescription);\n+ processDescriptions[processDescription.identifier] = processDescription;\n+ },\n+ \"DataInputs\": function(node, processDescription) {\n+ processDescription.dataInputs = [];\n+ this.readChildNodes(node, processDescription.dataInputs);\n+ },\n+ \"ProcessOutputs\": function(node, processDescription) {\n+ processDescription.processOutputs = [];\n+ this.readChildNodes(node, processDescription.processOutputs);\n+ },\n+ \"Output\": function(node, processOutputs) {\n+ var output = {};\n+ this.readChildNodes(node, output);\n+ processOutputs.push(output);\n+ },\n+ \"ComplexOutput\": function(node, output) {\n+ output.complexOutput = {};\n+ this.readChildNodes(node, output.complexOutput);\n+ },\n+ \"LiteralOutput\": function(node, output) {\n+ output.literalOutput = {};\n+ this.readChildNodes(node, output.literalOutput);\n+ },\n+ \"Input\": function(node, dataInputs) {\n+ var input = {\n+ maxOccurs: parseInt(node.getAttribute(\"maxOccurs\")),\n+ minOccurs: parseInt(node.getAttribute(\"minOccurs\"))\n+ };\n+ this.readChildNodes(node, input);\n+ dataInputs.push(input);\n+ },\n+ \"BoundingBoxData\": function(node, input) {\n+ input.boundingBoxData = {};\n+ this.readChildNodes(node, input.boundingBoxData);\n+ },\n+ \"CRS\": function(node, obj) {\n+ if (!obj.CRSs) {\n+ obj.CRSs = {};\n+ }\n+ obj.CRSs[this.getChildValue(node)] = true;\n+ },\n+ \"LiteralData\": function(node, input) {\n+ input.literalData = {};\n+ this.readChildNodes(node, input.literalData);\n+ },\n+ \"ComplexData\": function(node, input) {\n+ input.complexData = {};\n+ this.readChildNodes(node, input.complexData);\n+ },\n+ \"Default\": function(node, complexData) {\n+ complexData[\"default\"] = {};\n+ this.readChildNodes(node, complexData[\"default\"]);\n+ },\n+ \"Supported\": function(node, complexData) {\n+ complexData[\"supported\"] = {};\n+ this.readChildNodes(node, complexData[\"supported\"]);\n+ },\n+ \"Format\": function(node, obj) {\n+ var format = {};\n+ this.readChildNodes(node, format);\n+ if (!obj.formats) {\n+ obj.formats = {};\n+ }\n+ obj.formats[format.mimeType] = true;\n+ },\n+ \"MimeType\": function(node, format) {\n+ format.mimeType = this.getChildValue(node);\n+ }\n+ },\n+ \"ows\": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers[\"ows\"]\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Format.WPSDescribeProcess\"\n+\n+ });\n+/* ======================================================================\n+ OpenLayers/WPSClient.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+/**\n+ * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/WPSProcess.js\n+ * @requires OpenLayers/Format/WPSDescribeProcess.js\n+ * @requires OpenLayers/Request.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.WPSClient\n+ * High level API for interaction with Web Processing Services (WPS).\n+ * An instance is used to create \n+ * instances for servers known to the WPSClient. The WPSClient also caches\n+ * DescribeProcess responses to reduce the number of requests sent to servers\n+ * when processes are created.\n+ */\n+OpenLayers.WPSClient = OpenLayers.Class({\n+\n+ /**\n+ * Property: servers\n+ * {Object} Service metadata, keyed by a local identifier.\n+ *\n+ * Properties:\n+ * url - {String} the url of the server\n+ * version - {String} WPS version of the server\n+ * processDescription - {Object} Cache of raw DescribeProcess\n+ * responses, keyed by process identifier.\n+ */\n+ servers: null,\n+\n+ /**\n+ * Property: version\n+ * {String} The default WPS version to use if none is configured. Default\n+ * is '1.0.0'.\n+ */\n+ version: '1.0.0',\n+\n+ /**\n+ * Property: lazy\n+ * {Boolean} Should the DescribeProcess be deferred until a process is\n+ * fully configured? Default is false.\n+ */\n+ lazy: false,\n+\n+ /**\n+ * Property: events\n+ * {}\n+ *\n+ * Supported event types:\n+ * describeprocess - Fires when the process description is available.\n+ * Listeners receive an object with a 'raw' property holding the raw\n+ * DescribeProcess response, and an 'identifier' property holding the\n+ * process identifier of the described process.\n+ */\n+ events: null,\n+\n+ /**\n+ * Constructor: OpenLayers.WPSClient\n+ *\n+ * Parameters:\n+ * options - {Object} Object whose properties will be set on the instance.\n+ *\n+ * Avaliable options:\n+ * servers - {Object} Mandatory. Service metadata, keyed by a local\n+ * identifier. Can either be a string with the service url or an\n+ * object literal with additional metadata:\n+ *\n+ * (code)\n+ * servers: {\n+ * local: '/geoserver/wps'\n+ * }, {\n+ * opengeo: {\n+ * url: 'http://demo.opengeo.org/geoserver/wps',\n+ * version: '1.0.0'\n+ * }\n+ * }\n+ * (end)\n+ *\n+ * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be\n+ * requested until a process is fully configured. Default is false.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.events = new OpenLayers.Events(this);\n+ this.servers = {};\n+ for (var s in options.servers) {\n+ this.servers[s] = typeof options.servers[s] == 'string' ? {\n+ url: options.servers[s],\n+ version: this.version,\n+ processDescription: {}\n+ } : options.servers[s];\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: execute\n+ * Shortcut to execute a process with a single function call. This is\n+ * equivalent to using and then calling execute on the\n+ * process.\n+ *\n+ * Parameters:\n+ * options - {Object} Options for the execute operation.\n+ *\n+ * Available options:\n+ * server - {String} Mandatory. One of the local identifiers of the\n+ * configured servers.\n+ * process - {String} Mandatory. A process identifier known to the\n+ * server.\n+ * inputs - {Object} The inputs for the process, keyed by input identifier.\n+ * For spatial data inputs, the value of an input is usually an\n+ * , an or an array of\n+ * geometries or features.\n+ * output - {String} The identifier of an output to parse. Optional. If not\n+ * provided, the first output will be parsed.\n+ * success - {Function} Callback to call when the process is complete.\n+ * This function is called with an outputs object as argument, which\n+ * will have a property with the identifier of the requested output\n+ * (e.g. 'result'). For processes that generate spatial output, the\n+ * value will either be a single or an\n+ * array of features.\n+ * scope - {Object} Optional scope for the success callback.\n+ */\n+ execute: function(options) {\n+ var process = this.getProcess(options.server, options.process);\n+ process.execute({\n+ inputs: options.inputs,\n+ success: options.success,\n+ scope: options.scope\n+ });\n+ },\n+\n+ /**\n+ * APIMethod: getProcess\n+ * Creates an .\n+ *\n+ * Parameters:\n+ * serverID - {String} Local identifier from the servers that this instance\n+ * was constructed with.\n+ * processID - {String} Process identifier known to the server.\n+ *\n+ * Returns:\n+ * {}\n+ */\n+ getProcess: function(serverID, processID) {\n+ var process = new OpenLayers.WPSProcess({\n+ client: this,\n+ server: serverID,\n+ identifier: processID\n+ });\n+ if (!this.lazy) {\n+ process.describe();\n+ }\n+ return process;\n+ },\n+\n+ /**\n+ * Method: describeProcess\n+ *\n+ * Parameters:\n+ * serverID - {String} Identifier of the server\n+ * processID - {String} Identifier of the requested process\n+ * callback - {Function} Callback to call when the description is available\n+ * scope - {Object} Optional execution scope for the callback function\n+ */\n+ describeProcess: function(serverID, processID, callback, scope) {\n+ var server = this.servers[serverID];\n+ if (!server.processDescription[processID]) {\n+ if (!(processID in server.processDescription)) {\n+ // set to null so we know a describeFeature request is pending\n+ server.processDescription[processID] = null;\n+ OpenLayers.Request.GET({\n+ url: server.url,\n+ params: {\n+ SERVICE: 'WPS',\n+ VERSION: server.version,\n+ REQUEST: 'DescribeProcess',\n+ IDENTIFIER: processID\n+ },\n+ success: function(response) {\n+ server.processDescription[processID] = response.responseText;\n+ this.events.triggerEvent('describeprocess', {\n+ identifier: processID,\n+ raw: response.responseText\n+ });\n+ },\n+ scope: this\n+ });\n+ } else {\n+ // pending request\n+ this.events.register('describeprocess', this, function describe(evt) {\n+ if (evt.identifier === processID) {\n+ this.events.unregister('describeprocess', this, describe);\n+ callback.call(scope, evt.raw);\n+ }\n+ });\n+ }\n+ } else {\n+ window.setTimeout(function() {\n+ callback.call(scope, server.processDescription[processID]);\n+ }, 0);\n+ }\n+ },\n+\n+ /**\n+ * Method: destroy\n+ */\n+ destroy: function() {\n+ this.events.destroy();\n+ this.events = null;\n+ this.servers = null;\n+ },\n+\n+ CLASS_NAME: 'OpenLayers.WPSClient'\n+\n+});\n+/* ======================================================================\n+ OpenLayers/Kinetic.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Animation.js\n+ */\n+\n+OpenLayers.Kinetic = OpenLayers.Class({\n+\n+ /**\n+ * Property: threshold\n+ * In most cases changing the threshold isn't needed.\n+ * In px/ms, default to 0.\n+ */\n+ threshold: 0,\n+\n+ /**\n+ * Property: deceleration\n+ * {Float} the deseleration in px/ms\u00b2, default to 0.0035.\n+ */\n+ deceleration: 0.0035,\n+\n+ /**\n+ * Property: nbPoints\n+ * {Integer} the number of points we use to calculate the kinetic\n+ * initial values.\n+ */\n+ nbPoints: 100,\n+\n+ /**\n+ * Property: delay\n+ * {Float} time to consider to calculate the kinetic initial values.\n+ * In ms, default to 200.\n+ */\n+ delay: 200,\n+\n+ /**\n+ * Property: points\n+ * List of points use to calculate the kinetic initial values.\n+ */\n+ points: undefined,\n+\n+ /**\n+ * Property: timerId\n+ * ID of the timer.\n+ */\n+ timerId: undefined,\n+\n+ /**\n+ * Constructor: OpenLayers.Kinetic\n+ *\n+ * Parameters:\n+ * options - {Object}\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ },\n+\n+ /**\n+ * Method: begin\n+ * Begins the dragging.\n+ */\n+ begin: function() {\n+ OpenLayers.Animation.stop(this.timerId);\n+ this.timerId = undefined;\n+ this.points = [];\n+ },\n+\n+ /**\n+ * Method: update\n+ * Updates during the dragging.\n+ *\n+ * Parameters:\n+ * xy - {} The new position.\n+ */\n+ update: function(xy) {\n+ this.points.unshift({\n+ xy: xy,\n+ tick: new Date().getTime()\n+ });\n+ if (this.points.length > this.nbPoints) {\n+ this.points.pop();\n+ }\n+ },\n+\n+ /**\n+ * Method: end\n+ * Ends the dragging, start the kinetic.\n+ *\n+ * Parameters:\n+ * xy - {} The last position.\n+ *\n+ * Returns:\n+ * {Object} An object with two properties: \"speed\", and \"theta\". The\n+ * \"speed\" and \"theta\" values are to be passed to the move \n+ * function when starting the animation.\n+ */\n+ end: function(xy) {\n+ var last, now = new Date().getTime();\n+ for (var i = 0, l = this.points.length, point; i < l; i++) {\n+ point = this.points[i];\n+ if (now - point.tick > this.delay) {\n+ break;\n+ }\n+ last = point;\n+ }\n+ if (!last) {\n+ return;\n+ }\n+ var time = new Date().getTime() - last.tick;\n+ var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) +\n+ Math.pow(xy.y - last.xy.y, 2));\n+ var speed = dist / time;\n+ if (speed == 0 || speed < this.threshold) {\n+ return;\n+ }\n+ var theta = Math.asin((xy.y - last.xy.y) / dist);\n+ if (last.xy.x <= xy.x) {\n+ theta = Math.PI - theta;\n+ }\n+ return {\n+ speed: speed,\n+ theta: theta\n+ };\n+ },\n+\n+ /**\n+ * Method: move\n+ * Launch the kinetic move pan.\n+ *\n+ * Parameters:\n+ * info - {Object} An object with two properties, \"speed\", and \"theta\".\n+ * These values are those returned from the \"end\" call.\n+ * callback - {Function} Function called on every step of the animation,\n+ * receives x, y (values to pan), end (is the last point).\n+ */\n+ move: function(info, callback) {\n+ var v0 = info.speed;\n+ var fx = Math.cos(info.theta);\n+ var fy = -Math.sin(info.theta);\n+\n+ var initialTime = new Date().getTime();\n+\n+ var lastX = 0;\n+ var lastY = 0;\n+\n+ var timerCallback = function() {\n+ if (this.timerId == null) {\n+ return;\n+ }\n+\n+ var t = new Date().getTime() - initialTime;\n+\n+ var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t;\n+ var x = p * fx;\n+ var y = p * fy;\n+\n+ var args = {};\n+ args.end = false;\n+ var v = -this.deceleration * t + v0;\n+\n+ if (v <= 0) {\n+ OpenLayers.Animation.stop(this.timerId);\n+ this.timerId = null;\n+ args.end = true;\n+ }\n+\n+ args.x = x - lastX;\n+ args.y = y - lastY;\n+ lastX = x;\n+ lastY = y;\n+ callback(args.x, args.y, args.end);\n+ };\n+\n+ this.timerId = OpenLayers.Animation.start(\n+ OpenLayers.Function.bind(timerCallback, this)\n+ );\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Kinetic\"\n+});\n+/* ======================================================================\n OpenLayers/Layer.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -27200,14 +30468,573 @@\n }\n return bounds;\n },\n \n CLASS_NAME: \"OpenLayers.Layer\"\n });\n /* ======================================================================\n+ OpenLayers/Symbolizer/Point.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Symbolizer.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer.Point\n+ * A symbolizer used to render point features.\n+ */\n+OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {\n+\n+ /**\n+ * APIProperty: strokeColor\n+ * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n+ * for red).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeOpacity\n+ * {Number} Stroke opacity (0-1).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeWidth\n+ * {Number} Pixel stroke width.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeLinecap\n+ * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Property: strokeDashstyle\n+ * {String} Stroke dash style according to the SLD spec. Note that the\n+ * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n+ * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n+ * most SLD patterns will render correctly in OpenLayers.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: fillColor\n+ * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: fillOpacity\n+ * {Number} Fill opacity (0-1).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: pointRadius\n+ * {Number} Pixel point radius.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: externalGraphic\n+ * {String} Url to an external graphic that will be used for rendering \n+ * points.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicWidth\n+ * {Number} Pixel width for sizing an external graphic.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicHeight\n+ * {Number} Pixel height for sizing an external graphic.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicOpacity\n+ * {Number} Opacity (0-1) for an external graphic.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicXOffset\n+ * {Number} Pixel offset along the positive x axis for displacing an \n+ * external graphic.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicYOffset\n+ * {Number} Pixel offset along the positive y axis for displacing an \n+ * external graphic.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: rotation\n+ * {Number} The rotation of a graphic in the clockwise direction about its \n+ * center point (or any point off center as specified by \n+ * and ).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: graphicName\n+ * {String} Named graphic to use when rendering points. Supported values \n+ * include \"circle\", \"square\", \"star\", \"x\", \"cross\", and \"triangle\".\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer.Point\n+ * Create a symbolizer for rendering points.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new point symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer.Point\"\n+\n+});\n+\n+/* ======================================================================\n+ OpenLayers/Symbolizer/Line.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Symbolizer.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer.Line\n+ * A symbolizer used to render line features.\n+ */\n+OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {\n+\n+ /**\n+ * APIProperty: strokeColor\n+ * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n+ * for red). \n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeOpacity\n+ * {Number} Stroke opacity (0-1).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeWidth\n+ * {Number} Pixel stroke width.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeLinecap\n+ * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Property: strokeDashstyle\n+ * {String} Stroke dash style according to the SLD spec. Note that the\n+ * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n+ * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n+ * most SLD patterns will render correctly in OpenLayers.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer.Line\n+ * Create a symbolizer for rendering lines.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new line symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer.Line\"\n+\n+});\n+\n+/* ======================================================================\n+ OpenLayers/Symbolizer/Polygon.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Symbolizer.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer.Polygon\n+ * A symbolizer used to render line features.\n+ */\n+OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {\n+\n+ /**\n+ * APIProperty: strokeColor\n+ * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n+ * for red).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeOpacity\n+ * {Number} Stroke opacity (0-1).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeWidth\n+ * {Number} Pixel stroke width.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: strokeLinecap\n+ * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Property: strokeDashstyle\n+ * {String} Stroke dash style according to the SLD spec. Note that the\n+ * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n+ * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n+ * most SLD patterns will render correctly in OpenLayers.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: fillColor\n+ * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * APIProperty: fillOpacity\n+ * {Number} Fill opacity (0-1).\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer.Polygon\n+ * Create a symbolizer for rendering polygons.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new polygon symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer.Polygon\"\n+\n+});\n+\n+/* ======================================================================\n+ OpenLayers/Symbolizer/Text.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Symbolizer.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer.Text\n+ * A symbolizer used to render text labels for features.\n+ */\n+OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {\n+\n+ /** \n+ * APIProperty: label\n+ * {String} The text for the label.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /** \n+ * APIProperty: fontFamily\n+ * {String} The font family for the label.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /** \n+ * APIProperty: fontSize\n+ * {String} The font size for the label.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /** \n+ * APIProperty: fontWeight\n+ * {String} The font weight for the label.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Property: fontStyle\n+ * {String} The font style for the label.\n+ * \n+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer.Text\n+ * Create a symbolizer for rendering text labels.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new text symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer.Text\"\n+\n+});\n+\n+/* ======================================================================\n+ OpenLayers/Symbolizer/Raster.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Symbolizer.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Symbolizer.Raster\n+ * A symbolizer used to render raster images.\n+ */\n+OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {\n+\n+ /**\n+ * Constructor: OpenLayers.Symbolizer.Raster\n+ * Create a symbolizer for rendering rasters.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * symbolizer. Any documented symbolizer property can be set at \n+ * construction.\n+ *\n+ * Returns:\n+ * A new raster symbolizer.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Symbolizer.Raster\"\n+\n+});\n+/* ======================================================================\n+ OpenLayers/Style2.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Rule.js\n+ * @requires OpenLayers/Symbolizer/Point.js\n+ * @requires OpenLayers/Symbolizer/Line.js\n+ * @requires OpenLayers/Symbolizer/Polygon.js\n+ * @requires OpenLayers/Symbolizer/Text.js\n+ * @requires OpenLayers/Symbolizer/Raster.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Style2\n+ * This class represents a collection of rules for rendering features.\n+ */\n+OpenLayers.Style2 = OpenLayers.Class({\n+\n+ /**\n+ * Property: id\n+ * {String} A unique id for this session.\n+ */\n+ id: null,\n+\n+ /**\n+ * APIProperty: name\n+ * {String} Style identifier.\n+ */\n+ name: null,\n+\n+ /**\n+ * APIProperty: title\n+ * {String} Title of this style.\n+ */\n+ title: null,\n+\n+ /**\n+ * APIProperty: description\n+ * {String} Description of this style.\n+ */\n+ description: null,\n+\n+ /**\n+ * APIProperty: layerName\n+ * {} Name of the layer that this style belongs to, usually\n+ * according to the NamedLayer attribute of an SLD document.\n+ */\n+ layerName: null,\n+\n+ /**\n+ * APIProperty: isDefault\n+ * {Boolean}\n+ */\n+ isDefault: false,\n+\n+ /** \n+ * APIProperty: rules \n+ * {Array()} Collection of rendering rules.\n+ */\n+ rules: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Style2\n+ * Creates a style representing a collection of rendering rules.\n+ *\n+ * Parameters:\n+ * config - {Object} An object containing properties to be set on the \n+ * style. Any documented properties may be set at construction.\n+ *\n+ * Returns:\n+ * {} A new style object.\n+ */\n+ initialize: function(config) {\n+ OpenLayers.Util.extend(this, config);\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n+\n+ /** \n+ * APIMethod: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ for (var i = 0, len = this.rules.length; i < len; i++) {\n+ this.rules[i].destroy();\n+ }\n+ delete this.rules;\n+ },\n+\n+ /**\n+ * APIMethod: clone\n+ * Clones this style.\n+ * \n+ * Returns:\n+ * {} Clone of this style.\n+ */\n+ clone: function() {\n+ var config = OpenLayers.Util.extend({}, this);\n+ // clone rules\n+ if (this.rules) {\n+ config.rules = [];\n+ for (var i = 0, len = this.rules.length; i < len; ++i) {\n+ config.rules.push(this.rules[i].clone());\n+ }\n+ }\n+ return new OpenLayers.Style2(config);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Style2\"\n+});\n+/* ======================================================================\n OpenLayers/Layer/HTTPRequest.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -27436,313 +31263,14 @@\n \n return OpenLayers.Util.urlAppend(url, paramsString);\n },\n \n CLASS_NAME: \"OpenLayers.Layer.HTTPRequest\"\n });\n /* ======================================================================\n- OpenLayers/Tile.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- */\n-\n-/**\n- * Class: OpenLayers.Tile \n- * This is a class designed to designate a single tile, however\n- * it is explicitly designed to do relatively little. Tiles store \n- * information about themselves -- such as the URL that they are related\n- * to, and their size - but do not add themselves to the layer div \n- * automatically, for example. Create a new tile with the \n- * constructor, or a subclass. \n- * \n- * TBD 3.0 - remove reference to url in above paragraph\n- * \n- */\n-OpenLayers.Tile = OpenLayers.Class({\n-\n- /**\n- * APIProperty: events\n- * {} An events object that handles all \n- * events on the tile.\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * tile.events.register(type, obj, listener);\n- * (end)\n- *\n- * Supported event types:\n- * beforedraw - Triggered before the tile is drawn. Used to defer\n- * drawing to an animation queue. To defer drawing, listeners need\n- * to return false, which will abort drawing. The queue handler needs\n- * to call (true) to actually draw the tile.\n- * loadstart - Triggered when tile loading starts.\n- * loadend - Triggered when tile loading ends.\n- * loaderror - Triggered before the loadend event (i.e. when the tile is\n- * still hidden) if the tile could not be loaded.\n- * reload - Triggered when an already loading tile is reloaded.\n- * unload - Triggered before a tile is unloaded.\n- */\n- events: null,\n-\n- /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n- *\n- * This options can be set in the ``tileOptions`` option from\n- * . For example, to be notified of the\n- * ``loadend`` event of each tiles:\n- * (code)\n- * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', {\n- * tileOptions: {\n- * eventListeners: {\n- * 'loadend': function(evt) {\n- * // do something on loadend\n- * }\n- * }\n- * }\n- * });\n- * (end)\n- */\n- eventListeners: null,\n-\n- /**\n- * Property: id \n- * {String} null\n- */\n- id: null,\n-\n- /** \n- * Property: layer \n- * {} layer the tile is attached to \n- */\n- layer: null,\n-\n- /**\n- * Property: url\n- * {String} url of the request.\n- *\n- * TBD 3.0 \n- * Deprecated. The base tile class does not need an url. This should be \n- * handled in subclasses. Does not belong here.\n- */\n- url: null,\n-\n- /** \n- * APIProperty: bounds \n- * {} null\n- */\n- bounds: null,\n-\n- /** \n- * Property: size \n- * {} null\n- */\n- size: null,\n-\n- /** \n- * Property: position \n- * {} Top Left pixel of the tile\n- */\n- position: null,\n-\n- /**\n- * Property: isLoading\n- * {Boolean} Is the tile loading?\n- */\n- isLoading: false,\n-\n- /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.\n- * there is no need for the base tile class to have a url.\n- */\n-\n- /** \n- * Constructor: OpenLayers.Tile\n- * Constructor for a new instance.\n- * \n- * Parameters:\n- * layer - {} layer that the tile will go in.\n- * position - {}\n- * bounds - {}\n- * url - {}\n- * size - {}\n- * options - {Object}\n- */\n- initialize: function(layer, position, bounds, url, size, options) {\n- this.layer = layer;\n- this.position = position.clone();\n- this.setBounds(bounds);\n- this.url = url;\n- if (size) {\n- this.size = size.clone();\n- }\n-\n- //give the tile a unique id based on its BBOX.\n- this.id = OpenLayers.Util.createUniqueID(\"Tile_\");\n-\n- OpenLayers.Util.extend(this, options);\n-\n- this.events = new OpenLayers.Events(this);\n- if (this.eventListeners instanceof Object) {\n- this.events.on(this.eventListeners);\n- }\n- },\n-\n- /**\n- * Method: unload\n- * Call immediately before destroying if you are listening to tile\n- * events, so that counters are properly handled if tile is still\n- * loading at destroy-time. Will only fire an event if the tile is\n- * still loading.\n- */\n- unload: function() {\n- if (this.isLoading) {\n- this.isLoading = false;\n- this.events.triggerEvent(\"unload\");\n- }\n- },\n-\n- /** \n- * APIMethod: destroy\n- * Nullify references to prevent circular references and memory leaks.\n- */\n- destroy: function() {\n- this.layer = null;\n- this.bounds = null;\n- this.size = null;\n- this.position = null;\n-\n- if (this.eventListeners) {\n- this.events.un(this.eventListeners);\n- }\n- this.events.destroy();\n- this.eventListeners = null;\n- this.events = null;\n- },\n-\n- /**\n- * Method: draw\n- * Clear whatever is currently in the tile, then return whether or not \n- * it should actually be re-drawn. This is an example implementation\n- * that can be overridden by subclasses. The minimum thing to do here\n- * is to call and return the result from .\n- *\n- * Parameters:\n- * force - {Boolean} If true, the tile will not be cleared and no beforedraw\n- * event will be fired. This is used for drawing tiles asynchronously\n- * after drawing has been cancelled by returning false from a beforedraw\n- * listener.\n- * \n- * Returns:\n- * {Boolean} Whether or not the tile should actually be drawn. Returns null\n- * if a beforedraw listener returned false.\n- */\n- draw: function(force) {\n- if (!force) {\n- //clear tile's contents and mark as not drawn\n- this.clear();\n- }\n- var draw = this.shouldDraw();\n- if (draw && !force && this.events.triggerEvent(\"beforedraw\") === false) {\n- draw = null;\n- }\n- return draw;\n- },\n-\n- /**\n- * Method: shouldDraw\n- * Return whether or not the tile should actually be (re-)drawn. The only\n- * case where we *wouldn't* want to draw the tile is if the tile is outside\n- * its layer's maxExtent\n- * \n- * Returns:\n- * {Boolean} Whether or not the tile should actually be drawn.\n- */\n- shouldDraw: function() {\n- var withinMaxExtent = false,\n- maxExtent = this.layer.maxExtent;\n- if (maxExtent) {\n- var map = this.layer.map;\n- var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();\n- if (this.bounds.intersectsBounds(maxExtent, {\n- inclusive: false,\n- worldBounds: worldBounds\n- })) {\n- withinMaxExtent = true;\n- }\n- }\n-\n- return withinMaxExtent || this.layer.displayOutsideMaxExtent;\n- },\n-\n- /**\n- * Method: setBounds\n- * Sets the bounds on this instance\n- *\n- * Parameters:\n- * bounds {}\n- */\n- setBounds: function(bounds) {\n- bounds = bounds.clone();\n- if (this.layer.map.baseLayer.wrapDateLine) {\n- var worldExtent = this.layer.map.getMaxExtent(),\n- tolerance = this.layer.map.getResolution();\n- bounds = bounds.wrapDateLine(worldExtent, {\n- leftTolerance: tolerance,\n- rightTolerance: tolerance\n- });\n- }\n- this.bounds = bounds;\n- },\n-\n- /** \n- * Method: moveTo\n- * Reposition the tile.\n- *\n- * Parameters:\n- * bounds - {}\n- * position - {}\n- * redraw - {Boolean} Call draw method on tile after moving.\n- * Default is true\n- */\n- moveTo: function(bounds, position, redraw) {\n- if (redraw == null) {\n- redraw = true;\n- }\n-\n- this.setBounds(bounds);\n- this.position = position.clone();\n- if (redraw) {\n- this.draw();\n- }\n- },\n-\n- /** \n- * Method: clear\n- * Clear the tile of any bounds/position-related data so that it can \n- * be reused in a new location.\n- */\n- clear: function(draw) {\n- // to be extended by subclasses\n- },\n-\n- CLASS_NAME: \"OpenLayers.Tile\"\n-});\n-/* ======================================================================\n OpenLayers/Tile/Image.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -30087,3127 +33615,1704 @@\n this.tileCache = null;\n this.tileCacheIndex = null;\n this._destroyed = true;\n }\n \n });\n /* ======================================================================\n- OpenLayers/Marker.js\n+ OpenLayers/Marker/Box.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Icon.js\n+ * @requires OpenLayers/Marker.js\n */\n \n /**\n- * Class: OpenLayers.Marker\n- * Instances of OpenLayers.Marker are a combination of a \n- * and an . \n- *\n- * Markers are generally added to a special layer called\n- * .\n- *\n- * Example:\n- * (code)\n- * var markers = new OpenLayers.Layer.Markers( \"Markers\" );\n- * map.addLayer(markers);\n- *\n- * var size = new OpenLayers.Size(21,25);\n- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);\n- * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);\n- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));\n- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));\n- *\n- * (end)\n+ * Class: OpenLayers.Marker.Box\n *\n- * Note that if you pass an icon into the Marker constructor, it will take\n- * that icon and use it. This means that you should not share icons between\n- * markers -- you use them once, but you should clone() for any additional\n- * markers using that same icon.\n+ * Inherits from:\n+ * - \n */\n-OpenLayers.Marker = OpenLayers.Class({\n-\n- /** \n- * Property: icon \n- * {} The icon used by this marker.\n- */\n- icon: null,\n-\n- /** \n- * Property: lonlat \n- * {} location of object\n- */\n- lonlat: null,\n+OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {\n \n /** \n- * Property: events \n- * {} the event handler.\n+ * Property: bounds \n+ * {} \n */\n- events: null,\n+ bounds: null,\n \n /** \n- * Property: map \n- * {} the map this marker is attached to\n+ * Property: div \n+ * {DOMElement} \n */\n- map: null,\n+ div: null,\n \n /** \n- * Constructor: OpenLayers.Marker\n+ * Constructor: OpenLayers.Marker.Box\n *\n * Parameters:\n- * lonlat - {} the position of this marker\n- * icon - {} the icon for this marker\n+ * bounds - {} \n+ * borderColor - {String} \n+ * borderWidth - {int} \n */\n- initialize: function(lonlat, icon) {\n- this.lonlat = lonlat;\n-\n- var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();\n- if (this.icon == null) {\n- this.icon = newIcon;\n- } else {\n- this.icon.url = newIcon.url;\n- this.icon.size = newIcon.size;\n- this.icon.offset = newIcon.offset;\n- this.icon.calculateOffset = newIcon.calculateOffset;\n- }\n- this.events = new OpenLayers.Events(this, this.icon.imageDiv);\n+ initialize: function(bounds, borderColor, borderWidth) {\n+ this.bounds = bounds;\n+ this.div = OpenLayers.Util.createDiv();\n+ this.div.style.overflow = 'hidden';\n+ this.events = new OpenLayers.Events(this, this.div);\n+ this.setBorder(borderColor, borderWidth);\n },\n \n /**\n- * APIMethod: destroy\n- * Destroy the marker. You must first remove the marker from any \n- * layer which it has been added to, or you will get buggy behavior.\n- * (This can not be done within the marker since the marker does not\n- * know which layer it is attached to.)\n+ * Method: destroy \n */\n destroy: function() {\n- // erase any drawn features\n- this.erase();\n \n- this.map = null;\n-\n- this.events.destroy();\n- this.events = null;\n+ this.bounds = null;\n+ this.div = null;\n \n- if (this.icon != null) {\n- this.icon.destroy();\n- this.icon = null;\n- }\n+ OpenLayers.Marker.prototype.destroy.apply(this, arguments);\n },\n \n /** \n- * Method: draw\n- * Calls draw on the icon, and returns that output.\n+ * Method: setBorder\n+ * Allow the user to change the box's color and border width\n * \n * Parameters:\n- * px - {}\n- * \n- * Returns:\n- * {DOMElement} A new DOM Image with this marker's icon set at the \n- * location passed-in\n- */\n- draw: function(px) {\n- return this.icon.draw(px);\n- },\n-\n- /** \n- * Method: erase\n- * Erases any drawn elements for this marker.\n+ * color - {String} Default is \"red\"\n+ * width - {int} Default is 2\n */\n- erase: function() {\n- if (this.icon != null) {\n- this.icon.erase();\n+ setBorder: function(color, width) {\n+ if (!color) {\n+ color = \"red\";\n }\n- },\n-\n- /**\n- * Method: moveTo\n- * Move the marker to the new location.\n- *\n- * Parameters:\n- * px - {|Object} the pixel position to move to.\n- * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n- */\n- moveTo: function(px) {\n- if ((px != null) && (this.icon != null)) {\n- this.icon.moveTo(px);\n+ if (!width) {\n+ width = 2;\n }\n- this.lonlat = this.map.getLonLatFromLayerPx(px);\n+ this.div.style.border = width + \"px solid \" + color;\n },\n \n- /**\n- * APIMethod: isDrawn\n+ /** \n+ * Method: draw\n * \n- * Returns:\n- * {Boolean} Whether or not the marker is drawn.\n+ * Parameters:\n+ * px - {} \n+ * sz - {} \n+ * \n+ * Returns: \n+ * {DOMElement} A new DOM Image with this marker's icon set at the \n+ * location passed-in\n */\n- isDrawn: function() {\n- var isDrawn = (this.icon && this.icon.isDrawn());\n- return isDrawn;\n+ draw: function(px, sz) {\n+ OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);\n+ return this.div;\n },\n \n /**\n * Method: onScreen\n- *\n- * Returns:\n+ * \n+ * Rreturn:\n * {Boolean} Whether or not the marker is currently visible on screen.\n */\n onScreen: function() {\n-\n var onScreen = false;\n if (this.map) {\n var screenBounds = this.map.getExtent();\n- onScreen = screenBounds.containsLonLat(this.lonlat);\n+ onScreen = screenBounds.containsBounds(this.bounds, true, true);\n }\n return onScreen;\n },\n \n /**\n- * Method: inflate\n- * Englarges the markers icon by the specified ratio.\n- *\n- * Parameters:\n- * inflate - {float} the ratio to enlarge the marker by (passing 2\n- * will double the size).\n- */\n- inflate: function(inflate) {\n- if (this.icon) {\n- this.icon.setSize({\n- w: this.icon.size.w * inflate,\n- h: this.icon.size.h * inflate\n- });\n- }\n- },\n-\n- /** \n- * Method: setOpacity\n- * Change the opacity of the marker by changin the opacity of \n- * its icon\n- * \n- * Parameters:\n- * opacity - {float} Specified as fraction (0.4, etc)\n- */\n- setOpacity: function(opacity) {\n- this.icon.setOpacity(opacity);\n- },\n-\n- /**\n- * Method: setUrl\n- * Change URL of the Icon Image.\n- * \n- * url - {String} \n- */\n- setUrl: function(url) {\n- this.icon.setUrl(url);\n- },\n-\n- /** \n * Method: display\n * Hide or show the icon\n * \n+ * Parameters:\n * display - {Boolean} \n */\n display: function(display) {\n- this.icon.display(display);\n+ this.div.style.display = (display) ? \"\" : \"none\";\n },\n \n- CLASS_NAME: \"OpenLayers.Marker\"\n+ CLASS_NAME: \"OpenLayers.Marker.Box\"\n });\n \n-\n-/**\n- * Function: defaultIcon\n- * Creates a default .\n- * \n- * Returns:\n- * {} A default OpenLayers.Icon to use for a marker\n- */\n-OpenLayers.Marker.defaultIcon = function() {\n- return new OpenLayers.Icon(OpenLayers.Util.getImageLocation(\"marker.png\"), {\n- w: 21,\n- h: 25\n- }, {\n- x: -10.5,\n- y: -25\n- });\n-};\n-\n-\n /* ======================================================================\n- OpenLayers/Strategy.js\n+ OpenLayers/Strategy/Paging.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Strategy.js\n */\n \n /**\n- * Class: OpenLayers.Strategy\n- * Abstract vector layer strategy class. Not to be instantiated directly. Use\n- * one of the strategy subclasses instead.\n+ * Class: OpenLayers.Strategy.Paging\n+ * Strategy for vector feature paging\n+ *\n+ * Inherits from:\n+ * - \n */\n-OpenLayers.Strategy = OpenLayers.Class({\n+OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {\n \n /**\n- * Property: layer\n- * {} The layer this strategy belongs to.\n+ * Property: features\n+ * {Array()} Cached features.\n */\n- layer: null,\n+ features: null,\n \n /**\n- * Property: options\n- * {Object} Any options sent to the constructor.\n- */\n- options: null,\n-\n- /** \n- * Property: active \n- * {Boolean} The control is active.\n+ * Property: length\n+ * {Integer} Number of features per page. Default is 10.\n */\n- active: null,\n+ length: 10,\n \n /**\n- * Property: autoActivate\n- * {Boolean} The creator of the strategy can set autoActivate to false\n- * to fully control when the protocol is activated and deactivated.\n- * Defaults to true.\n+ * Property: num\n+ * {Integer} The currently displayed page number.\n */\n- autoActivate: true,\n+ num: null,\n \n /**\n- * Property: autoDestroy\n- * {Boolean} The creator of the strategy can set autoDestroy to false\n- * to fully control when the strategy is destroyed. Defaults to\n- * true.\n+ * Property: paging\n+ * {Boolean} The strategy is currently changing pages.\n */\n- autoDestroy: true,\n+ paging: false,\n \n /**\n- * Constructor: OpenLayers.Strategy\n- * Abstract class for vector strategies. Create instances of a subclass.\n+ * Constructor: OpenLayers.Strategy.Paging\n+ * Create a new paging strategy.\n *\n * Parameters:\n * options - {Object} Optional object whose properties will be set on the\n * instance.\n */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.options = options;\n- // set the active property here, so that user cannot override it\n- this.active = false;\n+\n+ /**\n+ * APIMethod: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n+ * \n+ * Returns:\n+ * {Boolean} The strategy was successfully activated.\n+ */\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.call(this);\n+ if (activated) {\n+ this.layer.events.on({\n+ \"beforefeaturesadded\": this.cacheFeatures,\n+ scope: this\n+ });\n+ }\n+ return activated;\n },\n \n /**\n- * APIMethod: destroy\n- * Clean up the strategy.\n+ * APIMethod: deactivate\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n+ * \n+ * Returns:\n+ * {Boolean} The strategy was successfully deactivated.\n */\n- destroy: function() {\n- this.deactivate();\n- this.layer = null;\n- this.options = null;\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ this.clearCache();\n+ this.layer.events.un({\n+ \"beforefeaturesadded\": this.cacheFeatures,\n+ scope: this\n+ });\n+ }\n+ return deactivated;\n },\n \n /**\n- * Method: setLayer\n- * Called to set the property.\n+ * Method: cacheFeatures\n+ * Cache features before they are added to the layer.\n *\n * Parameters:\n- * layer - {}\n+ * event - {Object} The event that this was listening for. This will come\n+ * with a batch of features to be paged.\n */\n- setLayer: function(layer) {\n- this.layer = layer;\n+ cacheFeatures: function(event) {\n+ if (!this.paging) {\n+ this.clearCache();\n+ this.features = event.features;\n+ this.pageNext(event);\n+ }\n },\n \n /**\n- * Method: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n+ * Method: clearCache\n+ * Clear out the cached features. This destroys features, assuming\n+ * nothing else has a reference.\n+ */\n+ clearCache: function() {\n+ if (this.features) {\n+ for (var i = 0; i < this.features.length; ++i) {\n+ this.features[i].destroy();\n+ }\n+ }\n+ this.features = null;\n+ this.num = null;\n+ },\n+\n+ /**\n+ * APIMethod: pageCount\n+ * Get the total count of pages given the current cache of features.\n *\n * Returns:\n- * {Boolean} True if the strategy was successfully activated or false if\n- * the strategy was already active.\n+ * {Integer} The page count.\n */\n- activate: function() {\n- if (!this.active) {\n- this.active = true;\n- return true;\n+ pageCount: function() {\n+ var numFeatures = this.features ? this.features.length : 0;\n+ return Math.ceil(numFeatures / this.length);\n+ },\n+\n+ /**\n+ * APIMethod: pageNum\n+ * Get the zero based page number.\n+ *\n+ * Returns:\n+ * {Integer} The current page number being displayed.\n+ */\n+ pageNum: function() {\n+ return this.num;\n+ },\n+\n+ /**\n+ * APIMethod: pageLength\n+ * Gets or sets page length.\n+ *\n+ * Parameters:\n+ * newLength - {Integer} Optional length to be set.\n+ *\n+ * Returns:\n+ * {Integer} The length of a page (number of features per page).\n+ */\n+ pageLength: function(newLength) {\n+ if (newLength && newLength > 0) {\n+ this.length = newLength;\n }\n- return false;\n+ return this.length;\n },\n \n /**\n- * Method: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n+ * APIMethod: pageNext\n+ * Display the next page of features.\n *\n * Returns:\n- * {Boolean} True if the strategy was successfully deactivated or false if\n- * the strategy was already inactive.\n+ * {Boolean} A new page was displayed.\n */\n- deactivate: function() {\n- if (this.active) {\n- this.active = false;\n- return true;\n+ pageNext: function(event) {\n+ var changed = false;\n+ if (this.features) {\n+ if (this.num === null) {\n+ this.num = -1;\n+ }\n+ var start = (this.num + 1) * this.length;\n+ changed = this.page(start, event);\n }\n- return false;\n+ return changed;\n },\n \n- CLASS_NAME: \"OpenLayers.Strategy\"\n+ /**\n+ * APIMethod: pagePrevious\n+ * Display the previous page of features.\n+ *\n+ * Returns:\n+ * {Boolean} A new page was displayed.\n+ */\n+ pagePrevious: function() {\n+ var changed = false;\n+ if (this.features) {\n+ if (this.num === null) {\n+ this.num = this.pageCount();\n+ }\n+ var start = (this.num - 1) * this.length;\n+ changed = this.page(start);\n+ }\n+ return changed;\n+ },\n+\n+ /**\n+ * Method: page\n+ * Display the page starting at the given index from the cache.\n+ *\n+ * Returns:\n+ * {Boolean} A new page was displayed.\n+ */\n+ page: function(start, event) {\n+ var changed = false;\n+ if (this.features) {\n+ if (start >= 0 && start < this.features.length) {\n+ var num = Math.floor(start / this.length);\n+ if (num != this.num) {\n+ this.paging = true;\n+ var features = this.features.slice(start, start + this.length);\n+ this.layer.removeFeatures(this.layer.features);\n+ this.num = num;\n+ // modify the event if any\n+ if (event && event.features) {\n+ // this.was called by an event listener\n+ event.features = features;\n+ } else {\n+ // this was called directly on the strategy\n+ this.layer.addFeatures(features);\n+ }\n+ this.paging = false;\n+ changed = true;\n+ }\n+ }\n+ }\n+ return changed;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Strategy.Paging\"\n });\n /* ======================================================================\n- OpenLayers/Popup.js\n+ OpenLayers/Strategy/Filter.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Strategy.js\n+ * @requires OpenLayers/Filter.js\n */\n \n-\n /**\n- * Class: OpenLayers.Popup\n- * A popup is a small div that can opened and closed on the map.\n- * Typically opened in response to clicking on a marker. \n- * See . Popup's don't require their own\n- * layer and are added the the map using the \n- * method.\n+ * Class: OpenLayers.Strategy.Filter\n+ * Strategy for limiting features that get added to a layer by \n+ * evaluating a filter. The strategy maintains a cache of\n+ * all features until removeFeatures is called on the layer.\n *\n- * Example:\n- * (code)\n- * popup = new OpenLayers.Popup(\"chicken\", \n- * new OpenLayers.LonLat(5,40),\n- * new OpenLayers.Size(200,200),\n- * \"example popup\",\n- * true);\n- * \n- * map.addPopup(popup);\n- * (end)\n+ * Inherits from:\n+ * - \n */\n-OpenLayers.Popup = OpenLayers.Class({\n+OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, {\n \n- /** \n- * Property: events \n- * {} custom event manager \n+ /**\n+ * APIProperty: filter\n+ * {} Filter for limiting features sent to the layer.\n+ * Use the method to update this filter after construction.\n */\n- events: null,\n+ filter: null,\n \n- /** Property: id\n- * {String} the unique identifier assigned to this popup.\n+ /**\n+ * Property: cache\n+ * {Array()} List of currently cached\n+ * features.\n */\n- id: \"\",\n+ cache: null,\n \n- /** \n- * Property: lonlat \n- * {} the position of this popup on the map\n+ /**\n+ * Property: caching\n+ * {Boolean} The filter is currently caching features.\n */\n- lonlat: null,\n+ caching: false,\n \n- /** \n- * Property: div \n- * {DOMElement} the div that contains this popup.\n+ /**\n+ * Constructor: OpenLayers.Strategy.Filter\n+ * Create a new filter strategy.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- div: null,\n \n- /** \n- * Property: contentSize \n- * {} the width and height of the content.\n+ /**\n+ * APIMethod: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n+ * By default, this strategy automatically activates itself when a layer\n+ * is added to a map.\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully activated or false if\n+ * the strategy was already active.\n */\n- contentSize: null,\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);\n+ if (activated) {\n+ this.cache = [];\n+ this.layer.events.on({\n+ \"beforefeaturesadded\": this.handleAdd,\n+ \"beforefeaturesremoved\": this.handleRemove,\n+ scope: this\n+ });\n+ }\n+ return activated;\n+ },\n \n- /** \n- * Property: size \n- * {} the width and height of the popup.\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the strategy. Clear the feature cache.\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully deactivated or false if\n+ * the strategy was already inactive.\n */\n- size: null,\n+ deactivate: function() {\n+ this.cache = null;\n+ if (this.layer && this.layer.events) {\n+ this.layer.events.un({\n+ \"beforefeaturesadded\": this.handleAdd,\n+ \"beforefeaturesremoved\": this.handleRemove,\n+ scope: this\n+ });\n+ }\n+ return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments);\n+ },\n \n- /** \n- * Property: contentHTML \n- * {String} An HTML string for this popup to display.\n+ /**\n+ * Method: handleAdd\n */\n- contentHTML: null,\n+ handleAdd: function(event) {\n+ if (!this.caching && this.filter) {\n+ var features = event.features;\n+ event.features = [];\n+ var feature;\n+ for (var i = 0, ii = features.length; i < ii; ++i) {\n+ feature = features[i];\n+ if (this.filter.evaluate(feature)) {\n+ event.features.push(feature);\n+ } else {\n+ this.cache.push(feature);\n+ }\n+ }\n+ }\n+ },\n \n- /** \n- * Property: backgroundColor \n- * {String} the background color used by the popup.\n+ /**\n+ * Method: handleRemove\n */\n- backgroundColor: \"\",\n+ handleRemove: function(event) {\n+ if (!this.caching) {\n+ this.cache = [];\n+ }\n+ },\n \n /** \n- * Property: opacity \n- * {float} the opacity of this popup (between 0.0 and 1.0)\n+ * APIMethod: setFilter\n+ * Update the filter for this strategy. This will re-evaluate\n+ * any features on the layer and in the cache. Only features\n+ * for which filter.evalute(feature) returns true will be\n+ * added to the layer. Others will be cached by the strategy.\n+ *\n+ * Parameters:\n+ * filter - {} A filter for evaluating features.\n */\n- opacity: \"\",\n+ setFilter: function(filter) {\n+ this.filter = filter;\n+ var previousCache = this.cache;\n+ this.cache = [];\n+ // look through layer for features to remove from layer\n+ this.handleAdd({\n+ features: this.layer.features\n+ });\n+ // cache now contains features to remove from layer\n+ if (this.cache.length > 0) {\n+ this.caching = true;\n+ this.layer.removeFeatures(this.cache.slice());\n+ this.caching = false;\n+ }\n+ // now look through previous cache for features to add to layer\n+ if (previousCache.length > 0) {\n+ var event = {\n+ features: previousCache\n+ };\n+ this.handleAdd(event);\n+ if (event.features.length > 0) {\n+ // event has features to add to layer\n+ this.caching = true;\n+ this.layer.addFeatures(event.features);\n+ this.caching = false;\n+ }\n+ }\n+ },\n \n- /** \n- * Property: border \n- * {String} the border size of the popup. (eg 2px)\n- */\n- border: \"\",\n+ CLASS_NAME: \"OpenLayers.Strategy.Filter\"\n \n- /** \n- * Property: contentDiv \n- * {DOMElement} a reference to the element that holds the content of\n- * the div.\n- */\n- contentDiv: null,\n+});\n+/* ======================================================================\n+ OpenLayers/Strategy/Save.js\n+ ====================================================================== */\n \n- /** \n- * Property: groupDiv \n- * {DOMElement} First and only child of 'div'. The group Div contains the\n- * 'contentDiv' and the 'closeDiv'.\n- */\n- groupDiv: null,\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- /** \n- * Property: closeDiv\n- * {DOMElement} the optional closer image\n+/**\n+ * @requires OpenLayers/Strategy.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Strategy.Save\n+ * A strategy that commits newly created or modified features. By default\n+ * the strategy waits for a call to before persisting changes. By\n+ * configuring the strategy with the option, changes can be saved\n+ * automatically.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {\n+\n+ /**\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the strategy object.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * strategy.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types:\n+ * start - Triggered before saving\n+ * success - Triggered after a successful transaction\n+ * fail - Triggered after a failed transaction\n+ * \n */\n- closeDiv: null,\n \n /** \n- * APIProperty: autoSize\n- * {Boolean} Resize the popup to auto-fit the contents.\n- * Default is false.\n+ * Property: events\n+ * {} Events instance for triggering this protocol\n+ * events.\n */\n- autoSize: false,\n+ events: null,\n \n /**\n- * APIProperty: minSize\n- * {} Minimum size allowed for the popup's contents.\n+ * APIProperty: auto\n+ * {Boolean | Number} Auto-save. Default is false. If true, features will be\n+ * saved immediately after being added to the layer and with each\n+ * modification or deletion. If auto is a number, features will be\n+ * saved on an interval provided by the value (in seconds).\n */\n- minSize: null,\n+ auto: false,\n \n /**\n- * APIProperty: maxSize\n- * {} Maximum size allowed for the popup's contents.\n+ * Property: timer\n+ * {Number} The id of the timer.\n */\n- maxSize: null,\n+ timer: null,\n \n- /** \n- * Property: displayClass\n- * {String} The CSS class of the popup.\n+ /**\n+ * Constructor: OpenLayers.Strategy.Save\n+ * Create a new Save strategy.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- displayClass: \"olPopup\",\n+ initialize: function(options) {\n+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);\n+ this.events = new OpenLayers.Events(this);\n+ },\n \n- /** \n- * Property: contentDisplayClass\n- * {String} The CSS class of the popup content div.\n+ /**\n+ * APIMethod: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n+ * \n+ * Returns:\n+ * {Boolean} The strategy was successfully activated.\n */\n- contentDisplayClass: \"olPopupContent\",\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.call(this);\n+ if (activated) {\n+ if (this.auto) {\n+ if (typeof this.auto === \"number\") {\n+ this.timer = window.setInterval(\n+ OpenLayers.Function.bind(this.save, this),\n+ this.auto * 1000\n+ );\n+ } else {\n+ this.layer.events.on({\n+ \"featureadded\": this.triggerSave,\n+ \"afterfeaturemodified\": this.triggerSave,\n+ scope: this\n+ });\n+ }\n+ }\n+ }\n+ return activated;\n+ },\n \n- /** \n- * Property: padding \n- * {int or } An extra opportunity to specify internal \n- * padding of the content div inside the popup. This was originally\n- * confused with the css padding as specified in style.css's \n- * 'olPopupContent' class. We would like to get rid of this altogether,\n- * except that it does come in handy for the framed and anchoredbubble\n- * popups, who need to maintain yet another barrier between their \n- * content and the outer border of the popup itself. \n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n * \n- * Note that in order to not break API, we must continue to support \n- * this property being set as an integer. Really, though, we'd like to \n- * have this specified as a Bounds object so that user can specify\n- * distinct left, top, right, bottom paddings. With the 3.0 release\n- * we can make this only a bounds.\n+ * Returns:\n+ * {Boolean} The strategy was successfully deactivated.\n */\n- padding: 0,\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ if (this.auto) {\n+ if (typeof this.auto === \"number\") {\n+ window.clearInterval(this.timer);\n+ } else {\n+ this.layer.events.un({\n+ \"featureadded\": this.triggerSave,\n+ \"afterfeaturemodified\": this.triggerSave,\n+ scope: this\n+ });\n+ }\n+ }\n+ }\n+ return deactivated;\n+ },\n \n- /** \n- * Property: disableFirefoxOverflowHack\n- * {Boolean} The hack for overflow in Firefox causes all elements \n- * to be re-drawn, which causes Flash elements to be \n- * re-initialized, which is troublesome.\n- * With this property the hack can be disabled.\n+ /**\n+ * Method: triggerSave\n+ * Registered as a listener. Calls save if a feature has insert, update,\n+ * or delete state.\n+ *\n+ * Parameters:\n+ * event - {Object} The event this function is listening for.\n */\n- disableFirefoxOverflowHack: false,\n+ triggerSave: function(event) {\n+ var feature = event.feature;\n+ if (feature.state === OpenLayers.State.INSERT ||\n+ feature.state === OpenLayers.State.UPDATE ||\n+ feature.state === OpenLayers.State.DELETE) {\n+ this.save([event.feature]);\n+ }\n+ },\n \n /**\n- * Method: fixPadding\n- * To be removed in 3.0, this function merely helps us to deal with the \n- * case where the user may have set an integer value for padding, \n- * instead of an object.\n+ * APIMethod: save\n+ * Tell the layer protocol to commit unsaved features. If the layer\n+ * projection differs from the map projection, features will be\n+ * transformed into the layer projection before being committed.\n+ *\n+ * Parameters:\n+ * features - {Array} Features to be saved. If null, then default is all\n+ * features in the layer. Features are assumed to be in the map\n+ * projection.\n */\n- fixPadding: function() {\n- if (typeof this.padding == \"number\") {\n- this.padding = new OpenLayers.Bounds(\n- this.padding, this.padding, this.padding, this.padding\n- );\n+ save: function(features) {\n+ if (!features) {\n+ features = this.layer.features;\n }\n+ this.events.triggerEvent(\"start\", {\n+ features: features\n+ });\n+ var remote = this.layer.projection;\n+ var local = this.layer.map.getProjectionObject();\n+ if (!local.equals(remote)) {\n+ var len = features.length;\n+ var clones = new Array(len);\n+ var orig, clone;\n+ for (var i = 0; i < len; ++i) {\n+ orig = features[i];\n+ clone = orig.clone();\n+ clone.fid = orig.fid;\n+ clone.state = orig.state;\n+ if (orig.url) {\n+ clone.url = orig.url;\n+ }\n+ clone._original = orig;\n+ clone.geometry.transform(local, remote);\n+ clones[i] = clone;\n+ }\n+ features = clones;\n+ }\n+ this.layer.protocol.commit(features, {\n+ callback: this.onCommit,\n+ scope: this\n+ });\n },\n \n /**\n- * APIProperty: panMapIfOutOfView\n- * {Boolean} When drawn, pan map such that the entire popup is visible in\n- * the current viewport (if necessary).\n- * Default is false.\n+ * Method: onCommit\n+ * Called after protocol commit.\n+ *\n+ * Parameters:\n+ * response - {} A response object.\n */\n- panMapIfOutOfView: false,\n+ onCommit: function(response) {\n+ var evt = {\n+ \"response\": response\n+ };\n+ if (response.success()) {\n+ var features = response.reqFeatures;\n+ // deal with inserts, updates, and deletes\n+ var state, feature;\n+ var destroys = [];\n+ var insertIds = response.insertIds || [];\n+ var j = 0;\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ feature = features[i];\n+ // if projection was different, we may be dealing with clones\n+ feature = feature._original || feature;\n+ state = feature.state;\n+ if (state) {\n+ if (state == OpenLayers.State.DELETE) {\n+ destroys.push(feature);\n+ } else if (state == OpenLayers.State.INSERT) {\n+ feature.fid = insertIds[j];\n+ ++j;\n+ }\n+ feature.state = null;\n+ }\n+ }\n+\n+ if (destroys.length > 0) {\n+ this.layer.destroyFeatures(destroys);\n+ }\n+\n+ this.events.triggerEvent(\"success\", evt);\n+\n+ } else {\n+ this.events.triggerEvent(\"fail\", evt);\n+ }\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Strategy.Save\"\n+});\n+/* ======================================================================\n+ OpenLayers/Strategy/Fixed.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Strategy.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Strategy.Fixed\n+ * A simple strategy that requests features once and never requests new data.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {\n \n /**\n- * APIProperty: keepInMap \n- * {Boolean} If panMapIfOutOfView is false, and this property is true, \n- * contrain the popup such that it always fits in the available map\n- * space. By default, this is not set on the base class. If you are\n- * creating popups that are near map edges and not allowing pannning,\n- * and especially if you have a popup which has a\n- * fixedRelativePosition, setting this to false may be a smart thing to\n- * do. Subclasses may want to override this setting.\n- * \n- * Default is false.\n+ * APIProperty: preload\n+ * {Boolean} Load data before layer made visible. Enabling this may result\n+ * in considerable overhead if your application loads many data layers\n+ * that are not visible by default. Default is false.\n */\n- keepInMap: false,\n+ preload: false,\n \n /**\n- * APIProperty: closeOnMove\n- * {Boolean} When map pans, close the popup.\n- * Default is false.\n+ * Constructor: OpenLayers.Strategy.Fixed\n+ * Create a new Fixed strategy.\n+ *\n+ * Parameters:\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- closeOnMove: false,\n \n- /** \n- * Property: map \n- * {} this gets set in Map.js when the popup is added to the map\n+ /**\n+ * Method: activate\n+ * Activate the strategy: load data or add listener to load when visible\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully activated or false if\n+ * the strategy was already active.\n */\n- map: null,\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);\n+ if (activated) {\n+ this.layer.events.on({\n+ \"refresh\": this.load,\n+ scope: this\n+ });\n+ if (this.layer.visibility == true || this.preload) {\n+ this.load();\n+ } else {\n+ this.layer.events.on({\n+ \"visibilitychanged\": this.load,\n+ scope: this\n+ });\n+ }\n+ }\n+ return activated;\n+ },\n \n- /** \n- * Constructor: OpenLayers.Popup\n- * Create a popup.\n+ /**\n+ * Method: deactivate\n+ * Deactivate the strategy. Undo what is done in .\n * \n- * Parameters: \n- * id - {String} a unqiue identifier for this popup. If null is passed\n- * an identifier will be automatically generated. \n- * lonlat - {} The position on the map the popup will\n- * be shown.\n- * contentSize - {} The size of the content.\n- * contentHTML - {String} An HTML string to display inside the \n- * popup.\n- * closeBox - {Boolean} Whether to display a close box inside\n- * the popup.\n- * closeBoxCallback - {Function} Function to be called on closeBox click.\n+ * Returns:\n+ * {Boolean} The strategy was successfully deactivated.\n */\n- initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {\n- if (id == null) {\n- id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ this.layer.events.un({\n+ \"refresh\": this.load,\n+ \"visibilitychanged\": this.load,\n+ scope: this\n+ });\n }\n+ return deactivated;\n+ },\n \n- this.id = id;\n- this.lonlat = lonlat;\n+ /**\n+ * Method: load\n+ * Tells protocol to load data and unhooks the visibilitychanged event\n+ *\n+ * Parameters:\n+ * options - {Object} options to pass to protocol read.\n+ */\n+ load: function(options) {\n+ var layer = this.layer;\n+ layer.events.triggerEvent(\"loadstart\", {\n+ filter: layer.filter\n+ });\n+ layer.protocol.read(OpenLayers.Util.applyDefaults({\n+ callback: this.merge,\n+ filter: layer.filter,\n+ scope: this\n+ }, options));\n+ layer.events.un({\n+ \"visibilitychanged\": this.load,\n+ scope: this\n+ });\n+ },\n \n- this.contentSize = (contentSize != null) ? contentSize :\n- new OpenLayers.Size(\n- OpenLayers.Popup.WIDTH,\n- OpenLayers.Popup.HEIGHT);\n- if (contentHTML != null) {\n- this.contentHTML = contentHTML;\n+ /**\n+ * Method: merge\n+ * Add all features to the layer.\n+ * If the layer projection differs from the map projection, features\n+ * will be transformed from the layer projection to the map projection.\n+ *\n+ * Parameters:\n+ * resp - {} The response object passed\n+ * by the protocol.\n+ */\n+ merge: function(resp) {\n+ var layer = this.layer;\n+ layer.destroyFeatures();\n+ var features = resp.features;\n+ if (features && features.length > 0) {\n+ var remote = layer.projection;\n+ var local = layer.map.getProjectionObject();\n+ if (!local.equals(remote)) {\n+ var geom;\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ geom = features[i].geometry;\n+ if (geom) {\n+ geom.transform(remote, local);\n+ }\n+ }\n+ }\n+ layer.addFeatures(features);\n }\n- this.backgroundColor = OpenLayers.Popup.COLOR;\n- this.opacity = OpenLayers.Popup.OPACITY;\n- this.border = OpenLayers.Popup.BORDER;\n+ layer.events.triggerEvent(\"loadend\", {\n+ response: resp\n+ });\n+ },\n \n- this.div = OpenLayers.Util.createDiv(this.id, null, null,\n- null, null, null, \"hidden\");\n- this.div.className = this.displayClass;\n+ CLASS_NAME: \"OpenLayers.Strategy.Fixed\"\n+});\n+/* ======================================================================\n+ OpenLayers/Strategy/BBOX.js\n+ ====================================================================== */\n \n- var groupDivId = this.id + \"_GroupDiv\";\n- this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,\n- null, \"relative\", null,\n- \"hidden\");\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- var id = this.div.id + \"_contentDiv\";\n- this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),\n- null, \"relative\");\n- this.contentDiv.className = this.contentDisplayClass;\n- this.groupDiv.appendChild(this.contentDiv);\n- this.div.appendChild(this.groupDiv);\n+/**\n+ * @requires OpenLayers/Strategy.js\n+ * @requires OpenLayers/Filter/Spatial.js\n+ */\n \n- if (closeBox) {\n- this.addCloseBox(closeBoxCallback);\n- }\n+/**\n+ * Class: OpenLayers.Strategy.BBOX\n+ * A simple strategy that reads new features when the viewport invalidates\n+ * some bounds.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {\n \n- this.registerEvents();\n- },\n+ /**\n+ * Property: bounds\n+ * {} The current data bounds (in the same projection\n+ * as the layer - not always the same projection as the map).\n+ */\n+ bounds: null,\n \n /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n+ * Property: resolution \n+ * {Float} The current data resolution. \n */\n- destroy: function() {\n-\n- this.id = null;\n- this.lonlat = null;\n- this.size = null;\n- this.contentHTML = null;\n-\n- this.backgroundColor = null;\n- this.opacity = null;\n- this.border = null;\n-\n- if (this.closeOnMove && this.map) {\n- this.map.events.unregister(\"movestart\", this, this.hide);\n- }\n-\n- this.events.destroy();\n- this.events = null;\n-\n- if (this.closeDiv) {\n- OpenLayers.Event.stopObservingElement(this.closeDiv);\n- this.groupDiv.removeChild(this.closeDiv);\n- }\n- this.closeDiv = null;\n+ resolution: null,\n \n- this.div.removeChild(this.groupDiv);\n- this.groupDiv = null;\n+ /**\n+ * APIProperty: ratio\n+ * {Float} The ratio of the data bounds to the viewport bounds (in each\n+ * dimension). Default is 2.\n+ */\n+ ratio: 2,\n \n- if (this.map != null) {\n- this.map.removePopup(this);\n- }\n- this.map = null;\n- this.div = null;\n+ /** \n+ * Property: resFactor \n+ * {Float} Optional factor used to determine when previously requested \n+ * features are invalid. If set, the resFactor will be compared to the\n+ * resolution of the previous request to the current map resolution.\n+ * If resFactor > (old / new) and 1/resFactor < (old / new). If you\n+ * set a resFactor of 1, data will be requested every time the\n+ * resolution changes. If you set a resFactor of 3, data will be\n+ * requested if the old resolution is 3 times the new, or if the new is\n+ * 3 times the old. If the old bounds do not contain the new bounds\n+ * new data will always be requested (with or without considering\n+ * resFactor). \n+ */\n+ resFactor: null,\n \n- this.autoSize = null;\n- this.minSize = null;\n- this.maxSize = null;\n- this.padding = null;\n- this.panMapIfOutOfView = null;\n- },\n+ /**\n+ * Property: response\n+ * {} The protocol response object returned\n+ * by the layer protocol.\n+ */\n+ response: null,\n \n- /** \n- * Method: draw\n- * Constructs the elements that make up the popup.\n+ /**\n+ * Constructor: OpenLayers.Strategy.BBOX\n+ * Create a new BBOX strategy.\n *\n * Parameters:\n- * px - {} the position the popup in pixels.\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n+ */\n+\n+ /**\n+ * Method: activate\n+ * Set up strategy with regard to reading new batches of remote data.\n * \n * Returns:\n- * {DOMElement} Reference to a div that contains the drawn popup\n+ * {Boolean} The strategy was successfully activated.\n */\n- draw: function(px) {\n- if (px == null) {\n- if ((this.lonlat != null) && (this.map != null)) {\n- px = this.map.getLayerPxFromLonLat(this.lonlat);\n- }\n- }\n-\n- // this assumes that this.map already exists, which is okay because \n- // this.draw is only called once the popup has been added to the map.\n- if (this.closeOnMove) {\n- this.map.events.register(\"movestart\", this, this.hide);\n- }\n-\n- //listen to movestart, moveend to disable overflow (FF bug)\n- if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') {\n- this.map.events.register(\"movestart\", this, function() {\n- var style = document.defaultView.getComputedStyle(\n- this.contentDiv, null\n- );\n- var currentOverflow = style.getPropertyValue(\"overflow\");\n- if (currentOverflow != \"hidden\") {\n- this.contentDiv._oldOverflow = currentOverflow;\n- this.contentDiv.style.overflow = \"hidden\";\n- }\n- });\n- this.map.events.register(\"moveend\", this, function() {\n- var oldOverflow = this.contentDiv._oldOverflow;\n- if (oldOverflow) {\n- this.contentDiv.style.overflow = oldOverflow;\n- this.contentDiv._oldOverflow = null;\n- }\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.call(this);\n+ if (activated) {\n+ this.layer.events.on({\n+ \"moveend\": this.update,\n+ \"refresh\": this.update,\n+ \"visibilitychanged\": this.update,\n+ scope: this\n });\n+ this.update();\n }\n-\n- this.moveTo(px);\n- if (!this.autoSize && !this.size) {\n- this.setSize(this.contentSize);\n- }\n- this.setBackgroundColor();\n- this.setOpacity();\n- this.setBorder();\n- this.setContentHTML();\n-\n- if (this.panMapIfOutOfView) {\n- this.panIntoView();\n- }\n-\n- return this.div;\n+ return activated;\n },\n \n- /** \n- * Method: updatePosition\n- * if the popup has a lonlat and its map members set, \n- * then have it move itself to its proper position\n+ /**\n+ * Method: deactivate\n+ * Tear down strategy with regard to reading new batches of remote data.\n+ * \n+ * Returns:\n+ * {Boolean} The strategy was successfully deactivated.\n */\n- updatePosition: function() {\n- if ((this.lonlat) && (this.map)) {\n- var px = this.map.getLayerPxFromLonLat(this.lonlat);\n- if (px) {\n- this.moveTo(px);\n- }\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ this.layer.events.un({\n+ \"moveend\": this.update,\n+ \"refresh\": this.update,\n+ \"visibilitychanged\": this.update,\n+ scope: this\n+ });\n }\n+ return deactivated;\n },\n \n /**\n- * Method: moveTo\n- * \n+ * Method: update\n+ * Callback function called on \"moveend\" or \"refresh\" layer events.\n+ *\n * Parameters:\n- * px - {} the top and left position of the popup div. \n+ * options - {Object} Optional object whose properties will determine\n+ * the behaviour of this Strategy\n+ *\n+ * Valid options include:\n+ * force - {Boolean} if true, new data must be unconditionally read.\n+ * noAbort - {Boolean} if true, do not abort previous requests.\n */\n- moveTo: function(px) {\n- if ((px != null) && (this.div != null)) {\n- this.div.style.left = px.x + \"px\";\n- this.div.style.top = px.y + \"px\";\n+ update: function(options) {\n+ var mapBounds = this.getMapBounds();\n+ if (mapBounds !== null && ((options && options.force) ||\n+ (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) {\n+ this.calculateBounds(mapBounds);\n+ this.resolution = this.layer.map.getResolution();\n+ this.triggerRead(options);\n }\n },\n \n /**\n- * Method: visible\n+ * Method: getMapBounds\n+ * Get the map bounds expressed in the same projection as this layer.\n *\n- * Returns: \n- * {Boolean} Boolean indicating whether or not the popup is visible\n+ * Returns:\n+ * {} Map bounds in the projection of the layer.\n */\n- visible: function() {\n- return OpenLayers.Element.visible(this.div);\n+ getMapBounds: function() {\n+ if (this.layer.map === null) {\n+ return null;\n+ }\n+ var bounds = this.layer.map.getExtent();\n+ if (bounds && !this.layer.projection.equals(\n+ this.layer.map.getProjectionObject())) {\n+ bounds = bounds.clone().transform(\n+ this.layer.map.getProjectionObject(), this.layer.projection\n+ );\n+ }\n+ return bounds;\n },\n \n /**\n- * Method: toggle\n- * Toggles visibility of the popup.\n+ * Method: invalidBounds\n+ * Determine whether the previously requested set of features is invalid. \n+ * This occurs when the new map bounds do not contain the previously \n+ * requested bounds. In addition, if is set, it will be \n+ * considered.\n+ *\n+ * Parameters:\n+ * mapBounds - {} the current map extent, will be\n+ * retrieved from the map object if not provided\n+ *\n+ * Returns:\n+ * {Boolean} \n */\n- toggle: function() {\n- if (this.visible()) {\n- this.hide();\n- } else {\n- this.show();\n+ invalidBounds: function(mapBounds) {\n+ if (!mapBounds) {\n+ mapBounds = this.getMapBounds();\n+ }\n+ var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);\n+ if (!invalid && this.resFactor) {\n+ var ratio = this.resolution / this.layer.map.getResolution();\n+ invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));\n }\n+ return invalid;\n },\n \n /**\n- * Method: show\n- * Makes the popup visible.\n+ * Method: calculateBounds\n+ *\n+ * Parameters:\n+ * mapBounds - {} the current map extent, will be\n+ * retrieved from the map object if not provided\n */\n- show: function() {\n- this.div.style.display = '';\n+ calculateBounds: function(mapBounds) {\n+ if (!mapBounds) {\n+ mapBounds = this.getMapBounds();\n+ }\n+ var center = mapBounds.getCenterLonLat();\n+ var dataWidth = mapBounds.getWidth() * this.ratio;\n+ var dataHeight = mapBounds.getHeight() * this.ratio;\n+ this.bounds = new OpenLayers.Bounds(\n+ center.lon - (dataWidth / 2),\n+ center.lat - (dataHeight / 2),\n+ center.lon + (dataWidth / 2),\n+ center.lat + (dataHeight / 2)\n+ );\n+ },\n \n- if (this.panMapIfOutOfView) {\n- this.panIntoView();\n+ /**\n+ * Method: triggerRead\n+ *\n+ * Parameters:\n+ * options - {Object} Additional options for the protocol's read method \n+ * (optional)\n+ *\n+ * Returns:\n+ * {} The protocol response object\n+ * returned by the layer protocol.\n+ */\n+ triggerRead: function(options) {\n+ if (this.response && !(options && options.noAbort === true)) {\n+ this.layer.protocol.abort(this.response);\n+ this.layer.events.triggerEvent(\"loadend\");\n }\n+ var evt = {\n+ filter: this.createFilter()\n+ };\n+ this.layer.events.triggerEvent(\"loadstart\", evt);\n+ this.response = this.layer.protocol.read(\n+ OpenLayers.Util.applyDefaults({\n+ filter: evt.filter,\n+ callback: this.merge,\n+ scope: this\n+ }, options));\n },\n \n /**\n- * Method: hide\n- * Makes the popup invisible.\n+ * Method: createFilter\n+ * Creates a spatial BBOX filter. If the layer that this strategy belongs\n+ * to has a filter property, this filter will be combined with the BBOX \n+ * filter.\n+ * \n+ * Returns\n+ * {} The filter object.\n */\n- hide: function() {\n- this.div.style.display = 'none';\n+ createFilter: function() {\n+ var filter = new OpenLayers.Filter.Spatial({\n+ type: OpenLayers.Filter.Spatial.BBOX,\n+ value: this.bounds,\n+ projection: this.layer.projection\n+ });\n+ if (this.layer.filter) {\n+ filter = new OpenLayers.Filter.Logical({\n+ type: OpenLayers.Filter.Logical.AND,\n+ filters: [this.layer.filter, filter]\n+ });\n+ }\n+ return filter;\n },\n \n /**\n- * Method: setSize\n- * Used to adjust the size of the popup. \n+ * Method: merge\n+ * Given a list of features, determine which ones to add to the layer.\n+ * If the layer projection differs from the map projection, features\n+ * will be transformed from the layer projection to the map projection.\n *\n * Parameters:\n- * contentSize - {} the new size for the popup's \n- * contents div (in pixels).\n+ * resp - {} The response object passed\n+ * by the protocol.\n */\n- setSize: function(contentSize) {\n- this.size = contentSize.clone();\n-\n- // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n- // must add that to the desired \"size\". \n- var contentDivPadding = this.getContentDivPadding();\n- var wPadding = contentDivPadding.left + contentDivPadding.right;\n- var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n-\n- // take into account the popup's 'padding' property\n- this.fixPadding();\n- wPadding += this.padding.left + this.padding.right;\n- hPadding += this.padding.top + this.padding.bottom;\n-\n- // make extra space for the close div\n- if (this.closeDiv) {\n- var closeDivWidth = parseInt(this.closeDiv.style.width);\n- wPadding += closeDivWidth + contentDivPadding.right;\n- }\n-\n- //increase size of the main popup div to take into account the \n- // users's desired padding and close div. \n- this.size.w += wPadding;\n- this.size.h += hPadding;\n-\n- //now if our browser is IE, we need to actually make the contents \n- // div itself bigger to take its own padding into effect. this makes \n- // me want to shoot someone, but so it goes.\n- if (OpenLayers.BROWSER_NAME == \"msie\") {\n- this.contentSize.w +=\n- contentDivPadding.left + contentDivPadding.right;\n- this.contentSize.h +=\n- contentDivPadding.bottom + contentDivPadding.top;\n- }\n-\n- if (this.div != null) {\n- this.div.style.width = this.size.w + \"px\";\n- this.div.style.height = this.size.h + \"px\";\n- }\n- if (this.contentDiv != null) {\n- this.contentDiv.style.width = contentSize.w + \"px\";\n- this.contentDiv.style.height = contentSize.h + \"px\";\n+ merge: function(resp) {\n+ this.layer.destroyFeatures();\n+ if (resp.success()) {\n+ var features = resp.features;\n+ if (features && features.length > 0) {\n+ var remote = this.layer.projection;\n+ var local = this.layer.map.getProjectionObject();\n+ if (!local.equals(remote)) {\n+ var geom;\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ geom = features[i].geometry;\n+ if (geom) {\n+ geom.transform(remote, local);\n+ }\n+ }\n+ }\n+ this.layer.addFeatures(features);\n+ }\n+ } else {\n+ this.bounds = null;\n }\n+ this.response = null;\n+ this.layer.events.triggerEvent(\"loadend\", {\n+ response: resp\n+ });\n },\n \n- /**\n- * APIMethod: updateSize\n- * Auto size the popup so that it precisely fits its contents (as \n- * determined by this.contentDiv.innerHTML). Popup size will, of\n- * course, be limited by the available space on the current map\n- */\n- updateSize: function() {\n+ CLASS_NAME: \"OpenLayers.Strategy.BBOX\"\n+});\n+/* ======================================================================\n+ OpenLayers/Strategy/Cluster.js\n+ ====================================================================== */\n \n- // determine actual render dimensions of the contents by putting its\n- // contents into a fake contentDiv (for the CSS) and then measuring it\n- var preparedHTML = \"
\" +\n- this.contentDiv.innerHTML +\n- \"
\";\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- var containerElement = (this.map) ? this.map.div : document.body;\n- var realSize = OpenLayers.Util.getRenderedDimensions(\n- preparedHTML, null, {\n- displayClass: this.displayClass,\n- containerElement: containerElement\n- }\n- );\n+/**\n+ * @requires OpenLayers/Strategy.js\n+ */\n \n- // is the \"real\" size of the div is safe to display in our map?\n- var safeSize = this.getSafeContentSize(realSize);\n+/**\n+ * Class: OpenLayers.Strategy.Cluster\n+ * Strategy for vector feature clustering.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {\n \n- var newSize = null;\n- if (safeSize.equals(realSize)) {\n- //real size of content is small enough to fit on the map, \n- // so we use real size.\n- newSize = realSize;\n+ /**\n+ * APIProperty: distance\n+ * {Integer} Pixel distance between features that should be considered a\n+ * single cluster. Default is 20 pixels.\n+ */\n+ distance: 20,\n \n- } else {\n+ /**\n+ * APIProperty: threshold\n+ * {Integer} Optional threshold below which original features will be\n+ * added to the layer instead of clusters. For example, a threshold\n+ * of 3 would mean that any time there are 2 or fewer features in\n+ * a cluster, those features will be added directly to the layer instead\n+ * of a cluster representing those features. Default is null (which is\n+ * equivalent to 1 - meaning that clusters may contain just one feature).\n+ */\n+ threshold: null,\n \n- // make a new 'size' object with the clipped dimensions \n- // set or null if not clipped.\n- var fixedSize = {\n- w: (safeSize.w < realSize.w) ? safeSize.w : null,\n- h: (safeSize.h < realSize.h) ? safeSize.h : null\n- };\n+ /**\n+ * Property: features\n+ * {Array()} Cached features.\n+ */\n+ features: null,\n \n- if (fixedSize.w && fixedSize.h) {\n- //content is too big in both directions, so we will use \n- // max popup size (safeSize), knowing well that it will \n- // overflow both ways. \n- newSize = safeSize;\n- } else {\n- //content is clipped in only one direction, so we need to \n- // run getRenderedDimensions() again with a fixed dimension\n- var clippedSize = OpenLayers.Util.getRenderedDimensions(\n- preparedHTML, fixedSize, {\n- displayClass: this.contentDisplayClass,\n- containerElement: containerElement\n- }\n- );\n+ /**\n+ * Property: clusters\n+ * {Array()} Calculated clusters.\n+ */\n+ clusters: null,\n \n- //if the clipped size is still the same as the safeSize, \n- // that means that our content must be fixed in the \n- // offending direction. If overflow is 'auto', this means \n- // we are going to have a scrollbar for sure, so we must \n- // adjust for that.\n- //\n- var currentOverflow = OpenLayers.Element.getStyle(\n- this.contentDiv, \"overflow\"\n- );\n- if ((currentOverflow != \"hidden\") &&\n- (clippedSize.equals(safeSize))) {\n- var scrollBar = OpenLayers.Util.getScrollbarWidth();\n- if (fixedSize.w) {\n- clippedSize.h += scrollBar;\n- } else {\n- clippedSize.w += scrollBar;\n- }\n- }\n+ /**\n+ * Property: clustering\n+ * {Boolean} The strategy is currently clustering features.\n+ */\n+ clustering: false,\n \n- newSize = this.getSafeContentSize(clippedSize);\n- }\n- }\n- this.setSize(newSize);\n- },\n+ /**\n+ * Property: resolution\n+ * {Float} The resolution (map units per pixel) of the current cluster set.\n+ */\n+ resolution: null,\n \n /**\n- * Method: setBackgroundColor\n- * Sets the background color of the popup.\n+ * Constructor: OpenLayers.Strategy.Cluster\n+ * Create a new clustering strategy.\n *\n * Parameters:\n- * color - {String} the background color. eg \"#FFBBBB\"\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- setBackgroundColor: function(color) {\n- if (color != undefined) {\n- this.backgroundColor = color;\n- }\n \n- if (this.div != null) {\n- this.div.style.backgroundColor = this.backgroundColor;\n+ /**\n+ * APIMethod: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n+ * \n+ * Returns:\n+ * {Boolean} The strategy was successfully activated.\n+ */\n+ activate: function() {\n+ var activated = OpenLayers.Strategy.prototype.activate.call(this);\n+ if (activated) {\n+ this.layer.events.on({\n+ \"beforefeaturesadded\": this.cacheFeatures,\n+ \"featuresremoved\": this.clearCache,\n+ \"moveend\": this.cluster,\n+ scope: this\n+ });\n }\n+ return activated;\n },\n \n /**\n- * Method: setOpacity\n- * Sets the opacity of the popup.\n+ * APIMethod: deactivate\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n * \n- * Parameters:\n- * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). \n+ * Returns:\n+ * {Boolean} The strategy was successfully deactivated.\n */\n- setOpacity: function(opacity) {\n- if (opacity != undefined) {\n- this.opacity = opacity;\n- }\n-\n- if (this.div != null) {\n- // for Mozilla and Safari\n- this.div.style.opacity = this.opacity;\n-\n- // for IE\n- this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')';\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ this.clearCache();\n+ this.layer.events.un({\n+ \"beforefeaturesadded\": this.cacheFeatures,\n+ \"featuresremoved\": this.clearCache,\n+ \"moveend\": this.cluster,\n+ scope: this\n+ });\n }\n+ return deactivated;\n },\n \n /**\n- * Method: setBorder\n- * Sets the border style of the popup.\n+ * Method: cacheFeatures\n+ * Cache features before they are added to the layer.\n *\n * Parameters:\n- * border - {String} The border style value. eg 2px \n+ * event - {Object} The event that this was listening for. This will come\n+ * with a batch of features to be clustered.\n+ * \n+ * Returns:\n+ * {Boolean} False to stop features from being added to the layer.\n */\n- setBorder: function(border) {\n- if (border != undefined) {\n- this.border = border;\n+ cacheFeatures: function(event) {\n+ var propagate = true;\n+ if (!this.clustering) {\n+ this.clearCache();\n+ this.features = event.features;\n+ this.cluster();\n+ propagate = false;\n }\n+ return propagate;\n+ },\n \n- if (this.div != null) {\n- this.div.style.border = this.border;\n+ /**\n+ * Method: clearCache\n+ * Clear out the cached features.\n+ */\n+ clearCache: function() {\n+ if (!this.clustering) {\n+ this.features = null;\n }\n },\n \n /**\n- * Method: setContentHTML\n- * Allows the user to set the HTML content of the popup.\n+ * Method: cluster\n+ * Cluster features based on some threshold distance.\n *\n * Parameters:\n- * contentHTML - {String} HTML for the div.\n+ * event - {Object} The event received when cluster is called as a\n+ * result of a moveend event.\n */\n- setContentHTML: function(contentHTML) {\n-\n- if (contentHTML != null) {\n- this.contentHTML = contentHTML;\n- }\n-\n- if ((this.contentDiv != null) &&\n- (this.contentHTML != null) &&\n- (this.contentHTML != this.contentDiv.innerHTML)) {\n-\n- this.contentDiv.innerHTML = this.contentHTML;\n-\n- if (this.autoSize) {\n-\n- //if popup has images, listen for when they finish\n- // loading and resize accordingly\n- this.registerImageListeners();\n-\n- //auto size the popup to its current contents\n- this.updateSize();\n+ cluster: function(event) {\n+ if ((!event || event.zoomChanged) && this.features) {\n+ var resolution = this.layer.map.getResolution();\n+ if (resolution != this.resolution || !this.clustersExist()) {\n+ this.resolution = resolution;\n+ var clusters = [];\n+ var feature, clustered, cluster;\n+ for (var i = 0; i < this.features.length; ++i) {\n+ feature = this.features[i];\n+ if (feature.geometry) {\n+ clustered = false;\n+ for (var j = clusters.length - 1; j >= 0; --j) {\n+ cluster = clusters[j];\n+ if (this.shouldCluster(cluster, feature)) {\n+ this.addToCluster(cluster, feature);\n+ clustered = true;\n+ break;\n+ }\n+ }\n+ if (!clustered) {\n+ clusters.push(this.createCluster(this.features[i]));\n+ }\n+ }\n+ }\n+ this.clustering = true;\n+ this.layer.removeAllFeatures();\n+ this.clustering = false;\n+ if (clusters.length > 0) {\n+ if (this.threshold > 1) {\n+ var clone = clusters.slice();\n+ clusters = [];\n+ var candidate;\n+ for (var i = 0, len = clone.length; i < len; ++i) {\n+ candidate = clone[i];\n+ if (candidate.attributes.count < this.threshold) {\n+ Array.prototype.push.apply(clusters, candidate.cluster);\n+ } else {\n+ clusters.push(candidate);\n+ }\n+ }\n+ }\n+ this.clustering = true;\n+ // A legitimate feature addition could occur during this\n+ // addFeatures call. For clustering to behave well, features\n+ // should be removed from a layer before requesting a new batch.\n+ this.layer.addFeatures(clusters);\n+ this.clustering = false;\n+ }\n+ this.clusters = clusters;\n }\n }\n-\n },\n \n /**\n- * Method: registerImageListeners\n- * Called when an image contained by the popup loaded. this function\n- * updates the popup size, then unregisters the image load listener.\n+ * Method: clustersExist\n+ * Determine whether calculated clusters are already on the layer.\n+ *\n+ * Returns:\n+ * {Boolean} The calculated clusters are already on the layer.\n */\n- registerImageListeners: function() {\n-\n- // As the images load, this function will call updateSize() to \n- // resize the popup to fit the content div (which presumably is now\n- // bigger than when the image was not loaded).\n- // \n- // If the 'panMapIfOutOfView' property is set, we will pan the newly\n- // resized popup back into view.\n- // \n- // Note that this function, when called, will have 'popup' and \n- // 'img' properties in the context.\n- //\n- var onImgLoad = function() {\n- if (this.popup.id === null) { // this.popup has been destroyed!\n- return;\n- }\n- this.popup.updateSize();\n-\n- if (this.popup.visible() && this.popup.panMapIfOutOfView) {\n- this.popup.panIntoView();\n- }\n-\n- OpenLayers.Event.stopObserving(\n- this.img, \"load\", this.img._onImgLoad\n- );\n-\n- };\n-\n- //cycle through the images and if their size is 0x0, that means that \n- // they haven't been loaded yet, so we attach the listener, which \n- // will fire when the images finish loading and will resize the \n- // popup accordingly to its new size.\n- var images = this.contentDiv.getElementsByTagName(\"img\");\n- for (var i = 0, len = images.length; i < len; i++) {\n- var img = images[i];\n- if (img.width == 0 || img.height == 0) {\n-\n- var context = {\n- 'popup': this,\n- 'img': img\n- };\n-\n- //expando this function to the image itself before registering\n- // it. This way we can easily and properly unregister it.\n- img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);\n-\n- OpenLayers.Event.observe(img, 'load', img._onImgLoad);\n+ clustersExist: function() {\n+ var exist = false;\n+ if (this.clusters && this.clusters.length > 0 &&\n+ this.clusters.length == this.layer.features.length) {\n+ exist = true;\n+ for (var i = 0; i < this.clusters.length; ++i) {\n+ if (this.clusters[i] != this.layer.features[i]) {\n+ exist = false;\n+ break;\n+ }\n }\n }\n+ return exist;\n },\n \n /**\n- * APIMethod: getSafeContentSize\n- * \n+ * Method: shouldCluster\n+ * Determine whether to include a feature in a given cluster.\n+ *\n * Parameters:\n- * size - {} Desired size to make the popup.\n- * \n+ * cluster - {} A cluster.\n+ * feature - {} A feature.\n+ *\n * Returns:\n- * {} A size to make the popup which is neither smaller\n- * than the specified minimum size, nor bigger than the maximum \n- * size (which is calculated relative to the size of the viewport).\n+ * {Boolean} The feature should be included in the cluster.\n */\n- getSafeContentSize: function(size) {\n-\n- var safeContentSize = size.clone();\n+ shouldCluster: function(cluster, feature) {\n+ var cc = cluster.geometry.getBounds().getCenterLonLat();\n+ var fc = feature.geometry.getBounds().getCenterLonLat();\n+ var distance = (\n+ Math.sqrt(\n+ Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)\n+ ) / this.resolution\n+ );\n+ return (distance <= this.distance);\n+ },\n \n- // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n- // must add that to the desired \"size\". \n- var contentDivPadding = this.getContentDivPadding();\n- var wPadding = contentDivPadding.left + contentDivPadding.right;\n- var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n-\n- // take into account the popup's 'padding' property\n- this.fixPadding();\n- wPadding += this.padding.left + this.padding.right;\n- hPadding += this.padding.top + this.padding.bottom;\n-\n- if (this.closeDiv) {\n- var closeDivWidth = parseInt(this.closeDiv.style.width);\n- wPadding += closeDivWidth + contentDivPadding.right;\n- }\n-\n- // prevent the popup from being smaller than a specified minimal size\n- if (this.minSize) {\n- safeContentSize.w = Math.max(safeContentSize.w,\n- (this.minSize.w - wPadding));\n- safeContentSize.h = Math.max(safeContentSize.h,\n- (this.minSize.h - hPadding));\n- }\n-\n- // prevent the popup from being bigger than a specified maximum size\n- if (this.maxSize) {\n- safeContentSize.w = Math.min(safeContentSize.w,\n- (this.maxSize.w - wPadding));\n- safeContentSize.h = Math.min(safeContentSize.h,\n- (this.maxSize.h - hPadding));\n- }\n-\n- //make sure the desired size to set doesn't result in a popup that \n- // is bigger than the map's viewport.\n- //\n- if (this.map && this.map.size) {\n-\n- var extraX = 0,\n- extraY = 0;\n- if (this.keepInMap && !this.panMapIfOutOfView) {\n- var px = this.map.getPixelFromLonLat(this.lonlat);\n- switch (this.relativePosition) {\n- case \"tr\":\n- extraX = px.x;\n- extraY = this.map.size.h - px.y;\n- break;\n- case \"tl\":\n- extraX = this.map.size.w - px.x;\n- extraY = this.map.size.h - px.y;\n- break;\n- case \"bl\":\n- extraX = this.map.size.w - px.x;\n- extraY = px.y;\n- break;\n- case \"br\":\n- extraX = px.x;\n- extraY = px.y;\n- break;\n- default:\n- extraX = px.x;\n- extraY = this.map.size.h - px.y;\n- break;\n- }\n- }\n-\n- var maxY = this.map.size.h -\n- this.map.paddingForPopups.top -\n- this.map.paddingForPopups.bottom -\n- hPadding - extraY;\n-\n- var maxX = this.map.size.w -\n- this.map.paddingForPopups.left -\n- this.map.paddingForPopups.right -\n- wPadding - extraX;\n-\n- safeContentSize.w = Math.min(safeContentSize.w, maxX);\n- safeContentSize.h = Math.min(safeContentSize.h, maxY);\n- }\n-\n- return safeContentSize;\n- },\n+ /**\n+ * Method: addToCluster\n+ * Add a feature to a cluster.\n+ *\n+ * Parameters:\n+ * cluster - {} A cluster.\n+ * feature - {} A feature.\n+ */\n+ addToCluster: function(cluster, feature) {\n+ cluster.cluster.push(feature);\n+ cluster.attributes.count += 1;\n+ },\n \n /**\n- * Method: getContentDivPadding\n- * Glorious, oh glorious hack in order to determine the css 'padding' of \n- * the contentDiv. IE/Opera return null here unless we actually add the \n- * popup's main 'div' element (which contains contentDiv) to the DOM. \n- * So we make it invisible and then add it to the document temporarily. \n+ * Method: createCluster\n+ * Given a feature, create a cluster.\n *\n- * Once we've taken the padding readings we need, we then remove it \n- * from the DOM (it will actually get added to the DOM in \n- * Map.js's addPopup)\n+ * Parameters:\n+ * feature - {}\n *\n * Returns:\n- * {}\n- */\n- getContentDivPadding: function() {\n-\n- //use cached value if we have it\n- var contentDivPadding = this._contentDivPadding;\n- if (!contentDivPadding) {\n-\n- if (this.div.parentNode == null) {\n- //make the div invisible and add it to the page \n- this.div.style.display = \"none\";\n- document.body.appendChild(this.div);\n- }\n-\n- //read the padding settings from css, put them in an OL.Bounds \n- contentDivPadding = new OpenLayers.Bounds(\n- OpenLayers.Element.getStyle(this.contentDiv, \"padding-left\"),\n- OpenLayers.Element.getStyle(this.contentDiv, \"padding-bottom\"),\n- OpenLayers.Element.getStyle(this.contentDiv, \"padding-right\"),\n- OpenLayers.Element.getStyle(this.contentDiv, \"padding-top\")\n- );\n-\n- //cache the value\n- this._contentDivPadding = contentDivPadding;\n-\n- if (this.div.parentNode == document.body) {\n- //remove the div from the page and make it visible again\n- document.body.removeChild(this.div);\n- this.div.style.display = \"\";\n- }\n- }\n- return contentDivPadding;\n- },\n-\n- /**\n- * Method: addCloseBox\n- * \n- * Parameters:\n- * callback - {Function} The callback to be called when the close button\n- * is clicked.\n+ * {} A cluster.\n */\n- addCloseBox: function(callback) {\n-\n- this.closeDiv = OpenLayers.Util.createDiv(\n- this.id + \"_close\", null, {\n- w: 17,\n- h: 17\n+ createCluster: function(feature) {\n+ var center = feature.geometry.getBounds().getCenterLonLat();\n+ var cluster = new OpenLayers.Feature.Vector(\n+ new OpenLayers.Geometry.Point(center.lon, center.lat), {\n+ count: 1\n }\n );\n- this.closeDiv.className = \"olPopupCloseBox\";\n-\n- // use the content div's css padding to determine if we should\n- // padd the close div\n- var contentDivPadding = this.getContentDivPadding();\n-\n- this.closeDiv.style.right = contentDivPadding.right + \"px\";\n- this.closeDiv.style.top = contentDivPadding.top + \"px\";\n- this.groupDiv.appendChild(this.closeDiv);\n-\n- var closePopup = callback || function(e) {\n- this.hide();\n- OpenLayers.Event.stop(e);\n- };\n- OpenLayers.Event.observe(this.closeDiv, \"touchend\",\n- OpenLayers.Function.bindAsEventListener(closePopup, this));\n- OpenLayers.Event.observe(this.closeDiv, \"click\",\n- OpenLayers.Function.bindAsEventListener(closePopup, this));\n- },\n-\n- /**\n- * Method: panIntoView\n- * Pans the map such that the popup is totaly viewable (if necessary)\n- */\n- panIntoView: function() {\n-\n- var mapSize = this.map.getSize();\n-\n- //start with the top left corner of the popup, in px, \n- // relative to the viewport\n- var origTL = this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(\n- parseInt(this.div.style.left),\n- parseInt(this.div.style.top)\n- ));\n- var newTL = origTL.clone();\n-\n- //new left (compare to margins, using this.size to calculate right)\n- if (origTL.x < this.map.paddingForPopups.left) {\n- newTL.x = this.map.paddingForPopups.left;\n- } else\n- if ((origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {\n- newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;\n- }\n-\n- //new top (compare to margins, using this.size to calculate bottom)\n- if (origTL.y < this.map.paddingForPopups.top) {\n- newTL.y = this.map.paddingForPopups.top;\n- } else\n- if ((origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {\n- newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;\n- }\n-\n- var dx = origTL.x - newTL.x;\n- var dy = origTL.y - newTL.y;\n-\n- this.map.pan(dx, dy);\n- },\n-\n- /** \n- * Method: registerEvents\n- * Registers events on the popup.\n- *\n- * Do this in a separate function so that subclasses can \n- * choose to override it if they wish to deal differently\n- * with mouse events\n- * \n- * Note in the following handler functions that some special\n- * care is needed to deal correctly with mousing and popups. \n- * \n- * Because the user might select the zoom-rectangle option and\n- * then drag it over a popup, we need a safe way to allow the\n- * mousemove and mouseup events to pass through the popup when\n- * they are initiated from outside. The same procedure is needed for\n- * touchmove and touchend events.\n- * \n- * Otherwise, we want to essentially kill the event propagation\n- * for all other events, though we have to do so carefully, \n- * without disabling basic html functionality, like clicking on \n- * hyperlinks or drag-selecting text.\n- */\n- registerEvents: function() {\n- this.events = new OpenLayers.Events(this, this.div, null, true);\n-\n- function onTouchstart(evt) {\n- OpenLayers.Event.stop(evt, true);\n- }\n- this.events.on({\n- \"mousedown\": this.onmousedown,\n- \"mousemove\": this.onmousemove,\n- \"mouseup\": this.onmouseup,\n- \"click\": this.onclick,\n- \"mouseout\": this.onmouseout,\n- \"dblclick\": this.ondblclick,\n- \"touchstart\": onTouchstart,\n- scope: this\n- });\n-\n- },\n-\n- /** \n- * Method: onmousedown \n- * When mouse goes down within the popup, make a note of\n- * it locally, and then do not propagate the mousedown \n- * (but do so safely so that user can select text inside)\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- onmousedown: function(evt) {\n- this.mousedown = true;\n- OpenLayers.Event.stop(evt, true);\n- },\n-\n- /** \n- * Method: onmousemove\n- * If the drag was started within the popup, then \n- * do not propagate the mousemove (but do so safely\n- * so that user can select text inside)\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- onmousemove: function(evt) {\n- if (this.mousedown) {\n- OpenLayers.Event.stop(evt, true);\n- }\n- },\n-\n- /** \n- * Method: onmouseup\n- * When mouse comes up within the popup, after going down \n- * in it, reset the flag, and then (once again) do not \n- * propagate the event, but do so safely so that user can \n- * select text inside\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- onmouseup: function(evt) {\n- if (this.mousedown) {\n- this.mousedown = false;\n- OpenLayers.Event.stop(evt, true);\n- }\n- },\n-\n- /**\n- * Method: onclick\n- * Ignore clicks, but allowing default browser handling\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- onclick: function(evt) {\n- OpenLayers.Event.stop(evt, true);\n- },\n-\n- /** \n- * Method: onmouseout\n- * When mouse goes out of the popup set the flag to false so that\n- * if they let go and then drag back in, we won't be confused.\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- onmouseout: function(evt) {\n- this.mousedown = false;\n- },\n-\n- /** \n- * Method: ondblclick\n- * Ignore double-clicks, but allowing default browser handling\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- ondblclick: function(evt) {\n- OpenLayers.Event.stop(evt, true);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Popup\"\n-});\n-\n-OpenLayers.Popup.WIDTH = 200;\n-OpenLayers.Popup.HEIGHT = 200;\n-OpenLayers.Popup.COLOR = \"white\";\n-OpenLayers.Popup.OPACITY = 1;\n-OpenLayers.Popup.BORDER = \"0px\";\n-/* ======================================================================\n- OpenLayers/StyleMap.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Style.js\n- * @requires OpenLayers/Feature/Vector.js\n- */\n-\n-/**\n- * Class: OpenLayers.StyleMap\n- */\n-OpenLayers.StyleMap = OpenLayers.Class({\n-\n- /**\n- * Property: styles\n- * {Object} Hash of {}, keyed by names of well known\n- * rendering intents (e.g. \"default\", \"temporary\", \"select\", \"delete\").\n- */\n- styles: null,\n-\n- /**\n- * Property: extendDefault\n- * {Boolean} if true, every render intent will extend the symbolizers\n- * specified for the \"default\" intent at rendering time. Otherwise, every\n- * rendering intent will be treated as a completely independent style.\n- */\n- extendDefault: true,\n-\n- /**\n- * Constructor: OpenLayers.StyleMap\n- * \n- * Parameters:\n- * style - {Object} Optional. Either a style hash, or a style object, or\n- * a hash of style objects (style hashes) keyed by rendering\n- * intent. If just one style hash or style object is passed,\n- * this will be used for all known render intents (default,\n- * select, temporary)\n- * options - {Object} optional hash of additional options for this\n- * instance\n- */\n- initialize: function(style, options) {\n- this.styles = {\n- \"default\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"default\"]),\n- \"select\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"select\"]),\n- \"temporary\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"temporary\"]),\n- \"delete\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"delete\"])\n- };\n-\n- // take whatever the user passed as style parameter and convert it\n- // into parts of stylemap.\n- if (style instanceof OpenLayers.Style) {\n- // user passed a style object\n- this.styles[\"default\"] = style;\n- this.styles[\"select\"] = style;\n- this.styles[\"temporary\"] = style;\n- this.styles[\"delete\"] = style;\n- } else if (typeof style == \"object\") {\n- for (var key in style) {\n- if (style[key] instanceof OpenLayers.Style) {\n- // user passed a hash of style objects\n- this.styles[key] = style[key];\n- } else if (typeof style[key] == \"object\") {\n- // user passsed a hash of style hashes\n- this.styles[key] = new OpenLayers.Style(style[key]);\n- } else {\n- // user passed a style hash (i.e. symbolizer)\n- this.styles[\"default\"] = new OpenLayers.Style(style);\n- this.styles[\"select\"] = new OpenLayers.Style(style);\n- this.styles[\"temporary\"] = new OpenLayers.Style(style);\n- this.styles[\"delete\"] = new OpenLayers.Style(style);\n- break;\n- }\n- }\n- }\n- OpenLayers.Util.extend(this, options);\n- },\n-\n- /**\n- * Method: destroy\n- */\n- destroy: function() {\n- for (var key in this.styles) {\n- this.styles[key].destroy();\n- }\n- this.styles = null;\n- },\n-\n- /**\n- * Method: createSymbolizer\n- * Creates the symbolizer for a feature for a render intent.\n- * \n- * Parameters:\n- * feature - {} The feature to evaluate the rules\n- * of the intended style against.\n- * intent - {String} The intent determines the symbolizer that will be\n- * used to draw the feature. Well known intents are \"default\"\n- * (for just drawing the features), \"select\" (for selected\n- * features) and \"temporary\" (for drawing features).\n- * \n- * Returns:\n- * {Object} symbolizer hash\n- */\n- createSymbolizer: function(feature, intent) {\n- if (!feature) {\n- feature = new OpenLayers.Feature.Vector();\n- }\n- if (!this.styles[intent]) {\n- intent = \"default\";\n- }\n- feature.renderIntent = intent;\n- var defaultSymbolizer = {};\n- if (this.extendDefault && intent != \"default\") {\n- defaultSymbolizer = this.styles[\"default\"].createSymbolizer(feature);\n- }\n- return OpenLayers.Util.extend(defaultSymbolizer,\n- this.styles[intent].createSymbolizer(feature));\n- },\n-\n- /**\n- * Method: addUniqueValueRules\n- * Convenience method to create comparison rules for unique values of a\n- * property. The rules will be added to the style object for a specified\n- * rendering intent. This method is a shortcut for creating something like\n- * the \"unique value legends\" familiar from well known desktop GIS systems\n- * \n- * Parameters:\n- * renderIntent - {String} rendering intent to add the rules to\n- * property - {String} values of feature attributes to create the\n- * rules for\n- * symbolizers - {Object} Hash of symbolizers, keyed by the desired\n- * property values \n- * context - {Object} An optional object with properties that\n- * symbolizers' property values should be evaluated\n- * against. If no context is specified, feature.attributes\n- * will be used\n- */\n- addUniqueValueRules: function(renderIntent, property, symbolizers, context) {\n- var rules = [];\n- for (var value in symbolizers) {\n- rules.push(new OpenLayers.Rule({\n- symbolizer: symbolizers[value],\n- context: context,\n- filter: new OpenLayers.Filter.Comparison({\n- type: OpenLayers.Filter.Comparison.EQUAL_TO,\n- property: property,\n- value: value\n- })\n- }));\n- }\n- this.styles[renderIntent].addRules(rules);\n+ cluster.cluster = [feature];\n+ return cluster;\n },\n \n- CLASS_NAME: \"OpenLayers.StyleMap\"\n+ CLASS_NAME: \"OpenLayers.Strategy.Cluster\"\n });\n /* ======================================================================\n- OpenLayers/Handler.js\n+ OpenLayers/Strategy/Refresh.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Strategy.js\n */\n \n /**\n- * Class: OpenLayers.Handler\n- * Base class to construct a higher-level handler for event sequences. All\n- * handlers have activate and deactivate methods. In addition, they have\n- * methods named like browser events. When a handler is activated, any\n- * additional methods named like a browser event is registered as a\n- * listener for the corresponding event. When a handler is deactivated,\n- * those same methods are unregistered as event listeners.\n+ * Class: OpenLayers.Strategy.Refresh\n+ * A strategy that refreshes the layer. By default the strategy waits for a\n+ * call to before refreshing. By configuring the strategy with \n+ * the option, refreshing can take place automatically.\n *\n- * Handlers also typically have a callbacks object with keys named like\n- * the abstracted events or event sequences that they are in charge of\n- * handling. The controls that wrap handlers define the methods that\n- * correspond to these abstract events - so instead of listening for\n- * individual browser events, they only listen for the abstract events\n- * defined by the handler.\n- * \n- * Handlers are created by controls, which ultimately have the responsibility\n- * of making changes to the the state of the application. Handlers\n- * themselves may make temporary changes, but in general are expected to\n- * return the application in the same state that they found it.\n+ * Inherits from:\n+ * - \n */\n-OpenLayers.Handler = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String}\n- */\n- id: null,\n-\n- /**\n- * APIProperty: control\n- * {}. The control that initialized this handler. The\n- * control is assumed to have a valid map property - that map is used\n- * in the handler's own setMap method.\n- */\n- control: null,\n-\n- /**\n- * Property: map\n- * {}\n- */\n- map: null,\n-\n- /**\n- * APIProperty: keyMask\n- * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler\n- * constants to construct a keyMask. The keyMask is used by\n- * . If the keyMask matches the combination of keys\n- * down on an event, checkModifiers returns true.\n- *\n- * Example:\n- * (code)\n- * // handler only responds if the Shift key is down\n- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;\n- *\n- * // handler only responds if Ctrl-Shift is down\n- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |\n- * OpenLayers.Handler.MOD_CTRL;\n- * (end)\n- */\n- keyMask: null,\n+OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, {\n \n /**\n- * Property: active\n- * {Boolean}\n+ * Property: force\n+ * {Boolean} Force a refresh on the layer. Default is false.\n */\n- active: false,\n+ force: false,\n \n /**\n- * Property: evt\n- * {Event} This property references the last event handled by the handler.\n- * Note that this property is not part of the stable API. Use of the\n- * evt property should be restricted to controls in the library\n- * or other applications that are willing to update with changes to\n- * the OpenLayers code.\n+ * Property: interval\n+ * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed \n+ * every N milliseconds.\n */\n- evt: null,\n+ interval: 0,\n \n /**\n- * Property: touch\n- * {Boolean} Indicates the support of touch events. When touch events are \n- * started touch will be true and all mouse related listeners will do \n- * nothing.\n+ * Property: timer\n+ * {Number} The id of the timer.\n */\n- touch: false,\n+ timer: null,\n \n /**\n- * Constructor: OpenLayers.Handler\n- * Construct a handler.\n+ * Constructor: OpenLayers.Strategy.Refresh\n+ * Create a new Refresh strategy.\n *\n * Parameters:\n- * control - {} The control that initialized this\n- * handler. The control is assumed to have a valid map property; that\n- * map is used in the handler's own setMap method. If a map property\n- * is present in the options argument it will be used instead.\n- * callbacks - {Object} An object whose properties correspond to abstracted\n- * events or sequences of browser events. The values for these\n- * properties are functions defined by the control that get called by\n- * the handler.\n- * options - {Object} An optional object whose properties will be set on\n- * the handler.\n- */\n- initialize: function(control, callbacks, options) {\n- OpenLayers.Util.extend(this, options);\n- this.control = control;\n- this.callbacks = callbacks;\n-\n- var map = this.map || control.map;\n- if (map) {\n- this.setMap(map);\n- }\n-\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /**\n- * Method: setMap\n- */\n- setMap: function(map) {\n- this.map = map;\n- },\n-\n- /**\n- * Method: checkModifiers\n- * Check the keyMask on the handler. If no is set, this always\n- * returns true. If a is set and it matches the combination\n- * of keys down on an event, this returns true.\n- *\n- * Returns:\n- * {Boolean} The keyMask matches the keys down on an event.\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- checkModifiers: function(evt) {\n- if (this.keyMask == null) {\n- return true;\n- }\n- /* calculate the keyboard modifier mask for this event */\n- var keyModifiers =\n- (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |\n- (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |\n- (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) |\n- (evt.metaKey ? OpenLayers.Handler.MOD_META : 0);\n-\n- /* if it differs from the handler object's key mask,\n- bail out of the event handler */\n- return (keyModifiers == this.keyMask);\n- },\n \n /**\n * APIMethod: activate\n- * Turn on the handler. Returns false if the handler was already active.\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n * \n- * Returns: \n- * {Boolean} The handler was activated.\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully activated.\n */\n activate: function() {\n- if (this.active) {\n- return false;\n- }\n- // register for event handlers defined on this class.\n- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.register(events[i], this[events[i]]);\n+ var activated = OpenLayers.Strategy.prototype.activate.call(this);\n+ if (activated) {\n+ if (this.layer.visibility === true) {\n+ this.start();\n }\n+ this.layer.events.on({\n+ \"visibilitychanged\": this.reset,\n+ scope: this\n+ });\n }\n- this.active = true;\n- return true;\n+ return activated;\n },\n \n /**\n * APIMethod: deactivate\n- * Turn off the handler. Returns false if the handler was already inactive.\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n * \n * Returns:\n- * {Boolean} The handler was deactivated.\n+ * {Boolean} True if the strategy was successfully deactivated.\n */\n deactivate: function() {\n- if (!this.active) {\n- return false;\n- }\n- // unregister event handlers defined on this class.\n- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.unregister(events[i], this[events[i]]);\n- }\n- }\n- this.touch = false;\n- this.active = false;\n- return true;\n- },\n-\n- /**\n- * Method: startTouch\n- * Start touch events, this method must be called by subclasses in \n- * \"touchstart\" method. When touch events are started will be\n- * true and all mouse related listeners will do nothing.\n- */\n- startTouch: function() {\n- if (!this.touch) {\n- this.touch = true;\n- var events = [\n- \"mousedown\", \"mouseup\", \"mousemove\", \"click\", \"dblclick\",\n- \"mouseout\"\n- ];\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.unregister(events[i], this[events[i]]);\n- }\n- }\n- }\n- },\n-\n- /**\n- * Method: callback\n- * Trigger the control's named callback with the given arguments\n- *\n- * Parameters:\n- * name - {String} The key for the callback that is one of the properties\n- * of the handler's callbacks object.\n- * args - {Array(*)} An array of arguments (any type) with which to call \n- * the callback (defined by the control).\n- */\n- callback: function(name, args) {\n- if (name && this.callbacks[name]) {\n- this.callbacks[name].apply(this.control, args);\n- }\n- },\n-\n- /**\n- * Method: register\n- * register an event on the map\n- */\n- register: function(name, method) {\n- // TODO: deal with registerPriority in 3.0\n- this.map.events.registerPriority(name, this, method);\n- this.map.events.registerPriority(name, this, this.setEvent);\n- },\n-\n- /**\n- * Method: unregister\n- * unregister an event from the map\n- */\n- unregister: function(name, method) {\n- this.map.events.unregister(name, this, method);\n- this.map.events.unregister(name, this, this.setEvent);\n- },\n-\n- /**\n- * Method: setEvent\n- * With each registered browser event, the handler sets its own evt\n- * property. This property can be accessed by controls if needed\n- * to get more information about the event that the handler is\n- * processing.\n- *\n- * This allows modifier keys on the event to be checked (alt, shift, ctrl,\n- * and meta cannot be checked with the keyboard handler). For a\n- * control to determine which modifier keys are associated with the\n- * event that a handler is currently processing, it should access\n- * (code)handler.evt.altKey || handler.evt.shiftKey ||\n- * handler.evt.ctrlKey || handler.evt.metaKey(end).\n- *\n- * Parameters:\n- * evt - {Event} The browser event.\n- */\n- setEvent: function(evt) {\n- this.evt = evt;\n- return true;\n- },\n-\n- /**\n- * Method: destroy\n- * Deconstruct the handler.\n- */\n- destroy: function() {\n- // unregister event listeners\n- this.deactivate();\n- // eliminate circular references\n- this.control = this.map = null;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler\"\n-});\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_NONE\n- * If set as the , returns false if any key is down.\n- */\n-OpenLayers.Handler.MOD_NONE = 0;\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_SHIFT\n- * If set as the , returns false if Shift is down.\n- */\n-OpenLayers.Handler.MOD_SHIFT = 1;\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_CTRL\n- * If set as the , returns false if Ctrl is down.\n- */\n-OpenLayers.Handler.MOD_CTRL = 2;\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_ALT\n- * If set as the , returns false if Alt is down.\n- */\n-OpenLayers.Handler.MOD_ALT = 4;\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_META\n- * If set as the , returns false if Cmd is down.\n- */\n-OpenLayers.Handler.MOD_META = 8;\n-\n-\n-/* ======================================================================\n- OpenLayers/Spherical.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n-\n-/**\n- * Namespace: Spherical\n- * The OpenLayers.Spherical namespace includes utility functions for\n- * calculations on the basis of a spherical earth (ignoring ellipsoidal\n- * effects), which is accurate enough for most purposes.\n- *\n- * Relevant links:\n- * * http://www.movable-type.co.uk/scripts/latlong.html\n- * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical\n- */\n-\n-OpenLayers.Spherical = OpenLayers.Spherical || {};\n-\n-OpenLayers.Spherical.DEFAULT_RADIUS = 6378137;\n-\n-/**\n- * APIFunction: computeDistanceBetween\n- * Computes the distance between two LonLats.\n- *\n- * Parameters:\n- * from - {} or {Object} Starting point. A LonLat or\n- * a JavaScript literal with lon lat properties.\n- * to - {} or {Object} Ending point. A LonLat or a\n- * JavaScript literal with lon lat properties.\n- * radius - {Float} The radius. Optional. Defaults to 6378137 meters.\n- *\n- * Returns:\n- * {Float} The distance in meters.\n- */\n-OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) {\n- var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS;\n- var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360);\n- var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360);\n- var a = sinHalfDeltaLat * sinHalfDeltaLat +\n- sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180);\n- return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n-};\n-\n-\n-/**\n- * APIFunction: computeHeading\n- * Computes the heading from one LonLat to another LonLat.\n- *\n- * Parameters:\n- * from - {} or {Object} Starting point. A LonLat or\n- * a JavaScript literal with lon lat properties.\n- * to - {} or {Object} Ending point. A LonLat or a\n- * JavaScript literal with lon lat properties.\n- *\n- * Returns:\n- * {Float} The heading in degrees.\n- */\n-OpenLayers.Spherical.computeHeading = function(from, to) {\n- var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180);\n- var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) -\n- Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180);\n- return 180 * Math.atan2(y, x) / Math.PI;\n-};\n-/* ======================================================================\n- OpenLayers/Symbolizer.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer\n- * Base class representing a symbolizer used for feature rendering.\n- */\n-OpenLayers.Symbolizer = OpenLayers.Class({\n-\n-\n- /**\n- * APIProperty: zIndex\n- * {Number} The zIndex determines the rendering order for a symbolizer.\n- * Symbolizers with larger zIndex values are rendered over symbolizers\n- * with smaller zIndex values. Default is 0.\n- */\n- zIndex: 0,\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer\n- * Instances of this class are not useful. See one of the subclasses.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Util.extend(this, config);\n- },\n-\n- /** \n- * APIMethod: clone\n- * Create a copy of this symbolizer.\n- *\n- * Returns a symbolizer of the same type with the same properties.\n- */\n- clone: function() {\n- var Type = eval(this.CLASS_NAME);\n- return new Type(OpenLayers.Util.extend({}, this));\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Rule.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Style.js\n- */\n-\n-/**\n- * Class: OpenLayers.Rule\n- * This class represents an SLD Rule, as being used for rule-based SLD styling.\n- */\n-OpenLayers.Rule = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String} A unique id for this session.\n- */\n- id: null,\n-\n- /**\n- * APIProperty: name\n- * {String} name of this rule\n- */\n- name: null,\n-\n- /**\n- * Property: title\n- * {String} Title of this rule (set if included in SLD)\n- */\n- title: null,\n-\n- /**\n- * Property: description\n- * {String} Description of this rule (set if abstract is included in SLD)\n- */\n- description: null,\n-\n- /**\n- * Property: context\n- * {Object} An optional object with properties that the rule should be\n- * evaluated against. If no context is specified, feature.attributes will\n- * be used.\n- */\n- context: null,\n-\n- /**\n- * Property: filter\n- * {} Optional filter for the rule.\n- */\n- filter: null,\n-\n- /**\n- * Property: elseFilter\n- * {Boolean} Determines whether this rule is only to be applied only if\n- * no other rules match (ElseFilter according to the SLD specification). \n- * Default is false. For instances of OpenLayers.Rule, if elseFilter is\n- * false, the rule will always apply. For subclasses, the else property is \n- * ignored.\n- */\n- elseFilter: false,\n-\n- /**\n- * Property: symbolizer\n- * {Object} Symbolizer or hash of symbolizers for this rule. If hash of\n- * symbolizers, keys are one or more of [\"Point\", \"Line\", \"Polygon\"]. The\n- * latter if useful if it is required to style e.g. vertices of a line\n- * with a point symbolizer. Note, however, that this is not implemented\n- * yet in OpenLayers, but it is the way how symbolizers are defined in\n- * SLD.\n- */\n- symbolizer: null,\n-\n- /**\n- * Property: symbolizers\n- * {Array} Collection of symbolizers associated with this rule. If \n- * provided at construction, the symbolizers array has precedence\n- * over the deprecated symbolizer property. Note that multiple \n- * symbolizers are not currently supported by the vector renderers.\n- * Rules with multiple symbolizers are currently only useful for\n- * maintaining elements in an SLD document.\n- */\n- symbolizers: null,\n-\n- /**\n- * APIProperty: minScaleDenominator\n- * {Number} or {String} minimum scale at which to draw the feature.\n- * In the case of a String, this can be a combination of text and\n- * propertyNames in the form \"literal ${propertyName}\"\n- */\n- minScaleDenominator: null,\n-\n- /**\n- * APIProperty: maxScaleDenominator\n- * {Number} or {String} maximum scale at which to draw the feature.\n- * In the case of a String, this can be a combination of text and\n- * propertyNames in the form \"literal ${propertyName}\"\n- */\n- maxScaleDenominator: null,\n-\n- /** \n- * Constructor: OpenLayers.Rule\n- * Creates a Rule.\n- *\n- * Parameters:\n- * options - {Object} An optional object with properties to set on the\n- * rule\n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(options) {\n- this.symbolizer = {};\n- OpenLayers.Util.extend(this, options);\n- if (this.symbolizers) {\n- delete this.symbolizer;\n- }\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i in this.symbolizer) {\n- this.symbolizer[i] = null;\n- }\n- this.symbolizer = null;\n- delete this.symbolizers;\n- },\n-\n- /**\n- * APIMethod: evaluate\n- * evaluates this rule for a specific feature\n- * \n- * Parameters:\n- * feature - {} feature to apply the rule to.\n- * \n- * Returns:\n- * {Boolean} true if the rule applies, false if it does not.\n- * This rule is the default rule and always returns true.\n- */\n- evaluate: function(feature) {\n- var context = this.getContext(feature);\n- var applies = true;\n-\n- if (this.minScaleDenominator || this.maxScaleDenominator) {\n- var scale = feature.layer.map.getScale();\n- }\n-\n- // check if within minScale/maxScale bounds\n- if (this.minScaleDenominator) {\n- applies = scale >= OpenLayers.Style.createLiteral(\n- this.minScaleDenominator, context);\n- }\n- if (applies && this.maxScaleDenominator) {\n- applies = scale < OpenLayers.Style.createLiteral(\n- this.maxScaleDenominator, context);\n- }\n-\n- // check if optional filter applies\n- if (applies && this.filter) {\n- // feature id filters get the feature, others get the context\n- if (this.filter.CLASS_NAME == \"OpenLayers.Filter.FeatureId\") {\n- applies = this.filter.evaluate(feature);\n- } else {\n- applies = this.filter.evaluate(context);\n- }\n- }\n-\n- return applies;\n- },\n-\n- /**\n- * Method: getContext\n- * Gets the context for evaluating this rule\n- * \n- * Paramters:\n- * feature - {} feature to take the context from if\n- * none is specified.\n- */\n- getContext: function(feature) {\n- var context = this.context;\n- if (!context) {\n- context = feature.attributes || feature.data;\n- }\n- if (typeof this.context == \"function\") {\n- context = this.context(feature);\n+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ this.stop();\n+ this.layer.events.un({\n+ \"visibilitychanged\": this.reset,\n+ scope: this\n+ });\n }\n- return context;\n+ return deactivated;\n },\n \n /**\n- * APIMethod: clone\n- * Clones this rule.\n- * \n- * Returns:\n- * {} Clone of this rule.\n+ * Method: reset\n+ * Start or cancel the refresh interval depending on the visibility of \n+ * the layer.\n */\n- clone: function() {\n- var options = OpenLayers.Util.extend({}, this);\n- if (this.symbolizers) {\n- // clone symbolizers\n- var len = this.symbolizers.length;\n- options.symbolizers = new Array(len);\n- for (var i = 0; i < len; ++i) {\n- options.symbolizers[i] = this.symbolizers[i].clone();\n- }\n+ reset: function() {\n+ if (this.layer.visibility === true) {\n+ this.start();\n } else {\n- // clone symbolizer\n- options.symbolizer = {};\n- var value, type;\n- for (var key in this.symbolizer) {\n- value = this.symbolizer[key];\n- type = typeof value;\n- if (type === \"object\") {\n- options.symbolizer[key] = OpenLayers.Util.extend({}, value);\n- } else if (type === \"string\") {\n- options.symbolizer[key] = value;\n- }\n- }\n+ this.stop();\n }\n- // clone filter\n- options.filter = this.filter && this.filter.clone();\n- // clone context\n- options.context = this.context && OpenLayers.Util.extend({}, this.context);\n- return new OpenLayers.Rule(options);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Rule\"\n-});\n-/* ======================================================================\n- OpenLayers/Symbolizer/Point.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Point\n- * A symbolizer used to render point features.\n- */\n-OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillColor\n- * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillOpacity\n- * {Number} Fill opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: pointRadius\n- * {Number} Pixel point radius.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: externalGraphic\n- * {String} Url to an external graphic that will be used for rendering \n- * points.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicWidth\n- * {Number} Pixel width for sizing an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicHeight\n- * {Number} Pixel height for sizing an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicOpacity\n- * {Number} Opacity (0-1) for an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicXOffset\n- * {Number} Pixel offset along the positive x axis for displacing an \n- * external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicYOffset\n- * {Number} Pixel offset along the positive y axis for displacing an \n- * external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: rotation\n- * {Number} The rotation of a graphic in the clockwise direction about its \n- * center point (or any point off center as specified by \n- * and ).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicName\n- * {String} Named graphic to use when rendering points. Supported values \n- * include \"circle\", \"square\", \"star\", \"x\", \"cross\", and \"triangle\".\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Point\n- * Create a symbolizer for rendering points.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new point symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Point\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Line.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Line\n- * A symbolizer used to render line features.\n- */\n-OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red). \n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Line\n- * Create a symbolizer for rendering lines.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new line symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Line\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Polygon.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Polygon\n- * A symbolizer used to render line features.\n- */\n-OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillColor\n- * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillOpacity\n- * {Number} Fill opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Polygon\n- * Create a symbolizer for rendering polygons.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new polygon symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n },\n \n- CLASS_NAME: \"OpenLayers.Symbolizer.Polygon\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Text.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Text\n- * A symbolizer used to render text labels for features.\n- */\n-OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /** \n- * APIProperty: label\n- * {String} The text for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontFamily\n- * {String} The font family for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontSize\n- * {String} The font size for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontWeight\n- * {String} The font weight for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n /**\n- * Property: fontStyle\n- * {String} The font style for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Text\n- * Create a symbolizer for rendering text labels.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new text symbolizer.\n+ * Method: start\n+ * Start the refresh interval. \n */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Text\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Raster.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Raster\n- * A symbolizer used to render raster images.\n- */\n-OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {\n+ start: function() {\n+ if (this.interval && typeof this.interval === \"number\" &&\n+ this.interval > 0) {\n \n- /**\n- * Constructor: OpenLayers.Symbolizer.Raster\n- * Create a symbolizer for rendering rasters.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new raster symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n+ this.timer = window.setInterval(\n+ OpenLayers.Function.bind(this.refresh, this),\n+ this.interval);\n+ }\n },\n \n- CLASS_NAME: \"OpenLayers.Symbolizer.Raster\"\n-\n-});\n-/* ======================================================================\n- OpenLayers/Style2.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Rule.js\n- * @requires OpenLayers/Symbolizer/Point.js\n- * @requires OpenLayers/Symbolizer/Line.js\n- * @requires OpenLayers/Symbolizer/Polygon.js\n- * @requires OpenLayers/Symbolizer/Text.js\n- * @requires OpenLayers/Symbolizer/Raster.js\n- */\n-\n-/**\n- * Class: OpenLayers.Style2\n- * This class represents a collection of rules for rendering features.\n- */\n-OpenLayers.Style2 = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String} A unique id for this session.\n- */\n- id: null,\n-\n- /**\n- * APIProperty: name\n- * {String} Style identifier.\n- */\n- name: null,\n-\n- /**\n- * APIProperty: title\n- * {String} Title of this style.\n- */\n- title: null,\n-\n /**\n- * APIProperty: description\n- * {String} Description of this style.\n- */\n- description: null,\n-\n- /**\n- * APIProperty: layerName\n- * {} Name of the layer that this style belongs to, usually\n- * according to the NamedLayer attribute of an SLD document.\n- */\n- layerName: null,\n-\n- /**\n- * APIProperty: isDefault\n- * {Boolean}\n- */\n- isDefault: false,\n-\n- /** \n- * APIProperty: rules \n- * {Array()} Collection of rendering rules.\n- */\n- rules: null,\n-\n- /** \n- * Constructor: OpenLayers.Style2\n- * Creates a style representing a collection of rendering rules.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * style. Any documented properties may be set at construction.\n- *\n- * Returns:\n- * {} A new style object.\n+ * APIMethod: refresh\n+ * Tell the strategy to refresh which will refresh the layer.\n */\n- initialize: function(config) {\n- OpenLayers.Util.extend(this, config);\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n+ refresh: function() {\n+ if (this.layer && this.layer.refresh &&\n+ typeof this.layer.refresh == \"function\") {\n \n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i = 0, len = this.rules.length; i < len; i++) {\n- this.rules[i].destroy();\n+ this.layer.refresh({\n+ force: this.force\n+ });\n }\n- delete this.rules;\n },\n \n /**\n- * APIMethod: clone\n- * Clones this style.\n- * \n- * Returns:\n- * {} Clone of this style.\n+ * Method: stop\n+ * Cancels the refresh interval. \n */\n- clone: function() {\n- var config = OpenLayers.Util.extend({}, this);\n- // clone rules\n- if (this.rules) {\n- config.rules = [];\n- for (var i = 0, len = this.rules.length; i < len; ++i) {\n- config.rules.push(this.rules[i].clone());\n- }\n+ stop: function() {\n+ if (this.timer !== null) {\n+ window.clearInterval(this.timer);\n+ this.timer = null;\n }\n- return new OpenLayers.Style2(config);\n },\n \n- CLASS_NAME: \"OpenLayers.Style2\"\n+ CLASS_NAME: \"OpenLayers.Strategy.Refresh\"\n });\n /* ======================================================================\n- OpenLayers/Handler/Pinch.js\n+ OpenLayers/Control/Button.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Handler.js\n+ * @requires OpenLayers/Control.js\n */\n \n /**\n- * Class: OpenLayers.Handler.Pinch\n- * The pinch handler is used to deal with sequences of browser events related\n- * to pinch gestures. The handler is used by controls that want to know\n- * when a pinch sequence begins, when a pinch is happening, and when it has\n- * finished.\n- *\n- * Controls that use the pinch handler typically construct it with callbacks\n- * for 'start', 'move', and 'done'. Callbacks for these keys are\n- * called when the pinch begins, with each change, and when the pinch is\n- * done.\n- *\n- * Create a new pinch handler with the constructor.\n- *\n+ * Class: OpenLayers.Control.Button \n+ * The Button control is a very simple push-button, for use with \n+ * .\n+ * When clicked, the function trigger() is executed.\n+ * \n * Inherits from:\n- * - \n+ * - \n+ *\n+ * Use:\n+ * (code)\n+ * var button = new OpenLayers.Control.Button({\n+ * displayClass: \"MyButton\", trigger: myFunction\n+ * });\n+ * panel.addControls([button]);\n+ * (end)\n+ * \n+ * Will create a button with CSS class MyButtonItemInactive, that\n+ * will call the function MyFunction() when clicked.\n */\n-OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, {\n-\n- /**\n- * Property: started\n- * {Boolean} When a touchstart event is received, we want to record it,\n- * but not set 'pinching' until the touchmove get started after\n- * starting.\n- */\n- started: false,\n-\n- /**\n- * Property: stopDown\n- * {Boolean} Stop propagation of touchstart events from getting to\n- * listeners on the same element. Default is false.\n- */\n- stopDown: false,\n-\n- /**\n- * Property: pinching\n- * {Boolean}\n- */\n- pinching: false,\n-\n- /**\n- * Property: last\n- * {Object} Object that store informations related to pinch last touch.\n- */\n- last: null,\n-\n- /**\n- * Property: start\n- * {Object} Object that store informations related to pinch touchstart.\n- */\n- start: null,\n-\n- /**\n- * Constructor: OpenLayers.Handler.Pinch\n- * Returns OpenLayers.Handler.Pinch\n- *\n- * Parameters:\n- * control - {} The control that is making use of\n- * this handler. If a handler is being used without a control, the\n- * handlers setMap method must be overridden to deal properly with\n- * the map.\n- * callbacks - {Object} An object containing functions to be called when\n- * the pinch operation start, change, or is finished. The callbacks\n- * should expect to receive an object argument, which contains\n- * information about scale, distance, and position of touch points.\n- * options - {Object}\n- */\n-\n- /**\n- * Method: touchstart\n- * Handle touchstart events\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Boolean} Let the event propagate.\n- */\n- touchstart: function(evt) {\n- var propagate = true;\n- this.pinching = false;\n- if (OpenLayers.Event.isMultiTouch(evt)) {\n- this.started = true;\n- this.last = this.start = {\n- distance: this.getDistance(evt.touches),\n- delta: 0,\n- scale: 1\n- };\n- this.callback(\"start\", [evt, this.start]);\n- propagate = !this.stopDown;\n- } else if (this.started) {\n- // Some webkit versions send fake single-touch events during\n- // multitouch, which cause the drag handler to trigger\n- return false;\n- } else {\n- this.started = false;\n- this.start = null;\n- this.last = null;\n- }\n- // prevent document dragging\n- OpenLayers.Event.preventDefault(evt);\n- return propagate;\n- },\n-\n- /**\n- * Method: touchmove\n- * Handle touchmove events\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Boolean} Let the event propagate.\n- */\n- touchmove: function(evt) {\n- if (this.started && OpenLayers.Event.isMultiTouch(evt)) {\n- this.pinching = true;\n- var current = this.getPinchData(evt);\n- this.callback(\"move\", [evt, current]);\n- this.last = current;\n- // prevent document dragging\n- OpenLayers.Event.stop(evt);\n- } else if (this.started) {\n- // Some webkit versions send fake single-touch events during\n- // multitouch, which cause the drag handler to trigger\n- return false;\n- }\n- return true;\n- },\n-\n- /**\n- * Method: touchend\n- * Handle touchend events\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Boolean} Let the event propagate.\n- */\n- touchend: function(evt) {\n- if (this.started && !OpenLayers.Event.isMultiTouch(evt)) {\n- this.started = false;\n- this.pinching = false;\n- this.callback(\"done\", [evt, this.start, this.last]);\n- this.start = null;\n- this.last = null;\n- return false;\n- }\n- return true;\n- },\n-\n- /**\n- * Method: activate\n- * Activate the handler.\n- *\n- * Returns:\n- * {Boolean} The handler was successfully activated.\n- */\n- activate: function() {\n- var activated = false;\n- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n- this.pinching = false;\n- activated = true;\n- }\n- return activated;\n- },\n-\n- /**\n- * Method: deactivate\n- * Deactivate the handler.\n- *\n- * Returns:\n- * {Boolean} The handler was successfully deactivated.\n- */\n- deactivate: function() {\n- var deactivated = false;\n- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- this.started = false;\n- this.pinching = false;\n- this.start = null;\n- this.last = null;\n- deactivated = true;\n- }\n- return deactivated;\n- },\n-\n+OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, {\n /**\n- * Method: getDistance\n- * Get the distance in pixels between two touches.\n- *\n- * Parameters:\n- * touches - {Array(Object)}\n- *\n- * Returns:\n- * {Number} The distance in pixels.\n+ * Property: type\n+ * {Integer} OpenLayers.Control.TYPE_BUTTON.\n */\n- getDistance: function(touches) {\n- var t0 = touches[0];\n- var t1 = touches[1];\n- return Math.sqrt(\n- Math.pow(t0.olClientX - t1.olClientX, 2) +\n- Math.pow(t0.olClientY - t1.olClientY, 2)\n- );\n- },\n-\n+ type: OpenLayers.Control.TYPE_BUTTON,\n \n /**\n- * Method: getPinchData\n- * Get informations about the pinch event.\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Object} Object that contains data about the current pinch.\n+ * Method: trigger\n+ * Called by a control panel when the button is clicked.\n */\n- getPinchData: function(evt) {\n- var distance = this.getDistance(evt.touches);\n- var scale = distance / this.start.distance;\n- return {\n- distance: distance,\n- delta: this.last.distance - distance,\n- scale: scale\n- };\n- },\n+ trigger: function() {},\n \n- CLASS_NAME: \"OpenLayers.Handler.Pinch\"\n+ CLASS_NAME: \"OpenLayers.Control.Button\"\n });\n-\n /* ======================================================================\n OpenLayers/Handler/Click.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n@@ -33710,14 +35815,1043 @@\n }\n return deactivated;\n },\n \n CLASS_NAME: \"OpenLayers.Handler.Click\"\n });\n /* ======================================================================\n+ OpenLayers/Handler/Hover.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Handler.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Handler.Hover\n+ * The hover handler is to be used to emulate mouseovers on objects\n+ * on the map that aren't DOM elements. For example one can use\n+ * this handler to send WMS/GetFeatureInfo requests as the user\n+ * moves the mouve over the map.\n+ * \n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {\n+\n+ /**\n+ * APIProperty: delay\n+ * {Integer} - Number of milliseconds between mousemoves before\n+ * the event is considered a hover. Default is 500.\n+ */\n+ delay: 500,\n+\n+ /**\n+ * APIProperty: pixelTolerance\n+ * {Integer} - Maximum number of pixels between mousemoves for\n+ * an event to be considered a hover. Default is null.\n+ */\n+ pixelTolerance: null,\n+\n+ /**\n+ * APIProperty: stopMove\n+ * {Boolean} - Stop other listeners from being notified on mousemoves.\n+ * Default is false.\n+ */\n+ stopMove: false,\n+\n+ /**\n+ * Property: px\n+ * {} - The location of the last mousemove, expressed\n+ * in pixels.\n+ */\n+ px: null,\n+\n+ /**\n+ * Property: timerId\n+ * {Number} - The id of the timer.\n+ */\n+ timerId: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Handler.Hover\n+ * Construct a hover handler.\n+ *\n+ * Parameters:\n+ * control - {} The control that initialized this\n+ * handler. The control is assumed to have a valid map property; that\n+ * map is used in the handler's own setMap method.\n+ * callbacks - {Object} An object with keys corresponding to callbacks\n+ * that will be called by the handler. The callbacks should\n+ * expect to receive a single argument, the event. Callbacks for\n+ * 'move', the mouse is moving, and 'pause', the mouse is pausing,\n+ * are supported.\n+ * options - {Object} An optional object whose properties will be set on\n+ * the handler.\n+ */\n+\n+ /**\n+ * Method: mousemove\n+ * Called when the mouse moves on the map.\n+ *\n+ * Parameters:\n+ * evt - {}\n+ *\n+ * Returns:\n+ * {Boolean} Continue propagating this event.\n+ */\n+ mousemove: function(evt) {\n+ if (this.passesTolerance(evt.xy)) {\n+ this.clearTimer();\n+ this.callback('move', [evt]);\n+ this.px = evt.xy;\n+ // clone the evt so original properties can be accessed even\n+ // if the browser deletes them during the delay\n+ evt = OpenLayers.Util.extend({}, evt);\n+ this.timerId = window.setTimeout(\n+ OpenLayers.Function.bind(this.delayedCall, this, evt),\n+ this.delay\n+ );\n+ }\n+ return !this.stopMove;\n+ },\n+\n+ /**\n+ * Method: mouseout\n+ * Called when the mouse goes out of the map.\n+ *\n+ * Parameters:\n+ * evt - {}\n+ *\n+ * Returns:\n+ * {Boolean} Continue propagating this event.\n+ */\n+ mouseout: function(evt) {\n+ if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {\n+ this.clearTimer();\n+ this.callback('move', [evt]);\n+ }\n+ return true;\n+ },\n+\n+ /**\n+ * Method: passesTolerance\n+ * Determine whether the mouse move is within the optional pixel tolerance.\n+ *\n+ * Parameters:\n+ * px - {}\n+ *\n+ * Returns:\n+ * {Boolean} The mouse move is within the pixel tolerance.\n+ */\n+ passesTolerance: function(px) {\n+ var passes = true;\n+ if (this.pixelTolerance && this.px) {\n+ var dpx = Math.sqrt(\n+ Math.pow(this.px.x - px.x, 2) +\n+ Math.pow(this.px.y - px.y, 2)\n+ );\n+ if (dpx < this.pixelTolerance) {\n+ passes = false;\n+ }\n+ }\n+ return passes;\n+ },\n+\n+ /**\n+ * Method: clearTimer\n+ * Clear the timer and set to null.\n+ */\n+ clearTimer: function() {\n+ if (this.timerId != null) {\n+ window.clearTimeout(this.timerId);\n+ this.timerId = null;\n+ }\n+ },\n+\n+ /**\n+ * Method: delayedCall\n+ * Triggers pause callback.\n+ *\n+ * Parameters:\n+ * evt - {}\n+ */\n+ delayedCall: function(evt) {\n+ this.callback('pause', [evt]);\n+ },\n+\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the handler.\n+ *\n+ * Returns:\n+ * {Boolean} The handler was successfully deactivated.\n+ */\n+ deactivate: function() {\n+ var deactivated = false;\n+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n+ this.clearTimer();\n+ deactivated = true;\n+ }\n+ return deactivated;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Handler.Hover\"\n+});\n+/* ======================================================================\n+ OpenLayers/Format/WMSGetFeatureInfo.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Format/XML.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Format.WMSGetFeatureInfo\n+ * Class to read GetFeatureInfo responses from Web Mapping Services\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, {\n+\n+ /**\n+ * APIProperty: layerIdentifier\n+ * {String} All xml nodes containing this search criteria will populate an\n+ * internal array of layer nodes.\n+ */\n+ layerIdentifier: '_layer',\n+\n+ /**\n+ * APIProperty: featureIdentifier\n+ * {String} All xml nodes containing this search criteria will populate an \n+ * internal array of feature nodes for each layer node found.\n+ */\n+ featureIdentifier: '_feature',\n+\n+ /**\n+ * Property: regExes\n+ * Compiled regular expressions for manipulating strings.\n+ */\n+ regExes: {\n+ trimSpace: (/^\\s*|\\s*$/g),\n+ removeSpace: (/\\s*/g),\n+ splitSpace: (/\\s+/),\n+ trimComma: (/\\s*,\\s*/g)\n+ },\n+\n+ /**\n+ * Property: gmlFormat\n+ * {} internal GML format for parsing geometries\n+ * in msGMLOutput\n+ */\n+ gmlFormat: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Format.WMSGetFeatureInfo\n+ * Create a new parser for WMS GetFeatureInfo responses\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be set on\n+ * this instance.\n+ */\n+\n+ /**\n+ * APIMethod: read\n+ * Read WMS GetFeatureInfo data from a string, and return an array of features\n+ *\n+ * Parameters:\n+ * data - {String} or {DOMElement} data to read/parse.\n+ *\n+ * Returns:\n+ * {Array()} An array of features.\n+ */\n+ read: function(data) {\n+ var result;\n+ if (typeof data == \"string\") {\n+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n+ }\n+ var root = data.documentElement;\n+ if (root) {\n+ var scope = this;\n+ var read = this[\"read_\" + root.nodeName];\n+ if (read) {\n+ result = read.call(this, root);\n+ } else {\n+ // fall-back to GML since this is a common output format for WMS\n+ // GetFeatureInfo responses\n+ result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data);\n+ }\n+ } else {\n+ result = data;\n+ }\n+ return result;\n+ },\n+\n+\n+ /**\n+ * Method: read_msGMLOutput\n+ * Parse msGMLOutput nodes.\n+ *\n+ * Parameters:\n+ * data - {DOMElement}\n+ *\n+ * Returns:\n+ * {Array}\n+ */\n+ read_msGMLOutput: function(data) {\n+ var response = [];\n+ var layerNodes = this.getSiblingNodesByTagCriteria(data,\n+ this.layerIdentifier);\n+ if (layerNodes) {\n+ for (var i = 0, len = layerNodes.length; i < len; ++i) {\n+ var node = layerNodes[i];\n+ var layerName = node.nodeName;\n+ if (node.prefix) {\n+ layerName = layerName.split(':')[1];\n+ }\n+ var layerName = layerName.replace(this.layerIdentifier, '');\n+ var featureNodes = this.getSiblingNodesByTagCriteria(node,\n+ this.featureIdentifier);\n+ if (featureNodes) {\n+ for (var j = 0; j < featureNodes.length; j++) {\n+ var featureNode = featureNodes[j];\n+ var geomInfo = this.parseGeometry(featureNode);\n+ var attributes = this.parseAttributes(featureNode);\n+ var feature = new OpenLayers.Feature.Vector(geomInfo.geometry,\n+ attributes, null);\n+ feature.bounds = geomInfo.bounds;\n+ feature.type = layerName;\n+ response.push(feature);\n+ }\n+ }\n+ }\n+ }\n+ return response;\n+ },\n+\n+ /**\n+ * Method: read_FeatureInfoResponse\n+ * Parse FeatureInfoResponse nodes.\n+ *\n+ * Parameters:\n+ * data - {DOMElement}\n+ *\n+ * Returns:\n+ * {Array}\n+ */\n+ read_FeatureInfoResponse: function(data) {\n+ var response = [];\n+ var featureNodes = this.getElementsByTagNameNS(data, '*',\n+ 'FIELDS');\n+\n+ for (var i = 0, len = featureNodes.length; i < len; i++) {\n+ var featureNode = featureNodes[i];\n+ var geom = null;\n+\n+ // attributes can be actual attributes on the FIELDS tag, \n+ // or FIELD children\n+ var attributes = {};\n+ var j;\n+ var jlen = featureNode.attributes.length;\n+ if (jlen > 0) {\n+ for (j = 0; j < jlen; j++) {\n+ var attribute = featureNode.attributes[j];\n+ attributes[attribute.nodeName] = attribute.nodeValue;\n+ }\n+ } else {\n+ var nodes = featureNode.childNodes;\n+ for (j = 0, jlen = nodes.length; j < jlen; ++j) {\n+ var node = nodes[j];\n+ if (node.nodeType != 3) {\n+ attributes[node.getAttribute(\"name\")] =\n+ node.getAttribute(\"value\");\n+ }\n+ }\n+ }\n+\n+ response.push(\n+ new OpenLayers.Feature.Vector(geom, attributes, null)\n+ );\n+ }\n+ return response;\n+ },\n+\n+ /**\n+ * Method: getSiblingNodesByTagCriteria\n+ * Recursively searches passed xml node and all it's descendant levels for \n+ * nodes whose tagName contains the passed search string. This returns an \n+ * array of all sibling nodes which match the criteria from the highest \n+ * hierarchial level from which a match is found.\n+ * \n+ * Parameters:\n+ * node - {DOMElement} An xml node\n+ * criteria - {String} Search string which will match some part of a tagName \n+ * \n+ * Returns:\n+ * Array({DOMElement}) An array of sibling xml nodes\n+ */\n+ getSiblingNodesByTagCriteria: function(node, criteria) {\n+ var nodes = [];\n+ var children, tagName, n, matchNodes, child;\n+ if (node && node.hasChildNodes()) {\n+ children = node.childNodes;\n+ n = children.length;\n+\n+ for (var k = 0; k < n; k++) {\n+ child = children[k];\n+ while (child && child.nodeType != 1) {\n+ child = child.nextSibling;\n+ k++;\n+ }\n+ tagName = (child ? child.nodeName : '');\n+ if (tagName.length > 0 && tagName.indexOf(criteria) > -1) {\n+ nodes.push(child);\n+ } else {\n+ matchNodes = this.getSiblingNodesByTagCriteria(\n+ child, criteria);\n+\n+ if (matchNodes.length > 0) {\n+ (nodes.length == 0) ?\n+ nodes = matchNodes: nodes.push(matchNodes);\n+ }\n+ }\n+ }\n+\n+ }\n+ return nodes;\n+ },\n+\n+ /**\n+ * Method: parseAttributes\n+ *\n+ * Parameters:\n+ * node - {}\n+ *\n+ * Returns:\n+ * {Object} An attributes object.\n+ * \n+ * Notes:\n+ * Assumes that attributes are direct child xml nodes of the passed node\n+ * and contain only a single text node. \n+ */\n+ parseAttributes: function(node) {\n+ var attributes = {};\n+ if (node.nodeType == 1) {\n+ var children = node.childNodes;\n+ var n = children.length;\n+ for (var i = 0; i < n; ++i) {\n+ var child = children[i];\n+ if (child.nodeType == 1) {\n+ var grandchildren = child.childNodes;\n+ var name = (child.prefix) ?\n+ child.nodeName.split(\":\")[1] : child.nodeName;\n+ if (grandchildren.length == 0) {\n+ attributes[name] = null;\n+ } else if (grandchildren.length == 1) {\n+ var grandchild = grandchildren[0];\n+ if (grandchild.nodeType == 3 ||\n+ grandchild.nodeType == 4) {\n+ var value = grandchild.nodeValue.replace(\n+ this.regExes.trimSpace, \"\");\n+ attributes[name] = value;\n+ }\n+ }\n+ }\n+ }\n+ }\n+ return attributes;\n+ },\n+\n+ /**\n+ * Method: parseGeometry\n+ * Parse the geometry and the feature bounds out of the node using \n+ * Format.GML\n+ *\n+ * Parameters:\n+ * node - {}\n+ *\n+ * Returns:\n+ * {Object} An object containing the geometry and the feature bounds\n+ */\n+ parseGeometry: function(node) {\n+ // we need to use the old Format.GML parser since we do not know the \n+ // geometry name\n+ if (!this.gmlFormat) {\n+ this.gmlFormat = new OpenLayers.Format.GML();\n+ }\n+ var feature = this.gmlFormat.parseFeature(node);\n+ var geometry, bounds = null;\n+ if (feature) {\n+ geometry = feature.geometry && feature.geometry.clone();\n+ bounds = feature.bounds && feature.bounds.clone();\n+ feature.destroy();\n+ }\n+ return {\n+ geometry: geometry,\n+ bounds: bounds\n+ };\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Format.WMSGetFeatureInfo\"\n+\n+});\n+/* ======================================================================\n+ OpenLayers/Control/WMSGetFeatureInfo.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Handler/Click.js\n+ * @requires OpenLayers/Handler/Hover.js\n+ * @requires OpenLayers/Request.js\n+ * @requires OpenLayers/Format/WMSGetFeatureInfo.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control.WMSGetFeatureInfo\n+ * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The\n+ * information may be in a display-friendly format such as HTML, or a machine-friendly format such\n+ * as GML, depending on the server's capabilities and the client's configuration. This control\n+ * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and\n+ * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an\n+ * array of features if it successfully read the response.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /**\n+ * APIProperty: hover\n+ * {Boolean} Send GetFeatureInfo requests when mouse stops moving.\n+ * Default is false.\n+ */\n+ hover: false,\n+\n+ /**\n+ * APIProperty: drillDown\n+ * {Boolean} Drill down over all WMS layers in the map. When\n+ * using drillDown mode, hover is not possible, and an infoFormat that\n+ * returns parseable features is required. Default is false.\n+ */\n+ drillDown: false,\n+\n+ /**\n+ * APIProperty: maxFeatures\n+ * {Integer} Maximum number of features to return from a WMS query. This\n+ * sets the feature_count parameter on WMS GetFeatureInfo\n+ * requests.\n+ */\n+ maxFeatures: 10,\n+\n+ /**\n+ * APIProperty: clickCallback\n+ * {String} The click callback to register in the\n+ * {} object created when the hover\n+ * option is set to false. Default is \"click\".\n+ */\n+ clickCallback: \"click\",\n+\n+ /**\n+ * APIProperty: output\n+ * {String} Either \"features\" or \"object\". When triggering a getfeatureinfo\n+ * request should we pass on an array of features or an object with with\n+ * a \"features\" property and other properties (such as the url of the\n+ * WMS). Default is \"features\".\n+ */\n+ output: \"features\",\n+\n+ /**\n+ * APIProperty: layers\n+ * {Array()} The layers to query for feature info.\n+ * If omitted, all map WMS layers with a url that matches this or\n+ * will be considered.\n+ */\n+ layers: null,\n+\n+ /**\n+ * APIProperty: queryVisible\n+ * {Boolean} If true, filter out hidden layers when searching the map for\n+ * layers to query. Default is false.\n+ */\n+ queryVisible: false,\n+\n+ /**\n+ * APIProperty: url\n+ * {String} The URL of the WMS service to use. If not provided, the url\n+ * of the first eligible layer will be used.\n+ */\n+ url: null,\n+\n+ /**\n+ * APIProperty: layerUrls\n+ * {Array(String)} Optional list of urls for layers that should be queried.\n+ * This can be used when the layer url differs from the url used for\n+ * making GetFeatureInfo requests (in the case of a layer using cached\n+ * tiles).\n+ */\n+ layerUrls: null,\n+\n+ /**\n+ * APIProperty: infoFormat\n+ * {String} The mimetype to request from the server. If you are using\n+ * drillDown mode and have multiple servers that do not share a common\n+ * infoFormat, you can override the control's infoFormat by providing an\n+ * INFO_FORMAT parameter in your instance(s).\n+ */\n+ infoFormat: 'text/html',\n+\n+ /**\n+ * APIProperty: vendorParams\n+ * {Object} Additional parameters that will be added to the request, for\n+ * WMS implementations that support them. This could e.g. look like\n+ * (start code)\n+ * {\n+ * radius: 5\n+ * }\n+ * (end)\n+ */\n+ vendorParams: {},\n+\n+ /**\n+ * APIProperty: format\n+ * {} A format for parsing GetFeatureInfo responses.\n+ * Default is .\n+ */\n+ format: null,\n+\n+ /**\n+ * APIProperty: formatOptions\n+ * {Object} Optional properties to set on the format (if one is not provided\n+ * in the property.\n+ */\n+ formatOptions: null,\n+\n+ /**\n+ * APIProperty: handlerOptions\n+ * {Object} Additional options for the handlers used by this control, e.g.\n+ * (start code)\n+ * {\n+ * \"click\": {delay: 100},\n+ * \"hover\": {delay: 300}\n+ * }\n+ * (end)\n+ */\n+\n+ /**\n+ * Property: handler\n+ * {Object} Reference to the for this control\n+ */\n+ handler: null,\n+\n+ /**\n+ * Property: hoverRequest\n+ * {} contains the currently running hover request\n+ * (if any).\n+ */\n+ hoverRequest: null,\n+\n+ /**\n+ * APIProperty: events\n+ * {} Events instance for listeners and triggering\n+ * control specific events.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * control.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types (in addition to those from ):\n+ * beforegetfeatureinfo - Triggered before the request is sent.\n+ * The event object has an *xy* property with the position of the\n+ * mouse click or hover event that triggers the request.\n+ * nogetfeatureinfo - no queryable layers were found.\n+ * getfeatureinfo - Triggered when a GetFeatureInfo response is received.\n+ * The event object has a *text* property with the body of the\n+ * response (String), a *features* property with an array of the\n+ * parsed features, an *xy* property with the position of the mouse\n+ * click or hover event that triggered the request, and a *request*\n+ * property with the request itself. If drillDown is set to true and\n+ * multiple requests were issued to collect feature info from all\n+ * layers, *text* and *request* will only contain the response body\n+ * and request object of the last request.\n+ */\n+\n+ /**\n+ * Constructor: \n+ *\n+ * Parameters:\n+ * options - {Object}\n+ */\n+ initialize: function(options) {\n+ options = options || {};\n+ options.handlerOptions = options.handlerOptions || {};\n+\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+\n+ if (!this.format) {\n+ this.format = new OpenLayers.Format.WMSGetFeatureInfo(\n+ options.formatOptions\n+ );\n+ }\n+\n+ if (this.drillDown === true) {\n+ this.hover = false;\n+ }\n+\n+ if (this.hover) {\n+ this.handler = new OpenLayers.Handler.Hover(\n+ this, {\n+ 'move': this.cancelHover,\n+ 'pause': this.getInfoForHover\n+ },\n+ OpenLayers.Util.extend(this.handlerOptions.hover || {}, {\n+ 'delay': 250\n+ }));\n+ } else {\n+ var callbacks = {};\n+ callbacks[this.clickCallback] = this.getInfoForClick;\n+ this.handler = new OpenLayers.Handler.Click(\n+ this, callbacks, this.handlerOptions.click || {});\n+ }\n+ },\n+\n+ /**\n+ * Method: getInfoForClick\n+ * Called on click\n+ *\n+ * Parameters:\n+ * evt - {}\n+ */\n+ getInfoForClick: function(evt) {\n+ this.events.triggerEvent(\"beforegetfeatureinfo\", {\n+ xy: evt.xy\n+ });\n+ // Set the cursor to \"wait\" to tell the user we're working on their\n+ // click.\n+ OpenLayers.Element.addClass(this.map.viewPortDiv, \"olCursorWait\");\n+ this.request(evt.xy, {});\n+ },\n+\n+ /**\n+ * Method: getInfoForHover\n+ * Pause callback for the hover handler\n+ *\n+ * Parameters:\n+ * evt - {Object}\n+ */\n+ getInfoForHover: function(evt) {\n+ this.events.triggerEvent(\"beforegetfeatureinfo\", {\n+ xy: evt.xy\n+ });\n+ this.request(evt.xy, {\n+ hover: true\n+ });\n+ },\n+\n+ /**\n+ * Method: cancelHover\n+ * Cancel callback for the hover handler\n+ */\n+ cancelHover: function() {\n+ if (this.hoverRequest) {\n+ this.hoverRequest.abort();\n+ this.hoverRequest = null;\n+ }\n+ },\n+\n+ /**\n+ * Method: findLayers\n+ * Internal method to get the layers, independent of whether we are\n+ * inspecting the map or using a client-provided array\n+ */\n+ findLayers: function() {\n+\n+ var candidates = this.layers || this.map.layers;\n+ var layers = [];\n+ var layer, url;\n+ for (var i = candidates.length - 1; i >= 0; --i) {\n+ layer = candidates[i];\n+ if (layer instanceof OpenLayers.Layer.WMS &&\n+ (!this.queryVisible || layer.getVisibility())) {\n+ url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url;\n+ // if the control was not configured with a url, set it\n+ // to the first layer url\n+ if (this.drillDown === false && !this.url) {\n+ this.url = url;\n+ }\n+ if (this.drillDown === true || this.urlMatches(url)) {\n+ layers.push(layer);\n+ }\n+ }\n+ }\n+ return layers;\n+ },\n+\n+ /**\n+ * Method: urlMatches\n+ * Test to see if the provided url matches either the control or one\n+ * of the .\n+ *\n+ * Parameters:\n+ * url - {String} The url to test.\n+ *\n+ * Returns:\n+ * {Boolean} The provided url matches the control or one of the\n+ * .\n+ */\n+ urlMatches: function(url) {\n+ var matches = OpenLayers.Util.isEquivalentUrl(this.url, url);\n+ if (!matches && this.layerUrls) {\n+ for (var i = 0, len = this.layerUrls.length; i < len; ++i) {\n+ if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) {\n+ matches = true;\n+ break;\n+ }\n+ }\n+ }\n+ return matches;\n+ },\n+\n+ /**\n+ * Method: buildWMSOptions\n+ * Build an object with the relevant WMS options for the GetFeatureInfo request\n+ *\n+ * Parameters:\n+ * url - {String} The url to be used for sending the request\n+ * layers - {Array(} The position on the map where the mouse\n+ * event occurred.\n+ * format - {String} The format from the corresponding GetMap request\n+ */\n+ buildWMSOptions: function(url, layers, clickPosition, format) {\n+ var layerNames = [],\n+ styleNames = [];\n+ for (var i = 0, len = layers.length; i < len; i++) {\n+ if (layers[i].params.LAYERS != null) {\n+ layerNames = layerNames.concat(layers[i].params.LAYERS);\n+ styleNames = styleNames.concat(this.getStyleNames(layers[i]));\n+ }\n+ }\n+ var firstLayer = layers[0];\n+ // use the firstLayer's projection if it matches the map projection -\n+ // this assumes that all layers will be available in this projection\n+ var projection = this.map.getProjection();\n+ var layerProj = firstLayer.projection;\n+ if (layerProj && layerProj.equals(this.map.getProjectionObject())) {\n+ projection = layerProj.getCode();\n+ }\n+ var params = OpenLayers.Util.extend({\n+ service: \"WMS\",\n+ version: firstLayer.params.VERSION,\n+ request: \"GetFeatureInfo\",\n+ exceptions: firstLayer.params.EXCEPTIONS,\n+ bbox: this.map.getExtent().toBBOX(null,\n+ firstLayer.reverseAxisOrder()),\n+ feature_count: this.maxFeatures,\n+ height: this.map.getSize().h,\n+ width: this.map.getSize().w,\n+ format: format,\n+ info_format: firstLayer.params.INFO_FORMAT || this.infoFormat\n+ }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? {\n+ crs: projection,\n+ i: parseInt(clickPosition.x),\n+ j: parseInt(clickPosition.y)\n+ } : {\n+ srs: projection,\n+ x: parseInt(clickPosition.x),\n+ y: parseInt(clickPosition.y)\n+ });\n+ if (layerNames.length != 0) {\n+ params = OpenLayers.Util.extend({\n+ layers: layerNames,\n+ query_layers: layerNames,\n+ styles: styleNames\n+ }, params);\n+ }\n+ OpenLayers.Util.applyDefaults(params, this.vendorParams);\n+ return {\n+ url: url,\n+ params: OpenLayers.Util.upperCaseObject(params),\n+ callback: function(request) {\n+ this.handleResponse(clickPosition, request, url);\n+ },\n+ scope: this\n+ };\n+ },\n+\n+ /**\n+ * Method: getStyleNames\n+ * Gets the STYLES parameter for the layer. Make sure the STYLES parameter\n+ * matches the LAYERS parameter\n+ *\n+ * Parameters:\n+ * layer - {}\n+ *\n+ * Returns:\n+ * {Array(String)} The STYLES parameter\n+ */\n+ getStyleNames: function(layer) {\n+ // in the event of a WMS layer bundling multiple layers but not\n+ // specifying styles,we need the same number of commas to specify\n+ // the default style for each of the layers. We can't just leave it\n+ // blank as we may be including other layers that do specify styles.\n+ var styleNames;\n+ if (layer.params.STYLES) {\n+ styleNames = layer.params.STYLES;\n+ } else {\n+ if (OpenLayers.Util.isArray(layer.params.LAYERS)) {\n+ styleNames = new Array(layer.params.LAYERS.length);\n+ } else { // Assume it's a String\n+ styleNames = layer.params.LAYERS.replace(/[^,]/g, \"\");\n+ }\n+ }\n+ return styleNames;\n+ },\n+\n+ /**\n+ * Method: request\n+ * Sends a GetFeatureInfo request to the WMS\n+ *\n+ * Parameters:\n+ * clickPosition - {} The position on the map where the\n+ * mouse event occurred.\n+ * options - {Object} additional options for this method.\n+ *\n+ * Valid options:\n+ * - *hover* {Boolean} true if we do the request for the hover handler\n+ */\n+ request: function(clickPosition, options) {\n+ var layers = this.findLayers();\n+ if (layers.length == 0) {\n+ this.events.triggerEvent(\"nogetfeatureinfo\");\n+ // Reset the cursor.\n+ OpenLayers.Element.removeClass(this.map.viewPortDiv, \"olCursorWait\");\n+ return;\n+ }\n+\n+ options = options || {};\n+ if (this.drillDown === false) {\n+ var wmsOptions = this.buildWMSOptions(this.url, layers,\n+ clickPosition, layers[0].params.FORMAT);\n+ var request = OpenLayers.Request.GET(wmsOptions);\n+\n+ if (options.hover === true) {\n+ this.hoverRequest = request;\n+ }\n+ } else {\n+ this._requestCount = 0;\n+ this._numRequests = 0;\n+ this.features = [];\n+ // group according to service url to combine requests\n+ var services = {},\n+ url;\n+ for (var i = 0, len = layers.length; i < len; i++) {\n+ var layer = layers[i];\n+ var service, found = false;\n+ url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url;\n+ if (url in services) {\n+ services[url].push(layer);\n+ } else {\n+ this._numRequests++;\n+ services[url] = [layer];\n+ }\n+ }\n+ var layers;\n+ for (var url in services) {\n+ layers = services[url];\n+ var wmsOptions = this.buildWMSOptions(url, layers,\n+ clickPosition, layers[0].params.FORMAT);\n+ OpenLayers.Request.GET(wmsOptions);\n+ }\n+ }\n+ },\n+\n+ /**\n+ * Method: triggerGetFeatureInfo\n+ * Trigger the getfeatureinfo event when all is done\n+ *\n+ * Parameters:\n+ * request - {XMLHttpRequest} The request object\n+ * xy - {} The position on the map where the\n+ * mouse event occurred.\n+ * features - {Array()} or\n+ * {Array({Object}) when output is \"object\". The object has a url and a\n+ * features property which contains an array of features.\n+ */\n+ triggerGetFeatureInfo: function(request, xy, features) {\n+ this.events.triggerEvent(\"getfeatureinfo\", {\n+ text: request.responseText,\n+ features: features,\n+ request: request,\n+ xy: xy\n+ });\n+\n+ // Reset the cursor.\n+ OpenLayers.Element.removeClass(this.map.viewPortDiv, \"olCursorWait\");\n+ },\n+\n+ /**\n+ * Method: handleResponse\n+ * Handler for the GetFeatureInfo response.\n+ *\n+ * Parameters:\n+ * xy - {} The position on the map where the\n+ * mouse event occurred.\n+ * request - {XMLHttpRequest} The request object.\n+ * url - {String} The url which was used for this request.\n+ */\n+ handleResponse: function(xy, request, url) {\n+\n+ var doc = request.responseXML;\n+ if (!doc || !doc.documentElement) {\n+ doc = request.responseText;\n+ }\n+ var features = this.format.read(doc);\n+ if (this.drillDown === false) {\n+ this.triggerGetFeatureInfo(request, xy, features);\n+ } else {\n+ this._requestCount++;\n+ if (this.output === \"object\") {\n+ this._features = (this._features || []).concat({\n+ url: url,\n+ features: features\n+ });\n+ } else {\n+ this._features = (this._features || []).concat(features);\n+ }\n+ if (this._requestCount === this._numRequests) {\n+ this.triggerGetFeatureInfo(request, xy, this._features.concat());\n+ delete this._features;\n+ delete this._requestCount;\n+ delete this._numRequests;\n+ }\n+ }\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control.WMSGetFeatureInfo\"\n+});\n+/* ======================================================================\n OpenLayers/Handler/Drag.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -34265,134 +37399,828 @@\n OpenLayers.Event.stopObserving(document, \"mousemove\", this._docMove);\n OpenLayers.Event.stopObserving(document, \"mouseup\", this._docUp);\n },\n \n CLASS_NAME: \"OpenLayers.Handler.Drag\"\n });\n /* ======================================================================\n- OpenLayers/Handler/Keyboard.js\n+ OpenLayers/Handler/Box.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n * @requires OpenLayers/Handler.js\n- * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Handler/Drag.js\n */\n \n /**\n- * Class: OpenLayers.handler.Keyboard\n- * A handler for keyboard events. Create a new instance with the\n- * constructor.\n- * \n+ * Class: OpenLayers.Handler.Box\n+ * Handler for dragging a rectangle across the map. Box is displayed \n+ * on mouse down, moves on mouse move, and is finished on mouse up.\n+ *\n * Inherits from:\n * - \n */\n-OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {\n-\n- /* http://www.quirksmode.org/js/keys.html explains key x-browser\n- key handling quirks in pretty nice detail */\n+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {\n \n /** \n- * Constant: KEY_EVENTS\n- * keydown, keypress, keyup\n+ * Property: dragHandler \n+ * {} \n */\n- KEY_EVENTS: [\"keydown\", \"keyup\"],\n+ dragHandler: null,\n \n- /** \n- * Property: eventListener\n- * {Function}\n+ /**\n+ * APIProperty: boxDivClassName\n+ * {String} The CSS class to use for drawing the box. Default is\n+ * olHandlerBoxZoomBox\n */\n- eventListener: null,\n+ boxDivClassName: 'olHandlerBoxZoomBox',\n \n /**\n- * Property: observeElement\n- * {DOMElement|String} The DOM element on which we listen for\n- * key events. Default to the document.\n+ * Property: boxOffsets\n+ * {Object} Caches box offsets from css. This is used by the getBoxOffsets\n+ * method.\n */\n- observeElement: null,\n+ boxOffsets: null,\n \n /**\n- * Constructor: OpenLayers.Handler.Keyboard\n- * Returns a new keyboard handler.\n- * \n+ * Constructor: OpenLayers.Handler.Box\n+ *\n * Parameters:\n- * control - {} The control that is making use of\n- * this handler. If a handler is being used without a control, the\n- * handlers setMap method must be overridden to deal properly with\n- * the map.\n- * callbacks - {Object} An object containing a single function to be\n- * called when the drag operation is finished. The callback should\n- * expect to recieve a single argument, the pixel location of the event.\n- * Callbacks for 'keydown', 'keypress', and 'keyup' are supported.\n- * options - {Object} Optional object whose properties will be set on the\n- * handler.\n+ * control - {} \n+ * callbacks - {Object} An object with a properties whose values are\n+ * functions. Various callbacks described below.\n+ * options - {Object} \n+ *\n+ * Named callbacks:\n+ * start - Called when the box drag operation starts.\n+ * done - Called when the box drag operation is finished.\n+ * The callback should expect to receive a single argument, the box \n+ * bounds or a pixel. If the box dragging didn't span more than a 5 \n+ * pixel distance, a pixel will be returned instead of a bounds object.\n */\n initialize: function(control, callbacks, options) {\n OpenLayers.Handler.prototype.initialize.apply(this, arguments);\n- // cache the bound event listener method so it can be unobserved later\n- this.eventListener = OpenLayers.Function.bindAsEventListener(\n- this.handleKeyEvent, this\n+ this.dragHandler = new OpenLayers.Handler.Drag(\n+ this, {\n+ down: this.startBox,\n+ move: this.moveBox,\n+ out: this.removeBox,\n+ up: this.endBox\n+ }, {\n+ keyMask: this.keyMask\n+ }\n );\n },\n \n /**\n * Method: destroy\n */\n destroy: function() {\n- this.deactivate();\n- this.eventListener = null;\n OpenLayers.Handler.prototype.destroy.apply(this, arguments);\n+ if (this.dragHandler) {\n+ this.dragHandler.destroy();\n+ this.dragHandler = null;\n+ }\n+ },\n+\n+ /**\n+ * Method: setMap\n+ */\n+ setMap: function(map) {\n+ OpenLayers.Handler.prototype.setMap.apply(this, arguments);\n+ if (this.dragHandler) {\n+ this.dragHandler.setMap(map);\n+ }\n+ },\n+\n+ /**\n+ * Method: startBox\n+ *\n+ * Parameters:\n+ * xy - {}\n+ */\n+ startBox: function(xy) {\n+ this.callback(\"start\", []);\n+ this.zoomBox = OpenLayers.Util.createDiv('zoomBox', {\n+ x: -9999,\n+ y: -9999\n+ });\n+ this.zoomBox.className = this.boxDivClassName;\n+ this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE[\"Popup\"] - 1;\n+\n+ this.map.viewPortDiv.appendChild(this.zoomBox);\n+\n+ OpenLayers.Element.addClass(\n+ this.map.viewPortDiv, \"olDrawBox\"\n+ );\n+ },\n+\n+ /**\n+ * Method: moveBox\n+ */\n+ moveBox: function(xy) {\n+ var startX = this.dragHandler.start.x;\n+ var startY = this.dragHandler.start.y;\n+ var deltaX = Math.abs(startX - xy.x);\n+ var deltaY = Math.abs(startY - xy.y);\n+\n+ var offset = this.getBoxOffsets();\n+ this.zoomBox.style.width = (deltaX + offset.width + 1) + \"px\";\n+ this.zoomBox.style.height = (deltaY + offset.height + 1) + \"px\";\n+ this.zoomBox.style.left = (xy.x < startX ?\n+ startX - deltaX - offset.left : startX - offset.left) + \"px\";\n+ this.zoomBox.style.top = (xy.y < startY ?\n+ startY - deltaY - offset.top : startY - offset.top) + \"px\";\n+ },\n+\n+ /**\n+ * Method: endBox\n+ */\n+ endBox: function(end) {\n+ var result;\n+ if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||\n+ Math.abs(this.dragHandler.start.y - end.y) > 5) {\n+ var start = this.dragHandler.start;\n+ var top = Math.min(start.y, end.y);\n+ var bottom = Math.max(start.y, end.y);\n+ var left = Math.min(start.x, end.x);\n+ var right = Math.max(start.x, end.x);\n+ result = new OpenLayers.Bounds(left, bottom, right, top);\n+ } else {\n+ result = this.dragHandler.start.clone(); // i.e. OL.Pixel\n+ }\n+ this.removeBox();\n+\n+ this.callback(\"done\", [result]);\n+ },\n+\n+ /**\n+ * Method: removeBox\n+ * Remove the zoombox from the screen and nullify our reference to it.\n+ */\n+ removeBox: function() {\n+ this.map.viewPortDiv.removeChild(this.zoomBox);\n+ this.zoomBox = null;\n+ this.boxOffsets = null;\n+ OpenLayers.Element.removeClass(\n+ this.map.viewPortDiv, \"olDrawBox\"\n+ );\n+\n },\n \n /**\n * Method: activate\n */\n activate: function() {\n if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n- this.observeElement = this.observeElement || document;\n- for (var i = 0, len = this.KEY_EVENTS.length; i < len; i++) {\n- OpenLayers.Event.observe(\n- this.observeElement, this.KEY_EVENTS[i], this.eventListener);\n- }\n+ this.dragHandler.activate();\n return true;\n } else {\n return false;\n }\n },\n \n /**\n * Method: deactivate\n */\n deactivate: function() {\n- var deactivated = false;\n if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- for (var i = 0, len = this.KEY_EVENTS.length; i < len; i++) {\n- OpenLayers.Event.stopObserving(\n- this.observeElement, this.KEY_EVENTS[i], this.eventListener);\n+ if (this.dragHandler.deactivate()) {\n+ if (this.zoomBox) {\n+ this.removeBox();\n+ }\n }\n- deactivated = true;\n+ return true;\n+ } else {\n+ return false;\n }\n- return deactivated;\n },\n \n /**\n- * Method: handleKeyEvent \n+ * Method: getBoxOffsets\n+ * Determines border offsets for a box, according to the box model.\n+ * \n+ * Returns:\n+ * {Object} an object with the following offsets:\n+ * - left\n+ * - right\n+ * - top\n+ * - bottom\n+ * - width\n+ * - height\n */\n- handleKeyEvent: function(evt) {\n- if (this.checkModifiers(evt)) {\n- this.callback(evt.type, [evt]);\n+ getBoxOffsets: function() {\n+ if (!this.boxOffsets) {\n+ // Determine the box model. If the testDiv's clientWidth is 3, then\n+ // the borders are outside and we are dealing with the w3c box\n+ // model. Otherwise, the browser uses the traditional box model and\n+ // the borders are inside the box bounds, leaving us with a\n+ // clientWidth of 1.\n+ var testDiv = document.createElement(\"div\");\n+ //testDiv.style.visibility = \"hidden\";\n+ testDiv.style.position = \"absolute\";\n+ testDiv.style.border = \"1px solid black\";\n+ testDiv.style.width = \"3px\";\n+ document.body.appendChild(testDiv);\n+ var w3cBoxModel = testDiv.clientWidth == 3;\n+ document.body.removeChild(testDiv);\n+\n+ var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox,\n+ \"border-left-width\"));\n+ var right = parseInt(OpenLayers.Element.getStyle(\n+ this.zoomBox, \"border-right-width\"));\n+ var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox,\n+ \"border-top-width\"));\n+ var bottom = parseInt(OpenLayers.Element.getStyle(\n+ this.zoomBox, \"border-bottom-width\"));\n+ this.boxOffsets = {\n+ left: left,\n+ right: right,\n+ top: top,\n+ bottom: bottom,\n+ width: w3cBoxModel === false ? left + right : 0,\n+ height: w3cBoxModel === false ? top + bottom : 0\n+ };\n }\n+ return this.boxOffsets;\n },\n \n- CLASS_NAME: \"OpenLayers.Handler.Keyboard\"\n+ CLASS_NAME: \"OpenLayers.Handler.Box\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/ZoomBox.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Handler/Box.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control.ZoomBox\n+ * The ZoomBox control enables zooming directly to a given extent, by drawing \n+ * a box on the map. The box is drawn by holding down shift, whilst dragging \n+ * the mouse.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {\n+ /**\n+ * Property: type\n+ * {OpenLayers.Control.TYPE}\n+ */\n+ type: OpenLayers.Control.TYPE_TOOL,\n+\n+ /**\n+ * Property: out\n+ * {Boolean} Should the control be used for zooming out?\n+ */\n+ out: false,\n+\n+ /**\n+ * APIProperty: keyMask\n+ * {Integer} Zoom only occurs if the keyMask matches the combination of \n+ * keys down. Use bitwise operators and one or more of the\n+ * constants to construct a keyMask. Leave null if \n+ * not used mask. Default is null.\n+ */\n+ keyMask: null,\n+\n+ /**\n+ * APIProperty: alwaysZoom\n+ * {Boolean} Always zoom in/out when box drawn, even if the zoom level does\n+ * not change.\n+ */\n+ alwaysZoom: false,\n+\n+ /**\n+ * APIProperty: zoomOnClick\n+ * {Boolean} Should we zoom when no box was dragged, i.e. the user only\n+ * clicked? Default is true.\n+ */\n+ zoomOnClick: true,\n+\n+ /**\n+ * Method: draw\n+ */\n+ draw: function() {\n+ this.handler = new OpenLayers.Handler.Box(this, {\n+ done: this.zoomBox\n+ }, {\n+ keyMask: this.keyMask\n+ });\n+ },\n+\n+ /**\n+ * Method: zoomBox\n+ *\n+ * Parameters:\n+ * position - {} or {}\n+ */\n+ zoomBox: function(position) {\n+ if (position instanceof OpenLayers.Bounds) {\n+ var bounds,\n+ targetCenterPx = position.getCenterPixel();\n+ if (!this.out) {\n+ var minXY = this.map.getLonLatFromPixel({\n+ x: position.left,\n+ y: position.bottom\n+ });\n+ var maxXY = this.map.getLonLatFromPixel({\n+ x: position.right,\n+ y: position.top\n+ });\n+ bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,\n+ maxXY.lon, maxXY.lat);\n+ } else {\n+ var pixWidth = position.right - position.left;\n+ var pixHeight = position.bottom - position.top;\n+ var zoomFactor = Math.min((this.map.size.h / pixHeight),\n+ (this.map.size.w / pixWidth));\n+ var extent = this.map.getExtent();\n+ var center = this.map.getLonLatFromPixel(targetCenterPx);\n+ var xmin = center.lon - (extent.getWidth() / 2) * zoomFactor;\n+ var xmax = center.lon + (extent.getWidth() / 2) * zoomFactor;\n+ var ymin = center.lat - (extent.getHeight() / 2) * zoomFactor;\n+ var ymax = center.lat + (extent.getHeight() / 2) * zoomFactor;\n+ bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);\n+ }\n+ // always zoom in/out \n+ var lastZoom = this.map.getZoom(),\n+ size = this.map.getSize(),\n+ centerPx = {\n+ x: size.w / 2,\n+ y: size.h / 2\n+ },\n+ zoom = this.map.getZoomForExtent(bounds),\n+ oldRes = this.map.getResolution(),\n+ newRes = this.map.getResolutionForZoom(zoom);\n+ if (oldRes == newRes) {\n+ this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx));\n+ } else {\n+ var zoomOriginPx = {\n+ x: (oldRes * targetCenterPx.x - newRes * centerPx.x) /\n+ (oldRes - newRes),\n+ y: (oldRes * targetCenterPx.y - newRes * centerPx.y) /\n+ (oldRes - newRes)\n+ };\n+ this.map.zoomTo(zoom, zoomOriginPx);\n+ }\n+ if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) {\n+ this.map.zoomTo(lastZoom + (this.out ? -1 : 1));\n+ }\n+ } else if (this.zoomOnClick) { // it's a pixel\n+ if (!this.out) {\n+ this.map.zoomTo(this.map.getZoom() + 1, position);\n+ } else {\n+ this.map.zoomTo(this.map.getZoom() - 1, position);\n+ }\n+ }\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control.ZoomBox\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/NavigationHistory.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Control/Button.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control.NavigationHistory\n+ * A navigation history control. This is a meta-control, that creates two\n+ * dependent controls: and . Call the trigger method\n+ * on the and controls to restore previous and next\n+ * history states. The previous and next controls will become active\n+ * when there are available states to restore and will become deactive\n+ * when there are no states to restore.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /**\n+ * Property: type\n+ * {String} Note that this control is not intended to be added directly\n+ * to a control panel. Instead, add the sub-controls previous and\n+ * next. These sub-controls are button type controls that activate\n+ * and deactivate themselves. If this parent control is added to\n+ * a panel, it will act as a toggle.\n+ */\n+ type: OpenLayers.Control.TYPE_TOGGLE,\n+\n+ /**\n+ * APIProperty: previous\n+ * {} A button type control whose trigger method restores\n+ * the previous state managed by this control.\n+ */\n+ previous: null,\n+\n+ /**\n+ * APIProperty: previousOptions\n+ * {Object} Set this property on the options argument of the constructor\n+ * to set optional properties on the control.\n+ */\n+ previousOptions: null,\n+\n+ /**\n+ * APIProperty: next\n+ * {} A button type control whose trigger method restores\n+ * the next state managed by this control.\n+ */\n+ next: null,\n+\n+ /**\n+ * APIProperty: nextOptions\n+ * {Object} Set this property on the options argument of the constructor\n+ * to set optional properties on the control.\n+ */\n+ nextOptions: null,\n+\n+ /**\n+ * APIProperty: limit\n+ * {Integer} Optional limit on the number of history items to retain. If\n+ * null, there is no limit. Default is 50.\n+ */\n+ limit: 50,\n+\n+ /**\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * true.\n+ */\n+ autoActivate: true,\n+\n+ /**\n+ * Property: clearOnDeactivate\n+ * {Boolean} Clear the history when the control is deactivated. Default\n+ * is false.\n+ */\n+ clearOnDeactivate: false,\n+\n+ /**\n+ * Property: registry\n+ * {Object} An object with keys corresponding to event types. Values\n+ * are functions that return an object representing the current state.\n+ */\n+ registry: null,\n+\n+ /**\n+ * Property: nextStack\n+ * {Array} Array of items in the history.\n+ */\n+ nextStack: null,\n+\n+ /**\n+ * Property: previousStack\n+ * {Array} List of items in the history. First item represents the current\n+ * state.\n+ */\n+ previousStack: null,\n+\n+ /**\n+ * Property: listeners\n+ * {Object} An object containing properties corresponding to event types.\n+ * This object is used to configure the control and is modified on\n+ * construction.\n+ */\n+ listeners: null,\n+\n+ /**\n+ * Property: restoring\n+ * {Boolean} Currently restoring a history state. This is set to true\n+ * before calling restore and set to false after restore returns.\n+ */\n+ restoring: false,\n+\n+ /**\n+ * Constructor: OpenLayers.Control.NavigationHistory \n+ * \n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be used\n+ * to extend the control.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+\n+ this.registry = OpenLayers.Util.extend({\n+ \"moveend\": this.getState\n+ }, this.registry);\n+\n+ var previousOptions = {\n+ trigger: OpenLayers.Function.bind(this.previousTrigger, this),\n+ displayClass: this.displayClass + \" \" + this.displayClass + \"Previous\"\n+ };\n+ OpenLayers.Util.extend(previousOptions, this.previousOptions);\n+ this.previous = new OpenLayers.Control.Button(previousOptions);\n+\n+ var nextOptions = {\n+ trigger: OpenLayers.Function.bind(this.nextTrigger, this),\n+ displayClass: this.displayClass + \" \" + this.displayClass + \"Next\"\n+ };\n+ OpenLayers.Util.extend(nextOptions, this.nextOptions);\n+ this.next = new OpenLayers.Control.Button(nextOptions);\n+\n+ this.clear();\n+ },\n+\n+ /**\n+ * Method: onPreviousChange\n+ * Called when the previous history stack changes.\n+ *\n+ * Parameters:\n+ * state - {Object} An object representing the state to be restored\n+ * if previous is triggered again or null if no previous states remain.\n+ * length - {Integer} The number of remaining previous states that can\n+ * be restored.\n+ */\n+ onPreviousChange: function(state, length) {\n+ if (state && !this.previous.active) {\n+ this.previous.activate();\n+ } else if (!state && this.previous.active) {\n+ this.previous.deactivate();\n+ }\n+ },\n+\n+ /**\n+ * Method: onNextChange\n+ * Called when the next history stack changes.\n+ *\n+ * Parameters:\n+ * state - {Object} An object representing the state to be restored\n+ * if next is triggered again or null if no next states remain.\n+ * length - {Integer} The number of remaining next states that can\n+ * be restored.\n+ */\n+ onNextChange: function(state, length) {\n+ if (state && !this.next.active) {\n+ this.next.activate();\n+ } else if (!state && this.next.active) {\n+ this.next.deactivate();\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: destroy\n+ * Destroy the control.\n+ */\n+ destroy: function() {\n+ OpenLayers.Control.prototype.destroy.apply(this);\n+ this.previous.destroy();\n+ this.next.destroy();\n+ this.deactivate();\n+ for (var prop in this) {\n+ this[prop] = null;\n+ }\n+ },\n+\n+ /** \n+ * Method: setMap\n+ * Set the map property for the control and and child\n+ * controls.\n+ *\n+ * Parameters:\n+ * map - {} \n+ */\n+ setMap: function(map) {\n+ this.map = map;\n+ this.next.setMap(map);\n+ this.previous.setMap(map);\n+ },\n+\n+ /**\n+ * Method: draw\n+ * Called when the control is added to the map.\n+ */\n+ draw: function() {\n+ OpenLayers.Control.prototype.draw.apply(this, arguments);\n+ this.next.draw();\n+ this.previous.draw();\n+ },\n+\n+ /**\n+ * Method: previousTrigger\n+ * Restore the previous state. If no items are in the previous history\n+ * stack, this has no effect.\n+ *\n+ * Returns:\n+ * {Object} Item representing state that was restored. Undefined if no\n+ * items are in the previous history stack.\n+ */\n+ previousTrigger: function() {\n+ var current = this.previousStack.shift();\n+ var state = this.previousStack.shift();\n+ if (state != undefined) {\n+ this.nextStack.unshift(current);\n+ this.previousStack.unshift(state);\n+ this.restoring = true;\n+ this.restore(state);\n+ this.restoring = false;\n+ this.onNextChange(this.nextStack[0], this.nextStack.length);\n+ this.onPreviousChange(\n+ this.previousStack[1], this.previousStack.length - 1\n+ );\n+ } else {\n+ this.previousStack.unshift(current);\n+ }\n+ return state;\n+ },\n+\n+ /**\n+ * APIMethod: nextTrigger\n+ * Restore the next state. If no items are in the next history\n+ * stack, this has no effect. The next history stack is populated\n+ * as states are restored from the previous history stack.\n+ *\n+ * Returns:\n+ * {Object} Item representing state that was restored. Undefined if no\n+ * items are in the next history stack.\n+ */\n+ nextTrigger: function() {\n+ var state = this.nextStack.shift();\n+ if (state != undefined) {\n+ this.previousStack.unshift(state);\n+ this.restoring = true;\n+ this.restore(state);\n+ this.restoring = false;\n+ this.onNextChange(this.nextStack[0], this.nextStack.length);\n+ this.onPreviousChange(\n+ this.previousStack[1], this.previousStack.length - 1\n+ );\n+ }\n+ return state;\n+ },\n+\n+ /**\n+ * APIMethod: clear\n+ * Clear history.\n+ */\n+ clear: function() {\n+ this.previousStack = [];\n+ this.previous.deactivate();\n+ this.nextStack = [];\n+ this.next.deactivate();\n+ },\n+\n+ /**\n+ * Method: getState\n+ * Get the current state and return it.\n+ *\n+ * Returns:\n+ * {Object} An object representing the current state.\n+ */\n+ getState: function() {\n+ return {\n+ center: this.map.getCenter(),\n+ resolution: this.map.getResolution(),\n+ projection: this.map.getProjectionObject(),\n+ units: this.map.getProjectionObject().getUnits() ||\n+ this.map.units || this.map.baseLayer.units\n+ };\n+ },\n+\n+ /**\n+ * Method: restore\n+ * Update the state with the given object.\n+ *\n+ * Parameters:\n+ * state - {Object} An object representing the state to restore.\n+ */\n+ restore: function(state) {\n+ var center, zoom;\n+ if (this.map.getProjectionObject() == state.projection) {\n+ zoom = this.map.getZoomForResolution(state.resolution);\n+ center = state.center;\n+ } else {\n+ center = state.center.clone();\n+ center.transform(state.projection, this.map.getProjectionObject());\n+ var sourceUnits = state.units;\n+ var targetUnits = this.map.getProjectionObject().getUnits() ||\n+ this.map.units || this.map.baseLayer.units;\n+ var resolutionFactor = sourceUnits && targetUnits ?\n+ OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;\n+ zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution);\n+ }\n+ this.map.setCenter(center, zoom);\n+ },\n+\n+ /**\n+ * Method: setListeners\n+ * Sets functions to be registered in the listeners object.\n+ */\n+ setListeners: function() {\n+ this.listeners = {};\n+ for (var type in this.registry) {\n+ this.listeners[type] = OpenLayers.Function.bind(function() {\n+ if (!this.restoring) {\n+ var state = this.registry[type].apply(this, arguments);\n+ this.previousStack.unshift(state);\n+ if (this.previousStack.length > 1) {\n+ this.onPreviousChange(\n+ this.previousStack[1], this.previousStack.length - 1\n+ );\n+ }\n+ if (this.previousStack.length > (this.limit + 1)) {\n+ this.previousStack.pop();\n+ }\n+ if (this.nextStack.length > 0) {\n+ this.nextStack = [];\n+ this.onNextChange(null, 0);\n+ }\n+ }\n+ return true;\n+ }, this);\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: activate\n+ * Activate the control. This registers any listeners.\n+ *\n+ * Returns:\n+ * {Boolean} Control successfully activated.\n+ */\n+ activate: function() {\n+ var activated = false;\n+ if (this.map) {\n+ if (OpenLayers.Control.prototype.activate.apply(this)) {\n+ if (this.listeners == null) {\n+ this.setListeners();\n+ }\n+ for (var type in this.listeners) {\n+ this.map.events.register(type, this, this.listeners[type]);\n+ }\n+ activated = true;\n+ if (this.previousStack.length == 0) {\n+ this.initStack();\n+ }\n+ }\n+ }\n+ return activated;\n+ },\n+\n+ /**\n+ * Method: initStack\n+ * Called after the control is activated if the previous history stack is\n+ * empty.\n+ */\n+ initStack: function() {\n+ if (this.map.getCenter()) {\n+ this.listeners.moveend();\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the control. This unregisters any listeners.\n+ *\n+ * Returns:\n+ * {Boolean} Control successfully deactivated.\n+ */\n+ deactivate: function() {\n+ var deactivated = false;\n+ if (this.map) {\n+ if (OpenLayers.Control.prototype.deactivate.apply(this)) {\n+ for (var type in this.listeners) {\n+ this.map.events.unregister(\n+ type, this, this.listeners[type]\n+ );\n+ }\n+ if (this.clearOnDeactivate) {\n+ this.clear();\n+ }\n+ deactivated = true;\n+ }\n+ }\n+ return deactivated;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control.NavigationHistory\"\n });\n+\n /* ======================================================================\n OpenLayers/Handler/Point.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n@@ -35498,2145 +39326,234 @@\n }\n return false;\n },\n \n CLASS_NAME: \"OpenLayers.Handler.Path\"\n });\n /* ======================================================================\n- OpenLayers/Handler/MouseWheel.js\n+ OpenLayers/Layer/Vector.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Handler.js\n+ * @requires OpenLayers/Layer.js\n+ * @requires OpenLayers/Renderer.js\n+ * @requires OpenLayers/StyleMap.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ * @requires OpenLayers/Console.js\n+ * @requires OpenLayers/Lang.js\n */\n \n /**\n- * Class: OpenLayers.Handler.MouseWheel\n- * Handler for wheel up/down events.\n- * \n+ * Class: OpenLayers.Layer.Vector\n+ * Instances of OpenLayers.Layer.Vector are used to render vector data from\n+ * a variety of sources. Create a new vector layer with the\n+ * constructor.\n+ *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {\n- /** \n- * Property: wheelListener \n- * {function} \n+OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {\n+\n+ /**\n+ * APIProperty: events\n+ * {}\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * layer.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Listeners will be called with a reference to an event object. The\n+ * properties of this event depends on exactly what happened.\n+ *\n+ * All event objects have at least the following properties:\n+ * object - {Object} A reference to layer.events.object.\n+ * element - {DOMElement} A reference to layer.events.element.\n+ *\n+ * Supported map event types (in addition to those from ):\n+ * beforefeatureadded - Triggered before a feature is added. Listeners\n+ * will receive an object with a *feature* property referencing the\n+ * feature to be added. To stop the feature from being added, a\n+ * listener should return false.\n+ * beforefeaturesadded - Triggered before an array of features is added.\n+ * Listeners will receive an object with a *features* property\n+ * referencing the feature to be added. To stop the features from\n+ * being added, a listener should return false.\n+ * featureadded - Triggered after a feature is added. The event\n+ * object passed to listeners will have a *feature* property with a\n+ * reference to the added feature.\n+ * featuresadded - Triggered after features are added. The event\n+ * object passed to listeners will have a *features* property with a\n+ * reference to an array of added features.\n+ * beforefeatureremoved - Triggered before a feature is removed. Listeners\n+ * will receive an object with a *feature* property referencing the\n+ * feature to be removed.\n+ * beforefeaturesremoved - Triggered before multiple features are removed. \n+ * Listeners will receive an object with a *features* property\n+ * referencing the features to be removed.\n+ * featureremoved - Triggerd after a feature is removed. The event\n+ * object passed to listeners will have a *feature* property with a\n+ * reference to the removed feature.\n+ * featuresremoved - Triggered after features are removed. The event\n+ * object passed to listeners will have a *features* property with a\n+ * reference to an array of removed features.\n+ * beforefeatureselected - Triggered before a feature is selected. Listeners\n+ * will receive an object with a *feature* property referencing the\n+ * feature to be selected. To stop the feature from being selectd, a\n+ * listener should return false.\n+ * featureselected - Triggered after a feature is selected. Listeners\n+ * will receive an object with a *feature* property referencing the\n+ * selected feature.\n+ * featureunselected - Triggered after a feature is unselected.\n+ * Listeners will receive an object with a *feature* property\n+ * referencing the unselected feature.\n+ * beforefeaturemodified - Triggered when a feature is selected to \n+ * be modified. Listeners will receive an object with a *feature* \n+ * property referencing the selected feature.\n+ * featuremodified - Triggered when a feature has been modified.\n+ * Listeners will receive an object with a *feature* property referencing \n+ * the modified feature.\n+ * afterfeaturemodified - Triggered when a feature is finished being modified.\n+ * Listeners will receive an object with a *feature* property referencing \n+ * the modified feature.\n+ * vertexmodified - Triggered when a vertex within any feature geometry\n+ * has been modified. Listeners will receive an object with a\n+ * *feature* property referencing the modified feature, a *vertex*\n+ * property referencing the vertex modified (always a point geometry),\n+ * and a *pixel* property referencing the pixel location of the\n+ * modification.\n+ * vertexremoved - Triggered when a vertex within any feature geometry\n+ * has been deleted. Listeners will receive an object with a\n+ * *feature* property referencing the modified feature, a *vertex*\n+ * property referencing the vertex modified (always a point geometry),\n+ * and a *pixel* property referencing the pixel location of the\n+ * removal.\n+ * sketchstarted - Triggered when a feature sketch bound for this layer\n+ * is started. Listeners will receive an object with a *feature*\n+ * property referencing the new sketch feature and a *vertex* property\n+ * referencing the creation point.\n+ * sketchmodified - Triggered when a feature sketch bound for this layer\n+ * is modified. Listeners will receive an object with a *vertex*\n+ * property referencing the modified vertex and a *feature* property\n+ * referencing the sketch feature.\n+ * sketchcomplete - Triggered when a feature sketch bound for this layer\n+ * is complete. Listeners will receive an object with a *feature*\n+ * property referencing the sketch feature. By returning false, a\n+ * listener can stop the sketch feature from being added to the layer.\n+ * refresh - Triggered when something wants a strategy to ask the protocol\n+ * for a new set of features.\n */\n- wheelListener: null,\n \n /**\n- * Property: interval\n- * {Integer} In order to increase server performance, an interval (in \n- * milliseconds) can be set to reduce the number of up/down events \n- * called. If set, a new up/down event will not be set until the \n- * interval has passed. \n- * Defaults to 0, meaning no interval. \n+ * APIProperty: isBaseLayer\n+ * {Boolean} The layer is a base layer. Default is false. Set this property\n+ * in the layer options.\n */\n- interval: 0,\n+ isBaseLayer: false,\n+\n+ /** \n+ * APIProperty: isFixed\n+ * {Boolean} Whether the layer remains in one place while dragging the\n+ * map. Note that setting this to true will move the layer to the bottom\n+ * of the layer stack.\n+ */\n+ isFixed: false,\n+\n+ /** \n+ * APIProperty: features\n+ * {Array()} \n+ */\n+ features: null,\n+\n+ /** \n+ * Property: filter\n+ * {} The filter set in this layer,\n+ * a strategy launching read requests can combined\n+ * this filter with its own filter.\n+ */\n+ filter: null,\n+\n+ /** \n+ * Property: selectedFeatures\n+ * {Array()} \n+ */\n+ selectedFeatures: null,\n \n /**\n- * Property: maxDelta\n- * {Integer} Maximum delta to collect before breaking from the current\n- * interval. In cumulative mode, this also limits the maximum delta\n- * returned from the handler. Default is Number.POSITIVE_INFINITY.\n+ * Property: unrenderedFeatures\n+ * {Object} hash of features, keyed by feature.id, that the renderer\n+ * failed to draw\n */\n- maxDelta: Number.POSITIVE_INFINITY,\n+ unrenderedFeatures: null,\n \n /**\n- * Property: delta\n- * {Integer} When interval is set, delta collects the mousewheel z-deltas\n- * of the events that occur within the interval.\n- * See also the cumulative option\n+ * APIProperty: reportError\n+ * {Boolean} report friendly error message when loading of renderer\n+ * fails.\n */\n- delta: 0,\n+ reportError: true,\n+\n+ /** \n+ * APIProperty: style\n+ * {Object} Default style for the layer\n+ */\n+ style: null,\n \n /**\n- * Property: cumulative\n- * {Boolean} When interval is set: true to collect all the mousewheel \n- * z-deltas, false to only record the delta direction (positive or\n- * negative)\n+ * Property: styleMap\n+ * {}\n */\n- cumulative: true,\n+ styleMap: null,\n \n /**\n- * Constructor: OpenLayers.Handler.MouseWheel\n- *\n- * Parameters:\n- * control - {} \n- * callbacks - {Object} An object containing a single function to be\n- * called when the drag operation is finished.\n- * The callback should expect to recieve a single\n- * argument, the point geometry.\n- * options - {Object} \n+ * Property: strategies\n+ * {Array(})} Optional list of strategies for the layer.\n */\n- initialize: function(control, callbacks, options) {\n- OpenLayers.Handler.prototype.initialize.apply(this, arguments);\n- this.wheelListener = OpenLayers.Function.bindAsEventListener(\n- this.onWheelEvent, this\n- );\n- },\n+ strategies: null,\n \n /**\n- * Method: destroy\n+ * Property: protocol\n+ * {} Optional protocol for the layer.\n */\n- destroy: function() {\n- OpenLayers.Handler.prototype.destroy.apply(this, arguments);\n- this.wheelListener = null;\n- },\n+ protocol: null,\n \n /**\n- * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/\n+ * Property: renderers\n+ * {Array(String)} List of supported Renderer classes. Add to this list to\n+ * add support for additional renderers. This list is ordered:\n+ * the first renderer which returns true for the 'supported()'\n+ * method will be used, if not defined in the 'renderer' option.\n */\n+ renderers: ['SVG', 'VML', 'Canvas'],\n \n /** \n- * Method: onWheelEvent\n- * Catch the wheel event and handle it xbrowserly\n- * \n- * Parameters:\n- * e - {Event} \n+ * Property: renderer\n+ * {}\n */\n- onWheelEvent: function(e) {\n-\n- // make sure we have a map and check keyboard modifiers\n- if (!this.map || !this.checkModifiers(e)) {\n- return;\n- }\n+ renderer: null,\n \n- // Ride up the element's DOM hierarchy to determine if it or any of \n- // its ancestors was: \n- // * specifically marked as scrollable (CSS overflow property)\n- // * one of our layer divs or a div marked as scrollable\n- // ('olScrollable' CSS class)\n- // * the map div\n- //\n- var overScrollableDiv = false;\n- var allowScroll = false;\n- var overMapDiv = false;\n+ /**\n+ * APIProperty: rendererOptions\n+ * {Object} Options for the renderer. See {} for\n+ * supported options.\n+ */\n+ rendererOptions: null,\n \n- var elem = OpenLayers.Event.element(e);\n- while ((elem != null) && !overMapDiv && !overScrollableDiv) {\n-\n- if (!overScrollableDiv) {\n- try {\n- var overflow;\n- if (elem.currentStyle) {\n- overflow = elem.currentStyle[\"overflow\"];\n- } else {\n- var style =\n- document.defaultView.getComputedStyle(elem, null);\n- overflow = style.getPropertyValue(\"overflow\");\n- }\n- overScrollableDiv = (overflow &&\n- (overflow == \"auto\") || (overflow == \"scroll\"));\n- } catch (err) {\n- //sometimes when scrolling in a popup, this causes \n- // obscure browser error\n- }\n- }\n-\n- if (!allowScroll) {\n- allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable');\n- if (!allowScroll) {\n- for (var i = 0, len = this.map.layers.length; i < len; i++) {\n- // Are we in the layer div? Note that we have two cases\n- // here: one is to catch EventPane layers, which have a\n- // pane above the layer (layer.pane)\n- var layer = this.map.layers[i];\n- if (elem == layer.div || elem == layer.pane) {\n- allowScroll = true;\n- break;\n- }\n- }\n- }\n- }\n- overMapDiv = (elem == this.map.div);\n-\n- elem = elem.parentNode;\n- }\n-\n- // Logic below is the following:\n- //\n- // If we are over a scrollable div or not over the map div:\n- // * do nothing (let the browser handle scrolling)\n- //\n- // otherwise \n- // \n- // If we are over the layer div or a 'olScrollable' div:\n- // * zoom/in out\n- // then\n- // * kill event (so as not to also scroll the page after zooming)\n- //\n- // otherwise\n- //\n- // Kill the event (dont scroll the page if we wheel over the \n- // layerswitcher or the pan/zoom control)\n- //\n- if (!overScrollableDiv && overMapDiv) {\n- if (allowScroll) {\n- var delta = 0;\n-\n- if (e.wheelDelta) {\n- delta = e.wheelDelta;\n- if (delta % 160 === 0) {\n- // opera have steps of 160 instead of 120\n- delta = delta * 0.75;\n- }\n- delta = delta / 120;\n- } else if (e.detail) {\n- // detail in Firefox on OS X is 1/3 of Windows\n- // so force delta 1 / -1\n- delta = -(e.detail / Math.abs(e.detail));\n- }\n- this.delta += delta;\n-\n- window.clearTimeout(this._timeoutId);\n- if (this.interval && Math.abs(this.delta) < this.maxDelta) {\n- // store e because window.event might change during delay\n- var evt = OpenLayers.Util.extend({}, e);\n- this._timeoutId = window.setTimeout(\n- OpenLayers.Function.bind(function() {\n- this.wheelZoom(evt);\n- }, this),\n- this.interval\n- );\n- } else {\n- this.wheelZoom(e);\n- }\n- }\n- OpenLayers.Event.stop(e);\n- }\n- },\n-\n- /**\n- * Method: wheelZoom\n- * Given the wheel event, we carry out the appropriate zooming in or out,\n- * based on the 'wheelDelta' or 'detail' property of the event.\n- * \n- * Parameters:\n- * e - {Event}\n- */\n- wheelZoom: function(e) {\n- var delta = this.delta;\n- this.delta = 0;\n-\n- if (delta) {\n- e.xy = this.map.events.getMousePosition(e);\n- if (delta < 0) {\n- this.callback(\"down\",\n- [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]);\n- } else {\n- this.callback(\"up\",\n- [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]);\n- }\n- }\n- },\n-\n- /**\n- * Method: activate \n- */\n- activate: function(evt) {\n- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n- //register mousewheel events specifically on the window and document\n- var wheelListener = this.wheelListener;\n- OpenLayers.Event.observe(window, \"DOMMouseScroll\", wheelListener);\n- OpenLayers.Event.observe(window, \"mousewheel\", wheelListener);\n- OpenLayers.Event.observe(document, \"mousewheel\", wheelListener);\n- return true;\n- } else {\n- return false;\n- }\n- },\n-\n- /**\n- * Method: deactivate \n- */\n- deactivate: function(evt) {\n- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- // unregister mousewheel events specifically on the window and document\n- var wheelListener = this.wheelListener;\n- OpenLayers.Event.stopObserving(window, \"DOMMouseScroll\", wheelListener);\n- OpenLayers.Event.stopObserving(window, \"mousewheel\", wheelListener);\n- OpenLayers.Event.stopObserving(document, \"mousewheel\", wheelListener);\n- return true;\n- } else {\n- return false;\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.MouseWheel\"\n-});\n-/* ======================================================================\n- OpenLayers/Handler/Feature.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Handler.js\n- */\n-\n-/**\n- * Class: OpenLayers.Handler.Feature \n- * Handler to respond to mouse events related to a drawn feature. Callbacks\n- * with the following keys will be notified of the following events\n- * associated with features: click, clickout, over, out, and dblclick.\n- *\n- * This handler stops event propagation for mousedown and mouseup if those\n- * browser events target features that can be selected.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {\n-\n- /**\n- * Property: EVENTMAP\n- * {Object} A object mapping the browser events to objects with callback\n- * keys for in and out.\n- */\n- EVENTMAP: {\n- 'click': {\n- 'in': 'click',\n- 'out': 'clickout'\n- },\n- 'mousemove': {\n- 'in': 'over',\n- 'out': 'out'\n- },\n- 'dblclick': {\n- 'in': 'dblclick',\n- 'out': null\n- },\n- 'mousedown': {\n- 'in': null,\n- 'out': null\n- },\n- 'mouseup': {\n- 'in': null,\n- 'out': null\n- },\n- 'touchstart': {\n- 'in': 'click',\n- 'out': 'clickout'\n- }\n- },\n-\n- /**\n- * Property: feature\n- * {} The last feature that was hovered.\n- */\n- feature: null,\n-\n- /**\n- * Property: lastFeature\n- * {} The last feature that was handled.\n- */\n- lastFeature: null,\n-\n- /**\n- * Property: down\n- * {} The location of the last mousedown.\n- */\n- down: null,\n-\n- /**\n- * Property: up\n- * {} The location of the last mouseup.\n- */\n- up: null,\n-\n- /**\n- * Property: clickTolerance\n- * {Number} The number of pixels the mouse can move between mousedown\n- * and mouseup for the event to still be considered a click.\n- * Dragging the map should not trigger the click and clickout callbacks\n- * unless the map is moved by less than this tolerance. Defaults to 4.\n- */\n- clickTolerance: 4,\n-\n- /**\n- * Property: geometryTypes\n- * To restrict dragging to a limited set of geometry types, send a list\n- * of strings corresponding to the geometry class names.\n- * \n- * @type Array(String)\n- */\n- geometryTypes: null,\n-\n- /**\n- * Property: stopClick\n- * {Boolean} If stopClick is set to true, handled clicks do not\n- * propagate to other click listeners. Otherwise, handled clicks\n- * do propagate. Unhandled clicks always propagate, whatever the\n- * value of stopClick. Defaults to true.\n- */\n- stopClick: true,\n-\n- /**\n- * Property: stopDown\n- * {Boolean} If stopDown is set to true, handled mousedowns do not\n- * propagate to other mousedown listeners. Otherwise, handled\n- * mousedowns do propagate. Unhandled mousedowns always propagate,\n- * whatever the value of stopDown. Defaults to true.\n- */\n- stopDown: true,\n-\n- /**\n- * Property: stopUp\n- * {Boolean} If stopUp is set to true, handled mouseups do not\n- * propagate to other mouseup listeners. Otherwise, handled mouseups\n- * do propagate. Unhandled mouseups always propagate, whatever the\n- * value of stopUp. Defaults to false.\n- */\n- stopUp: false,\n-\n- /**\n- * Constructor: OpenLayers.Handler.Feature\n- *\n- * Parameters:\n- * control - {} \n- * layer - {}\n- * callbacks - {Object} An object with a 'over' property whos value is\n- * a function to be called when the mouse is over a feature. The \n- * callback should expect to recieve a single argument, the feature.\n- * options - {Object} \n- */\n- initialize: function(control, layer, callbacks, options) {\n- OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);\n- this.layer = layer;\n- },\n-\n- /**\n- * Method: touchstart\n- * Handle touchstart events\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Boolean} Let the event propagate.\n- */\n- touchstart: function(evt) {\n- this.startTouch();\n- return OpenLayers.Event.isMultiTouch(evt) ?\n- true : this.mousedown(evt);\n- },\n-\n- /**\n- * Method: touchmove\n- * Handle touchmove events. We just prevent the browser default behavior,\n- * for Android Webkit not to select text when moving the finger after\n- * selecting a feature.\n- *\n- * Parameters:\n- * evt - {Event}\n- */\n- touchmove: function(evt) {\n- OpenLayers.Event.preventDefault(evt);\n- },\n-\n- /**\n- * Method: mousedown\n- * Handle mouse down. Stop propagation if a feature is targeted by this\n- * event (stops map dragging during feature selection).\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- mousedown: function(evt) {\n- // Feature selection is only done with a left click. Other handlers may stop the\n- // propagation of left-click mousedown events but not right-click mousedown events.\n- // This mismatch causes problems when comparing the location of the down and up\n- // events in the click function so it is important ignore right-clicks.\n- if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) {\n- this.down = evt.xy;\n- }\n- return this.handle(evt) ? !this.stopDown : true;\n- },\n-\n- /**\n- * Method: mouseup\n- * Handle mouse up. Stop propagation if a feature is targeted by this\n- * event.\n- * \n- * Parameters:\n- * evt - {Event} \n- */\n- mouseup: function(evt) {\n- this.up = evt.xy;\n- return this.handle(evt) ? !this.stopUp : true;\n- },\n-\n- /**\n- * Method: click\n- * Handle click. Call the \"click\" callback if click on a feature,\n- * or the \"clickout\" callback if click outside any feature.\n- * \n- * Parameters:\n- * evt - {Event} \n- *\n- * Returns:\n- * {Boolean}\n- */\n- click: function(evt) {\n- return this.handle(evt) ? !this.stopClick : true;\n- },\n-\n- /**\n- * Method: mousemove\n- * Handle mouse moves. Call the \"over\" callback if moving in to a feature,\n- * or the \"out\" callback if moving out of a feature.\n- * \n- * Parameters:\n- * evt - {Event} \n- *\n- * Returns:\n- * {Boolean}\n- */\n- mousemove: function(evt) {\n- if (!this.callbacks['over'] && !this.callbacks['out']) {\n- return true;\n- }\n- this.handle(evt);\n- return true;\n- },\n-\n- /**\n- * Method: dblclick\n- * Handle dblclick. Call the \"dblclick\" callback if dblclick on a feature.\n- *\n- * Parameters:\n- * evt - {Event} \n- *\n- * Returns:\n- * {Boolean}\n- */\n- dblclick: function(evt) {\n- return !this.handle(evt);\n- },\n-\n- /**\n- * Method: geometryTypeMatches\n- * Return true if the geometry type of the passed feature matches\n- * one of the geometry types in the geometryTypes array.\n- *\n- * Parameters:\n- * feature - {}\n- *\n- * Returns:\n- * {Boolean}\n- */\n- geometryTypeMatches: function(feature) {\n- return this.geometryTypes == null ||\n- OpenLayers.Util.indexOf(this.geometryTypes,\n- feature.geometry.CLASS_NAME) > -1;\n- },\n-\n- /**\n- * Method: handle\n- *\n- * Parameters:\n- * evt - {Event}\n- *\n- * Returns:\n- * {Boolean} The event occurred over a relevant feature.\n- */\n- handle: function(evt) {\n- if (this.feature && !this.feature.layer) {\n- // feature has been destroyed\n- this.feature = null;\n- }\n- var type = evt.type;\n- var handled = false;\n- var previouslyIn = !!(this.feature); // previously in a feature\n- var click = (type == \"click\" || type == \"dblclick\" || type == \"touchstart\");\n- this.feature = this.layer.getFeatureFromEvent(evt);\n- if (this.feature && !this.feature.layer) {\n- // feature has been destroyed\n- this.feature = null;\n- }\n- if (this.lastFeature && !this.lastFeature.layer) {\n- // last feature has been destroyed\n- this.lastFeature = null;\n- }\n- if (this.feature) {\n- if (type === \"touchstart\") {\n- // stop the event to prevent Android Webkit from\n- // \"flashing\" the map div\n- OpenLayers.Event.preventDefault(evt);\n- }\n- var inNew = (this.feature != this.lastFeature);\n- if (this.geometryTypeMatches(this.feature)) {\n- // in to a feature\n- if (previouslyIn && inNew) {\n- // out of last feature and in to another\n- if (this.lastFeature) {\n- this.triggerCallback(type, 'out', [this.lastFeature]);\n- }\n- this.triggerCallback(type, 'in', [this.feature]);\n- } else if (!previouslyIn || click) {\n- // in feature for the first time\n- this.triggerCallback(type, 'in', [this.feature]);\n- }\n- this.lastFeature = this.feature;\n- handled = true;\n- } else {\n- // not in to a feature\n- if (this.lastFeature && (previouslyIn && inNew || click)) {\n- // out of last feature for the first time\n- this.triggerCallback(type, 'out', [this.lastFeature]);\n- }\n- // next time the mouse goes in a feature whose geometry type\n- // doesn't match we don't want to call the 'out' callback\n- // again, so let's set this.feature to null so that\n- // previouslyIn will evaluate to false the next time\n- // we enter handle. Yes, a bit hackish...\n- this.feature = null;\n- }\n- } else if (this.lastFeature && (previouslyIn || click)) {\n- this.triggerCallback(type, 'out', [this.lastFeature]);\n- }\n- return handled;\n- },\n-\n- /**\n- * Method: triggerCallback\n- * Call the callback keyed in the event map with the supplied arguments.\n- * For click and clickout, the is checked first.\n- *\n- * Parameters:\n- * type - {String}\n- */\n- triggerCallback: function(type, mode, args) {\n- var key = this.EVENTMAP[type][mode];\n- if (key) {\n- if (type == 'click' && this.up && this.down) {\n- // for click/clickout, only trigger callback if tolerance is met\n- var dpx = Math.sqrt(\n- Math.pow(this.up.x - this.down.x, 2) +\n- Math.pow(this.up.y - this.down.y, 2)\n- );\n- if (dpx <= this.clickTolerance) {\n- this.callback(key, args);\n- }\n- // we're done with this set of events now: clear the cached\n- // positions so we can't trip over them later (this can occur\n- // if one of the up/down events gets eaten before it gets to us\n- // but we still get the click)\n- this.up = this.down = null;\n- } else {\n- this.callback(key, args);\n- }\n- }\n- },\n-\n- /**\n- * Method: activate \n- * Turn on the handler. Returns false if the handler was already active.\n- *\n- * Returns:\n- * {Boolean}\n- */\n- activate: function() {\n- var activated = false;\n- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n- this.moveLayerToTop();\n- this.map.events.on({\n- \"removelayer\": this.handleMapEvents,\n- \"changelayer\": this.handleMapEvents,\n- scope: this\n- });\n- activated = true;\n- }\n- return activated;\n- },\n-\n- /**\n- * Method: deactivate \n- * Turn off the handler. Returns false if the handler was already active.\n- *\n- * Returns: \n- * {Boolean}\n- */\n- deactivate: function() {\n- var deactivated = false;\n- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- this.moveLayerBack();\n- this.feature = null;\n- this.lastFeature = null;\n- this.down = null;\n- this.up = null;\n- this.map.events.un({\n- \"removelayer\": this.handleMapEvents,\n- \"changelayer\": this.handleMapEvents,\n- scope: this\n- });\n- deactivated = true;\n- }\n- return deactivated;\n- },\n-\n- /**\n- * Method: handleMapEvents\n- * \n- * Parameters:\n- * evt - {Object}\n- */\n- handleMapEvents: function(evt) {\n- if (evt.type == \"removelayer\" || evt.property == \"order\") {\n- this.moveLayerToTop();\n- }\n- },\n-\n- /**\n- * Method: moveLayerToTop\n- * Moves the layer for this handler to the top, so mouse events can reach\n- * it.\n- */\n- moveLayerToTop: function() {\n- var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,\n- this.layer.getZIndex()) + 1;\n- this.layer.setZIndex(index);\n-\n- },\n-\n- /**\n- * Method: moveLayerBack\n- * Moves the layer back to the position determined by the map's layers\n- * array.\n- */\n- moveLayerBack: function() {\n- var index = this.layer.getZIndex() - 1;\n- if (index >= this.map.Z_INDEX_BASE['Feature']) {\n- this.layer.setZIndex(index);\n- } else {\n- this.map.setLayerZIndex(this.layer,\n- this.map.getLayerIndex(this.layer));\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.Feature\"\n-});\n-/* ======================================================================\n- OpenLayers/Handler/Polygon.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Handler/Path.js\n- * @requires OpenLayers/Geometry/Polygon.js\n- */\n-\n-/**\n- * Class: OpenLayers.Handler.Polygon\n- * Handler to draw a polygon on the map. Polygon is displayed on mouse down,\n- * moves on mouse move, and is finished on mouse up.\n- *\n- * Inherits from:\n- * - \n- * - \n- */\n-OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {\n-\n- /** \n- * APIProperty: holeModifier\n- * {String} Key modifier to trigger hole digitizing. Acceptable values are\n- * \"altKey\", \"shiftKey\", or \"ctrlKey\". If not set, no hole digitizing\n- * will take place. Default is null.\n- */\n- holeModifier: null,\n-\n- /**\n- * Property: drawingHole\n- * {Boolean} Currently drawing an interior ring.\n- */\n- drawingHole: false,\n-\n- /**\n- * Property: polygon\n- * {}\n- */\n- polygon: null,\n-\n- /**\n- * Constructor: OpenLayers.Handler.Polygon\n- * Create a Polygon Handler.\n- *\n- * Parameters:\n- * control - {} The control that owns this handler\n- * callbacks - {Object} An object with a properties whose values are\n- * functions. Various callbacks described below.\n- * options - {Object} An optional object with properties to be set on the\n- * handler\n- *\n- * Named callbacks:\n- * create - Called when a sketch is first created. Callback called with\n- * the creation point geometry and sketch feature.\n- * modify - Called with each move of a vertex with the vertex (point)\n- * geometry and the sketch feature.\n- * point - Called as each point is added. Receives the new point geometry.\n- * done - Called when the point drawing is finished. The callback will\n- * recieve a single argument, the polygon geometry.\n- * cancel - Called when the handler is deactivated while drawing. The\n- * cancel callback will receive a geometry.\n- */\n-\n- /**\n- * Method: createFeature\n- * Add temporary geometries\n- *\n- * Parameters:\n- * pixel - {} The initial pixel location for the new\n- * feature.\n- */\n- createFeature: function(pixel) {\n- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);\n- var geometry = new OpenLayers.Geometry.Point(\n- lonlat.lon, lonlat.lat\n- );\n- this.point = new OpenLayers.Feature.Vector(geometry);\n- this.line = new OpenLayers.Feature.Vector(\n- new OpenLayers.Geometry.LinearRing([this.point.geometry])\n- );\n- this.polygon = new OpenLayers.Feature.Vector(\n- new OpenLayers.Geometry.Polygon([this.line.geometry])\n- );\n- this.callback(\"create\", [this.point.geometry, this.getSketch()]);\n- this.point.geometry.clearBounds();\n- this.layer.addFeatures([this.polygon, this.point], {\n- silent: true\n- });\n- },\n-\n- /**\n- * Method: addPoint\n- * Add point to geometry.\n- *\n- * Parameters:\n- * pixel - {} The pixel location for the new point.\n- */\n- addPoint: function(pixel) {\n- if (!this.drawingHole && this.holeModifier &&\n- this.evt && this.evt[this.holeModifier]) {\n- var geometry = this.point.geometry;\n- var features = this.control.layer.features;\n- var candidate, polygon;\n- // look for intersections, last drawn gets priority\n- for (var i = features.length - 1; i >= 0; --i) {\n- candidate = features[i].geometry;\n- if ((candidate instanceof OpenLayers.Geometry.Polygon ||\n- candidate instanceof OpenLayers.Geometry.MultiPolygon) &&\n- candidate.intersects(geometry)) {\n- polygon = features[i];\n- this.control.layer.removeFeatures([polygon], {\n- silent: true\n- });\n- this.control.layer.events.registerPriority(\n- \"sketchcomplete\", this, this.finalizeInteriorRing\n- );\n- this.control.layer.events.registerPriority(\n- \"sketchmodified\", this, this.enforceTopology\n- );\n- polygon.geometry.addComponent(this.line.geometry);\n- this.polygon = polygon;\n- this.drawingHole = true;\n- break;\n- }\n- }\n- }\n- OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments);\n- },\n-\n- /**\n- * Method: getCurrentPointIndex\n- * \n- * Returns:\n- * {Number} The index of the most recently drawn point.\n- */\n- getCurrentPointIndex: function() {\n- return this.line.geometry.components.length - 2;\n- },\n-\n- /**\n- * Method: enforceTopology\n- * Simple topology enforcement for drawing interior rings. Ensures vertices\n- * of interior rings are contained by exterior ring. Other topology \n- * rules are enforced in to allow drawing of \n- * rings that intersect only during the sketch (e.g. a \"C\" shaped ring\n- * that nearly encloses another ring).\n- */\n- enforceTopology: function(event) {\n- var point = event.vertex;\n- var components = this.line.geometry.components;\n- // ensure that vertices of interior ring are contained by exterior ring\n- if (!this.polygon.geometry.intersects(point)) {\n- var last = components[components.length - 3];\n- point.x = last.x;\n- point.y = last.y;\n- }\n- },\n-\n- /**\n- * Method: finishGeometry\n- * Finish the geometry and send it back to the control.\n- */\n- finishGeometry: function() {\n- var index = this.line.geometry.components.length - 2;\n- this.line.geometry.removeComponent(this.line.geometry.components[index]);\n- this.removePoint();\n- this.finalize();\n- },\n-\n- /**\n- * Method: finalizeInteriorRing\n- * Enforces that new ring has some area and doesn't contain vertices of any\n- * other rings.\n- */\n- finalizeInteriorRing: function() {\n- var ring = this.line.geometry;\n- // ensure that ring has some area\n- var modified = (ring.getArea() !== 0);\n- if (modified) {\n- // ensure that new ring doesn't intersect any other rings\n- var rings = this.polygon.geometry.components;\n- for (var i = rings.length - 2; i >= 0; --i) {\n- if (ring.intersects(rings[i])) {\n- modified = false;\n- break;\n- }\n- }\n- if (modified) {\n- // ensure that new ring doesn't contain any other rings\n- var target;\n- outer: for (var i = rings.length - 2; i > 0; --i) {\n- var points = rings[i].components;\n- for (var j = 0, jj = points.length; j < jj; ++j) {\n- if (ring.containsPoint(points[j])) {\n- modified = false;\n- break outer;\n- }\n- }\n- }\n- }\n- }\n- if (modified) {\n- if (this.polygon.state !== OpenLayers.State.INSERT) {\n- this.polygon.state = OpenLayers.State.UPDATE;\n- }\n- } else {\n- this.polygon.geometry.removeComponent(ring);\n- }\n- this.restoreFeature();\n- return false;\n- },\n-\n- /**\n- * APIMethod: cancel\n- * Finish the geometry and call the \"cancel\" callback.\n- */\n- cancel: function() {\n- if (this.drawingHole) {\n- this.polygon.geometry.removeComponent(this.line.geometry);\n- this.restoreFeature(true);\n- }\n- return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments);\n- },\n-\n- /**\n- * Method: restoreFeature\n- * Move the feature from the sketch layer to the target layer.\n- *\n- * Properties: \n- * cancel - {Boolean} Cancel drawing. If falsey, the \"sketchcomplete\" event\n- * will be fired.\n- */\n- restoreFeature: function(cancel) {\n- this.control.layer.events.unregister(\n- \"sketchcomplete\", this, this.finalizeInteriorRing\n- );\n- this.control.layer.events.unregister(\n- \"sketchmodified\", this, this.enforceTopology\n- );\n- this.layer.removeFeatures([this.polygon], {\n- silent: true\n- });\n- this.control.layer.addFeatures([this.polygon], {\n- silent: true\n- });\n- this.drawingHole = false;\n- if (!cancel) {\n- // Re-trigger \"sketchcomplete\" so other listeners can do their\n- // business. While this is somewhat sloppy (if a listener is \n- // registered with registerPriority - not common - between the start\n- // and end of a single ring drawing - very uncommon - it will be \n- // called twice).\n- // TODO: In 3.0, collapse sketch handlers into geometry specific\n- // drawing controls.\n- this.control.layer.events.triggerEvent(\n- \"sketchcomplete\", {\n- feature: this.polygon\n- }\n- );\n- }\n- },\n-\n- /**\n- * Method: destroyFeature\n- * Destroy temporary geometries\n- *\n- * Parameters:\n- * force - {Boolean} Destroy even if persist is true.\n- */\n- destroyFeature: function(force) {\n- OpenLayers.Handler.Path.prototype.destroyFeature.call(\n- this, force);\n- this.polygon = null;\n- },\n-\n- /**\n- * Method: drawFeature\n- * Render geometries on the temporary layer.\n- */\n- drawFeature: function() {\n- this.layer.drawFeature(this.polygon, this.style);\n- this.layer.drawFeature(this.point, this.style);\n- },\n-\n- /**\n- * Method: getSketch\n- * Return the sketch feature.\n- *\n- * Returns:\n- * {}\n- */\n- getSketch: function() {\n- return this.polygon;\n- },\n-\n- /**\n- * Method: getGeometry\n- * Return the sketch geometry. If is true, this will return\n- * a multi-part geometry.\n- *\n- * Returns:\n- * {}\n- */\n- getGeometry: function() {\n- var geometry = this.polygon && this.polygon.geometry;\n- if (geometry && this.multi) {\n- geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);\n- }\n- return geometry;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.Polygon\"\n-});\n-/* ======================================================================\n- OpenLayers/Handler/RegularPolygon.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Handler/Drag.js\n- */\n-\n-/**\n- * Class: OpenLayers.Handler.RegularPolygon\n- * Handler to draw a regular polygon on the map. Polygon is displayed on mouse\n- * down, moves or is modified on mouse move, and is finished on mouse up.\n- * The handler triggers callbacks for 'done' and 'cancel'. Create a new\n- * instance with the constructor.\n- * \n- * Inherits from:\n- * - \n- */\n-OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, {\n-\n- /**\n- * APIProperty: sides\n- * {Integer} Number of sides for the regular polygon. Needs to be greater\n- * than 2. Defaults to 4.\n- */\n- sides: 4,\n-\n- /**\n- * APIProperty: radius\n- * {Float} Optional radius in map units of the regular polygon. If this is\n- * set to some non-zero value, a polygon with a fixed radius will be\n- * drawn and dragged with mose movements. If this property is not\n- * set, dragging changes the radius of the polygon. Set to null by\n- * default.\n- */\n- radius: null,\n-\n- /**\n- * APIProperty: snapAngle\n- * {Float} If set to a non-zero value, the handler will snap the polygon\n- * rotation to multiples of the snapAngle. Value is an angle measured\n- * in degrees counterclockwise from the positive x-axis. \n- */\n- snapAngle: null,\n-\n- /**\n- * APIProperty: snapToggle\n- * {String} If set, snapToggle is checked on mouse events and will set\n- * the snap mode to the opposite of what it currently is. To disallow\n- * toggling between snap and non-snap mode, set freehandToggle to\n- * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and\n- * 'altKey'. Snap mode is only possible if this.snapAngle is set to a\n- * non-zero value.\n- */\n- snapToggle: 'shiftKey',\n-\n- /**\n- * Property: layerOptions\n- * {Object} Any optional properties to be set on the sketch layer.\n- */\n- layerOptions: null,\n-\n- /**\n- * APIProperty: persist\n- * {Boolean} Leave the feature rendered until clear is called. Default\n- * is false. If set to true, the feature remains rendered until\n- * clear is called, typically by deactivating the handler or starting\n- * another drawing.\n- */\n- persist: false,\n-\n- /**\n- * APIProperty: irregular\n- * {Boolean} Draw an irregular polygon instead of a regular polygon.\n- * Default is false. If true, the initial mouse down will represent\n- * one corner of the polygon bounds and with each mouse movement, the\n- * polygon will be stretched so the opposite corner of its bounds\n- * follows the mouse position. This property takes precedence over\n- * the radius property. If set to true, the radius property will\n- * be ignored.\n- */\n- irregular: false,\n-\n- /**\n- * APIProperty: citeCompliant\n- * {Boolean} If set to true, coordinates of features drawn in a map extent\n- * crossing the date line won't exceed the world bounds. Default is false.\n- */\n- citeCompliant: false,\n-\n- /**\n- * Property: angle\n- * {Float} The angle from the origin (mouse down) to the current mouse\n- * position, in radians. This is measured counterclockwise from the\n- * positive x-axis.\n- */\n- angle: null,\n-\n- /**\n- * Property: fixedRadius\n- * {Boolean} The polygon has a fixed radius. True if a radius is set before\n- * drawing begins. False otherwise.\n- */\n- fixedRadius: false,\n-\n- /**\n- * Property: feature\n- * {} The currently drawn polygon feature\n- */\n- feature: null,\n-\n- /**\n- * Property: layer\n- * {} The temporary drawing layer\n- */\n- layer: null,\n-\n- /**\n- * Property: origin\n- * {} Location of the first mouse down\n- */\n- origin: null,\n-\n- /**\n- * Constructor: OpenLayers.Handler.RegularPolygon\n- * Create a new regular polygon handler.\n- *\n- * Parameters:\n- * control - {} The control that owns this handler\n- * callbacks - {Object} An object with a properties whose values are\n- * functions. Various callbacks described below.\n- * options - {Object} An object with properties to be set on the handler.\n- * If the options.sides property is not specified, the number of sides\n- * will default to 4.\n- *\n- * Named callbacks:\n- * create - Called when a sketch is first created. Callback called with\n- * the creation point geometry and sketch feature.\n- * done - Called when the sketch drawing is finished. The callback will\n- * recieve a single argument, the sketch geometry.\n- * cancel - Called when the handler is deactivated while drawing. The\n- * cancel callback will receive a geometry.\n- */\n- initialize: function(control, callbacks, options) {\n- if (!(options && options.layerOptions && options.layerOptions.styleMap)) {\n- this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});\n- }\n-\n- OpenLayers.Handler.Drag.prototype.initialize.apply(this,\n- [control, callbacks, options]);\n- this.options = (options) ? options : {};\n- },\n-\n- /**\n- * APIMethod: setOptions\n- * \n- * Parameters:\n- * newOptions - {Object} \n- */\n- setOptions: function(newOptions) {\n- OpenLayers.Util.extend(this.options, newOptions);\n- OpenLayers.Util.extend(this, newOptions);\n- },\n-\n- /**\n- * APIMethod: activate\n- * Turn on the handler.\n- *\n- * Returns:\n- * {Boolean} The handler was successfully activated\n- */\n- activate: function() {\n- var activated = false;\n- if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) {\n- // create temporary vector layer for rendering geometry sketch\n- var options = OpenLayers.Util.extend({\n- displayInLayerSwitcher: false,\n- // indicate that the temp vector layer will never be out of range\n- // without this, resolution properties must be specified at the\n- // map-level for this temporary layer to init its resolutions\n- // correctly\n- calculateInRange: OpenLayers.Function.True,\n- wrapDateLine: this.citeCompliant\n- }, this.layerOptions);\n- this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);\n- this.map.addLayer(this.layer);\n- activated = true;\n- }\n- return activated;\n- },\n-\n- /**\n- * APIMethod: deactivate\n- * Turn off the handler.\n- *\n- * Returns:\n- * {Boolean} The handler was successfully deactivated\n- */\n- deactivate: function() {\n- var deactivated = false;\n- if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) {\n- // call the cancel callback if mid-drawing\n- if (this.dragging) {\n- this.cancel();\n- }\n- // If a layer's map property is set to null, it means that that\n- // layer isn't added to the map. Since we ourself added the layer\n- // to the map in activate(), we can assume that if this.layer.map\n- // is null it means that the layer has been destroyed (as a result\n- // of map.destroy() for example.\n- if (this.layer.map != null) {\n- this.layer.destroy(false);\n- if (this.feature) {\n- this.feature.destroy();\n- }\n- }\n- this.layer = null;\n- this.feature = null;\n- deactivated = true;\n- }\n- return deactivated;\n- },\n-\n- /**\n- * Method: down\n- * Start drawing a new feature\n- *\n- * Parameters:\n- * evt - {Event} The drag start event\n- */\n- down: function(evt) {\n- this.fixedRadius = !!(this.radius);\n- var maploc = this.layer.getLonLatFromViewPortPx(evt.xy);\n- this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);\n- // create the new polygon\n- if (!this.fixedRadius || this.irregular) {\n- // smallest radius should not be less one pixel in map units\n- // VML doesn't behave well with smaller\n- this.radius = this.map.getResolution();\n- }\n- if (this.persist) {\n- this.clear();\n- }\n- this.feature = new OpenLayers.Feature.Vector();\n- this.createGeometry();\n- this.callback(\"create\", [this.origin, this.feature]);\n- this.layer.addFeatures([this.feature], {\n- silent: true\n- });\n- this.layer.drawFeature(this.feature, this.style);\n- },\n-\n- /**\n- * Method: move\n- * Respond to drag move events\n- *\n- * Parameters:\n- * evt - {Evt} The move event\n- */\n- move: function(evt) {\n- var maploc = this.layer.getLonLatFromViewPortPx(evt.xy);\n- var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);\n- if (this.irregular) {\n- var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2;\n- this.radius = Math.max(this.map.getResolution() / 2, ry);\n- } else if (this.fixedRadius) {\n- this.origin = point;\n- } else {\n- this.calculateAngle(point, evt);\n- this.radius = Math.max(this.map.getResolution() / 2,\n- point.distanceTo(this.origin));\n- }\n- this.modifyGeometry();\n- if (this.irregular) {\n- var dx = point.x - this.origin.x;\n- var dy = point.y - this.origin.y;\n- var ratio;\n- if (dy == 0) {\n- ratio = dx / (this.radius * Math.sqrt(2));\n- } else {\n- ratio = dx / dy;\n- }\n- this.feature.geometry.resize(1, this.origin, ratio);\n- this.feature.geometry.move(dx / 2, dy / 2);\n- }\n- this.layer.drawFeature(this.feature, this.style);\n- },\n-\n- /**\n- * Method: up\n- * Finish drawing the feature\n- *\n- * Parameters:\n- * evt - {Event} The mouse up event\n- */\n- up: function(evt) {\n- this.finalize();\n- // the mouseup method of superclass doesn't call the\n- // \"done\" callback if there's been no move between\n- // down and up\n- if (this.start == this.last) {\n- this.callback(\"done\", [evt.xy]);\n- }\n- },\n-\n- /**\n- * Method: out\n- * Finish drawing the feature.\n- *\n- * Parameters:\n- * evt - {Event} The mouse out event\n- */\n- out: function(evt) {\n- this.finalize();\n- },\n-\n- /**\n- * Method: createGeometry\n- * Create the new polygon geometry. This is called at the start of the\n- * drag and at any point during the drag if the number of sides\n- * changes.\n- */\n- createGeometry: function() {\n- this.angle = Math.PI * ((1 / this.sides) - (1 / 2));\n- if (this.snapAngle) {\n- this.angle += this.snapAngle * (Math.PI / 180);\n- }\n- this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(\n- this.origin, this.radius, this.sides, this.snapAngle\n- );\n- },\n-\n- /**\n- * Method: modifyGeometry\n- * Modify the polygon geometry in place.\n- */\n- modifyGeometry: function() {\n- var angle, point;\n- var ring = this.feature.geometry.components[0];\n- // if the number of sides ever changes, create a new geometry\n- if (ring.components.length != (this.sides + 1)) {\n- this.createGeometry();\n- ring = this.feature.geometry.components[0];\n- }\n- for (var i = 0; i < this.sides; ++i) {\n- point = ring.components[i];\n- angle = this.angle + (i * 2 * Math.PI / this.sides);\n- point.x = this.origin.x + (this.radius * Math.cos(angle));\n- point.y = this.origin.y + (this.radius * Math.sin(angle));\n- point.clearBounds();\n- }\n- },\n-\n- /**\n- * Method: calculateAngle\n- * Calculate the angle based on settings.\n- *\n- * Parameters:\n- * point - {}\n- * evt - {Event}\n- */\n- calculateAngle: function(point, evt) {\n- var alpha = Math.atan2(point.y - this.origin.y,\n- point.x - this.origin.x);\n- if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) {\n- var snapAngleRad = (Math.PI / 180) * this.snapAngle;\n- this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad;\n- } else {\n- this.angle = alpha;\n- }\n- },\n-\n- /**\n- * APIMethod: cancel\n- * Finish the geometry and call the \"cancel\" callback.\n- */\n- cancel: function() {\n- // the polygon geometry gets cloned in the callback method\n- this.callback(\"cancel\", null);\n- this.finalize();\n- },\n-\n- /**\n- * Method: finalize\n- * Finish the geometry and call the \"done\" callback.\n- */\n- finalize: function() {\n- this.origin = null;\n- this.radius = this.options.radius;\n- },\n-\n- /**\n- * APIMethod: clear\n- * Clear any rendered features on the temporary layer. This is called\n- * when the handler is deactivated, canceled, or done (unless persist\n- * is true).\n- */\n- clear: function() {\n- if (this.layer) {\n- this.layer.renderer.clear();\n- this.layer.destroyFeatures();\n- }\n- },\n-\n- /**\n- * Method: callback\n- * Trigger the control's named callback with the given arguments\n- *\n- * Parameters:\n- * name - {String} The key for the callback that is one of the properties\n- * of the handler's callbacks object.\n- * args - {Array} An array of arguments with which to call the callback\n- * (defined by the control).\n- */\n- callback: function(name, args) {\n- // override the callback method to always send the polygon geometry\n- if (this.callbacks[name]) {\n- this.callbacks[name].apply(this.control,\n- [this.feature.geometry.clone()]);\n- }\n- // since sketch features are added to the temporary layer\n- // they must be cleared here if done or cancel\n- if (!this.persist && (name == \"done\" || name == \"cancel\")) {\n- this.clear();\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.RegularPolygon\"\n-});\n-/* ======================================================================\n- OpenLayers/Handler/Box.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Handler.js\n- * @requires OpenLayers/Handler/Drag.js\n- */\n-\n-/**\n- * Class: OpenLayers.Handler.Box\n- * Handler for dragging a rectangle across the map. Box is displayed \n- * on mouse down, moves on mouse move, and is finished on mouse up.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {\n-\n- /** \n- * Property: dragHandler \n- * {} \n- */\n- dragHandler: null,\n-\n- /**\n- * APIProperty: boxDivClassName\n- * {String} The CSS class to use for drawing the box. Default is\n- * olHandlerBoxZoomBox\n- */\n- boxDivClassName: 'olHandlerBoxZoomBox',\n-\n- /**\n- * Property: boxOffsets\n- * {Object} Caches box offsets from css. This is used by the getBoxOffsets\n- * method.\n- */\n- boxOffsets: null,\n-\n- /**\n- * Constructor: OpenLayers.Handler.Box\n- *\n- * Parameters:\n- * control - {} \n- * callbacks - {Object} An object with a properties whose values are\n- * functions. Various callbacks described below.\n- * options - {Object} \n- *\n- * Named callbacks:\n- * start - Called when the box drag operation starts.\n- * done - Called when the box drag operation is finished.\n- * The callback should expect to receive a single argument, the box \n- * bounds or a pixel. If the box dragging didn't span more than a 5 \n- * pixel distance, a pixel will be returned instead of a bounds object.\n- */\n- initialize: function(control, callbacks, options) {\n- OpenLayers.Handler.prototype.initialize.apply(this, arguments);\n- this.dragHandler = new OpenLayers.Handler.Drag(\n- this, {\n- down: this.startBox,\n- move: this.moveBox,\n- out: this.removeBox,\n- up: this.endBox\n- }, {\n- keyMask: this.keyMask\n- }\n- );\n- },\n-\n- /**\n- * Method: destroy\n- */\n- destroy: function() {\n- OpenLayers.Handler.prototype.destroy.apply(this, arguments);\n- if (this.dragHandler) {\n- this.dragHandler.destroy();\n- this.dragHandler = null;\n- }\n- },\n-\n- /**\n- * Method: setMap\n- */\n- setMap: function(map) {\n- OpenLayers.Handler.prototype.setMap.apply(this, arguments);\n- if (this.dragHandler) {\n- this.dragHandler.setMap(map);\n- }\n- },\n-\n- /**\n- * Method: startBox\n- *\n- * Parameters:\n- * xy - {}\n- */\n- startBox: function(xy) {\n- this.callback(\"start\", []);\n- this.zoomBox = OpenLayers.Util.createDiv('zoomBox', {\n- x: -9999,\n- y: -9999\n- });\n- this.zoomBox.className = this.boxDivClassName;\n- this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE[\"Popup\"] - 1;\n-\n- this.map.viewPortDiv.appendChild(this.zoomBox);\n-\n- OpenLayers.Element.addClass(\n- this.map.viewPortDiv, \"olDrawBox\"\n- );\n- },\n-\n- /**\n- * Method: moveBox\n- */\n- moveBox: function(xy) {\n- var startX = this.dragHandler.start.x;\n- var startY = this.dragHandler.start.y;\n- var deltaX = Math.abs(startX - xy.x);\n- var deltaY = Math.abs(startY - xy.y);\n-\n- var offset = this.getBoxOffsets();\n- this.zoomBox.style.width = (deltaX + offset.width + 1) + \"px\";\n- this.zoomBox.style.height = (deltaY + offset.height + 1) + \"px\";\n- this.zoomBox.style.left = (xy.x < startX ?\n- startX - deltaX - offset.left : startX - offset.left) + \"px\";\n- this.zoomBox.style.top = (xy.y < startY ?\n- startY - deltaY - offset.top : startY - offset.top) + \"px\";\n- },\n-\n- /**\n- * Method: endBox\n- */\n- endBox: function(end) {\n- var result;\n- if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||\n- Math.abs(this.dragHandler.start.y - end.y) > 5) {\n- var start = this.dragHandler.start;\n- var top = Math.min(start.y, end.y);\n- var bottom = Math.max(start.y, end.y);\n- var left = Math.min(start.x, end.x);\n- var right = Math.max(start.x, end.x);\n- result = new OpenLayers.Bounds(left, bottom, right, top);\n- } else {\n- result = this.dragHandler.start.clone(); // i.e. OL.Pixel\n- }\n- this.removeBox();\n-\n- this.callback(\"done\", [result]);\n- },\n-\n- /**\n- * Method: removeBox\n- * Remove the zoombox from the screen and nullify our reference to it.\n- */\n- removeBox: function() {\n- this.map.viewPortDiv.removeChild(this.zoomBox);\n- this.zoomBox = null;\n- this.boxOffsets = null;\n- OpenLayers.Element.removeClass(\n- this.map.viewPortDiv, \"olDrawBox\"\n- );\n-\n- },\n-\n- /**\n- * Method: activate\n- */\n- activate: function() {\n- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n- this.dragHandler.activate();\n- return true;\n- } else {\n- return false;\n- }\n- },\n-\n- /**\n- * Method: deactivate\n- */\n- deactivate: function() {\n- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- if (this.dragHandler.deactivate()) {\n- if (this.zoomBox) {\n- this.removeBox();\n- }\n- }\n- return true;\n- } else {\n- return false;\n- }\n- },\n-\n- /**\n- * Method: getBoxOffsets\n- * Determines border offsets for a box, according to the box model.\n- * \n- * Returns:\n- * {Object} an object with the following offsets:\n- * - left\n- * - right\n- * - top\n- * - bottom\n- * - width\n- * - height\n- */\n- getBoxOffsets: function() {\n- if (!this.boxOffsets) {\n- // Determine the box model. If the testDiv's clientWidth is 3, then\n- // the borders are outside and we are dealing with the w3c box\n- // model. Otherwise, the browser uses the traditional box model and\n- // the borders are inside the box bounds, leaving us with a\n- // clientWidth of 1.\n- var testDiv = document.createElement(\"div\");\n- //testDiv.style.visibility = \"hidden\";\n- testDiv.style.position = \"absolute\";\n- testDiv.style.border = \"1px solid black\";\n- testDiv.style.width = \"3px\";\n- document.body.appendChild(testDiv);\n- var w3cBoxModel = testDiv.clientWidth == 3;\n- document.body.removeChild(testDiv);\n-\n- var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox,\n- \"border-left-width\"));\n- var right = parseInt(OpenLayers.Element.getStyle(\n- this.zoomBox, \"border-right-width\"));\n- var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox,\n- \"border-top-width\"));\n- var bottom = parseInt(OpenLayers.Element.getStyle(\n- this.zoomBox, \"border-bottom-width\"));\n- this.boxOffsets = {\n- left: left,\n- right: right,\n- top: top,\n- bottom: bottom,\n- width: w3cBoxModel === false ? left + right : 0,\n- height: w3cBoxModel === false ? top + bottom : 0\n- };\n- }\n- return this.boxOffsets;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.Box\"\n-});\n-/* ======================================================================\n- OpenLayers/Handler/Hover.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Handler.js\n- */\n-\n-/**\n- * Class: OpenLayers.Handler.Hover\n- * The hover handler is to be used to emulate mouseovers on objects\n- * on the map that aren't DOM elements. For example one can use\n- * this handler to send WMS/GetFeatureInfo requests as the user\n- * moves the mouve over the map.\n- * \n- * Inherits from:\n- * - \n- */\n-OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {\n-\n- /**\n- * APIProperty: delay\n- * {Integer} - Number of milliseconds between mousemoves before\n- * the event is considered a hover. Default is 500.\n- */\n- delay: 500,\n-\n- /**\n- * APIProperty: pixelTolerance\n- * {Integer} - Maximum number of pixels between mousemoves for\n- * an event to be considered a hover. Default is null.\n- */\n- pixelTolerance: null,\n-\n- /**\n- * APIProperty: stopMove\n- * {Boolean} - Stop other listeners from being notified on mousemoves.\n- * Default is false.\n- */\n- stopMove: false,\n-\n- /**\n- * Property: px\n- * {} - The location of the last mousemove, expressed\n- * in pixels.\n- */\n- px: null,\n-\n- /**\n- * Property: timerId\n- * {Number} - The id of the timer.\n- */\n- timerId: null,\n-\n- /**\n- * Constructor: OpenLayers.Handler.Hover\n- * Construct a hover handler.\n- *\n- * Parameters:\n- * control - {} The control that initialized this\n- * handler. The control is assumed to have a valid map property; that\n- * map is used in the handler's own setMap method.\n- * callbacks - {Object} An object with keys corresponding to callbacks\n- * that will be called by the handler. The callbacks should\n- * expect to receive a single argument, the event. Callbacks for\n- * 'move', the mouse is moving, and 'pause', the mouse is pausing,\n- * are supported.\n- * options - {Object} An optional object whose properties will be set on\n- * the handler.\n- */\n-\n- /**\n- * Method: mousemove\n- * Called when the mouse moves on the map.\n- *\n- * Parameters:\n- * evt - {}\n- *\n- * Returns:\n- * {Boolean} Continue propagating this event.\n- */\n- mousemove: function(evt) {\n- if (this.passesTolerance(evt.xy)) {\n- this.clearTimer();\n- this.callback('move', [evt]);\n- this.px = evt.xy;\n- // clone the evt so original properties can be accessed even\n- // if the browser deletes them during the delay\n- evt = OpenLayers.Util.extend({}, evt);\n- this.timerId = window.setTimeout(\n- OpenLayers.Function.bind(this.delayedCall, this, evt),\n- this.delay\n- );\n- }\n- return !this.stopMove;\n- },\n-\n- /**\n- * Method: mouseout\n- * Called when the mouse goes out of the map.\n- *\n- * Parameters:\n- * evt - {}\n- *\n- * Returns:\n- * {Boolean} Continue propagating this event.\n- */\n- mouseout: function(evt) {\n- if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {\n- this.clearTimer();\n- this.callback('move', [evt]);\n- }\n- return true;\n- },\n-\n- /**\n- * Method: passesTolerance\n- * Determine whether the mouse move is within the optional pixel tolerance.\n- *\n- * Parameters:\n- * px - {}\n- *\n- * Returns:\n- * {Boolean} The mouse move is within the pixel tolerance.\n- */\n- passesTolerance: function(px) {\n- var passes = true;\n- if (this.pixelTolerance && this.px) {\n- var dpx = Math.sqrt(\n- Math.pow(this.px.x - px.x, 2) +\n- Math.pow(this.px.y - px.y, 2)\n- );\n- if (dpx < this.pixelTolerance) {\n- passes = false;\n- }\n- }\n- return passes;\n- },\n-\n- /**\n- * Method: clearTimer\n- * Clear the timer and set to null.\n- */\n- clearTimer: function() {\n- if (this.timerId != null) {\n- window.clearTimeout(this.timerId);\n- this.timerId = null;\n- }\n- },\n-\n- /**\n- * Method: delayedCall\n- * Triggers pause callback.\n- *\n- * Parameters:\n- * evt - {}\n- */\n- delayedCall: function(evt) {\n- this.callback('pause', [evt]);\n- },\n-\n- /**\n- * APIMethod: deactivate\n- * Deactivate the handler.\n- *\n- * Returns:\n- * {Boolean} The handler was successfully deactivated.\n- */\n- deactivate: function() {\n- var deactivated = false;\n- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n- this.clearTimer();\n- deactivated = true;\n- }\n- return deactivated;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Handler.Hover\"\n-});\n-/* ======================================================================\n- OpenLayers/Layer/Vector.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Layer.js\n- * @requires OpenLayers/Renderer.js\n- * @requires OpenLayers/StyleMap.js\n- * @requires OpenLayers/Feature/Vector.js\n- * @requires OpenLayers/Console.js\n- * @requires OpenLayers/Lang.js\n- */\n-\n-/**\n- * Class: OpenLayers.Layer.Vector\n- * Instances of OpenLayers.Layer.Vector are used to render vector data from\n- * a variety of sources. Create a new vector layer with the\n- * constructor.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {\n-\n- /**\n- * APIProperty: events\n- * {}\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * layer.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to layer.events.object.\n- * element - {DOMElement} A reference to layer.events.element.\n- *\n- * Supported map event types (in addition to those from ):\n- * beforefeatureadded - Triggered before a feature is added. Listeners\n- * will receive an object with a *feature* property referencing the\n- * feature to be added. To stop the feature from being added, a\n- * listener should return false.\n- * beforefeaturesadded - Triggered before an array of features is added.\n- * Listeners will receive an object with a *features* property\n- * referencing the feature to be added. To stop the features from\n- * being added, a listener should return false.\n- * featureadded - Triggered after a feature is added. The event\n- * object passed to listeners will have a *feature* property with a\n- * reference to the added feature.\n- * featuresadded - Triggered after features are added. The event\n- * object passed to listeners will have a *features* property with a\n- * reference to an array of added features.\n- * beforefeatureremoved - Triggered before a feature is removed. Listeners\n- * will receive an object with a *feature* property referencing the\n- * feature to be removed.\n- * beforefeaturesremoved - Triggered before multiple features are removed. \n- * Listeners will receive an object with a *features* property\n- * referencing the features to be removed.\n- * featureremoved - Triggerd after a feature is removed. The event\n- * object passed to listeners will have a *feature* property with a\n- * reference to the removed feature.\n- * featuresremoved - Triggered after features are removed. The event\n- * object passed to listeners will have a *features* property with a\n- * reference to an array of removed features.\n- * beforefeatureselected - Triggered before a feature is selected. Listeners\n- * will receive an object with a *feature* property referencing the\n- * feature to be selected. To stop the feature from being selectd, a\n- * listener should return false.\n- * featureselected - Triggered after a feature is selected. Listeners\n- * will receive an object with a *feature* property referencing the\n- * selected feature.\n- * featureunselected - Triggered after a feature is unselected.\n- * Listeners will receive an object with a *feature* property\n- * referencing the unselected feature.\n- * beforefeaturemodified - Triggered when a feature is selected to \n- * be modified. Listeners will receive an object with a *feature* \n- * property referencing the selected feature.\n- * featuremodified - Triggered when a feature has been modified.\n- * Listeners will receive an object with a *feature* property referencing \n- * the modified feature.\n- * afterfeaturemodified - Triggered when a feature is finished being modified.\n- * Listeners will receive an object with a *feature* property referencing \n- * the modified feature.\n- * vertexmodified - Triggered when a vertex within any feature geometry\n- * has been modified. Listeners will receive an object with a\n- * *feature* property referencing the modified feature, a *vertex*\n- * property referencing the vertex modified (always a point geometry),\n- * and a *pixel* property referencing the pixel location of the\n- * modification.\n- * vertexremoved - Triggered when a vertex within any feature geometry\n- * has been deleted. Listeners will receive an object with a\n- * *feature* property referencing the modified feature, a *vertex*\n- * property referencing the vertex modified (always a point geometry),\n- * and a *pixel* property referencing the pixel location of the\n- * removal.\n- * sketchstarted - Triggered when a feature sketch bound for this layer\n- * is started. Listeners will receive an object with a *feature*\n- * property referencing the new sketch feature and a *vertex* property\n- * referencing the creation point.\n- * sketchmodified - Triggered when a feature sketch bound for this layer\n- * is modified. Listeners will receive an object with a *vertex*\n- * property referencing the modified vertex and a *feature* property\n- * referencing the sketch feature.\n- * sketchcomplete - Triggered when a feature sketch bound for this layer\n- * is complete. Listeners will receive an object with a *feature*\n- * property referencing the sketch feature. By returning false, a\n- * listener can stop the sketch feature from being added to the layer.\n- * refresh - Triggered when something wants a strategy to ask the protocol\n- * for a new set of features.\n- */\n-\n- /**\n- * APIProperty: isBaseLayer\n- * {Boolean} The layer is a base layer. Default is false. Set this property\n- * in the layer options.\n- */\n- isBaseLayer: false,\n-\n- /** \n- * APIProperty: isFixed\n- * {Boolean} Whether the layer remains in one place while dragging the\n- * map. Note that setting this to true will move the layer to the bottom\n- * of the layer stack.\n- */\n- isFixed: false,\n-\n- /** \n- * APIProperty: features\n- * {Array()} \n- */\n- features: null,\n-\n- /** \n- * Property: filter\n- * {} The filter set in this layer,\n- * a strategy launching read requests can combined\n- * this filter with its own filter.\n- */\n- filter: null,\n-\n- /** \n- * Property: selectedFeatures\n- * {Array()} \n- */\n- selectedFeatures: null,\n-\n- /**\n- * Property: unrenderedFeatures\n- * {Object} hash of features, keyed by feature.id, that the renderer\n- * failed to draw\n- */\n- unrenderedFeatures: null,\n-\n- /**\n- * APIProperty: reportError\n- * {Boolean} report friendly error message when loading of renderer\n- * fails.\n- */\n- reportError: true,\n-\n- /** \n- * APIProperty: style\n- * {Object} Default style for the layer\n- */\n- style: null,\n-\n- /**\n- * Property: styleMap\n- * {}\n- */\n- styleMap: null,\n-\n- /**\n- * Property: strategies\n- * {Array(})} Optional list of strategies for the layer.\n- */\n- strategies: null,\n-\n- /**\n- * Property: protocol\n- * {} Optional protocol for the layer.\n- */\n- protocol: null,\n-\n- /**\n- * Property: renderers\n- * {Array(String)} List of supported Renderer classes. Add to this list to\n- * add support for additional renderers. This list is ordered:\n- * the first renderer which returns true for the 'supported()'\n- * method will be used, if not defined in the 'renderer' option.\n- */\n- renderers: ['SVG', 'VML', 'Canvas'],\n-\n- /** \n- * Property: renderer\n- * {}\n- */\n- renderer: null,\n-\n- /**\n- * APIProperty: rendererOptions\n- * {Object} Options for the renderer. See {} for\n- * supported options.\n- */\n- rendererOptions: null,\n-\n- /** \n- * APIProperty: geometryType\n- * {String} geometryType allows you to limit the types of geometries this\n- * layer supports. This should be set to something like\n- * \"OpenLayers.Geometry.Point\" to limit types.\n- */\n- geometryType: null,\n+ /** \n+ * APIProperty: geometryType\n+ * {String} geometryType allows you to limit the types of geometries this\n+ * layer supports. This should be set to something like\n+ * \"OpenLayers.Geometry.Point\" to limit types.\n+ */\n+ geometryType: null,\n \n /** \n * Property: drawn\n * {Boolean} Whether the Vector Layer features have been drawn yet.\n */\n drawn: false,\n \n@@ -38432,8932 +40349,8680 @@\n }\n return maxExtent;\n },\n \n CLASS_NAME: \"OpenLayers.Layer.Vector\"\n });\n /* ======================================================================\n- OpenLayers/Layer/PointTrack.js\n+ OpenLayers/Control/Split.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Handler/Path.js\n * @requires OpenLayers/Layer/Vector.js\n */\n \n /**\n- * Class: OpenLayers.Layer.PointTrack\n- * Vector layer to display ordered point features as a line, creating one\n- * LineString feature for each pair of two points.\n+ * Class: OpenLayers.Control.Split\n+ * Acts as a split feature agent while editing vector features.\n *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, {\n+OpenLayers.Control.Split = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /** \n+ * APIProperty: events\n+ * {} Events instance for listeners and triggering\n+ * control specific events.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * control.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types (in addition to those from ):\n+ * beforesplit - Triggered before a split occurs. Listeners receive an\n+ * event object with *source* and *target* properties.\n+ * split - Triggered when a split occurs. Listeners receive an event with\n+ * an *original* property and a *features* property. The original\n+ * is a reference to the target feature that the sketch or modified\n+ * feature intersects. The features property is a list of all features\n+ * that result from this single split. This event is triggered before\n+ * the resulting features are added to the layer (while the layer still\n+ * has a reference to the original).\n+ * aftersplit - Triggered after all splits resulting from a single sketch\n+ * or feature modification have occurred. The original features\n+ * have been destroyed and features that result from the split\n+ * have already been added to the layer. Listeners receive an event\n+ * with a *source* and *features* property. The source references the\n+ * sketch or modified feature used as a splitter. The features\n+ * property is a list of all resulting features.\n+ */\n \n /**\n- * APIProperty: dataFrom\n- * {} or\n- * {} optional. If the lines\n- * should get the data/attributes from one of the two points it is\n- * composed of, which one should it be?\n+ * APIProperty: layer\n+ * {} The target layer with features to be split.\n+ * Set at construction or after construction with .\n */\n- dataFrom: null,\n+ layer: null,\n \n /**\n- * APIProperty: styleFrom\n- * {} or\n- * {} optional. If the lines\n- * should get the style from one of the two points it is composed of,\n- * which one should it be?\n+ * Property: source\n+ * {} Optional source layer. Any newly created\n+ * or modified features from this layer will be used to split features\n+ * on the target layer. If not provided, a temporary sketch layer will\n+ * be created.\n */\n- styleFrom: null,\n+ source: null,\n \n /**\n- * Constructor: OpenLayers.PointTrack\n- * Constructor for a new OpenLayers.PointTrack instance.\n+ * Property: sourceOptions\n+ * {Options} If a temporary sketch layer is created, these layer options\n+ * will be applied.\n+ */\n+ sourceOptions: null,\n+\n+ /**\n+ * APIProperty: tolerance\n+ * {Number} Distance between the calculated intersection and a vertex on\n+ * the source geometry below which the existing vertex will be used\n+ * for the split. Default is null.\n+ */\n+ tolerance: null,\n+\n+ /**\n+ * APIProperty: edge\n+ * {Boolean} Allow splits given intersection of edges only. Default is\n+ * true. If false, a vertex on the source must be within the\n+ * distance of the calculated intersection for a split\n+ * to occur.\n+ */\n+ edge: true,\n+\n+ /**\n+ * APIProperty: deferDelete\n+ * {Boolean} Instead of removing features from the layer, set feature\n+ * states of split features to DELETE. This assumes a save strategy\n+ * or other component is in charge of removing features from the\n+ * layer. Default is false. If false, split features will be\n+ * immediately deleted from the layer.\n+ */\n+ deferDelete: false,\n+\n+ /**\n+ * APIProperty: mutual\n+ * {Boolean} If source and target layers are the same, split source\n+ * features and target features where they intersect. Default is\n+ * true. If false, only target features will be split.\n+ */\n+ mutual: true,\n+\n+ /**\n+ * APIProperty: targetFilter\n+ * {} Optional filter that will be evaluated\n+ * to determine if a feature from the target layer is eligible for\n+ * splitting.\n+ */\n+ targetFilter: null,\n+\n+ /**\n+ * APIProperty: sourceFilter\n+ * {} Optional filter that will be evaluated\n+ * to determine if a feature from the source layer is eligible for\n+ * splitting.\n+ */\n+ sourceFilter: null,\n+\n+ /**\n+ * Property: handler\n+ * {} The temporary sketch handler created if\n+ * no source layer is provided.\n+ */\n+ handler: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Control.Split\n+ * Creates a new split control. A control is constructed with a target\n+ * layer and an optional source layer. While the control is active,\n+ * creating new features or modifying existing features on the source\n+ * layer will result in splitting any eligible features on the target\n+ * layer. If no source layer is provided, a temporary sketch layer will\n+ * be created to create lines for splitting features on the target.\n *\n * Parameters:\n- * name - {String} name of the layer\n- * options - {Object} Optional object with properties to tag onto the\n- * instance.\n+ * options - {Object} An object containing all configuration properties for\n+ * the control.\n+ *\n+ * Valid options:\n+ * layer - {} The target layer. Features from this\n+ * layer will be split by new or modified features on the source layer\n+ * or temporary sketch layer.\n+ * source - {} Optional source layer. If provided\n+ * newly created features or modified features will be used to split\n+ * features on the target layer. If not provided, a temporary sketch\n+ * layer will be created for drawing lines.\n+ * tolerance - {Number} Optional value for the distance between a source\n+ * vertex and the calculated intersection below which the split will\n+ * occur at the vertex.\n+ * edge - {Boolean} Allow splits given intersection of edges only. Default\n+ * is true. If false, a vertex on the source must be within the\n+ * distance of the calculated intersection for a split\n+ * to occur.\n+ * mutual - {Boolean} If source and target are the same, split source\n+ * features and target features where they intersect. Default is\n+ * true. If false, only target features will be split.\n+ * targetFilter - {} Optional filter that will be evaluated\n+ * to determine if a feature from the target layer is eligible for\n+ * splitting.\n+ * sourceFilter - {} Optional filter that will be evaluated\n+ * to determine if a feature from the target layer is eligible for\n+ * splitting.\n */\n+ initialize: function(options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ this.options = options || {}; // TODO: this could be done by the super\n+\n+ // set the source layer if provided\n+ if (this.options.source) {\n+ this.setSource(this.options.source);\n+ }\n+ },\n \n /**\n- * APIMethod: addNodes\n- * Adds point features that will be used to create lines from, using point\n- * pairs. The first point of a pair will be the source node, the second\n- * will be the target node.\n- * \n+ * APIMethod: setSource\n+ * Set the source layer for edits layer.\n+ *\n * Parameters:\n- * pointFeatures - {Array()}\n- * options - {Object}\n- * \n- * Supported options:\n- * silent - {Boolean} true to suppress (before)feature(s)added events\n+ * layer - {} The new source layer layer. If\n+ * null, a temporary sketch layer will be created.\n */\n- addNodes: function(pointFeatures, options) {\n- if (pointFeatures.length < 2) {\n- throw new Error(\"At least two point features have to be added to \" +\n- \"create a line from\");\n+ setSource: function(layer) {\n+ if (this.active) {\n+ this.deactivate();\n+ if (this.handler) {\n+ this.handler.destroy();\n+ delete this.handler;\n+ }\n+ this.source = layer;\n+ this.activate();\n+ } else {\n+ this.source = layer;\n }\n+ },\n \n- var lines = new Array(pointFeatures.length - 1);\n-\n- var pointFeature, startPoint, endPoint;\n- for (var i = 0, len = pointFeatures.length; i < len; i++) {\n- pointFeature = pointFeatures[i];\n- endPoint = pointFeature.geometry;\n+ /**\n+ * APIMethod: activate\n+ * Activate the control. Activating the control registers listeners for\n+ * editing related events so that during feature creation and\n+ * modification, features in the target will be considered for\n+ * splitting.\n+ */\n+ activate: function() {\n+ var activated = OpenLayers.Control.prototype.activate.call(this);\n+ if (activated) {\n+ if (!this.source) {\n+ if (!this.handler) {\n+ this.handler = new OpenLayers.Handler.Path(this, {\n+ done: function(geometry) {\n+ this.onSketchComplete({\n+ feature: new OpenLayers.Feature.Vector(geometry)\n+ });\n+ }\n+ }, {\n+ layerOptions: this.sourceOptions\n+ });\n+ }\n+ this.handler.activate();\n+ } else if (this.source.events) {\n+ this.source.events.on({\n+ sketchcomplete: this.onSketchComplete,\n+ afterfeaturemodified: this.afterFeatureModified,\n+ scope: this\n+ });\n+ }\n+ }\n+ return activated;\n+ },\n \n- if (!endPoint) {\n- var lonlat = pointFeature.lonlat;\n- endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);\n- } else if (endPoint.CLASS_NAME != \"OpenLayers.Geometry.Point\") {\n- throw new TypeError(\"Only features with point geometries are supported.\");\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the control. Deactivating the control unregisters listeners\n+ * so feature editing may proceed without engaging the split agent.\n+ */\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Control.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ if (this.source && this.source.events) {\n+ this.source.events.un({\n+ sketchcomplete: this.onSketchComplete,\n+ afterfeaturemodified: this.afterFeatureModified,\n+ scope: this\n+ });\n }\n+ }\n+ return deactivated;\n+ },\n \n- if (i > 0) {\n- var attributes = (this.dataFrom != null) ?\n- (pointFeatures[i + this.dataFrom].data ||\n- pointFeatures[i + this.dataFrom].attributes) :\n- null;\n- var style = (this.styleFrom != null) ?\n- (pointFeatures[i + this.styleFrom].style) :\n- null;\n- var line = new OpenLayers.Geometry.LineString([startPoint,\n- endPoint\n- ]);\n+ /**\n+ * Method: onSketchComplete\n+ * Registered as a listener for the sketchcomplete event on the editable\n+ * layer.\n+ *\n+ * Parameters:\n+ * event - {Object} The sketch complete event.\n+ *\n+ * Returns:\n+ * {Boolean} Stop the sketch from being added to the layer (it has been\n+ * split).\n+ */\n+ onSketchComplete: function(event) {\n+ this.feature = null;\n+ return !this.considerSplit(event.feature);\n+ },\n \n- lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes,\n- style);\n+ /**\n+ * Method: afterFeatureModified\n+ * Registered as a listener for the afterfeaturemodified event on the\n+ * editable layer.\n+ *\n+ * Parameters:\n+ * event - {Object} The after feature modified event.\n+ */\n+ afterFeatureModified: function(event) {\n+ if (event.modified) {\n+ var feature = event.feature;\n+ if (typeof feature.geometry.split === \"function\") {\n+ this.feature = event.feature;\n+ this.considerSplit(event.feature);\n }\n+ }\n+ },\n \n- startPoint = endPoint;\n+ /**\n+ * Method: removeByGeometry\n+ * Remove a feature from a list based on the given geometry.\n+ *\n+ * Parameters:\n+ * features - {Array()} A list of features.\n+ * geometry - {} A geometry.\n+ */\n+ removeByGeometry: function(features, geometry) {\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ if (features[i].geometry === geometry) {\n+ features.splice(i, 1);\n+ break;\n+ }\n }\n+ },\n \n- this.addFeatures(lines, options);\n+ /**\n+ * Method: isEligible\n+ * Test if a target feature is eligible for splitting.\n+ *\n+ * Parameters:\n+ * target - {} The target feature.\n+ *\n+ * Returns:\n+ * {Boolean} The target is eligible for splitting.\n+ */\n+ isEligible: function(target) {\n+ if (!target.geometry) {\n+ return false;\n+ } else {\n+ return (\n+ target.state !== OpenLayers.State.DELETE\n+ ) && (\n+ typeof target.geometry.split === \"function\"\n+ ) && (\n+ this.feature !== target\n+ ) && (\n+ !this.targetFilter ||\n+ this.targetFilter.evaluate(target.attributes)\n+ );\n+ }\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.PointTrack\"\n-});\n+ /**\n+ * Method: considerSplit\n+ * Decide whether or not to split target features with the supplied\n+ * feature. If is true, both the source and target features\n+ * will be split if eligible.\n+ *\n+ * Parameters:\n+ * feature - {} The newly created or modified\n+ * feature.\n+ *\n+ * Returns:\n+ * {Boolean} The supplied feature was split (and destroyed).\n+ */\n+ considerSplit: function(feature) {\n+ var sourceSplit = false;\n+ var targetSplit = false;\n+ if (!this.sourceFilter ||\n+ this.sourceFilter.evaluate(feature.attributes)) {\n+ var features = this.layer && this.layer.features || [];\n+ var target, results, proceed;\n+ var additions = [],\n+ removals = [];\n+ var mutual = (this.layer === this.source) && this.mutual;\n+ var options = {\n+ edge: this.edge,\n+ tolerance: this.tolerance,\n+ mutual: mutual\n+ };\n+ var sourceParts = [feature.geometry];\n+ var targetFeature, targetParts;\n+ var source, parts;\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ targetFeature = features[i];\n+ if (this.isEligible(targetFeature)) {\n+ targetParts = [targetFeature.geometry];\n+ // work through source geoms - this array may change\n+ for (var j = 0; j < sourceParts.length; ++j) {\n+ source = sourceParts[j];\n+ // work through target parts - this array may change\n+ for (var k = 0; k < targetParts.length; ++k) {\n+ target = targetParts[k];\n+ if (source.getBounds().intersectsBounds(target.getBounds())) {\n+ results = source.split(target, options);\n+ if (results) {\n+ proceed = this.events.triggerEvent(\n+ \"beforesplit\", {\n+ source: feature,\n+ target: targetFeature\n+ }\n+ );\n+ if (proceed !== false) {\n+ if (mutual) {\n+ parts = results[0];\n+ // handle parts that result from source splitting\n+ if (parts.length > 1) {\n+ // splice in new source parts\n+ parts.unshift(j, 1); // add args for splice below\n+ Array.prototype.splice.apply(sourceParts, parts);\n+ j += parts.length - 3;\n+ }\n+ results = results[1];\n+ }\n+ // handle parts that result from target splitting\n+ if (results.length > 1) {\n+ // splice in new target parts\n+ results.unshift(k, 1); // add args for splice below\n+ Array.prototype.splice.apply(targetParts, results);\n+ k += results.length - 3;\n+ }\n+ }\n+ }\n+ }\n+ }\n+ }\n+ if (targetParts && targetParts.length > 1) {\n+ this.geomsToFeatures(targetFeature, targetParts);\n+ this.events.triggerEvent(\"split\", {\n+ original: targetFeature,\n+ features: targetParts\n+ });\n+ Array.prototype.push.apply(additions, targetParts);\n+ removals.push(targetFeature);\n+ targetSplit = true;\n+ }\n+ }\n+ }\n+ if (sourceParts && sourceParts.length > 1) {\n+ this.geomsToFeatures(feature, sourceParts);\n+ this.events.triggerEvent(\"split\", {\n+ original: feature,\n+ features: sourceParts\n+ });\n+ Array.prototype.push.apply(additions, sourceParts);\n+ removals.push(feature);\n+ sourceSplit = true;\n+ }\n+ if (sourceSplit || targetSplit) {\n+ // remove and add feature events are suppressed\n+ // listen for split event on this control instead\n+ if (this.deferDelete) {\n+ // Set state instead of removing. Take care to avoid\n+ // setting delete for features that have not yet been\n+ // inserted - those should be destroyed immediately.\n+ var feat, destroys = [];\n+ for (var i = 0, len = removals.length; i < len; ++i) {\n+ feat = removals[i];\n+ if (feat.state === OpenLayers.State.INSERT) {\n+ destroys.push(feat);\n+ } else {\n+ feat.state = OpenLayers.State.DELETE;\n+ this.layer.drawFeature(feat);\n+ }\n+ }\n+ this.layer.destroyFeatures(destroys, {\n+ silent: true\n+ });\n+ for (var i = 0, len = additions.length; i < len; ++i) {\n+ additions[i].state = OpenLayers.State.INSERT;\n+ }\n+ } else {\n+ this.layer.destroyFeatures(removals, {\n+ silent: true\n+ });\n+ }\n+ this.layer.addFeatures(additions, {\n+ silent: true\n+ });\n+ this.events.triggerEvent(\"aftersplit\", {\n+ source: feature,\n+ features: additions\n+ });\n+ }\n+ }\n+ return sourceSplit;\n+ },\n \n-/**\n- * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE\n- * {Number} value for and\n- * \n- */\n-OpenLayers.Layer.PointTrack.SOURCE_NODE = -1;\n+ /**\n+ * Method: geomsToFeatures\n+ * Create new features given a template feature and a list of geometries.\n+ * The list of geometries is modified in place. The result will be\n+ * a list of new features.\n+ *\n+ * Parameters:\n+ * feature - {} The feature to be cloned.\n+ * geoms - {Array()} List of goemetries. This will\n+ * become a list of new features.\n+ */\n+ geomsToFeatures: function(feature, geoms) {\n+ var clone = feature.clone();\n+ delete clone.geometry;\n+ var newFeature;\n+ for (var i = 0, len = geoms.length; i < len; ++i) {\n+ // turn results list from geoms to features\n+ newFeature = clone.clone();\n+ newFeature.geometry = geoms[i];\n+ newFeature.state = OpenLayers.State.INSERT;\n+ geoms[i] = newFeature;\n+ }\n+ },\n \n-/**\n- * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE\n- * {Number} value for and\n- * \n- */\n-OpenLayers.Layer.PointTrack.TARGET_NODE = 0;\n+ /**\n+ * Method: destroy\n+ * Clean up the control.\n+ */\n+ destroy: function() {\n+ if (this.active) {\n+ this.deactivate(); // TODO: this should be handled by the super\n+ }\n+ OpenLayers.Control.prototype.destroy.call(this);\n+ },\n \n-/**\n- * Constant: OpenLayers.Layer.PointTrack.dataFrom\n- * {Object} with the following keys - *deprecated*\n- * - SOURCE_NODE: take data/attributes from the source node of the line\n- * - TARGET_NODE: take data/attributes from the target node of the line\n- */\n-OpenLayers.Layer.PointTrack.dataFrom = {\n- 'SOURCE_NODE': -1,\n- 'TARGET_NODE': 0\n-};\n+ CLASS_NAME: \"OpenLayers.Control.Split\"\n+});\n /* ======================================================================\n- OpenLayers/Layer/EventPane.js\n+ OpenLayers/Handler/Pinch.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n- * @requires OpenLayers/Layer.js\n- * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Handler.js\n */\n \n /**\n- * Class: OpenLayers.Layer.EventPane\n- * Base class for 3rd party layers, providing a DOM element which isolates\n- * the 3rd-party layer from mouse events.\n- * Only used by Google layers.\n+ * Class: OpenLayers.Handler.Pinch\n+ * The pinch handler is used to deal with sequences of browser events related\n+ * to pinch gestures. The handler is used by controls that want to know\n+ * when a pinch sequence begins, when a pinch is happening, and when it has\n+ * finished.\n *\n- * Automatically instantiated by the Google constructor, and not usually instantiated directly.\n+ * Controls that use the pinch handler typically construct it with callbacks\n+ * for 'start', 'move', and 'done'. Callbacks for these keys are\n+ * called when the pinch begins, with each change, and when the pinch is\n+ * done.\n+ *\n+ * Create a new pinch handler with the constructor.\n *\n- * Create a new event pane layer with the\n- * constructor.\n- * \n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {\n+OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, {\n \n /**\n- * APIProperty: smoothDragPan\n- * {Boolean} smoothDragPan determines whether non-public/internal API\n- * methods are used for better performance while dragging EventPane \n- * layers. When not in sphericalMercator mode, the smoother dragging \n- * doesn't actually move north/south directly with the number of \n- * pixels moved, resulting in a slight offset when you drag your mouse \n- * north south with this option on. If this visual disparity bothers \n- * you, you should turn this option off, or use spherical mercator. \n- * Default is on.\n+ * Property: started\n+ * {Boolean} When a touchstart event is received, we want to record it,\n+ * but not set 'pinching' until the touchmove get started after\n+ * starting.\n */\n- smoothDragPan: true,\n+ started: false,\n \n /**\n- * Property: isBaseLayer\n- * {Boolean} EventPaned layers are always base layers, by necessity.\n+ * Property: stopDown\n+ * {Boolean} Stop propagation of touchstart events from getting to\n+ * listeners on the same element. Default is false.\n */\n- isBaseLayer: true,\n+ stopDown: false,\n \n /**\n- * APIProperty: isFixed\n- * {Boolean} EventPaned layers are fixed by default.\n+ * Property: pinching\n+ * {Boolean}\n */\n- isFixed: true,\n+ pinching: false,\n \n /**\n- * Property: pane\n- * {DOMElement} A reference to the element that controls the events.\n+ * Property: last\n+ * {Object} Object that store informations related to pinch last touch.\n */\n- pane: null,\n-\n+ last: null,\n \n /**\n- * Property: mapObject\n- * {Object} This is the object which will be used to load the 3rd party library\n- * in the case of the google layer, this will be of type GMap, \n- * in the case of the ve layer, this will be of type VEMap\n+ * Property: start\n+ * {Object} Object that store informations related to pinch touchstart.\n */\n- mapObject: null,\n+ start: null,\n \n+ /**\n+ * Constructor: OpenLayers.Handler.Pinch\n+ * Returns OpenLayers.Handler.Pinch\n+ *\n+ * Parameters:\n+ * control - {} The control that is making use of\n+ * this handler. If a handler is being used without a control, the\n+ * handlers setMap method must be overridden to deal properly with\n+ * the map.\n+ * callbacks - {Object} An object containing functions to be called when\n+ * the pinch operation start, change, or is finished. The callbacks\n+ * should expect to receive an object argument, which contains\n+ * information about scale, distance, and position of touch points.\n+ * options - {Object}\n+ */\n \n /**\n- * Constructor: OpenLayers.Layer.EventPane\n- * Create a new event pane layer\n+ * Method: touchstart\n+ * Handle touchstart events\n *\n * Parameters:\n- * name - {String}\n- * options - {Object} Hashtable of extra options to tag onto the layer\n+ * evt - {Event}\n+ *\n+ * Returns:\n+ * {Boolean} Let the event propagate.\n */\n- initialize: function(name, options) {\n- OpenLayers.Layer.prototype.initialize.apply(this, arguments);\n- if (this.pane == null) {\n- this.pane = OpenLayers.Util.createDiv(this.div.id + \"_EventPane\");\n+ touchstart: function(evt) {\n+ var propagate = true;\n+ this.pinching = false;\n+ if (OpenLayers.Event.isMultiTouch(evt)) {\n+ this.started = true;\n+ this.last = this.start = {\n+ distance: this.getDistance(evt.touches),\n+ delta: 0,\n+ scale: 1\n+ };\n+ this.callback(\"start\", [evt, this.start]);\n+ propagate = !this.stopDown;\n+ } else if (this.started) {\n+ // Some webkit versions send fake single-touch events during\n+ // multitouch, which cause the drag handler to trigger\n+ return false;\n+ } else {\n+ this.started = false;\n+ this.start = null;\n+ this.last = null;\n }\n+ // prevent document dragging\n+ OpenLayers.Event.preventDefault(evt);\n+ return propagate;\n },\n \n /**\n- * APIMethod: destroy\n- * Deconstruct this layer.\n+ * Method: touchmove\n+ * Handle touchmove events\n+ *\n+ * Parameters:\n+ * evt - {Event}\n+ *\n+ * Returns:\n+ * {Boolean} Let the event propagate.\n */\n- destroy: function() {\n- this.mapObject = null;\n- this.pane = null;\n- OpenLayers.Layer.prototype.destroy.apply(this, arguments);\n+ touchmove: function(evt) {\n+ if (this.started && OpenLayers.Event.isMultiTouch(evt)) {\n+ this.pinching = true;\n+ var current = this.getPinchData(evt);\n+ this.callback(\"move\", [evt, current]);\n+ this.last = current;\n+ // prevent document dragging\n+ OpenLayers.Event.stop(evt);\n+ } else if (this.started) {\n+ // Some webkit versions send fake single-touch events during\n+ // multitouch, which cause the drag handler to trigger\n+ return false;\n+ }\n+ return true;\n },\n \n-\n /**\n- * Method: setMap\n- * Set the map property for the layer. This is done through an accessor\n- * so that subclasses can override this and take special action once \n- * they have their map variable set. \n+ * Method: touchend\n+ * Handle touchend events\n *\n * Parameters:\n- * map - {}\n+ * evt - {Event}\n+ *\n+ * Returns:\n+ * {Boolean} Let the event propagate.\n */\n- setMap: function(map) {\n- OpenLayers.Layer.prototype.setMap.apply(this, arguments);\n-\n- this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;\n- this.pane.style.display = this.div.style.display;\n- this.pane.style.width = \"100%\";\n- this.pane.style.height = \"100%\";\n- if (OpenLayers.BROWSER_NAME == \"msie\") {\n- this.pane.style.background =\n- \"url(\" + OpenLayers.Util.getImageLocation(\"blank.gif\") + \")\";\n+ touchend: function(evt) {\n+ if (this.started && !OpenLayers.Event.isMultiTouch(evt)) {\n+ this.started = false;\n+ this.pinching = false;\n+ this.callback(\"done\", [evt, this.start, this.last]);\n+ this.start = null;\n+ this.last = null;\n+ return false;\n }\n+ return true;\n+ },\n \n- if (this.isFixed) {\n- this.map.viewPortDiv.appendChild(this.pane);\n- } else {\n- this.map.layerContainerDiv.appendChild(this.pane);\n+ /**\n+ * Method: activate\n+ * Activate the handler.\n+ *\n+ * Returns:\n+ * {Boolean} The handler was successfully activated.\n+ */\n+ activate: function() {\n+ var activated = false;\n+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n+ this.pinching = false;\n+ activated = true;\n }\n+ return activated;\n+ },\n \n- // once our layer has been added to the map, we can load it\n- this.loadMapObject();\n-\n- // if map didn't load, display warning\n- if (this.mapObject == null) {\n- this.loadWarningMessage();\n+ /**\n+ * Method: deactivate\n+ * Deactivate the handler.\n+ *\n+ * Returns:\n+ * {Boolean} The handler was successfully deactivated.\n+ */\n+ deactivate: function() {\n+ var deactivated = false;\n+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n+ this.started = false;\n+ this.pinching = false;\n+ this.start = null;\n+ this.last = null;\n+ deactivated = true;\n }\n+ return deactivated;\n },\n \n /**\n- * APIMethod: removeMap\n- * On being removed from the map, we'll like to remove the invisible 'pane'\n- * div that we added to it on creation. \n- * \n+ * Method: getDistance\n+ * Get the distance in pixels between two touches.\n+ *\n * Parameters:\n- * map - {}\n+ * touches - {Array(Object)}\n+ *\n+ * Returns:\n+ * {Number} The distance in pixels.\n */\n- removeMap: function(map) {\n- if (this.pane && this.pane.parentNode) {\n- this.pane.parentNode.removeChild(this.pane);\n- }\n- OpenLayers.Layer.prototype.removeMap.apply(this, arguments);\n+ getDistance: function(touches) {\n+ var t0 = touches[0];\n+ var t1 = touches[1];\n+ return Math.sqrt(\n+ Math.pow(t0.olClientX - t1.olClientX, 2) +\n+ Math.pow(t0.olClientY - t1.olClientY, 2)\n+ );\n },\n \n+\n /**\n- * Method: loadWarningMessage\n- * If we can't load the map lib, then display an error message to the \n- * user and tell them where to go for help.\n- * \n- * This function sets up the layout for the warning message. Each 3rd\n- * party layer must implement its own getWarningHTML() function to \n- * provide the actual warning message.\n+ * Method: getPinchData\n+ * Get informations about the pinch event.\n+ *\n+ * Parameters:\n+ * evt - {Event}\n+ *\n+ * Returns:\n+ * {Object} Object that contains data about the current pinch.\n */\n- loadWarningMessage: function() {\n+ getPinchData: function(evt) {\n+ var distance = this.getDistance(evt.touches);\n+ var scale = distance / this.start.distance;\n+ return {\n+ distance: distance,\n+ delta: this.last.distance - distance,\n+ scale: scale\n+ };\n+ },\n \n- this.div.style.backgroundColor = \"darkblue\";\n+ CLASS_NAME: \"OpenLayers.Handler.Pinch\"\n+});\n \n- var viewSize = this.map.getSize();\n+/* ======================================================================\n+ OpenLayers/Control/PinchZoom.js\n+ ====================================================================== */\n \n- var msgW = Math.min(viewSize.w, 300);\n- var msgH = Math.min(viewSize.h, 200);\n- var size = new OpenLayers.Size(msgW, msgH);\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2);\n+/**\n+ * @requires OpenLayers/Handler/Pinch.js\n+ */\n \n- var topLeft = centerPx.add(-size.w / 2, -size.h / 2);\n+/**\n+ * Class: OpenLayers.Control.PinchZoom\n+ *\n+ * Inherits:\n+ * - \n+ */\n+OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, {\n \n- var div = OpenLayers.Util.createDiv(this.name + \"_warning\",\n- topLeft,\n- size,\n- null,\n- null,\n- null,\n- \"auto\");\n+ /** \n+ * Property: type\n+ * {OpenLayers.Control.TYPES}\n+ */\n+ type: OpenLayers.Control.TYPE_TOOL,\n \n- div.style.padding = \"7px\";\n- div.style.backgroundColor = \"yellow\";\n+ /**\n+ * Property: pinchOrigin\n+ * {Object} Cached object representing the pinch start (in pixels).\n+ */\n+ pinchOrigin: null,\n \n- div.innerHTML = this.getWarningHTML();\n- this.div.appendChild(div);\n- },\n+ /**\n+ * Property: currentCenter\n+ * {Object} Cached object representing the latest pinch center (in pixels).\n+ */\n+ currentCenter: null,\n \n- /** \n- * Method: getWarningHTML\n- * To be implemented by subclasses.\n- * \n- * Returns:\n- * {String} String with information on why layer is broken, how to get\n- * it working.\n+ /**\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * true.\n */\n- getWarningHTML: function() {\n- //should be implemented by subclasses\n- return \"\";\n- },\n+ autoActivate: true,\n \n /**\n- * Method: display\n- * Set the display on the pane\n+ * APIProperty: preserveCenter\n+ * {Boolean} Set this to true if you don't want the map center to change\n+ * while pinching. For example you may want to set preserveCenter to\n+ * true when the user location is being watched and you want to preserve\n+ * the user location at the center of the map even if he zooms in or\n+ * out using pinch. This property's value can be changed any time on an\n+ * existing instance. Default is false.\n+ */\n+ preserveCenter: false,\n+\n+ /**\n+ * APIProperty: handlerOptions\n+ * {Object} Used to set non-default properties on the pinch handler\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Control.PinchZoom\n+ * Create a control for zooming with pinch gestures. This works on devices\n+ * with multi-touch support.\n *\n * Parameters:\n- * display - {Boolean}\n+ * options - {Object} An optional object whose properties will be set on\n+ * the control\n */\n- display: function(display) {\n- OpenLayers.Layer.prototype.display.apply(this, arguments);\n- this.pane.style.display = this.div.style.display;\n+ initialize: function(options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, arguments);\n+ this.handler = new OpenLayers.Handler.Pinch(this, {\n+ start: this.pinchStart,\n+ move: this.pinchMove,\n+ done: this.pinchDone\n+ }, this.handlerOptions);\n },\n \n /**\n- * Method: setZIndex\n- * Set the z-index order for the pane.\n- * \n+ * Method: pinchStart\n+ *\n * Parameters:\n- * zIndex - {int}\n+ * evt - {Event}\n+ * pinchData - {Object} pinch data object related to the current touchmove\n+ * of the pinch gesture. This give us the current scale of the pinch.\n */\n- setZIndex: function(zIndex) {\n- OpenLayers.Layer.prototype.setZIndex.apply(this, arguments);\n- this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;\n+ pinchStart: function(evt, pinchData) {\n+ var xy = (this.preserveCenter) ?\n+ this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy;\n+ this.pinchOrigin = xy;\n+ this.currentCenter = xy;\n },\n \n /**\n- * Method: moveByPx\n- * Move the layer based on pixel vector. To be implemented by subclasses.\n+ * Method: pinchMove\n *\n * Parameters:\n- * dx - {Number} The x coord of the displacement vector.\n- * dy - {Number} The y coord of the displacement vector.\n+ * evt - {Event}\n+ * pinchData - {Object} pinch data object related to the current touchmove\n+ * of the pinch gesture. This give us the current scale of the pinch.\n */\n- moveByPx: function(dx, dy) {\n- OpenLayers.Layer.prototype.moveByPx.apply(this, arguments);\n+ pinchMove: function(evt, pinchData) {\n+ var scale = pinchData.scale;\n+ var containerOrigin = this.map.layerContainerOriginPx;\n+ var pinchOrigin = this.pinchOrigin;\n+ var current = (this.preserveCenter) ?\n+ this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy;\n \n- if (this.dragPanMapObject) {\n- this.dragPanMapObject(dx, -dy);\n- } else {\n- this.moveTo(this.map.getCachedCenter());\n- }\n+ var dx = Math.round((containerOrigin.x + current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x));\n+ var dy = Math.round((containerOrigin.y + current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y));\n+\n+ this.map.applyTransform(dx, dy, scale);\n+ this.currentCenter = current;\n },\n \n /**\n- * Method: moveTo\n- * Handle calls to move the layer.\n- * \n+ * Method: pinchDone\n+ *\n * Parameters:\n- * bounds - {}\n- * zoomChanged - {Boolean}\n- * dragging - {Boolean}\n+ * evt - {Event}\n+ * start - {Object} pinch data object related to the touchstart event that\n+ * started the pinch gesture.\n+ * last - {Object} pinch data object related to the last touchmove event\n+ * of the pinch gesture. This give us the final scale of the pinch.\n */\n- moveTo: function(bounds, zoomChanged, dragging) {\n- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);\n+ pinchDone: function(evt, start, last) {\n+ this.map.applyTransform();\n+ var zoom = this.map.getZoomForResolution(this.map.getResolution() / last.scale, true);\n+ if (zoom !== this.map.getZoom() || !this.currentCenter.equals(this.pinchOrigin)) {\n+ var resolution = this.map.getResolutionForZoom(zoom);\n \n- if (this.mapObject != null) {\n+ var location = this.map.getLonLatFromPixel(this.pinchOrigin);\n+ var zoomPixel = this.currentCenter;\n+ var size = this.map.getSize();\n \n- var newCenter = this.map.getCenter();\n- var newZoom = this.map.getZoom();\n+ location.lon += resolution * ((size.w / 2) - zoomPixel.x);\n+ location.lat -= resolution * ((size.h / 2) - zoomPixel.y);\n \n- if (newCenter != null) {\n+ // Force a reflow before calling setCenter. This is to work\n+ // around an issue occuring in iOS.\n+ //\n+ // See https://github.com/openlayers/openlayers/pull/351.\n+ //\n+ // Without a reflow setting the layer container div's top left\n+ // style properties to \"0px\" - as done in Map.moveTo when zoom\n+ // is changed - won't actually correctly reposition the layer\n+ // container div.\n+ //\n+ // Also, we need to use a statement that the Google Closure\n+ // compiler won't optimize away.\n+ this.map.div.clientWidth = this.map.div.clientWidth;\n \n- var moOldCenter = this.getMapObjectCenter();\n- var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter);\n+ this.map.setCenter(location, zoom);\n+ }\n+ },\n \n- var moOldZoom = this.getMapObjectZoom();\n- var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom);\n+ CLASS_NAME: \"OpenLayers.Control.PinchZoom\"\n \n- if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) {\n+});\n+/* ======================================================================\n+ OpenLayers/Control/ZoomIn.js\n+ ====================================================================== */\n \n- if (!zoomChanged && oldCenter && this.dragPanMapObject &&\n- this.smoothDragPan) {\n- var oldPx = this.map.getViewPortPxFromLonLat(oldCenter);\n- var newPx = this.map.getViewPortPxFromLonLat(newCenter);\n- this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y);\n- } else {\n- var center = this.getMapObjectLonLatFromOLLonLat(newCenter);\n- var zoom = this.getMapObjectZoomFromOLZoom(newZoom);\n- this.setMapObjectCenter(center, zoom, dragging);\n- }\n- }\n- }\n- }\n- },\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n+/**\n+ * @requires OpenLayers/Control/Button.js\n+ */\n \n- /********************************************************/\n- /* */\n- /* Baselayer Functions */\n- /* */\n- /********************************************************/\n+/**\n+ * Class: OpenLayers.Control.ZoomIn\n+ * The ZoomIn control is a button to increase the zoom level of a map.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, {\n \n /**\n- * Method: getLonLatFromViewPortPx\n- * Get a map location from a pixel location\n- * \n- * Parameters:\n- * viewPortPx - {}\n- *\n- * Returns:\n- * {} An OpenLayers.LonLat which is the passed-in view\n- * port OpenLayers.Pixel, translated into lon/lat by map lib\n- * If the map lib is not loaded or not centered, returns null\n+ * Method: trigger\n */\n- getLonLatFromViewPortPx: function(viewPortPx) {\n- var lonlat = null;\n- if ((this.mapObject != null) &&\n- (this.getMapObjectCenter() != null)) {\n- var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx);\n- var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel);\n- lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat);\n+ trigger: function() {\n+ if (this.map) {\n+ this.map.zoomIn();\n }\n- return lonlat;\n },\n \n+ CLASS_NAME: \"OpenLayers.Control.ZoomIn\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/DragPan.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Handler/Drag.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control.DragPan\n+ * The DragPan control pans the map with a drag of the mouse.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /** \n+ * Property: type\n+ * {OpenLayers.Control.TYPES}\n+ */\n+ type: OpenLayers.Control.TYPE_TOOL,\n \n /**\n- * Method: getViewPortPxFromLonLat\n- * Get a pixel location from a map location\n- *\n- * Parameters:\n- * lonlat - {}\n- *\n- * Returns:\n- * {} An OpenLayers.Pixel which is the passed-in\n- * OpenLayers.LonLat, translated into view port pixels by map lib\n- * If map lib is not loaded or not centered, returns null\n+ * Property: panned\n+ * {Boolean} The map moved.\n */\n- getViewPortPxFromLonLat: function(lonlat) {\n- var viewPortPx = null;\n- if ((this.mapObject != null) &&\n- (this.getMapObjectCenter() != null)) {\n+ panned: false,\n \n- var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat);\n- var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat);\n+ /**\n+ * Property: interval\n+ * {Integer} The number of milliseconds that should ellapse before\n+ * panning the map again. Defaults to 0 milliseconds, which means that\n+ * no separate cycle is used for panning. In most cases you won't want\n+ * to change this value. For slow machines/devices larger values can be\n+ * tried out.\n+ */\n+ interval: 0,\n \n- viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel);\n+ /**\n+ * APIProperty: documentDrag\n+ * {Boolean} If set to true, mouse dragging will continue even if the\n+ * mouse cursor leaves the map viewport. Default is false.\n+ */\n+ documentDrag: false,\n+\n+ /**\n+ * Property: kinetic\n+ * {} The OpenLayers.Kinetic object.\n+ */\n+ kinetic: null,\n+\n+ /**\n+ * APIProperty: enableKinetic\n+ * {Boolean} Set this option to enable \"kinetic dragging\". Can be\n+ * set to true or to an object. If set to an object this\n+ * object will be passed to the {}\n+ * constructor. Defaults to true.\n+ * To get kinetic dragging, ensure that OpenLayers/Kinetic.js is\n+ * included in your build config.\n+ */\n+ enableKinetic: true,\n+\n+ /**\n+ * APIProperty: kineticInterval\n+ * {Integer} Interval in milliseconds between 2 steps in the \"kinetic\n+ * scrolling\". Applies only if enableKinetic is set. Defaults\n+ * to 10 milliseconds.\n+ */\n+ kineticInterval: 10,\n+\n+\n+ /**\n+ * Method: draw\n+ * Creates a Drag handler, using and\n+ * as callbacks.\n+ */\n+ draw: function() {\n+ if (this.enableKinetic && OpenLayers.Kinetic) {\n+ var config = {\n+ interval: this.kineticInterval\n+ };\n+ if (typeof this.enableKinetic === \"object\") {\n+ config = OpenLayers.Util.extend(config, this.enableKinetic);\n+ }\n+ this.kinetic = new OpenLayers.Kinetic(config);\n }\n- return viewPortPx;\n+ this.handler = new OpenLayers.Handler.Drag(this, {\n+ \"move\": this.panMap,\n+ \"done\": this.panMapDone,\n+ \"down\": this.panMapStart\n+ }, {\n+ interval: this.interval,\n+ documentDrag: this.documentDrag\n+ });\n },\n \n- /********************************************************/\n- /* */\n- /* Translation Functions */\n- /* */\n- /* The following functions translate Map Object and */\n- /* OL formats for Pixel, LonLat */\n- /* */\n- /********************************************************/\n-\n- //\n- // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat\n- //\n+ /**\n+ * Method: panMapStart\n+ */\n+ panMapStart: function() {\n+ if (this.kinetic) {\n+ this.kinetic.begin();\n+ }\n+ },\n \n /**\n- * Method: getOLLonLatFromMapObjectLonLat\n- * Get an OL style map location from a 3rd party style map location\n+ * Method: panMap\n *\n- * Parameters\n- * moLonLat - {Object}\n- * \n- * Returns:\n- * {} An OpenLayers.LonLat, translated from the passed in \n- * MapObject LonLat\n- * Returns null if null value is passed in\n+ * Parameters:\n+ * xy - {} Pixel of the mouse position\n */\n- getOLLonLatFromMapObjectLonLat: function(moLonLat) {\n- var olLonLat = null;\n- if (moLonLat != null) {\n- var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);\n- var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);\n- olLonLat = new OpenLayers.LonLat(lon, lat);\n+ panMap: function(xy) {\n+ if (this.kinetic) {\n+ this.kinetic.update(xy);\n }\n- return olLonLat;\n+ this.panned = true;\n+ this.map.pan(\n+ this.handler.last.x - xy.x,\n+ this.handler.last.y - xy.y, {\n+ dragging: true,\n+ animate: false\n+ }\n+ );\n },\n \n /**\n- * Method: getMapObjectLonLatFromOLLonLat\n- * Get a 3rd party map location from an OL map location.\n+ * Method: panMapDone\n+ * Finish the panning operation. Only call setCenter (through )\n+ * if the map has actually been moved.\n *\n * Parameters:\n- * olLonLat - {}\n- * \n- * Returns:\n- * {Object} A MapObject LonLat, translated from the passed in \n- * OpenLayers.LonLat\n- * Returns null if null value is passed in\n+ * xy - {} Pixel of the mouse position\n */\n- getMapObjectLonLatFromOLLonLat: function(olLonLat) {\n- var moLatLng = null;\n- if (olLonLat != null) {\n- moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon,\n- olLonLat.lat);\n+ panMapDone: function(xy) {\n+ if (this.panned) {\n+ var res = null;\n+ if (this.kinetic) {\n+ res = this.kinetic.end(xy);\n+ }\n+ this.map.pan(\n+ this.handler.last.x - xy.x,\n+ this.handler.last.y - xy.y, {\n+ dragging: !!res,\n+ animate: false\n+ }\n+ );\n+ if (res) {\n+ var self = this;\n+ this.kinetic.move(res, function(x, y, end) {\n+ self.map.pan(x, y, {\n+ dragging: !end,\n+ animate: false\n+ });\n+ });\n+ }\n+ this.panned = false;\n }\n- return moLatLng;\n },\n \n+ CLASS_NAME: \"OpenLayers.Control.DragPan\"\n+});\n+/* ======================================================================\n+ OpenLayers/Events/buttonclick.js\n+ ====================================================================== */\n \n- //\n- // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel\n- //\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Events.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Events.buttonclick\n+ * Extension event type for handling buttons on top of a dom element. This\n+ * event type fires \"buttonclick\" on its when a button was\n+ * clicked. Buttons are detected by the \"olButton\" class.\n+ *\n+ * This event type makes sure that button clicks do not interfere with other\n+ * events that are registered on the same .\n+ *\n+ * Event types provided by this extension:\n+ * - *buttonclick* Triggered when a button is clicked. Listeners receive an\n+ * object with a *buttonElement* property referencing the dom element of\n+ * the clicked button, and an *buttonXY* property with the click position\n+ * relative to the button.\n+ */\n+OpenLayers.Events.buttonclick = OpenLayers.Class({\n \n /**\n- * Method: getOLPixelFromMapObjectPixel\n- * Get an OL pixel location from a 3rd party pixel location.\n+ * Property: target\n+ * {} The events instance that the buttonclick event will\n+ * be triggered on.\n+ */\n+ target: null,\n+\n+ /**\n+ * Property: events\n+ * {Array} Events to observe and conditionally stop from propagating when\n+ * an element with the olButton class (or its olAlphaImg child) is\n+ * clicked.\n+ */\n+ events: [\n+ 'mousedown', 'mouseup', 'click', 'dblclick',\n+ 'touchstart', 'touchmove', 'touchend', 'keydown'\n+ ],\n+\n+ /**\n+ * Property: startRegEx\n+ * {RegExp} Regular expression to test Event.type for events that start\n+ * a buttonclick sequence.\n+ */\n+ startRegEx: /^mousedown|touchstart$/,\n+\n+ /**\n+ * Property: cancelRegEx\n+ * {RegExp} Regular expression to test Event.type for events that cancel\n+ * a buttonclick sequence.\n+ */\n+ cancelRegEx: /^touchmove$/,\n+\n+ /**\n+ * Property: completeRegEx\n+ * {RegExp} Regular expression to test Event.type for events that complete\n+ * a buttonclick sequence.\n+ */\n+ completeRegEx: /^mouseup|touchend$/,\n+\n+ /**\n+ * Property: startEvt\n+ * {Event} The event that started the click sequence\n+ */\n+\n+ /**\n+ * Constructor: OpenLayers.Events.buttonclick\n+ * Construct a buttonclick event type. Applications are not supposed to\n+ * create instances of this class - they are created on demand by\n+ * instances.\n *\n * Parameters:\n- * moPixel - {Object}\n- * \n- * Returns:\n- * {} An OpenLayers.Pixel, translated from the passed in \n- * MapObject Pixel\n- * Returns null if null value is passed in\n+ * target - {} The events instance that the buttonclick\n+ * event will be triggered on.\n */\n- getOLPixelFromMapObjectPixel: function(moPixel) {\n- var olPixel = null;\n- if (moPixel != null) {\n- var x = this.getXFromMapObjectPixel(moPixel);\n- var y = this.getYFromMapObjectPixel(moPixel);\n- olPixel = new OpenLayers.Pixel(x, y);\n+ initialize: function(target) {\n+ this.target = target;\n+ for (var i = this.events.length - 1; i >= 0; --i) {\n+ this.target.register(this.events[i], this, this.buttonClick, {\n+ extension: true\n+ });\n }\n- return olPixel;\n },\n \n /**\n- * Method: getMapObjectPixelFromOLPixel\n- * Get a 3rd party pixel location from an OL pixel location\n+ * Method: destroy\n+ */\n+ destroy: function() {\n+ for (var i = this.events.length - 1; i >= 0; --i) {\n+ this.target.unregister(this.events[i], this, this.buttonClick);\n+ }\n+ delete this.target;\n+ },\n+\n+ /**\n+ * Method: getPressedButton\n+ * Get the pressed button, if any. Returns undefined if no button\n+ * was pressed.\n+ *\n+ * Arguments:\n+ * element - {DOMElement} The event target.\n *\n- * Parameters:\n- * olPixel - {}\n- * \n * Returns:\n- * {Object} A MapObject Pixel, translated from the passed in \n- * OpenLayers.Pixel\n- * Returns null if null value is passed in\n+ * {DOMElement} The button element, or undefined.\n */\n- getMapObjectPixelFromOLPixel: function(olPixel) {\n- var moPixel = null;\n- if (olPixel != null) {\n- moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y);\n- }\n- return moPixel;\n+ getPressedButton: function(element) {\n+ var depth = 3, // limit the search depth\n+ button;\n+ do {\n+ if (OpenLayers.Element.hasClass(element, \"olButton\")) {\n+ // hit!\n+ button = element;\n+ break;\n+ }\n+ element = element.parentNode;\n+ } while (--depth > 0 && element);\n+ return button;\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.EventPane\"\n+ /**\n+ * Method: ignore\n+ * Check for event target elements that should be ignored by OpenLayers.\n+ *\n+ * Parameters:\n+ * element - {DOMElement} The event target.\n+ */\n+ ignore: function(element) {\n+ var depth = 3,\n+ ignore = false;\n+ do {\n+ if (element.nodeName.toLowerCase() === 'a') {\n+ ignore = true;\n+ break;\n+ }\n+ element = element.parentNode;\n+ } while (--depth > 0 && element);\n+ return ignore;\n+ },\n+\n+ /**\n+ * Method: buttonClick\n+ * Check if a button was clicked, and fire the buttonclick event\n+ *\n+ * Parameters:\n+ * evt - {Event}\n+ */\n+ buttonClick: function(evt) {\n+ var propagate = true,\n+ element = OpenLayers.Event.element(evt);\n+ if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf(\"mouse\"))) {\n+ // was a button pressed?\n+ var button = this.getPressedButton(element);\n+ if (button) {\n+ if (evt.type === \"keydown\") {\n+ switch (evt.keyCode) {\n+ case OpenLayers.Event.KEY_RETURN:\n+ case OpenLayers.Event.KEY_SPACE:\n+ this.target.triggerEvent(\"buttonclick\", {\n+ buttonElement: button\n+ });\n+ OpenLayers.Event.stop(evt);\n+ propagate = false;\n+ break;\n+ }\n+ } else if (this.startEvt) {\n+ if (this.completeRegEx.test(evt.type)) {\n+ var pos = OpenLayers.Util.pagePosition(button);\n+ var viewportElement = OpenLayers.Util.getViewportElement();\n+ var scrollTop = window.pageYOffset || viewportElement.scrollTop;\n+ var scrollLeft = window.pageXOffset || viewportElement.scrollLeft;\n+ pos[0] = pos[0] - scrollLeft;\n+ pos[1] = pos[1] - scrollTop;\n+\n+ this.target.triggerEvent(\"buttonclick\", {\n+ buttonElement: button,\n+ buttonXY: {\n+ x: this.startEvt.clientX - pos[0],\n+ y: this.startEvt.clientY - pos[1]\n+ }\n+ });\n+ }\n+ if (this.cancelRegEx.test(evt.type)) {\n+ delete this.startEvt;\n+ }\n+ OpenLayers.Event.stop(evt);\n+ propagate = false;\n+ }\n+ if (this.startRegEx.test(evt.type)) {\n+ this.startEvt = evt;\n+ OpenLayers.Event.stop(evt);\n+ propagate = false;\n+ }\n+ } else {\n+ propagate = !this.ignore(OpenLayers.Event.element(evt));\n+ delete this.startEvt;\n+ }\n+ }\n+ return propagate;\n+ }\n+\n });\n /* ======================================================================\n- OpenLayers/Format/ArcXML.js\n+ OpenLayers/Control/Panel.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Format/XML.js\n- * @requires OpenLayers/Geometry/Polygon.js\n- * @requires OpenLayers/Geometry/Point.js\n- * @requires OpenLayers/Geometry/MultiPolygon.js\n- * @requires OpenLayers/Geometry/LinearRing.js\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Events/buttonclick.js\n */\n \n /**\n- * Class: OpenLayers.Format.ArcXML\n- * Read/Write ArcXML. Create a new instance with the \n- * constructor.\n- * \n+ * Class: OpenLayers.Control.Panel\n+ * The Panel control is a container for other controls. With it toolbars\n+ * may be composed.\n+ *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, {\n+OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, {\n+ /**\n+ * Property: controls\n+ * {Array()}\n+ */\n+ controls: null,\n \n /**\n- * Property: fontStyleKeys\n- * {Array} List of keys used in font styling.\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * true.\n */\n- fontStyleKeys: [\n- 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle',\n- 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency'\n- ],\n+ autoActivate: true,\n+\n+ /** \n+ * APIProperty: defaultControl\n+ * {} The control which is activated when the control is\n+ * activated (turned on), which also happens at instantiation.\n+ * If is true, will be nullified after the\n+ * first activation of the panel.\n+ */\n+ defaultControl: null,\n \n /**\n- * Property: request\n- * A get_image request destined for an ArcIMS server.\n+ * APIProperty: saveState\n+ * {Boolean} If set to true, the active state of this panel's controls will\n+ * be stored on panel deactivation, and restored on reactivation. Default\n+ * is false.\n */\n- request: null,\n+ saveState: false,\n \n /**\n- * Property: response\n- * A parsed response from an ArcIMS server.\n+ * APIProperty: allowDepress\n+ * {Boolean} If is true the controls can \n+ * be deactivated by clicking the icon that represents them. Default \n+ * is false.\n */\n- response: null,\n+ allowDepress: false,\n \n /**\n- * Constructor: OpenLayers.Format.ArcXML\n- * Create a new parser/writer for ArcXML. Create an instance of this class\n- * to begin authoring a request to an ArcIMS service. This is used\n- * primarily by the ArcIMS layer, but could be used to do other wild\n- * stuff, like geocoding.\n+ * Property: activeState\n+ * {Object} stores the active state of this panel's controls.\n+ */\n+ activeState: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Control.Panel\n+ * Create a new control panel.\n+ *\n+ * Each control in the panel is represented by an icon. When clicking \n+ * on an icon, the method is called.\n+ *\n+ * Specific properties for controls on a panel:\n+ * type - {Number} One of ,\n+ * , .\n+ * If not provided, is assumed.\n+ * title - {string} Text displayed when mouse is over the icon that \n+ * represents the control. \n+ *\n+ * The of a control determines the behavior when\n+ * clicking its icon:\n+ * - The control is activated and other\n+ * controls of this type in the same panel are deactivated. This is\n+ * the default type.\n+ * - The active state of the control is\n+ * toggled.\n+ * - The\n+ * method of the control is called,\n+ * but its active state is not changed.\n+ *\n+ * If a control is , it will be drawn with the\n+ * olControl[Name]ItemActive class, otherwise with the\n+ * olControl[Name]ItemInactive class.\n *\n * Parameters:\n- * options - {Object} An optional object whose properties will be set on\n- * this instance.\n+ * options - {Object} An optional object whose properties will be used\n+ * to extend the control.\n */\n initialize: function(options) {\n- this.request = new OpenLayers.Format.ArcXML.Request();\n- this.response = new OpenLayers.Format.ArcXML.Response();\n-\n- if (options) {\n- if (options.requesttype == \"feature\") {\n- this.request.get_image = null;\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ this.controls = [];\n+ this.activeState = {};\n+ },\n \n- var qry = this.request.get_feature.query;\n- this.addCoordSys(qry.featurecoordsys, options.featureCoordSys);\n- this.addCoordSys(qry.filtercoordsys, options.filterCoordSys);\n+ /**\n+ * APIMethod: destroy\n+ */\n+ destroy: function() {\n+ if (this.map) {\n+ this.map.events.unregister(\"buttonclick\", this, this.onButtonClick);\n+ }\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n+ for (var ctl, i = this.controls.length - 1; i >= 0; i--) {\n+ ctl = this.controls[i];\n+ if (ctl.events) {\n+ ctl.events.un({\n+ activate: this.iconOn,\n+ deactivate: this.iconOff\n+ });\n+ }\n+ ctl.panel_div = null;\n+ }\n+ this.activeState = null;\n+ },\n \n- if (options.polygon) {\n- qry.isspatial = true;\n- qry.spatialfilter.polygon = options.polygon;\n- } else if (options.envelope) {\n- qry.isspatial = true;\n- qry.spatialfilter.envelope = {\n- minx: 0,\n- miny: 0,\n- maxx: 0,\n- maxy: 0\n- };\n- this.parseEnvelope(qry.spatialfilter.envelope, options.envelope);\n+ /**\n+ * APIMethod: activate\n+ */\n+ activate: function() {\n+ if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {\n+ var control;\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ control = this.controls[i];\n+ if (control === this.defaultControl ||\n+ (this.saveState && this.activeState[control.id])) {\n+ control.activate();\n }\n- } else if (options.requesttype == \"image\") {\n- this.request.get_feature = null;\n-\n- var props = this.request.get_image.properties;\n- this.parseEnvelope(props.envelope, options.envelope);\n-\n- this.addLayers(props.layerlist, options.layers);\n- this.addImageSize(props.imagesize, options.tileSize);\n- this.addCoordSys(props.featurecoordsys, options.featureCoordSys);\n- this.addCoordSys(props.filtercoordsys, options.filterCoordSys);\n- } else {\n- // if an arcxml object is being created with no request type, it is\n- // probably going to consume a response, so do not throw an error if\n- // the requesttype is not defined\n- this.request = null;\n }\n+ if (this.saveState === true) {\n+ this.defaultControl = null;\n+ }\n+ this.redraw();\n+ return true;\n+ } else {\n+ return false;\n }\n-\n- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);\n },\n \n /**\n- * Method: parseEnvelope\n- * Parse an array of coordinates into an ArcXML envelope structure.\n- *\n- * Parameters:\n- * env - {Object} An envelope object that will contain the parsed coordinates.\n- * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ]\n+ * APIMethod: deactivate\n */\n- parseEnvelope: function(env, arr) {\n- if (arr && arr.length == 4) {\n- env.minx = arr[0];\n- env.miny = arr[1];\n- env.maxx = arr[2];\n- env.maxy = arr[3];\n+ deactivate: function() {\n+ if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {\n+ var control;\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ control = this.controls[i];\n+ this.activeState[control.id] = control.deactivate();\n+ }\n+ this.redraw();\n+ return true;\n+ } else {\n+ return false;\n }\n },\n \n- /** \n- * Method: addLayers\n- * Add a collection of layers to another collection of layers. Each layer in the list is tuple of\n- * { id, visible }. These layer collections represent the \n- * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML\n- *\n- * TODO: Add support for dynamic layer rendering.\n+ /**\n+ * Method: draw\n *\n- * Parameters:\n- * ll - {Array({id,visible})} A list of layer definitions.\n- * lyrs - {Array({id,visible})} A list of layer definitions.\n+ * Returns:\n+ * {DOMElement}\n */\n- addLayers: function(ll, lyrs) {\n- for (var lind = 0, len = lyrs.length; lind < len; lind++) {\n- ll.push(lyrs[lind]);\n+ draw: function() {\n+ OpenLayers.Control.prototype.draw.apply(this, arguments);\n+ if (this.outsideViewport) {\n+ this.events.attachToElement(this.div);\n+ this.events.register(\"buttonclick\", this, this.onButtonClick);\n+ } else {\n+ this.map.events.register(\"buttonclick\", this, this.onButtonClick);\n }\n+ this.addControlsToMap(this.controls);\n+ return this.div;\n },\n \n /**\n- * Method: addImageSize\n- * Set the size of the requested image.\n- *\n- * Parameters:\n- * imsize - {Object} An ArcXML imagesize object.\n- * olsize - {} The image size to set.\n+ * Method: redraw\n */\n- addImageSize: function(imsize, olsize) {\n- if (olsize !== null) {\n- imsize.width = olsize.w;\n- imsize.height = olsize.h;\n- imsize.printwidth = olsize.w;\n- imsize.printheight = olsize.h;\n+ redraw: function() {\n+ for (var l = this.div.childNodes.length, i = l - 1; i >= 0; i--) {\n+ this.div.removeChild(this.div.childNodes[i]);\n+ }\n+ this.div.innerHTML = \"\";\n+ if (this.active) {\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ this.div.appendChild(this.controls[i].panel_div);\n+ }\n }\n },\n \n /**\n- * Method: addCoordSys\n- * Add the coordinate system information to an object. The object may be \n+ * APIMethod: activateControl\n+ * This method is called when the user click on the icon representing a \n+ * control in the panel.\n *\n * Parameters:\n- * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure.\n- * fsys - {String} or {} or {filtercoordsys} or \n- * {featurecoordsys} A projection representation. If it's a {String}, \n- * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} \n- * AND Proj4js is available, the projection number and name are extracted \n- * from there. If it's a filter or feature ArcXML structure, it is copied.\n+ * control - {}\n */\n- addCoordSys: function(featOrFilt, fsys) {\n- if (typeof fsys == \"string\") {\n- featOrFilt.id = parseInt(fsys);\n- featOrFilt.string = fsys;\n+ activateControl: function(control) {\n+ if (!this.active) {\n+ return false;\n }\n- // is this a proj4js instance?\n- else if (typeof fsys == \"object\" && fsys.proj !== null) {\n- featOrFilt.id = fsys.proj.srsProjNumber;\n- featOrFilt.string = fsys.proj.srsCode;\n+ if (control.type == OpenLayers.Control.TYPE_BUTTON) {\n+ control.trigger();\n+ return;\n+ }\n+ if (control.type == OpenLayers.Control.TYPE_TOGGLE) {\n+ if (control.active) {\n+ control.deactivate();\n+ } else {\n+ control.activate();\n+ }\n+ return;\n+ }\n+ if (this.allowDepress && control.active) {\n+ control.deactivate();\n } else {\n- featOrFilt = fsys;\n+ var c;\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ c = this.controls[i];\n+ if (c != control &&\n+ (c.type === OpenLayers.Control.TYPE_TOOL || c.type == null)) {\n+ c.deactivate();\n+ }\n+ }\n+ control.activate();\n }\n },\n \n /**\n- * APIMethod: iserror\n- * Check to see if the response from the server was an error.\n+ * APIMethod: addControls\n+ * To build a toolbar, you add a set of controls to it. addControls\n+ * lets you add a single control or a list of controls to the \n+ * Control Panel.\n *\n * Parameters:\n- * data - {String} or {DOMElement} data to read/parse. If nothing is supplied,\n- * the current response is examined.\n- *\n- * Returns:\n- * {Boolean} true if the response was an error.\n+ * controls - {} Controls to add in the panel.\n */\n- iserror: function(data) {\n- var ret = null;\n+ addControls: function(controls) {\n+ if (!(OpenLayers.Util.isArray(controls))) {\n+ controls = [controls];\n+ }\n+ this.controls = this.controls.concat(controls);\n \n- if (!data) {\n- ret = (this.response.error !== '');\n- } else {\n- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n- var errorNodes = data.documentElement.getElementsByTagName(\"ERROR\");\n- ret = (errorNodes !== null && errorNodes.length > 0);\n+ for (var i = 0, len = controls.length; i < len; i++) {\n+ var control = controls[i],\n+ element = this.createControlMarkup(control);\n+ OpenLayers.Element.addClass(element,\n+ control.displayClass + \"ItemInactive\");\n+ OpenLayers.Element.addClass(element, \"olButton\");\n+ if (control.title != \"\" && !element.title) {\n+ element.title = control.title;\n+ }\n+ control.panel_div = element;\n }\n \n- return ret;\n+ if (this.map) { // map.addControl() has already been called on the panel\n+ this.addControlsToMap(controls);\n+ this.redraw();\n+ }\n },\n \n /**\n- * APIMethod: read\n- * Read data from a string, and return an response. \n- * \n+ * APIMethod: createControlMarkup\n+ * This function just creates a div for the control. If specific HTML\n+ * markup is needed this function can be overridden in specific classes,\n+ * or at panel instantiation time:\n+ *\n+ * Example:\n+ * (code)\n+ * var panel = new OpenLayers.Control.Panel({\n+ * defaultControl: control,\n+ * // ovverride createControlMarkup to create actual buttons\n+ * // including texts wrapped into span elements.\n+ * createControlMarkup: function(control) {\n+ * var button = document.createElement('button'),\n+ * span = document.createElement('span');\n+ * if (control.text) {\n+ * span.innerHTML = control.text;\n+ * }\n+ * return button;\n+ * }\n+ * });\n+ * (end)\n+ *\n * Parameters:\n- * data - {String} or {DOMElement} data to read/parse.\n+ * control - {} The control to create the HTML\n+ * markup for.\n *\n * Returns:\n- * {} An ArcXML response. Note that this response\n- * data may change in the future. \n+ * {DOMElement} The markup.\n */\n- read: function(data) {\n- if (typeof data == \"string\") {\n- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n- }\n+ createControlMarkup: function(control) {\n+ return document.createElement(\"div\");\n+ },\n \n- var arcNode = null;\n- if (data && data.documentElement) {\n- if (data.documentElement.nodeName == \"ARCXML\") {\n- arcNode = data.documentElement;\n+ /**\n+ * Method: addControlsToMap\n+ * Only for internal use in draw() and addControls() methods.\n+ *\n+ * Parameters:\n+ * controls - {Array()} Controls to add into map.\n+ */\n+ addControlsToMap: function(controls) {\n+ var control;\n+ for (var i = 0, len = controls.length; i < len; i++) {\n+ control = controls[i];\n+ if (control.autoActivate === true) {\n+ control.autoActivate = false;\n+ this.map.addControl(control);\n+ control.autoActivate = true;\n } else {\n- arcNode = data.documentElement.getElementsByTagName(\"ARCXML\")[0];\n+ this.map.addControl(control);\n+ control.deactivate();\n }\n+ control.events.on({\n+ activate: this.iconOn,\n+ deactivate: this.iconOff\n+ });\n }\n+ },\n \n- // in Safari, arcNode will be there but will have a child named \n- // parsererror\n- if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') {\n- var error, source;\n- try {\n- error = data.firstChild.nodeValue;\n- source = data.firstChild.childNodes[1].firstChild.nodeValue;\n- } catch (err) {\n- // pass\n+ /**\n+ * Method: iconOn\n+ * Internal use, for use only with \"controls[i].events.on/un\".\n+ */\n+ iconOn: function() {\n+ var d = this.panel_div; // \"this\" refers to a control on panel!\n+ var re = new RegExp(\"\\\\b(\" + this.displayClass + \"Item)Inactive\\\\b\");\n+ d.className = d.className.replace(re, \"$1Active\");\n+ },\n+\n+ /**\n+ * Method: iconOff\n+ * Internal use, for use only with \"controls[i].events.on/un\".\n+ */\n+ iconOff: function() {\n+ var d = this.panel_div; // \"this\" refers to a control on panel!\n+ var re = new RegExp(\"\\\\b(\" + this.displayClass + \"Item)Active\\\\b\");\n+ d.className = d.className.replace(re, \"$1Inactive\");\n+ },\n+\n+ /**\n+ * Method: onButtonClick\n+ *\n+ * Parameters:\n+ * evt - {Event}\n+ */\n+ onButtonClick: function(evt) {\n+ var controls = this.controls,\n+ button = evt.buttonElement;\n+ for (var i = controls.length - 1; i >= 0; --i) {\n+ if (controls[i].panel_div === button) {\n+ this.activateControl(controls[i]);\n+ break;\n }\n- throw {\n- message: \"Error parsing the ArcXML request\",\n- error: error,\n- source: source\n- };\n }\n+ },\n \n- var response = this.parseResponse(arcNode);\n- return response;\n+ /**\n+ * APIMethod: getControlsBy\n+ * Get a list of controls with properties matching the given criteria.\n+ *\n+ * Parameters:\n+ * property - {String} A control property to be matched.\n+ * match - {String | Object} A string to match. Can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * match.test(control[property]) evaluates to true, the control will be\n+ * included in the array returned. If no controls are found, an empty\n+ * array is returned.\n+ *\n+ * Returns:\n+ * {Array()} A list of controls matching the given criteria.\n+ * An empty array is returned if no matches are found.\n+ */\n+ getControlsBy: function(property, match) {\n+ var test = (typeof match.test == \"function\");\n+ var found = OpenLayers.Array.filter(this.controls, function(item) {\n+ return item[property] == match || (test && match.test(item[property]));\n+ });\n+ return found;\n },\n \n /**\n- * APIMethod: write\n- * Generate an ArcXml document string for sending to an ArcIMS server. \n- * \n+ * APIMethod: getControlsByName\n+ * Get a list of contorls with names matching the given name.\n+ *\n+ * Parameters:\n+ * match - {String | Object} A control name. The name can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * name.test(control.name) evaluates to true, the control will be included\n+ * in the list of controls returned. If no controls are found, an empty\n+ * array is returned.\n+ *\n * Returns:\n- * {String} A string representing the ArcXML document request.\n+ * {Array()} A list of controls matching the given name.\n+ * An empty array is returned if no matches are found.\n */\n- write: function(request) {\n- if (!request) {\n- request = this.request;\n- }\n- var root = this.createElementNS(\"\", \"ARCXML\");\n- root.setAttribute(\"version\", \"1.1\");\n+ getControlsByName: function(match) {\n+ return this.getControlsBy(\"name\", match);\n+ },\n \n- var reqElem = this.createElementNS(\"\", \"REQUEST\");\n+ /**\n+ * APIMethod: getControlsByClass\n+ * Get a list of controls of a given type (CLASS_NAME).\n+ *\n+ * Parameters:\n+ * match - {String | Object} A control class name. The type can also be a\n+ * regular expression literal or object. In addition, it can be any\n+ * object with a method named test. For reqular expressions or other,\n+ * if type.test(control.CLASS_NAME) evaluates to true, the control will\n+ * be included in the list of controls returned. If no controls are\n+ * found, an empty array is returned.\n+ *\n+ * Returns:\n+ * {Array()} A list of controls matching the given type.\n+ * An empty array is returned if no matches are found.\n+ */\n+ getControlsByClass: function(match) {\n+ return this.getControlsBy(\"CLASS_NAME\", match);\n+ },\n \n- if (request.get_image != null) {\n- var getElem = this.createElementNS(\"\", \"GET_IMAGE\");\n- reqElem.appendChild(getElem);\n+ CLASS_NAME: \"OpenLayers.Control.Panel\"\n+});\n \n- var propElem = this.createElementNS(\"\", \"PROPERTIES\");\n- getElem.appendChild(propElem);\n+/* ======================================================================\n+ OpenLayers/Control/Pan.js\n+ ====================================================================== */\n \n- var props = request.get_image.properties;\n- if (props.featurecoordsys != null) {\n- var feat = this.createElementNS(\"\", \"FEATURECOORDSYS\");\n- propElem.appendChild(feat);\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (props.featurecoordsys.id === 0) {\n- feat.setAttribute(\"string\", props.featurecoordsys['string']);\n- } else {\n- feat.setAttribute(\"id\", props.featurecoordsys.id);\n- }\n- }\n+/**\n+ * @requires OpenLayers/Control/Button.js\n+ */\n \n- if (props.filtercoordsys != null) {\n- var filt = this.createElementNS(\"\", \"FILTERCOORDSYS\");\n- propElem.appendChild(filt);\n+/**\n+ * Class: OpenLayers.Control.Pan\n+ * The Pan control is a single button to pan the map in one direction. For\n+ * a more complete control see .\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, {\n \n- if (props.filtercoordsys.id === 0) {\n- filt.setAttribute(\"string\", props.filtercoordsys.string);\n- } else {\n- filt.setAttribute(\"id\", props.filtercoordsys.id);\n- }\n- }\n+ /** \n+ * APIProperty: slideFactor\n+ * {Integer} Number of pixels by which we'll pan the map in any direction \n+ * on clicking the arrow buttons, defaults to 50. If you want to pan\n+ * by some ratio of the map dimensions, use instead.\n+ */\n+ slideFactor: 50,\n \n- if (props.envelope != null) {\n- var env = this.createElementNS(\"\", \"ENVELOPE\");\n- propElem.appendChild(env);\n+ /** \n+ * APIProperty: slideRatio\n+ * {Number} The fraction of map width/height by which we'll pan the map \n+ * on clicking the arrow buttons. Default is null. If set, will\n+ * override . E.g. if slideRatio is .5, then Pan Up will\n+ * pan up half the map height. \n+ */\n+ slideRatio: null,\n \n- env.setAttribute(\"minx\", props.envelope.minx);\n- env.setAttribute(\"miny\", props.envelope.miny);\n- env.setAttribute(\"maxx\", props.envelope.maxx);\n- env.setAttribute(\"maxy\", props.envelope.maxy);\n- }\n+ /** \n+ * Property: direction\n+ * {String} in {'North', 'South', 'East', 'West'}\n+ */\n+ direction: null,\n \n- var imagesz = this.createElementNS(\"\", \"IMAGESIZE\");\n- propElem.appendChild(imagesz);\n+ /**\n+ * Constructor: OpenLayers.Control.Pan \n+ * Control which handles the panning (in any of the cardinal directions)\n+ * of the map by a set px distance. \n+ *\n+ * Parameters:\n+ * direction - {String} The direction this button should pan.\n+ * options - {Object} An optional object whose properties will be used\n+ * to extend the control.\n+ */\n+ initialize: function(direction, options) {\n \n- imagesz.setAttribute(\"height\", props.imagesize.height);\n- imagesz.setAttribute(\"width\", props.imagesize.width);\n+ this.direction = direction;\n+ this.CLASS_NAME += this.direction;\n \n- if (props.imagesize.height != props.imagesize.printheight ||\n- props.imagesize.width != props.imagesize.printwidth) {\n- imagesz.setAttribute(\"printheight\", props.imagesize.printheight);\n- imagesz.setArrtibute(\"printwidth\", props.imagesize.printwidth);\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ },\n+\n+ /**\n+ * Method: trigger\n+ */\n+ trigger: function() {\n+ if (this.map) {\n+ var getSlideFactor = OpenLayers.Function.bind(function(dim) {\n+ return this.slideRatio ?\n+ this.map.getSize()[dim] * this.slideRatio :\n+ this.slideFactor;\n+ }, this);\n+\n+ switch (this.direction) {\n+ case OpenLayers.Control.Pan.NORTH:\n+ this.map.pan(0, -getSlideFactor(\"h\"));\n+ break;\n+ case OpenLayers.Control.Pan.SOUTH:\n+ this.map.pan(0, getSlideFactor(\"h\"));\n+ break;\n+ case OpenLayers.Control.Pan.WEST:\n+ this.map.pan(-getSlideFactor(\"w\"), 0);\n+ break;\n+ case OpenLayers.Control.Pan.EAST:\n+ this.map.pan(getSlideFactor(\"w\"), 0);\n+ break;\n }\n+ }\n+ },\n \n- if (props.background != null) {\n- var backgrnd = this.createElementNS(\"\", \"BACKGROUND\");\n- propElem.appendChild(backgrnd);\n+ CLASS_NAME: \"OpenLayers.Control.Pan\"\n+});\n \n- backgrnd.setAttribute(\"color\",\n- props.background.color.r + \",\" +\n- props.background.color.g + \",\" +\n- props.background.color.b);\n+OpenLayers.Control.Pan.NORTH = \"North\";\n+OpenLayers.Control.Pan.SOUTH = \"South\";\n+OpenLayers.Control.Pan.EAST = \"East\";\n+OpenLayers.Control.Pan.WEST = \"West\";\n+/* ======================================================================\n+ OpenLayers/Control/PanPanel.js\n+ ====================================================================== */\n \n- if (props.background.transcolor !== null) {\n- backgrnd.setAttribute(\"transcolor\",\n- props.background.transcolor.r + \",\" +\n- props.background.transcolor.g + \",\" +\n- props.background.transcolor.b);\n- }\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (props.layerlist != null && props.layerlist.length > 0) {\n- var layerlst = this.createElementNS(\"\", \"LAYERLIST\");\n- propElem.appendChild(layerlst);\n+/**\n+ * @requires OpenLayers/Control/Panel.js\n+ * @requires OpenLayers/Control/Pan.js\n+ */\n \n- for (var ld = 0; ld < props.layerlist.length; ld++) {\n- var ldef = this.createElementNS(\"\", \"LAYERDEF\");\n- layerlst.appendChild(ldef);\n+/**\n+ * Class: OpenLayers.Control.PanPanel\n+ * The PanPanel is visible control for panning the map North, South, East or\n+ * West in small steps. By default it is drawn in the top left corner of the\n+ * map.\n+ *\n+ * Note: \n+ * If you wish to use this class with the default images and you want \n+ * it to look nice in ie6, you should add the following, conditionally\n+ * added css stylesheet to your HTML file:\n+ * \n+ * (code)\n+ * \n+ * (end)\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, {\n \n- ldef.setAttribute(\"id\", props.layerlist[ld].id);\n- ldef.setAttribute(\"visible\", props.layerlist[ld].visible);\n+ /** \n+ * APIProperty: slideFactor\n+ * {Integer} Number of pixels by which we'll pan the map in any direction \n+ * on clicking the arrow buttons, defaults to 50. If you want to pan\n+ * by some ratio of the map dimensions, use instead.\n+ */\n+ slideFactor: 50,\n \n- if (typeof props.layerlist[ld].query == \"object\") {\n- var query = props.layerlist[ld].query;\n+ /** \n+ * APIProperty: slideRatio\n+ * {Number} The fraction of map width/height by which we'll pan the map \n+ * on clicking the arrow buttons. Default is null. If set, will\n+ * override . E.g. if slideRatio is .5, then Pan Up will\n+ * pan up half the map height. \n+ */\n+ slideRatio: null,\n \n- if (query.where.length < 0) {\n- continue;\n- }\n+ /**\n+ * Constructor: OpenLayers.Control.PanPanel \n+ * Add the four directional pan buttons.\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be used\n+ * to extend the control.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);\n+ var options = {\n+ slideFactor: this.slideFactor,\n+ slideRatio: this.slideRatio\n+ };\n+ this.addControls([\n+ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options),\n+ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options),\n+ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options),\n+ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options)\n+ ]);\n+ },\n \n- var queryElem = null;\n- if (typeof query.spatialfilter == \"boolean\" && query.spatialfilter) {\n- // handle spatial filter madness\n- queryElem = this.createElementNS(\"\", \"SPATIALQUERY\");\n- } else {\n- queryElem = this.createElementNS(\"\", \"QUERY\");\n- }\n+ CLASS_NAME: \"OpenLayers.Control.PanPanel\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/ZoomOut.js\n+ ====================================================================== */\n \n- queryElem.setAttribute(\"where\", query.where);\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (typeof query.accuracy == \"number\" && query.accuracy > 0) {\n- queryElem.setAttribute(\"accuracy\", query.accuracy);\n- }\n- if (typeof query.featurelimit == \"number\" && query.featurelimit < 2000) {\n- queryElem.setAttribute(\"featurelimit\", query.featurelimit);\n- }\n- if (typeof query.subfields == \"string\" && query.subfields != \"#ALL#\") {\n- queryElem.setAttribute(\"subfields\", query.subfields);\n- }\n- if (typeof query.joinexpression == \"string\" && query.joinexpression.length > 0) {\n- queryElem.setAttribute(\"joinexpression\", query.joinexpression);\n- }\n- if (typeof query.jointables == \"string\" && query.jointables.length > 0) {\n- queryElem.setAttribute(\"jointables\", query.jointables);\n- }\n+/**\n+ * @requires OpenLayers/Control/Button.js\n+ */\n \n- ldef.appendChild(queryElem);\n- }\n+/**\n+ * Class: OpenLayers.Control.ZoomOut\n+ * The ZoomOut control is a button to decrease the zoom level of a map.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, {\n \n- if (typeof props.layerlist[ld].renderer == \"object\") {\n- this.addRenderer(ldef, props.layerlist[ld].renderer);\n- }\n- }\n- }\n- } else if (request.get_feature != null) {\n- var getElem = this.createElementNS(\"\", \"GET_FEATURES\");\n- getElem.setAttribute(\"outputmode\", \"newxml\");\n- getElem.setAttribute(\"checkesc\", \"true\");\n+ /**\n+ * Method: trigger\n+ */\n+ trigger: function() {\n+ if (this.map) {\n+ this.map.zoomOut();\n+ }\n+ },\n \n- if (request.get_feature.geometry) {\n- getElem.setAttribute(\"geometry\", request.get_feature.geometry);\n- } else {\n- getElem.setAttribute(\"geometry\", \"false\");\n- }\n+ CLASS_NAME: \"OpenLayers.Control.ZoomOut\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/ZoomToMaxExtent.js\n+ ====================================================================== */\n \n- if (request.get_feature.compact) {\n- getElem.setAttribute(\"compact\", request.get_feature.compact);\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (request.get_feature.featurelimit == \"number\") {\n- getElem.setAttribute(\"featurelimit\", request.get_feature.featurelimit);\n- }\n+/**\n+ * @requires OpenLayers/Control/Button.js\n+ */\n \n- getElem.setAttribute(\"globalenvelope\", \"true\");\n- reqElem.appendChild(getElem);\n+/**\n+ * Class: OpenLayers.Control.ZoomToMaxExtent \n+ * The ZoomToMaxExtent control is a button that zooms out to the maximum\n+ * extent of the map. It is designed to be used with a \n+ * .\n+ * \n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, {\n \n- if (request.get_feature.layer != null && request.get_feature.layer.length > 0) {\n- var lyrElem = this.createElementNS(\"\", \"LAYER\");\n- lyrElem.setAttribute(\"id\", request.get_feature.layer);\n- getElem.appendChild(lyrElem);\n- }\n+ /**\n+ * Method: trigger\n+ * \n+ * Called whenever this control is being rendered inside of a panel and a \n+ * click occurs on this controls element. Actually zooms to the maximum\n+ * extent of this controls map.\n+ */\n+ trigger: function() {\n+ if (this.map) {\n+ this.map.zoomToMaxExtent();\n+ }\n+ },\n \n- var fquery = request.get_feature.query;\n- if (fquery != null) {\n- var qElem = null;\n- if (fquery.isspatial) {\n- qElem = this.createElementNS(\"\", \"SPATIALQUERY\");\n- } else {\n- qElem = this.createElementNS(\"\", \"QUERY\");\n- }\n- getElem.appendChild(qElem);\n+ CLASS_NAME: \"OpenLayers.Control.ZoomToMaxExtent\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/ZoomPanel.js\n+ ====================================================================== */\n \n- if (typeof fquery.accuracy == \"number\") {\n- qElem.setAttribute(\"accuracy\", fquery.accuracy);\n- }\n- //qElem.setAttribute(\"featurelimit\", \"5\");\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (fquery.featurecoordsys != null) {\n- var fcsElem1 = this.createElementNS(\"\", \"FEATURECOORDSYS\");\n+/**\n+ * @requires OpenLayers/Control/Panel.js\n+ * @requires OpenLayers/Control/ZoomIn.js\n+ * @requires OpenLayers/Control/ZoomOut.js\n+ * @requires OpenLayers/Control/ZoomToMaxExtent.js\n+ */\n \n- if (fquery.featurecoordsys.id == 0) {\n- fcsElem1.setAttribute(\"string\", fquery.featurecoordsys.string);\n- } else {\n- fcsElem1.setAttribute(\"id\", fquery.featurecoordsys.id);\n- }\n- qElem.appendChild(fcsElem1);\n- }\n+/**\n+ * Class: OpenLayers.Control.ZoomPanel\n+ * The ZoomPanel control is a compact collecton of 3 zoom controls: a \n+ * , a , and a\n+ * . By default it is drawn in the upper left \n+ * corner of the map.\n+ *\n+ * Note: \n+ * If you wish to use this class with the default images and you want \n+ * it to look nice in ie6, you should add the following, conditionally\n+ * added css stylesheet to your HTML file:\n+ * \n+ * (code)\n+ * \n+ * (end)\n+ * \n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, {\n \n- if (fquery.filtercoordsys != null) {\n- var fcsElem2 = this.createElementNS(\"\", \"FILTERCOORDSYS\");\n+ /**\n+ * Constructor: OpenLayers.Control.ZoomPanel \n+ * Add the three zooming controls.\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be used\n+ * to extend the control.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);\n+ this.addControls([\n+ new OpenLayers.Control.ZoomIn(),\n+ new OpenLayers.Control.ZoomToMaxExtent(),\n+ new OpenLayers.Control.ZoomOut()\n+ ]);\n+ },\n \n- if (fquery.filtercoordsys.id === 0) {\n- fcsElem2.setAttribute(\"string\", fquery.filtercoordsys.string);\n- } else {\n- fcsElem2.setAttribute(\"id\", fquery.filtercoordsys.id);\n- }\n- qElem.appendChild(fcsElem2);\n- }\n+ CLASS_NAME: \"OpenLayers.Control.ZoomPanel\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/Zoom.js\n+ ====================================================================== */\n \n- if (fquery.buffer > 0) {\n- var bufElem = this.createElementNS(\"\", \"BUFFER\");\n- bufElem.setAttribute(\"distance\", fquery.buffer);\n- qElem.appendChild(bufElem);\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (fquery.isspatial) {\n- var spfElem = this.createElementNS(\"\", \"SPATIALFILTER\");\n- spfElem.setAttribute(\"relation\", fquery.spatialfilter.relation);\n- qElem.appendChild(spfElem);\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Events/buttonclick.js\n+ */\n \n- if (fquery.spatialfilter.envelope) {\n- var envElem = this.createElementNS(\"\", \"ENVELOPE\");\n- envElem.setAttribute(\"minx\", fquery.spatialfilter.envelope.minx);\n- envElem.setAttribute(\"miny\", fquery.spatialfilter.envelope.miny);\n- envElem.setAttribute(\"maxx\", fquery.spatialfilter.envelope.maxx);\n- envElem.setAttribute(\"maxy\", fquery.spatialfilter.envelope.maxy);\n- spfElem.appendChild(envElem);\n- } else if (typeof fquery.spatialfilter.polygon == \"object\") {\n- spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon));\n- }\n- }\n+/**\n+ * Class: OpenLayers.Control.Zoom\n+ * The Zoom control is a pair of +/- links for zooming in and out.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, {\n \n- if (fquery.where != null && fquery.where.length > 0) {\n- qElem.setAttribute(\"where\", fquery.where);\n- }\n- }\n- }\n+ /**\n+ * APIProperty: zoomInText\n+ * {String}\n+ * Text for zoom-in link. Default is \"+\".\n+ */\n+ zoomInText: \"+\",\n \n- root.appendChild(reqElem);\n+ /**\n+ * APIProperty: zoomInId\n+ * {String}\n+ * Instead of having the control create a zoom in link, you can provide \n+ * the identifier for an anchor element already added to the document.\n+ * By default, an element with id \"olZoomInLink\" will be searched for\n+ * and used if it exists.\n+ */\n+ zoomInId: \"olZoomInLink\",\n \n- return OpenLayers.Format.XML.prototype.write.apply(this, [root]);\n- },\n+ /**\n+ * APIProperty: zoomOutText\n+ * {String}\n+ * Text for zoom-out link. Default is \"\\u2212\".\n+ */\n+ zoomOutText: \"\\u2212\",\n \n+ /**\n+ * APIProperty: zoomOutId\n+ * {String}\n+ * Instead of having the control create a zoom out link, you can provide \n+ * the identifier for an anchor element already added to the document.\n+ * By default, an element with id \"olZoomOutLink\" will be searched for\n+ * and used if it exists.\n+ */\n+ zoomOutId: \"olZoomOutLink\",\n \n- addGroupRenderer: function(ldef, toprenderer) {\n- var topRelem = this.createElementNS(\"\", \"GROUPRENDERER\");\n- ldef.appendChild(topRelem);\n+ /**\n+ * Method: draw\n+ *\n+ * Returns:\n+ * {DOMElement} A reference to the DOMElement containing the zoom links.\n+ */\n+ draw: function() {\n+ var div = OpenLayers.Control.prototype.draw.apply(this),\n+ links = this.getOrCreateLinks(div),\n+ zoomIn = links.zoomIn,\n+ zoomOut = links.zoomOut,\n+ eventsInstance = this.map.events;\n \n- for (var rind = 0; rind < toprenderer.length; rind++) {\n- var renderer = toprenderer[rind];\n- this.addRenderer(topRelem, renderer);\n+ if (zoomOut.parentNode !== div) {\n+ eventsInstance = this.events;\n+ eventsInstance.attachToElement(zoomOut.parentNode);\n }\n+ eventsInstance.register(\"buttonclick\", this, this.onZoomClick);\n+\n+ this.zoomInLink = zoomIn;\n+ this.zoomOutLink = zoomOut;\n+ return div;\n },\n \n+ /**\n+ * Method: getOrCreateLinks\n+ * \n+ * Parameters:\n+ * el - {DOMElement}\n+ *\n+ * Return: \n+ * {Object} Object with zoomIn and zoomOut properties referencing links.\n+ */\n+ getOrCreateLinks: function(el) {\n+ var zoomIn = document.getElementById(this.zoomInId),\n+ zoomOut = document.getElementById(this.zoomOutId);\n+ if (!zoomIn) {\n+ zoomIn = document.createElement(\"a\");\n+ zoomIn.href = \"#zoomIn\";\n+ zoomIn.appendChild(document.createTextNode(this.zoomInText));\n+ zoomIn.className = \"olControlZoomIn\";\n+ el.appendChild(zoomIn);\n+ }\n+ OpenLayers.Element.addClass(zoomIn, \"olButton\");\n+ if (!zoomOut) {\n+ zoomOut = document.createElement(\"a\");\n+ zoomOut.href = \"#zoomOut\";\n+ zoomOut.appendChild(document.createTextNode(this.zoomOutText));\n+ zoomOut.className = \"olControlZoomOut\";\n+ el.appendChild(zoomOut);\n+ }\n+ OpenLayers.Element.addClass(zoomOut, \"olButton\");\n+ return {\n+ zoomIn: zoomIn,\n+ zoomOut: zoomOut\n+ };\n+ },\n \n- addRenderer: function(topRelem, renderer) {\n- if (OpenLayers.Util.isArray(renderer)) {\n- this.addGroupRenderer(topRelem, renderer);\n- } else {\n- var renderElem = this.createElementNS(\"\", renderer.type.toUpperCase() + \"RENDERER\");\n- topRelem.appendChild(renderElem);\n+ /**\n+ * Method: onZoomClick\n+ * Called when zoomin/out link is clicked.\n+ */\n+ onZoomClick: function(evt) {\n+ var button = evt.buttonElement;\n+ if (button === this.zoomInLink) {\n+ this.map.zoomIn();\n+ } else if (button === this.zoomOutLink) {\n+ this.map.zoomOut();\n+ }\n+ },\n \n- if (renderElem.tagName == \"VALUEMAPRENDERER\") {\n- this.addValueMapRenderer(renderElem, renderer);\n- } else if (renderElem.tagName == \"VALUEMAPLABELRENDERER\") {\n- this.addValueMapLabelRenderer(renderElem, renderer);\n- } else if (renderElem.tagName == \"SIMPLELABELRENDERER\") {\n- this.addSimpleLabelRenderer(renderElem, renderer);\n- } else if (renderElem.tagName == \"SCALEDEPENDENTRENDERER\") {\n- this.addScaleDependentRenderer(renderElem, renderer);\n- }\n+ /** \n+ * Method: destroy\n+ * Clean up.\n+ */\n+ destroy: function() {\n+ if (this.map) {\n+ this.map.events.unregister(\"buttonclick\", this, this.onZoomClick);\n }\n+ delete this.zoomInLink;\n+ delete this.zoomOutLink;\n+ OpenLayers.Control.prototype.destroy.apply(this);\n },\n \n+ CLASS_NAME: \"OpenLayers.Control.Zoom\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/Attribution.js\n+ ====================================================================== */\n \n- addScaleDependentRenderer: function(renderElem, renderer) {\n- if (typeof renderer.lower == \"string\" || typeof renderer.lower == \"number\") {\n- renderElem.setAttribute(\"lower\", renderer.lower);\n- }\n- if (typeof renderer.upper == \"string\" || typeof renderer.upper == \"number\") {\n- renderElem.setAttribute(\"upper\", renderer.upper);\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- this.addRenderer(renderElem, renderer.renderer);\n- },\n+/**\n+ * @requires OpenLayers/Control.js\n+ */\n \n+/**\n+ * Class: OpenLayers.Control.Attribution\n+ * The attribution control adds attribution from layers to the map display. \n+ * It uses 'attribution' property of each layer.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.Attribution =\n+ OpenLayers.Class(OpenLayers.Control, {\n \n- addValueMapLabelRenderer: function(renderElem, renderer) {\n- renderElem.setAttribute(\"lookupfield\", renderer.lookupfield);\n- renderElem.setAttribute(\"labelfield\", renderer.labelfield);\n+ /**\n+ * APIProperty: separator\n+ * {String} String used to separate layers.\n+ */\n+ separator: \", \",\n \n- if (typeof renderer.exacts == \"object\") {\n- for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) {\n- var exact = renderer.exacts[ext];\n+ /**\n+ * APIProperty: template\n+ * {String} Template for the attribution. This has to include the substring\n+ * \"${layers}\", which will be replaced by the layer specific\n+ * attributions, separated by . The default is \"${layers}\".\n+ */\n+ template: \"${layers}\",\n \n- var eelem = this.createElementNS(\"\", \"EXACT\");\n+ /**\n+ * Constructor: OpenLayers.Control.Attribution \n+ * \n+ * Parameters:\n+ * options - {Object} Options for control.\n+ */\n \n- if (typeof exact.value == \"string\") {\n- eelem.setAttribute(\"value\", exact.value);\n- }\n- if (typeof exact.label == \"string\") {\n- eelem.setAttribute(\"label\", exact.label);\n- }\n- if (typeof exact.method == \"string\") {\n- eelem.setAttribute(\"method\", exact.method);\n- }\n+ /** \n+ * Method: destroy\n+ * Destroy control.\n+ */\n+ destroy: function() {\n+ this.map.events.un({\n+ \"removelayer\": this.updateAttribution,\n+ \"addlayer\": this.updateAttribution,\n+ \"changelayer\": this.updateAttribution,\n+ \"changebaselayer\": this.updateAttribution,\n+ scope: this\n+ });\n \n- renderElem.appendChild(eelem);\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n+ },\n \n- if (typeof exact.symbol == \"object\") {\n- var selem = null;\n+ /**\n+ * Method: draw\n+ * Initialize control.\n+ * \n+ * Returns: \n+ * {DOMElement} A reference to the DIV DOMElement containing the control\n+ */\n+ draw: function() {\n+ OpenLayers.Control.prototype.draw.apply(this, arguments);\n \n- if (exact.symbol.type == \"text\") {\n- selem = this.createElementNS(\"\", \"TEXTSYMBOL\");\n- }\n+ this.map.events.on({\n+ 'changebaselayer': this.updateAttribution,\n+ 'changelayer': this.updateAttribution,\n+ 'addlayer': this.updateAttribution,\n+ 'removelayer': this.updateAttribution,\n+ scope: this\n+ });\n+ this.updateAttribution();\n \n- if (selem != null) {\n- var keys = this.fontStyleKeys;\n- for (var i = 0, len = keys.length; i < len; i++) {\n- var key = keys[i];\n- if (exact.symbol[key]) {\n- selem.setAttribute(key, exact.symbol[key]);\n- }\n+ return this.div;\n+ },\n+\n+ /**\n+ * Method: updateAttribution\n+ * Update attribution string.\n+ */\n+ updateAttribution: function() {\n+ var attributions = [];\n+ if (this.map && this.map.layers) {\n+ for (var i = 0, len = this.map.layers.length; i < len; i++) {\n+ var layer = this.map.layers[i];\n+ if (layer.attribution && layer.getVisibility()) {\n+ // add attribution only if attribution text is unique\n+ if (OpenLayers.Util.indexOf(\n+ attributions, layer.attribution) === -1) {\n+ attributions.push(layer.attribution);\n }\n- eelem.appendChild(selem);\n }\n }\n- } // for each exact\n- }\n- },\n-\n- addValueMapRenderer: function(renderElem, renderer) {\n- renderElem.setAttribute(\"lookupfield\", renderer.lookupfield);\n+ this.div.innerHTML = OpenLayers.String.format(this.template, {\n+ layers: attributions.join(this.separator)\n+ });\n+ }\n+ },\n \n- if (typeof renderer.ranges == \"object\") {\n- for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) {\n- var range = renderer.ranges[rng];\n+ CLASS_NAME: \"OpenLayers.Control.Attribution\"\n+ });\n+/* ======================================================================\n+ OpenLayers/Control/TouchNavigation.js\n+ ====================================================================== */\n \n- var relem = this.createElementNS(\"\", \"RANGE\");\n- relem.setAttribute(\"lower\", range.lower);\n- relem.setAttribute(\"upper\", range.upper);\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- renderElem.appendChild(relem);\n+/**\n+ * @requires OpenLayers/Control/DragPan.js\n+ * @requires OpenLayers/Control/PinchZoom.js\n+ * @requires OpenLayers/Handler/Click.js\n+ */\n \n- if (typeof range.symbol == \"object\") {\n- var selem = null;\n+/**\n+ * Class: OpenLayers.Control.TouchNavigation\n+ * The navigation control handles map browsing with touch events (dragging,\n+ * double-tapping, tap with two fingers, and pinch zoom). Create a new \n+ * control with the constructor.\n+ *\n+ * If you\u2019re only targeting touch enabled devices with your mapping application,\n+ * you can create a map with only a TouchNavigation control. The \n+ * control is mobile ready by default, but \n+ * you can generate a smaller build of the library by only including this\n+ * touch navigation control if you aren't concerned about mouse interaction.\n+ *\n+ * Inherits:\n+ * - \n+ */\n+OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, {\n \n- if (range.symbol.type == \"simplepolygon\") {\n- selem = this.createElementNS(\"\", \"SIMPLEPOLYGONSYMBOL\");\n- }\n+ /**\n+ * Property: dragPan\n+ * {}\n+ */\n+ dragPan: null,\n \n- if (selem != null) {\n- if (typeof range.symbol.boundarycolor == \"string\") {\n- selem.setAttribute(\"boundarycolor\", range.symbol.boundarycolor);\n- }\n- if (typeof range.symbol.fillcolor == \"string\") {\n- selem.setAttribute(\"fillcolor\", range.symbol.fillcolor);\n- }\n- if (typeof range.symbol.filltransparency == \"number\") {\n- selem.setAttribute(\"filltransparency\", range.symbol.filltransparency);\n- }\n- relem.appendChild(selem);\n- }\n- }\n- } // for each range\n- } else if (typeof renderer.exacts == \"object\") {\n- for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) {\n- var exact = renderer.exacts[ext];\n+ /**\n+ * APIProperty: dragPanOptions\n+ * {Object} Options passed to the DragPan control.\n+ */\n+ dragPanOptions: null,\n \n- var eelem = this.createElementNS(\"\", \"EXACT\");\n- if (typeof exact.value == \"string\") {\n- eelem.setAttribute(\"value\", exact.value);\n- }\n- if (typeof exact.label == \"string\") {\n- eelem.setAttribute(\"label\", exact.label);\n- }\n- if (typeof exact.method == \"string\") {\n- eelem.setAttribute(\"method\", exact.method);\n- }\n+ /**\n+ * Property: pinchZoom\n+ * {}\n+ */\n+ pinchZoom: null,\n \n- renderElem.appendChild(eelem);\n+ /**\n+ * APIProperty: pinchZoomOptions\n+ * {Object} Options passed to the PinchZoom control.\n+ */\n+ pinchZoomOptions: null,\n \n- if (typeof exact.symbol == \"object\") {\n- var selem = null;\n+ /**\n+ * APIProperty: clickHandlerOptions\n+ * {Object} Options passed to the Click handler.\n+ */\n+ clickHandlerOptions: null,\n \n- if (exact.symbol.type == \"simplemarker\") {\n- selem = this.createElementNS(\"\", \"SIMPLEMARKERSYMBOL\");\n- }\n+ /**\n+ * APIProperty: documentDrag\n+ * {Boolean} Allow panning of the map by dragging outside map viewport.\n+ * Default is false.\n+ */\n+ documentDrag: false,\n \n- if (selem != null) {\n- if (typeof exact.symbol.antialiasing == \"string\") {\n- selem.setAttribute(\"antialiasing\", exact.symbol.antialiasing);\n- }\n- if (typeof exact.symbol.color == \"string\") {\n- selem.setAttribute(\"color\", exact.symbol.color);\n- }\n- if (typeof exact.symbol.outline == \"string\") {\n- selem.setAttribute(\"outline\", exact.symbol.outline);\n- }\n- if (typeof exact.symbol.overlap == \"string\") {\n- selem.setAttribute(\"overlap\", exact.symbol.overlap);\n- }\n- if (typeof exact.symbol.shadow == \"string\") {\n- selem.setAttribute(\"shadow\", exact.symbol.shadow);\n- }\n- if (typeof exact.symbol.transparency == \"number\") {\n- selem.setAttribute(\"transparency\", exact.symbol.transparency);\n- }\n- //if (typeof exact.symbol.type == \"string\")\n- // selem.setAttribute(\"type\", exact.symbol.type);\n- if (typeof exact.symbol.usecentroid == \"string\") {\n- selem.setAttribute(\"usecentroid\", exact.symbol.usecentroid);\n- }\n- if (typeof exact.symbol.width == \"number\") {\n- selem.setAttribute(\"width\", exact.symbol.width);\n- }\n+ /**\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * true.\n+ */\n+ autoActivate: true,\n \n- eelem.appendChild(selem);\n- }\n- }\n- } // for each exact\n- }\n+ /**\n+ * Constructor: OpenLayers.Control.TouchNavigation\n+ * Create a new navigation control\n+ *\n+ * Parameters:\n+ * options - {Object} An optional object whose properties will be set on\n+ * the control\n+ */\n+ initialize: function(options) {\n+ this.handlers = {};\n+ OpenLayers.Control.prototype.initialize.apply(this, arguments);\n },\n \n-\n- addSimpleLabelRenderer: function(renderElem, renderer) {\n- renderElem.setAttribute(\"field\", renderer.field);\n- var keys = ['featureweight', 'howmanylabels', 'labelbufferratio',\n- 'labelpriorities', 'labelweight', 'linelabelposition',\n- 'rotationalangles'\n- ];\n- for (var i = 0, len = keys.length; i < len; i++) {\n- var key = keys[i];\n- if (renderer[key]) {\n- renderElem.setAttribute(key, renderer[key]);\n- }\n+ /**\n+ * Method: destroy\n+ * The destroy method is used to perform any clean up before the control\n+ * is dereferenced. Typically this is where event listeners are removed\n+ * to prevent memory leaks.\n+ */\n+ destroy: function() {\n+ this.deactivate();\n+ if (this.dragPan) {\n+ this.dragPan.destroy();\n }\n-\n- if (renderer.symbol.type == \"text\") {\n- var symbol = renderer.symbol;\n- var selem = this.createElementNS(\"\", \"TEXTSYMBOL\");\n- renderElem.appendChild(selem);\n-\n- var keys = this.fontStyleKeys;\n- for (var i = 0, len = keys.length; i < len; i++) {\n- var key = keys[i];\n- if (symbol[key]) {\n- selem.setAttribute(key, renderer[key]);\n- }\n- }\n+ this.dragPan = null;\n+ if (this.pinchZoom) {\n+ this.pinchZoom.destroy();\n+ delete this.pinchZoom;\n }\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n },\n \n- writePolygonGeometry: function(polygon) {\n- if (!(polygon instanceof OpenLayers.Geometry.Polygon)) {\n- throw {\n- message: 'Cannot write polygon geometry to ArcXML with an ' +\n- polygon.CLASS_NAME + ' object.',\n- geometry: polygon\n- };\n+ /**\n+ * Method: activate\n+ */\n+ activate: function() {\n+ if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {\n+ this.dragPan.activate();\n+ this.handlers.click.activate();\n+ this.pinchZoom.activate();\n+ return true;\n }\n+ return false;\n+ },\n \n- var polyElem = this.createElementNS(\"\", \"POLYGON\");\n-\n- for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) {\n- var ring = polygon.components[ln];\n- var ringElem = this.createElementNS(\"\", \"RING\");\n-\n- for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) {\n- var point = ring.components[rn];\n- var pointElem = this.createElementNS(\"\", \"POINT\");\n-\n- pointElem.setAttribute(\"x\", point.x);\n- pointElem.setAttribute(\"y\", point.y);\n-\n- ringElem.appendChild(pointElem);\n- }\n-\n- polyElem.appendChild(ringElem);\n+ /**\n+ * Method: deactivate\n+ */\n+ deactivate: function() {\n+ if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {\n+ this.dragPan.deactivate();\n+ this.handlers.click.deactivate();\n+ this.pinchZoom.deactivate();\n+ return true;\n }\n+ return false;\n+ },\n \n- return polyElem;\n+ /**\n+ * Method: draw\n+ */\n+ draw: function() {\n+ var clickCallbacks = {\n+ click: this.defaultClick,\n+ dblclick: this.defaultDblClick\n+ };\n+ var clickOptions = OpenLayers.Util.extend({\n+ \"double\": true,\n+ stopDouble: true,\n+ pixelTolerance: 2\n+ }, this.clickHandlerOptions);\n+ this.handlers.click = new OpenLayers.Handler.Click(\n+ this, clickCallbacks, clickOptions\n+ );\n+ this.dragPan = new OpenLayers.Control.DragPan(\n+ OpenLayers.Util.extend({\n+ map: this.map,\n+ documentDrag: this.documentDrag\n+ }, this.dragPanOptions)\n+ );\n+ this.dragPan.draw();\n+ this.pinchZoom = new OpenLayers.Control.PinchZoom(\n+ OpenLayers.Util.extend({\n+ map: this.map\n+ }, this.pinchZoomOptions)\n+ );\n },\n \n /**\n- * Method: parseResponse\n- * Take an ArcXML response, and parse in into this object's internal properties.\n+ * Method: defaultClick\n *\n * Parameters:\n- * data - {String} or {DOMElement} The ArcXML response, as either a string or the\n- * top level DOMElement of the response.\n+ * evt - {Event}\n */\n- parseResponse: function(data) {\n- if (typeof data == \"string\") {\n- var newData = new OpenLayers.Format.XML();\n- data = newData.read(data);\n+ defaultClick: function(evt) {\n+ if (evt.lastTouches && evt.lastTouches.length == 2) {\n+ this.map.zoomOut();\n }\n- var response = new OpenLayers.Format.ArcXML.Response();\n-\n- var errorNode = data.getElementsByTagName(\"ERROR\");\n-\n- if (errorNode != null && errorNode.length > 0) {\n- response.error = this.getChildValue(errorNode, \"Unknown error.\");\n- } else {\n- var responseNode = data.getElementsByTagName(\"RESPONSE\");\n-\n- if (responseNode == null || responseNode.length == 0) {\n- response.error = \"No RESPONSE tag found in ArcXML response.\";\n- return response;\n- }\n+ },\n \n- var rtype = responseNode[0].firstChild.nodeName;\n- if (rtype == \"#text\") {\n- rtype = responseNode[0].firstChild.nextSibling.nodeName;\n- }\n+ /**\n+ * Method: defaultDblClick\n+ *\n+ * Parameters:\n+ * evt - {Event}\n+ */\n+ defaultDblClick: function(evt) {\n+ this.map.zoomTo(this.map.zoom + 1, evt.xy);\n+ },\n \n- if (rtype == \"IMAGE\") {\n- var envelopeNode = data.getElementsByTagName(\"ENVELOPE\");\n- var outputNode = data.getElementsByTagName(\"OUTPUT\");\n+ CLASS_NAME: \"OpenLayers.Control.TouchNavigation\"\n+});\n+/* ======================================================================\n+ OpenLayers/Control/DrawFeature.js\n+ ====================================================================== */\n \n- if (envelopeNode == null || envelopeNode.length == 0) {\n- response.error = \"No ENVELOPE tag found in ArcXML response.\";\n- } else if (outputNode == null || outputNode.length == 0) {\n- response.error = \"No OUTPUT tag found in ArcXML response.\";\n- } else {\n- var envAttr = this.parseAttributes(envelopeNode[0]);\n- var outputAttr = this.parseAttributes(outputNode[0]);\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (typeof outputAttr.type == \"string\") {\n- response.image = {\n- envelope: envAttr,\n- output: {\n- type: outputAttr.type,\n- data: this.getChildValue(outputNode[0])\n- }\n- };\n- } else {\n- response.image = {\n- envelope: envAttr,\n- output: outputAttr\n- };\n- }\n- }\n- } else if (rtype == \"FEATURES\") {\n- var features = responseNode[0].getElementsByTagName(\"FEATURES\");\n \n- // get the feature count\n- var featureCount = features[0].getElementsByTagName(\"FEATURECOUNT\");\n- response.features.featurecount = featureCount[0].getAttribute(\"count\");\n+/**\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ */\n \n- if (response.features.featurecount > 0) {\n- // get the feature envelope\n- var envelope = features[0].getElementsByTagName(\"ENVELOPE\");\n- response.features.envelope = this.parseAttributes(envelope[0], typeof(0));\n+/**\n+ * Class: OpenLayers.Control.DrawFeature\n+ * The DrawFeature control draws point, line or polygon features on a vector\n+ * layer when active.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {\n \n- // get the field values per feature\n- var featureList = features[0].getElementsByTagName(\"FEATURE\");\n- for (var fn = 0; fn < featureList.length; fn++) {\n- var feature = new OpenLayers.Feature.Vector();\n- var fields = featureList[fn].getElementsByTagName(\"FIELD\");\n+ /**\n+ * Property: layer\n+ * {}\n+ */\n+ layer: null,\n \n- for (var fdn = 0; fdn < fields.length; fdn++) {\n- var fieldName = fields[fdn].getAttribute(\"name\");\n- var fieldValue = fields[fdn].getAttribute(\"value\");\n- feature.attributes[fieldName] = fieldValue;\n- }\n+ /**\n+ * Property: callbacks\n+ * {Object} The functions that are sent to the handler for callback\n+ */\n+ callbacks: null,\n \n- var geom = featureList[fn].getElementsByTagName(\"POLYGON\");\n+ /** \n+ * APIProperty: events\n+ * {} Events instance for listeners and triggering\n+ * control specific events.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * control.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types (in addition to those from ):\n+ * featureadded - Triggered when a feature is added\n+ */\n \n- if (geom.length > 0) {\n- // if there is a polygon, create an openlayers polygon, and assign\n- // it to the .geometry property of the feature\n- var ring = geom[0].getElementsByTagName(\"RING\");\n+ /**\n+ * APIProperty: multi\n+ * {Boolean} Cast features to multi-part geometries before passing to the\n+ * layer. Default is false.\n+ */\n+ multi: false,\n \n- var polys = [];\n- for (var rn = 0; rn < ring.length; rn++) {\n- var linearRings = [];\n- linearRings.push(this.parsePointGeometry(ring[rn]));\n+ /**\n+ * APIProperty: featureAdded\n+ * {Function} Called after each feature is added\n+ */\n+ featureAdded: function() {},\n \n- var holes = ring[rn].getElementsByTagName(\"HOLE\");\n- for (var hn = 0; hn < holes.length; hn++) {\n- linearRings.push(this.parsePointGeometry(holes[hn]));\n- }\n- holes = null;\n- polys.push(new OpenLayers.Geometry.Polygon(linearRings));\n- linearRings = null;\n- }\n- ring = null;\n+ /**\n+ * APIProperty: handlerOptions\n+ * {Object} Used to set non-default properties on the control's handler\n+ */\n \n- if (polys.length == 1) {\n- feature.geometry = polys[0];\n- } else {\n- feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys);\n- }\n+ /**\n+ * Constructor: OpenLayers.Control.DrawFeature\n+ * \n+ * Parameters:\n+ * layer - {} \n+ * handler - {} \n+ * options - {Object} \n+ */\n+ initialize: function(layer, handler, options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ this.callbacks = OpenLayers.Util.extend({\n+ done: this.drawFeature,\n+ modify: function(vertex, feature) {\n+ this.layer.events.triggerEvent(\n+ \"sketchmodified\", {\n+ vertex: vertex,\n+ feature: feature\n }\n-\n- response.features.feature.push(feature);\n- }\n+ );\n+ },\n+ create: function(vertex, feature) {\n+ this.layer.events.triggerEvent(\n+ \"sketchstarted\", {\n+ vertex: vertex,\n+ feature: feature\n+ }\n+ );\n }\n- } else {\n- response.error = \"Unidentified response type.\";\n+ },\n+ this.callbacks\n+ );\n+ this.layer = layer;\n+ this.handlerOptions = this.handlerOptions || {};\n+ this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(\n+ this.handlerOptions.layerOptions, {\n+ renderers: layer.renderers,\n+ rendererOptions: layer.rendererOptions\n }\n+ );\n+ if (!(\"multi\" in this.handlerOptions)) {\n+ this.handlerOptions.multi = this.multi;\n }\n- return response;\n+ var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary;\n+ if (sketchStyle) {\n+ this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(\n+ this.handlerOptions.layerOptions, {\n+ styleMap: new OpenLayers.StyleMap({\n+ \"default\": sketchStyle\n+ })\n+ }\n+ );\n+ }\n+ this.handler = new handler(this, this.callbacks, this.handlerOptions);\n },\n \n+ /**\n+ * Method: drawFeature\n+ */\n+ drawFeature: function(geometry) {\n+ var feature = new OpenLayers.Feature.Vector(geometry);\n+ var proceed = this.layer.events.triggerEvent(\n+ \"sketchcomplete\", {\n+ feature: feature\n+ }\n+ );\n+ if (proceed !== false) {\n+ feature.state = OpenLayers.State.INSERT;\n+ this.layer.addFeatures([feature]);\n+ this.featureAdded(feature);\n+ this.events.triggerEvent(\"featureadded\", {\n+ feature: feature\n+ });\n+ }\n+ },\n \n /**\n- * Method: parseAttributes\n+ * APIMethod: insertXY\n+ * Insert a point in the current sketch given x & y coordinates.\n *\n * Parameters:\n- * node - {} An element to parse attributes from.\n- *\n- * Returns:\n- * {Object} An attributes object, with properties set to attribute values.\n+ * x - {Number} The x-coordinate of the point.\n+ * y - {Number} The y-coordinate of the point.\n */\n- parseAttributes: function(node, type) {\n- var attributes = {};\n- for (var attr = 0; attr < node.attributes.length; attr++) {\n- if (type == \"number\") {\n- attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue);\n- } else {\n- attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue;\n- }\n+ insertXY: function(x, y) {\n+ if (this.handler && this.handler.line) {\n+ this.handler.insertXY(x, y);\n }\n- return attributes;\n },\n \n-\n /**\n- * Method: parsePointGeometry\n+ * APIMethod: insertDeltaXY\n+ * Insert a point given offsets from the previously inserted point.\n *\n * Parameters:\n- * node - {} An element to parse or arcxml data from.\n- *\n- * Returns:\n- * {} A linear ring represented by the node's points.\n+ * dx - {Number} The x-coordinate offset of the point.\n+ * dy - {Number} The y-coordinate offset of the point.\n */\n- parsePointGeometry: function(node) {\n- var ringPoints = [];\n- var coords = node.getElementsByTagName(\"COORDS\");\n-\n- if (coords.length > 0) {\n- // if coords is present, it's the only coords item\n- var coordArr = this.getChildValue(coords[0]);\n- coordArr = coordArr.split(/;/);\n- for (var cn = 0; cn < coordArr.length; cn++) {\n- var coordItems = coordArr[cn].split(/ /);\n- ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1]));\n- }\n- coords = null;\n- } else {\n- var point = node.getElementsByTagName(\"POINT\");\n- if (point.length > 0) {\n- for (var pn = 0; pn < point.length; pn++) {\n- ringPoints.push(\n- new OpenLayers.Geometry.Point(\n- parseFloat(point[pn].getAttribute(\"x\")),\n- parseFloat(point[pn].getAttribute(\"y\"))\n- )\n- );\n- }\n- }\n- point = null;\n+ insertDeltaXY: function(dx, dy) {\n+ if (this.handler && this.handler.line) {\n+ this.handler.insertDeltaXY(dx, dy);\n }\n-\n- return new OpenLayers.Geometry.LinearRing(ringPoints);\n },\n \n- CLASS_NAME: \"OpenLayers.Format.ArcXML\"\n-});\n-\n-OpenLayers.Format.ArcXML.Request = OpenLayers.Class({\n- initialize: function(params) {\n- var defaults = {\n- get_image: {\n- properties: {\n- background: null,\n- /*{ \n- color: { r:255, g:255, b:255 },\n- transcolor: null\n- },*/\n- draw: true,\n- envelope: {\n- minx: 0,\n- miny: 0,\n- maxx: 0,\n- maxy: 0\n- },\n- featurecoordsys: {\n- id: 0,\n- string: \"\",\n- datumtransformid: 0,\n- datumtransformstring: \"\"\n- },\n- filtercoordsys: {\n- id: 0,\n- string: \"\",\n- datumtransformid: 0,\n- datumtransformstring: \"\"\n- },\n- imagesize: {\n- height: 0,\n- width: 0,\n- dpi: 96,\n- printheight: 0,\n- printwidth: 0,\n- scalesymbols: false\n- },\n- layerlist: [],\n- /* no support for legends */\n- output: {\n- baseurl: \"\",\n- legendbaseurl: \"\",\n- legendname: \"\",\n- legendpath: \"\",\n- legendurl: \"\",\n- name: \"\",\n- path: \"\",\n- type: \"jpg\",\n- url: \"\"\n- }\n- }\n- },\n-\n- get_feature: {\n- layer: \"\",\n- query: {\n- isspatial: false,\n- featurecoordsys: {\n- id: 0,\n- string: \"\",\n- datumtransformid: 0,\n- datumtransformstring: \"\"\n- },\n- filtercoordsys: {\n- id: 0,\n- string: \"\",\n- datumtransformid: 0,\n- datumtransformstring: \"\"\n- },\n- buffer: 0,\n- where: \"\",\n- spatialfilter: {\n- relation: \"envelope_intersection\",\n- envelope: null\n- }\n- }\n- },\n-\n- environment: {\n- separators: {\n- cs: \" \",\n- ts: \";\"\n- }\n- },\n-\n- layer: [],\n- workspaces: []\n- };\n-\n- return OpenLayers.Util.extend(this, defaults);\n+ /**\n+ * APIMethod: insertDirectionLength\n+ * Insert a point in the current sketch given a direction and a length.\n+ *\n+ * Parameters:\n+ * direction - {Number} Degrees clockwise from the positive x-axis.\n+ * length - {Number} Distance from the previously drawn point.\n+ */\n+ insertDirectionLength: function(direction, length) {\n+ if (this.handler && this.handler.line) {\n+ this.handler.insertDirectionLength(direction, length);\n+ }\n },\n \n- CLASS_NAME: \"OpenLayers.Format.ArcXML.Request\"\n-});\n+ /**\n+ * APIMethod: insertDeflectionLength\n+ * Insert a point in the current sketch given a deflection and a length.\n+ * The deflection should be degrees clockwise from the previously \n+ * digitized segment.\n+ *\n+ * Parameters:\n+ * deflection - {Number} Degrees clockwise from the previous segment.\n+ * length - {Number} Distance from the previously drawn point.\n+ */\n+ insertDeflectionLength: function(deflection, length) {\n+ if (this.handler && this.handler.line) {\n+ this.handler.insertDeflectionLength(deflection, length);\n+ }\n+ },\n \n-OpenLayers.Format.ArcXML.Response = OpenLayers.Class({\n- initialize: function(params) {\n- var defaults = {\n- image: {\n- envelope: null,\n- output: ''\n- },\n+ /**\n+ * APIMethod: undo\n+ * Remove the most recently added point in the current sketch geometry.\n+ *\n+ * Returns: \n+ * {Boolean} An edit was undone.\n+ */\n+ undo: function() {\n+ return this.handler.undo && this.handler.undo();\n+ },\n \n- features: {\n- featurecount: 0,\n- envelope: null,\n- feature: []\n- },\n+ /**\n+ * APIMethod: redo\n+ * Reinsert the most recently removed point resulting from an call.\n+ * The undo stack is deleted whenever a point is added by other means.\n+ *\n+ * Returns: \n+ * {Boolean} An edit was redone.\n+ */\n+ redo: function() {\n+ return this.handler.redo && this.handler.redo();\n+ },\n \n- error: ''\n- };\n+ /**\n+ * APIMethod: finishSketch\n+ * Finishes the sketch without including the currently drawn point.\n+ * This method can be called to terminate drawing programmatically\n+ * instead of waiting for the user to end the sketch.\n+ */\n+ finishSketch: function() {\n+ this.handler.finishGeometry();\n+ },\n \n- return OpenLayers.Util.extend(this, defaults);\n+ /**\n+ * APIMethod: cancel\n+ * Cancel the current sketch. This removes the current sketch and keeps\n+ * the drawing control active.\n+ */\n+ cancel: function() {\n+ this.handler.cancel();\n },\n \n- CLASS_NAME: \"OpenLayers.Format.ArcXML.Response\"\n+ CLASS_NAME: \"OpenLayers.Control.DrawFeature\"\n });\n /* ======================================================================\n- OpenLayers/Layer/ArcIMS.js\n+ OpenLayers/Control/Snapping.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Layer/Grid.js\n- * @requires OpenLayers/Format/ArcXML.js\n- * @requires OpenLayers/Request.js\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Layer/Vector.js\n */\n \n /**\n- * Class: OpenLayers.Layer.ArcIMS\n- * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS\n- * Mapping Services. Create a new ArcIMS layer with the \n- * constructor.\n- * \n+ * Class: OpenLayers.Control.Snapping\n+ * Acts as a snapping agent while editing vector features.\n+ *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, {\n+OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /** \n+ * APIProperty: events\n+ * {} Events instance for listeners and triggering\n+ * control specific events.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * control.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types (in addition to those from ):\n+ * beforesnap - Triggered before a snap occurs. Listeners receive an\n+ * event object with *point*, *x*, *y*, *distance*, *layer*, and\n+ * *snapType* properties. The point property will be original point\n+ * geometry considered for snapping. The x and y properties represent\n+ * coordinates the point will receive. The distance is the distance\n+ * of the snap. The layer is the target layer. The snapType property\n+ * will be one of \"node\", \"vertex\", or \"edge\". Return false to stop\n+ * snapping from occurring.\n+ * snap - Triggered when a snap occurs. Listeners receive an event with\n+ * *point*, *snapType*, *layer*, and *distance* properties. The point\n+ * will be the location snapped to. The snapType will be one of \"node\",\n+ * \"vertex\", or \"edge\". The layer will be the target layer. The\n+ * distance will be the distance of the snap in map units.\n+ * unsnap - Triggered when a vertex is unsnapped. Listeners receive an\n+ * event with a *point* property.\n+ */\n \n /**\n- * Constant: DEFAULT_PARAMS\n- * {Object} Default query string parameters.\n+ * CONSTANT: DEFAULTS\n+ * Default target properties.\n */\n- DEFAULT_PARAMS: {\n- ClientVersion: \"9.2\",\n- ServiceName: ''\n+ DEFAULTS: {\n+ tolerance: 10,\n+ node: true,\n+ edge: true,\n+ vertex: true\n },\n \n /**\n- * APIProperty: featureCoordSys\n- * {String} Code for feature coordinate system. Default is \"4326\".\n+ * Property: greedy\n+ * {Boolean} Snap to closest feature in first layer with an eligible\n+ * feature. Default is true.\n */\n- featureCoordSys: \"4326\",\n+ greedy: true,\n \n /**\n- * APIProperty: filterCoordSys\n- * {String} Code for filter coordinate system. Default is \"4326\".\n+ * Property: precedence\n+ * {Array} List representing precedence of different snapping types.\n+ * Default is \"node\", \"vertex\", \"edge\".\n */\n- filterCoordSys: \"4326\",\n+ precedence: [\"node\", \"vertex\", \"edge\"],\n \n /**\n- * APIProperty: layers\n- * {Array} An array of objects with layer properties.\n+ * Property: resolution\n+ * {Float} The map resolution for the previously considered snap.\n */\n- layers: null,\n+ resolution: null,\n \n /**\n- * APIProperty: async\n- * {Boolean} Request images asynchronously. Default is true.\n+ * Property: geoToleranceCache\n+ * {Object} A cache of geo-tolerances. Tolerance values (in map units) are\n+ * calculated when the map resolution changes.\n */\n- async: true,\n+ geoToleranceCache: null,\n \n /**\n- * APIProperty: name\n- * {String} Layer name. Default is \"ArcIMS\".\n+ * Property: layer\n+ * {} The current editable layer. Set at\n+ * construction or after construction with .\n */\n- name: \"ArcIMS\",\n+ layer: null,\n \n /**\n- * APIProperty: isBaseLayer\n- * {Boolean} The layer is a base layer. Default is true.\n+ * Property: feature\n+ * {} The current editable feature.\n */\n- isBaseLayer: true,\n+ feature: null,\n \n /**\n- * Constant: DEFAULT_OPTIONS\n- * {Object} Default layers properties.\n+ * Property: point\n+ * {} The currently snapped vertex.\n */\n- DEFAULT_OPTIONS: {\n- tileSize: new OpenLayers.Size(512, 512),\n- featureCoordSys: \"4326\",\n- filterCoordSys: \"4326\",\n- layers: null,\n- isBaseLayer: true,\n- async: true,\n- name: \"ArcIMS\"\n- },\n+ point: null,\n \n /**\n- * Constructor: OpenLayers.Layer.ArcIMS\n- * Create a new ArcIMS layer object.\n- *\n- * Example:\n- * (code)\n- * var arcims = new OpenLayers.Layer.ArcIMS(\n- * \"Global Sample\",\n- * \"http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap\", \n- * {\n- * service: \"OpenLayers_Sample\", \n- * layers: [\n- * // layers to manipulate\n- * {id: \"1\", visible: true}\n- * ]\n- * }\n- * );\n- * (end)\n+ * Constructor: OpenLayers.Control.Snapping\n+ * Creates a new snapping control. A control is constructed with an editable\n+ * layer and a set of configuration objects for target layers. While the\n+ * control is active, dragging vertices while drawing new features or\n+ * modifying existing features on the editable layer will engage\n+ * snapping to features on the target layers. Whether a vertex snaps to\n+ * a feature on a target layer depends on the target layer configuration.\n *\n * Parameters:\n- * name - {String} A name for the layer\n- * url - {String} Base url for the ArcIMS server\n- * options - {Object} Optional object with properties to be set on the\n+ * options - {Object} An object containing all configuration properties for\n+ * the control.\n+ *\n+ * Valid options:\n+ * layer - {} The editable layer. Features from this\n+ * layer that are digitized or modified may have vertices snapped to\n+ * features from any of the target layers.\n+ * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for\n+ * configuring target layers. See valid properties of the target\n+ * objects below. If the items in the targets list are vector layers\n+ * (instead of configuration objects), the defaults from the \n+ * property will apply. The editable layer itself may be a target\n+ * layer, allowing newly created or edited features to be snapped to\n+ * existing features from the same layer. If no targets are provided\n+ * the layer given in the constructor (as ) will become the\n+ * initial target.\n+ * defaults - {Object} An object with default properties to be applied\n+ * to all target objects.\n+ * greedy - {Boolean} Snap to closest feature in first target layer that\n+ * applies. Default is true. If false, all features in all target\n+ * layers will be checked and the closest feature in all target layers\n+ * will be chosen. The greedy property determines if the order of the\n+ * target layers is significant. By default, the order of the target\n+ * layers is significant where layers earlier in the target layer list\n+ * have precedence over layers later in the list. Within a single\n+ * layer, the closest feature is always chosen for snapping. This\n+ * property only determines whether the search for a closer feature\n+ * continues after an eligible feature is found in a target layer.\n+ *\n+ * Valid target properties:\n+ * layer - {} A target layer. Features from this\n+ * layer will be eligible to act as snapping target for the editable\n * layer.\n+ * tolerance - {Float} The distance (in pixels) at which snapping may occur.\n+ * Default is 10.\n+ * node - {Boolean} Snap to nodes (first or last point in a geometry) in\n+ * target layer. Default is true.\n+ * nodeTolerance - {Float} Optional distance at which snapping may occur\n+ * for nodes specifically. If none is provided, will be\n+ * used.\n+ * vertex - {Boolean} Snap to vertices in target layer. Default is true.\n+ * vertexTolerance - {Float} Optional distance at which snapping may occur\n+ * for vertices specifically. If none is provided, will be\n+ * used.\n+ * edge - {Boolean} Snap to edges in target layer. Default is true.\n+ * edgeTolerance - {Float} Optional distance at which snapping may occur\n+ * for edges specifically. If none is provided, will be\n+ * used.\n+ * filter - {} Optional filter to evaluate to determine if\n+ * feature is eligible for snapping. If filter evaluates to true for a\n+ * target feature a vertex may be snapped to the feature. \n+ * minResolution - {Number} If a minResolution is provided, snapping to this\n+ * target will only be considered if the map resolution is greater than\n+ * or equal to this value (the minResolution is inclusive). Default is\n+ * no minimum resolution limit.\n+ * maxResolution - {Number} If a maxResolution is provided, snapping to this\n+ * target will only be considered if the map resolution is strictly\n+ * less than this value (the maxResolution is exclusive). Default is\n+ * no maximum resolution limit.\n */\n- initialize: function(name, url, options) {\n-\n- this.tileSize = new OpenLayers.Size(512, 512);\n-\n- // parameters\n- this.params = OpenLayers.Util.applyDefaults({\n- ServiceName: options.serviceName\n- },\n- this.DEFAULT_PARAMS\n- );\n- this.options = OpenLayers.Util.applyDefaults(\n- options, this.DEFAULT_OPTIONS\n- );\n-\n- OpenLayers.Layer.Grid.prototype.initialize.apply(\n- this, [name, url, this.params, options]\n- );\n-\n- //layer is transparent \n- if (this.transparent) {\n-\n- // unless explicitly set in options, make layer an overlay\n- if (!this.isBaseLayer) {\n- this.isBaseLayer = false;\n- }\n+ initialize: function(options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ this.options = options || {}; // TODO: this could be done by the super\n \n- // jpegs can never be transparent, so intelligently switch the \n- // format, depending on the browser's capabilities\n- if (this.format == \"image/jpeg\") {\n- this.format = OpenLayers.Util.alphaHack() ? \"image/gif\" : \"image/png\";\n- }\n+ // set the editable layer if provided\n+ if (this.options.layer) {\n+ this.setLayer(this.options.layer);\n }\n-\n- // create an empty layer list if no layers specified in the options\n- if (this.options.layers === null) {\n- this.options.layers = [];\n+ // configure target layers\n+ var defaults = OpenLayers.Util.extend({}, this.options.defaults);\n+ this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS);\n+ this.setTargets(this.options.targets);\n+ if (this.targets.length === 0 && this.layer) {\n+ this.addTargetLayer(this.layer);\n }\n+\n+ this.geoToleranceCache = {};\n },\n \n /**\n- * Method: getURL\n- * Return an image url this layer.\n+ * APIMethod: setLayer\n+ * Set the editable layer. Call the setLayer method if the editable layer\n+ * changes and the same control should be used on a new editable layer.\n+ * If the control is already active, it will be active after the new\n+ * layer is set.\n *\n * Parameters:\n- * bounds - {} A bounds representing the bbox for the\n- * request.\n- *\n- * Returns:\n- * {String} A string with the map image's url.\n+ * layer - {} The new editable layer.\n */\n- getURL: function(bounds) {\n- var url = \"\";\n- bounds = this.adjustBounds(bounds);\n-\n- // create an arcxml request to generate the image\n- var axlReq = new OpenLayers.Format.ArcXML(\n- OpenLayers.Util.extend(this.options, {\n- requesttype: \"image\",\n- envelope: bounds.toArray(),\n- tileSize: this.tileSize\n- })\n- );\n-\n- // create a synchronous ajax request to get an arcims image\n- var req = new OpenLayers.Request.POST({\n- url: this.getFullRequestString(),\n- data: axlReq.write(),\n- async: false\n- });\n-\n- // if the response exists\n- if (req != null) {\n- var doc = req.responseXML;\n-\n- if (!doc || !doc.documentElement) {\n- doc = req.responseText;\n- }\n-\n- // create a new arcxml format to read the response\n- var axlResp = new OpenLayers.Format.ArcXML();\n- var arcxml = axlResp.read(doc);\n- url = this.getUrlOrImage(arcxml.image.output);\n+ setLayer: function(layer) {\n+ if (this.active) {\n+ this.deactivate();\n+ this.layer = layer;\n+ this.activate();\n+ } else {\n+ this.layer = layer;\n }\n-\n- return url;\n },\n \n-\n /**\n- * Method: getURLasync\n- * Get an image url this layer asynchronously, and execute a callback\n- * when the image url is generated.\n+ * Method: setTargets\n+ * Set the targets for the snapping agent.\n *\n * Parameters:\n- * bounds - {} A bounds representing the bbox for the\n- * request.\n- * callback - {Function} Function to call when image url is retrieved.\n- * scope - {Object} The scope of the callback method.\n+ * targets - {Array} An array of target configs or target layers.\n */\n- getURLasync: function(bounds, callback, scope) {\n- bounds = this.adjustBounds(bounds);\n-\n- // create an arcxml request to generate the image\n- var axlReq = new OpenLayers.Format.ArcXML(\n- OpenLayers.Util.extend(this.options, {\n- requesttype: \"image\",\n- envelope: bounds.toArray(),\n- tileSize: this.tileSize\n- })\n- );\n-\n- // create an asynchronous ajax request to get an arcims image\n- OpenLayers.Request.POST({\n- url: this.getFullRequestString(),\n- async: true,\n- data: axlReq.write(),\n- callback: function(req) {\n- // process the response from ArcIMS, and call the callback function\n- // to set the image URL\n- var doc = req.responseXML;\n- if (!doc || !doc.documentElement) {\n- doc = req.responseText;\n+ setTargets: function(targets) {\n+ this.targets = [];\n+ if (targets && targets.length) {\n+ var target;\n+ for (var i = 0, len = targets.length; i < len; ++i) {\n+ target = targets[i];\n+ if (target instanceof OpenLayers.Layer.Vector) {\n+ this.addTargetLayer(target);\n+ } else {\n+ this.addTarget(target);\n }\n+ }\n+ }\n+ },\n \n- // create a new arcxml format to read the response\n- var axlResp = new OpenLayers.Format.ArcXML();\n- var arcxml = axlResp.read(doc);\n-\n- callback.call(scope, this.getUrlOrImage(arcxml.image.output));\n- },\n- scope: this\n+ /**\n+ * Method: addTargetLayer\n+ * Add a target layer with the default target config.\n+ *\n+ * Parameters:\n+ * layer - {} A target layer.\n+ */\n+ addTargetLayer: function(layer) {\n+ this.addTarget({\n+ layer: layer\n });\n },\n \n /**\n- * Method: getUrlOrImage\n- * Extract a url or image from the ArcXML image output.\n+ * Method: addTarget\n+ * Add a configured target layer.\n *\n * Parameters:\n- * output - {Object} The image.output property of the object returned from\n- * the ArcXML format read method.\n- *\n- * Returns:\n- * {String} A URL for an image (potentially with the data protocol).\n+ * target - {Object} A target config.\n */\n- getUrlOrImage: function(output) {\n- var ret = \"\";\n- if (output.url) {\n- // If the image response output url is a string, then the image\n- // data is not inline.\n- ret = output.url;\n- } else if (output.data) {\n- // The image data is inline and base64 encoded, create a data\n- // url for the image. This will only work for small images,\n- // due to browser url length limits.\n- ret = \"data:image/\" + output.type +\n- \";base64,\" + output.data;\n- }\n- return ret;\n+ addTarget: function(target) {\n+ target = OpenLayers.Util.applyDefaults(target, this.defaults);\n+ target.nodeTolerance = target.nodeTolerance || target.tolerance;\n+ target.vertexTolerance = target.vertexTolerance || target.tolerance;\n+ target.edgeTolerance = target.edgeTolerance || target.tolerance;\n+ this.targets.push(target);\n },\n \n /**\n- * Method: setLayerQuery\n- * Set the query definition on this layer. Query definitions are used to\n- * render parts of the spatial data in an image, and can be used to\n- * filter features or layers in the ArcIMS service.\n+ * Method: removeTargetLayer\n+ * Remove a target layer.\n *\n * Parameters:\n- * id - {String} The ArcIMS layer ID.\n- * querydef - {Object} The query definition to apply to this layer.\n+ * layer - {} The target layer to remove.\n */\n- setLayerQuery: function(id, querydef) {\n- // find the matching layer, if it exists\n- for (var lyr = 0; lyr < this.options.layers.length; lyr++) {\n- if (id == this.options.layers[lyr].id) {\n- // replace this layer definition\n- this.options.layers[lyr].query = querydef;\n- return;\n+ removeTargetLayer: function(layer) {\n+ var target;\n+ for (var i = this.targets.length - 1; i >= 0; --i) {\n+ target = this.targets[i];\n+ if (target.layer === layer) {\n+ this.removeTarget(target);\n }\n }\n-\n- // no layer found, create a new definition\n- this.options.layers.push({\n- id: id,\n- visible: true,\n- query: querydef\n- });\n },\n \n /**\n- * Method: getFeatureInfo\n- * Get feature information from ArcIMS. Using the applied geometry, apply\n- * the options to the query (buffer, area/envelope intersection), and\n- * query the ArcIMS service.\n- *\n- * A note about accuracy:\n- * ArcIMS interprets the accuracy attribute in feature requests to be\n- * something like the 'modulus' operator on feature coordinates,\n- * applied to the database geometry of the feature. It doesn't round,\n- * so your feature coordinates may be up to (1 x accuracy) offset from\n- * the actual feature coordinates. If the accuracy of the layer is not\n- * specified, the accuracy will be computed to be approximately 1\n- * feature coordinate per screen pixel.\n+ * Method: removeTarget\n+ * Remove a target.\n *\n * Parameters:\n- * geometry - {} or {} The\n- * geometry to use when making the query. This should be a closed\n- * polygon for behavior approximating a free selection.\n- * layer - {Object} The ArcIMS layer definition. This is an anonymous object\n- * that looks like:\n- * (code)\n- * {\n- * id: \"ArcXML layer ID\", // the ArcXML layer ID\n- * query: {\n- * where: \"STATE = 'PA'\", // the where clause of the query\n- * accuracy: 100 // the accuracy of the returned feature\n- * }\n- * }\n- * (end)\n- * options - {Object} Object with non-default properties to set on the layer.\n- * Supported properties are buffer, callback, scope, and any other\n- * properties applicable to the ArcXML format. Set the 'callback' and\n- * 'scope' for an object and function to recieve the parsed features\n- * from ArcIMS.\n+ * target - {Object} A target config.\n+ *\n+ * Returns:\n+ * {Array} The targets array.\n */\n- getFeatureInfo: function(geometry, layer, options) {\n- // set the buffer to 1 unit (dd/m/ft?) by default\n- var buffer = options.buffer || 1;\n- // empty callback by default\n- var callback = options.callback || function() {};\n- // default scope is window (global)\n- var scope = options.scope || window;\n-\n- // apply these option to the request options\n- var requestOptions = {};\n- OpenLayers.Util.extend(requestOptions, this.options);\n-\n- // this is a feature request\n- requestOptions.requesttype = \"feature\";\n+ removeTarget: function(target) {\n+ return OpenLayers.Util.removeItem(this.targets, target);\n+ },\n \n- if (geometry instanceof OpenLayers.LonLat) {\n- // create an envelope if the geometry is really a lon/lat\n- requestOptions.polygon = null;\n- requestOptions.envelope = [\n- geometry.lon - buffer,\n- geometry.lat - buffer,\n- geometry.lon + buffer,\n- geometry.lat + buffer\n- ];\n- } else if (geometry instanceof OpenLayers.Geometry.Polygon) {\n- // use the polygon assigned, and empty the envelope\n- requestOptions.envelope = null;\n- requestOptions.polygon = geometry;\n+ /**\n+ * APIMethod: activate\n+ * Activate the control. Activating the control registers listeners for\n+ * editing related events so that during feature creation and\n+ * modification, moving vertices will trigger snapping.\n+ */\n+ activate: function() {\n+ var activated = OpenLayers.Control.prototype.activate.call(this);\n+ if (activated) {\n+ if (this.layer && this.layer.events) {\n+ this.layer.events.on({\n+ sketchstarted: this.onSketchModified,\n+ sketchmodified: this.onSketchModified,\n+ vertexmodified: this.onVertexModified,\n+ scope: this\n+ });\n+ }\n }\n+ return activated;\n+ },\n \n- // create an arcxml request to get feature requests\n- var arcxml = new OpenLayers.Format.ArcXML(requestOptions);\n-\n- // apply any get feature options to the arcxml request\n- OpenLayers.Util.extend(arcxml.request.get_feature, options);\n-\n- arcxml.request.get_feature.layer = layer.id;\n- if (typeof layer.query.accuracy == \"number\") {\n- // set the accuracy if it was specified\n- arcxml.request.get_feature.query.accuracy = layer.query.accuracy;\n- } else {\n- // guess that the accuracy is 1 per screen pixel\n- var mapCenter = this.map.getCenter();\n- var viewPx = this.map.getViewPortPxFromLonLat(mapCenter);\n- viewPx.x++;\n- var mapOffCenter = this.map.getLonLatFromPixel(viewPx);\n- arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon;\n+ /**\n+ * APIMethod: deactivate\n+ * Deactivate the control. Deactivating the control unregisters listeners\n+ * so feature editing may proceed without engaging the snapping agent.\n+ */\n+ deactivate: function() {\n+ var deactivated = OpenLayers.Control.prototype.deactivate.call(this);\n+ if (deactivated) {\n+ if (this.layer && this.layer.events) {\n+ this.layer.events.un({\n+ sketchstarted: this.onSketchModified,\n+ sketchmodified: this.onSketchModified,\n+ vertexmodified: this.onVertexModified,\n+ scope: this\n+ });\n+ }\n }\n+ this.feature = null;\n+ this.point = null;\n+ return deactivated;\n+ },\n \n- // set the get_feature query to be the same as the layer passed in\n- arcxml.request.get_feature.query.where = layer.query.where;\n-\n- // use area_intersection\n- arcxml.request.get_feature.query.spatialfilter.relation = \"area_intersection\";\n+ /**\n+ * Method: onSketchModified\n+ * Registered as a listener for the sketchmodified event on the editable\n+ * layer.\n+ *\n+ * Parameters:\n+ * event - {Object} The sketch modified event.\n+ */\n+ onSketchModified: function(event) {\n+ this.feature = event.feature;\n+ this.considerSnapping(event.vertex, event.vertex);\n+ },\n \n- // create a new asynchronous request to get the feature info\n- OpenLayers.Request.POST({\n- url: this.getFullRequestString({\n- 'CustomService': 'Query'\n- }),\n- data: arcxml.write(),\n- callback: function(request) {\n- // parse the arcxml response\n- var response = arcxml.parseResponse(request.responseText);\n+ /**\n+ * Method: onVertexModified\n+ * Registered as a listener for the vertexmodified event on the editable\n+ * layer.\n+ *\n+ * Parameters:\n+ * event - {Object} The vertex modified event.\n+ */\n+ onVertexModified: function(event) {\n+ this.feature = event.feature;\n+ var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel);\n+ this.considerSnapping(\n+ event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)\n+ );\n+ },\n \n- if (!arcxml.iserror()) {\n- // if the arcxml is not an error, call the callback with the features parsed\n- callback.call(scope, response.features);\n+ /**\n+ * Method: considerSnapping\n+ *\n+ * Parameters:\n+ * point - {} The vertex to be snapped (or\n+ * unsnapped).\n+ * loc - {} The location of the mouse in map\n+ * coords.\n+ */\n+ considerSnapping: function(point, loc) {\n+ var best = {\n+ rank: Number.POSITIVE_INFINITY,\n+ dist: Number.POSITIVE_INFINITY,\n+ x: null,\n+ y: null\n+ };\n+ var snapped = false;\n+ var result, target;\n+ for (var i = 0, len = this.targets.length; i < len; ++i) {\n+ target = this.targets[i];\n+ result = this.testTarget(target, loc);\n+ if (result) {\n+ if (this.greedy) {\n+ best = result;\n+ best.target = target;\n+ snapped = true;\n+ break;\n } else {\n- // if the arcxml is an error, return null features selected\n- callback.call(scope, null);\n+ if ((result.rank < best.rank) ||\n+ (result.rank === best.rank && result.dist < best.dist)) {\n+ best = result;\n+ best.target = target;\n+ snapped = true;\n+ }\n }\n }\n- });\n+ }\n+ if (snapped) {\n+ var proceed = this.events.triggerEvent(\"beforesnap\", {\n+ point: point,\n+ x: best.x,\n+ y: best.y,\n+ distance: best.dist,\n+ layer: best.target.layer,\n+ snapType: this.precedence[best.rank]\n+ });\n+ if (proceed !== false) {\n+ point.x = best.x;\n+ point.y = best.y;\n+ this.point = point;\n+ this.events.triggerEvent(\"snap\", {\n+ point: point,\n+ snapType: this.precedence[best.rank],\n+ layer: best.target.layer,\n+ distance: best.dist\n+ });\n+ } else {\n+ snapped = false;\n+ }\n+ }\n+ if (this.point && !snapped) {\n+ point.x = loc.x;\n+ point.y = loc.y;\n+ this.point = null;\n+ this.events.triggerEvent(\"unsnap\", {\n+ point: point\n+ });\n+ }\n },\n \n /**\n- * Method: clone\n- * Create a clone of this layer\n+ * Method: testTarget\n+ *\n+ * Parameters:\n+ * target - {Object} Object with target layer configuration.\n+ * loc - {} The location of the mouse in map\n+ * coords.\n *\n * Returns:\n- * {} An exact clone of this layer\n+ * {Object} A result object with rank, dist, x, and y properties.\n+ * Returns null if candidate is not eligible for snapping.\n */\n- clone: function(obj) {\n-\n- if (obj == null) {\n- obj = new OpenLayers.Layer.ArcIMS(this.name,\n- this.url,\n- this.getOptions());\n+ testTarget: function(target, loc) {\n+ var resolution = this.layer.map.getResolution();\n+ if (\"minResolution\" in target) {\n+ if (resolution < target.minResolution) {\n+ return null;\n+ }\n }\n+ if (\"maxResolution\" in target) {\n+ if (resolution >= target.maxResolution) {\n+ return null;\n+ }\n+ }\n+ var tolerance = {\n+ node: this.getGeoTolerance(target.nodeTolerance, resolution),\n+ vertex: this.getGeoTolerance(target.vertexTolerance, resolution),\n+ edge: this.getGeoTolerance(target.edgeTolerance, resolution)\n+ };\n+ // this could be cached if we don't support setting tolerance values directly\n+ var maxTolerance = Math.max(\n+ tolerance.node, tolerance.vertex, tolerance.edge\n+ );\n+ var result = {\n+ rank: Number.POSITIVE_INFINITY,\n+ dist: Number.POSITIVE_INFINITY\n+ };\n+ var eligible = false;\n+ var features = target.layer.features;\n+ var feature, type, vertices, vertex, closest, dist, found;\n+ var numTypes = this.precedence.length;\n+ var ll = new OpenLayers.LonLat(loc.x, loc.y);\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ feature = features[i];\n+ if (feature !== this.feature && !feature._sketch &&\n+ feature.state !== OpenLayers.State.DELETE &&\n+ (!target.filter || target.filter.evaluate(feature))) {\n+ if (feature.atPoint(ll, maxTolerance, maxTolerance)) {\n+ for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) {\n+ type = this.precedence[j];\n+ if (target[type]) {\n+ if (type === \"edge\") {\n+ closest = feature.geometry.distanceTo(loc, {\n+ details: true\n+ });\n+ dist = closest.distance;\n+ if (dist <= tolerance[type] && dist < result.dist) {\n+ result = {\n+ rank: j,\n+ dist: dist,\n+ x: closest.x0,\n+ y: closest.y0 // closest coords on feature\n+ };\n+ eligible = true;\n+ // don't look for lower precedence types for this feature\n+ break;\n+ }\n+ } else {\n+ // look for nodes or vertices\n+ vertices = feature.geometry.getVertices(type === \"node\");\n+ found = false;\n+ for (var k = 0, klen = vertices.length; k < klen; ++k) {\n+ vertex = vertices[k];\n+ dist = vertex.distanceTo(loc);\n+ if (dist <= tolerance[type] &&\n+ (j < result.rank || (j === result.rank && dist < result.dist))) {\n+ result = {\n+ rank: j,\n+ dist: dist,\n+ x: vertex.x,\n+ y: vertex.y\n+ };\n+ eligible = true;\n+ found = true;\n+ }\n+ }\n+ if (found) {\n+ // don't look for lower precedence types for this feature\n+ break;\n+ }\n+ }\n+ }\n+ }\n+ }\n+ }\n+ }\n+ return eligible ? result : null;\n+ },\n \n- //get all additions from superclasses\n- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);\n-\n- // copy/set any non-init, non-simple values here\n+ /**\n+ * Method: getGeoTolerance\n+ * Calculate a tolerance in map units given a tolerance in pixels. This\n+ * takes advantage of the when the map resolution\n+ * has not changed.\n+ * \n+ * Parameters:\n+ * tolerance - {Number} A tolerance value in pixels.\n+ * resolution - {Number} Map resolution.\n+ *\n+ * Returns:\n+ * {Number} A tolerance value in map units.\n+ */\n+ getGeoTolerance: function(tolerance, resolution) {\n+ if (resolution !== this.resolution) {\n+ this.resolution = resolution;\n+ this.geoToleranceCache = {};\n+ }\n+ var geoTolerance = this.geoToleranceCache[tolerance];\n+ if (geoTolerance === undefined) {\n+ geoTolerance = tolerance * resolution;\n+ this.geoToleranceCache[tolerance] = geoTolerance;\n+ }\n+ return geoTolerance;\n+ },\n \n- return obj;\n+ /**\n+ * Method: destroy\n+ * Clean up the control.\n+ */\n+ destroy: function() {\n+ if (this.active) {\n+ this.deactivate(); // TODO: this should be handled by the super\n+ }\n+ delete this.layer;\n+ delete this.targets;\n+ OpenLayers.Control.prototype.destroy.call(this);\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.ArcIMS\"\n+ CLASS_NAME: \"OpenLayers.Control.Snapping\"\n });\n /* ======================================================================\n- OpenLayers/Layer/WorldWind.js\n+ OpenLayers/Control/LayerSwitcher.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n- * @requires OpenLayers/Layer/Grid.js\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Lang.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Events/buttonclick.js\n */\n \n /**\n- * Class: OpenLayers.Layer.WorldWind\n- * \n+ * Class: OpenLayers.Control.LayerSwitcher\n+ * The LayerSwitcher control displays a table of contents for the map. This\n+ * allows the user interface to switch between BaseLasyers and to show or hide\n+ * Overlays. By default the switcher is shown minimized on the right edge of\n+ * the map, the user may expand it by clicking on the handle.\n+ *\n+ * To create the LayerSwitcher outside of the map, pass the Id of a html div\n+ * as the first argument to the constructor.\n+ *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, {\n+OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, {\n \n- DEFAULT_PARAMS: {},\n+ /** \n+ * Property: layerStates \n+ * {Array(Object)} Basically a copy of the \"state\" of the map's layers \n+ * the last time the control was drawn. We have this in order to avoid\n+ * unnecessarily redrawing the control.\n+ */\n+ layerStates: null,\n+\n+ // DOM Elements\n \n /**\n- * APIProperty: isBaseLayer\n- * {Boolean} WorldWind layer is a base layer by default.\n+ * Property: layersDiv\n+ * {DOMElement}\n */\n- isBaseLayer: true,\n+ layersDiv: null,\n \n- /** \n- * APIProperty: lzd\n- * {Float} LevelZeroTileSizeDegrees\n+ /**\n+ * Property: baseLayersDiv\n+ * {DOMElement}\n */\n- lzd: null,\n+ baseLayersDiv: null,\n \n /**\n- * APIProperty: zoomLevels\n- * {Integer} Number of zoom levels.\n+ * Property: baseLayers\n+ * {Array(Object)}\n */\n- zoomLevels: null,\n+ baseLayers: null,\n+\n \n /**\n- * Constructor: OpenLayers.Layer.WorldWind\n- * \n- * Parameters:\n- * name - {String} Name of Layer\n- * url - {String} Base URL \n- * lzd - {Float} Level zero tile size degrees \n- * zoomLevels - {Integer} number of zoom levels\n- * params - {Object} additional parameters\n- * options - {Object} additional options\n+ * Property: dataLbl\n+ * {DOMElement}\n */\n- initialize: function(name, url, lzd, zoomLevels, params, options) {\n- this.lzd = lzd;\n- this.zoomLevels = zoomLevels;\n- var newArguments = [];\n- newArguments.push(name, url, params, options);\n- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);\n- this.params = OpenLayers.Util.applyDefaults(\n- this.params, this.DEFAULT_PARAMS\n- );\n- },\n+ dataLbl: null,\n \n /**\n- * Method: getZoom\n- * Convert map zoom to WW zoom.\n+ * Property: dataLayersDiv\n+ * {DOMElement}\n */\n- getZoom: function() {\n- var zoom = this.map.getZoom();\n- var extent = this.map.getMaxExtent();\n- zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2);\n- return zoom;\n- },\n+ dataLayersDiv: null,\n \n /**\n- * Method: getURL\n+ * Property: dataLayers\n+ * {Array(Object)}\n+ */\n+ dataLayers: null,\n+\n+\n+ /**\n+ * Property: minimizeDiv\n+ * {DOMElement}\n+ */\n+ minimizeDiv: null,\n+\n+ /**\n+ * Property: maximizeDiv\n+ * {DOMElement}\n+ */\n+ maximizeDiv: null,\n+\n+ /**\n+ * APIProperty: ascending\n+ * {Boolean}\n+ */\n+ ascending: true,\n+\n+ /**\n+ * Constructor: OpenLayers.Control.LayerSwitcher\n *\n * Parameters:\n- * bounds - {} \n- *\n- * Returns:\n- * {String} A string with the layer's url and parameters and also the \n- * passed-in bounds and appropriate tile size specified as \n- * parameters\n+ * options - {Object}\n */\n- getURL: function(bounds) {\n- bounds = this.adjustBounds(bounds);\n- var zoom = this.getZoom();\n- var extent = this.map.getMaxExtent();\n- var deg = this.lzd / Math.pow(2, this.getZoom());\n- var x = Math.floor((bounds.left - extent.left) / deg);\n- var y = Math.floor((bounds.bottom - extent.bottom) / deg);\n- if (this.map.getResolution() <= (this.lzd / 512) &&\n- this.getZoom() <= this.zoomLevels) {\n- return this.getFullRequestString({\n- L: zoom,\n- X: x,\n- Y: y\n- });\n- } else {\n- return OpenLayers.Util.getImageLocation(\"blank.gif\");\n- }\n-\n+ initialize: function(options) {\n+ OpenLayers.Control.prototype.initialize.apply(this, arguments);\n+ this.layerStates = [];\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.WorldWind\"\n-});\n-/* ======================================================================\n- OpenLayers/Layer/ArcGIS93Rest.js\n- ====================================================================== */\n+ /**\n+ * APIMethod: destroy\n+ */\n+ destroy: function() {\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ //clear out layers info and unregister their events\n+ this.clearLayersArray(\"base\");\n+ this.clearLayersArray(\"data\");\n \n-/**\n- * @requires OpenLayers/Layer/Grid.js\n- */\n+ this.map.events.un({\n+ buttonclick: this.onButtonClick,\n+ addlayer: this.redraw,\n+ changelayer: this.redraw,\n+ removelayer: this.redraw,\n+ changebaselayer: this.redraw,\n+ scope: this\n+ });\n+ this.events.unregister(\"buttonclick\", this, this.onButtonClick);\n \n-/**\n- * Class: OpenLayers.Layer.ArcGIS93Rest\n- * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from\n- * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API.\n- * Create a new ArcGIS93Rest layer with the \n- * constructor. More detail on the REST API is available at\n- * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ;\n- * specifically, the URL provided to this layer should be an export service\n- * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html \n- * \n- * Inherits from:\n- * - \n- */\n-OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, {\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n+ },\n \n /**\n- * Constant: DEFAULT_PARAMS\n- * {Object} Hashtable of default parameter key/value pairs \n+ * Method: setMap\n+ *\n+ * Properties:\n+ * map - {}\n */\n- DEFAULT_PARAMS: {\n- format: \"png\"\n+ setMap: function(map) {\n+ OpenLayers.Control.prototype.setMap.apply(this, arguments);\n+\n+ this.map.events.on({\n+ addlayer: this.redraw,\n+ changelayer: this.redraw,\n+ removelayer: this.redraw,\n+ changebaselayer: this.redraw,\n+ scope: this\n+ });\n+ if (this.outsideViewport) {\n+ this.events.attachToElement(this.div);\n+ this.events.register(\"buttonclick\", this, this.onButtonClick);\n+ } else {\n+ this.map.events.register(\"buttonclick\", this, this.onButtonClick);\n+ }\n },\n \n /**\n- * APIProperty: isBaseLayer\n- * {Boolean} Default is true for ArcGIS93Rest layer\n+ * Method: draw\n+ *\n+ * Returns:\n+ * {DOMElement} A reference to the DIV DOMElement containing the\n+ * switcher tabs.\n */\n- isBaseLayer: true,\n+ draw: function() {\n+ OpenLayers.Control.prototype.draw.apply(this);\n+\n+ // create layout divs\n+ this.loadContents();\n+\n+ // set mode to minimize\n+ if (!this.outsideViewport) {\n+ this.minimizeControl();\n+ }\n+\n+ // populate div with current info\n+ this.redraw();\n \n+ return this.div;\n+ },\n \n /**\n- * Constructor: OpenLayers.Layer.ArcGIS93Rest\n- * Create a new ArcGIS93Rest layer object.\n- *\n- * Example:\n- * (code)\n- * var arcims = new OpenLayers.Layer.ArcGIS93Rest(\"MyName\",\n- * \"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export\", \n- * {\n- * layers: \"0,1,2\"\n- * });\n- * (end)\n+ * Method: onButtonClick\n *\n * Parameters:\n- * name - {String} A name for the layer\n- * url - {String} Base url for the ArcGIS server REST service\n- * options - {Object} An object with key/value pairs representing the\n- * options and option values.\n+ * evt - {Event}\n+ */\n+ onButtonClick: function(evt) {\n+ var button = evt.buttonElement;\n+ if (button === this.minimizeDiv) {\n+ this.minimizeControl();\n+ } else if (button === this.maximizeDiv) {\n+ this.maximizeControl();\n+ } else if (button._layerSwitcher === this.id) {\n+ if (button[\"for\"]) {\n+ button = document.getElementById(button[\"for\"]);\n+ }\n+ if (!button.disabled) {\n+ if (button.type == \"radio\") {\n+ button.checked = true;\n+ this.map.setBaseLayer(this.map.getLayer(button._layer));\n+ } else {\n+ button.checked = !button.checked;\n+ this.updateMap();\n+ }\n+ }\n+ }\n+ },\n+\n+ /**\n+ * Method: clearLayersArray\n+ * User specifies either \"base\" or \"data\". we then clear all the\n+ * corresponding listeners, the div, and reinitialize a new array.\n *\n- * Valid Options:\n- * format - {String} MIME type of desired image type.\n- * layers - {String} Comma-separated list of layers to display.\n- * srs - {String} Projection ID.\n+ * Parameters:\n+ * layersType - {String}\n */\n- initialize: function(name, url, params, options) {\n- var newArguments = [];\n- //uppercase params\n- params = OpenLayers.Util.upperCaseObject(params);\n- newArguments.push(name, url, params, options);\n- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);\n- OpenLayers.Util.applyDefaults(\n- this.params,\n- OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)\n- );\n+ clearLayersArray: function(layersType) {\n+ this[layersType + \"LayersDiv\"].innerHTML = \"\";\n+ this[layersType + \"Layers\"] = [];\n+ },\n \n- //layer is transparent \n- if (this.params.TRANSPARENT &&\n- this.params.TRANSPARENT.toString().toLowerCase() == \"true\") {\n \n- // unless explicitly set in options, make layer an overlay\n- if ((options == null) || (!options.isBaseLayer)) {\n- this.isBaseLayer = false;\n- }\n+ /**\n+ * Method: checkRedraw\n+ * Checks if the layer state has changed since the last redraw() call.\n+ *\n+ * Returns:\n+ * {Boolean} The layer state changed since the last redraw() call.\n+ */\n+ checkRedraw: function() {\n+ if (!this.layerStates.length ||\n+ (this.map.layers.length != this.layerStates.length)) {\n+ return true;\n+ }\n \n- // jpegs can never be transparent, so intelligently switch the \n- // format, depending on the browser's capabilities\n- if (this.params.FORMAT == \"jpg\") {\n- this.params.FORMAT = OpenLayers.Util.alphaHack() ? \"gif\" :\n- \"png\";\n+ for (var i = 0, len = this.layerStates.length; i < len; i++) {\n+ var layerState = this.layerStates[i];\n+ var layer = this.map.layers[i];\n+ if ((layerState.name != layer.name) ||\n+ (layerState.inRange != layer.inRange) ||\n+ (layerState.id != layer.id) ||\n+ (layerState.visibility != layer.visibility)) {\n+ return true;\n }\n }\n+\n+ return false;\n },\n \n /**\n- * Method: clone\n- * Create a clone of this layer\n+ * Method: redraw\n+ * Goes through and takes the current state of the Map and rebuilds the\n+ * control to display that state. Groups base layers into a\n+ * radio-button group and lists each data layer with a checkbox.\n *\n * Returns:\n- * {} An exact clone of this layer\n+ * {DOMElement} A reference to the DIV DOMElement containing the control\n */\n- clone: function(obj) {\n+ redraw: function() {\n+ //if the state hasn't changed since last redraw, no need\n+ // to do anything. Just return the existing div.\n+ if (!this.checkRedraw()) {\n+ return this.div;\n+ }\n \n- if (obj == null) {\n- obj = new OpenLayers.Layer.ArcGIS93Rest(this.name,\n- this.url,\n- this.params,\n- this.getOptions());\n+ //clear out previous layers\n+ this.clearLayersArray(\"base\");\n+ this.clearLayersArray(\"data\");\n+\n+ var containsOverlays = false;\n+ var containsBaseLayers = false;\n+\n+ // Save state -- for checking layer if the map state changed.\n+ // We save this before redrawing, because in the process of redrawing\n+ // we will trigger more visibility changes, and we want to not redraw\n+ // and enter an infinite loop.\n+ var len = this.map.layers.length;\n+ this.layerStates = new Array(len);\n+ for (var i = 0; i < len; i++) {\n+ var layer = this.map.layers[i];\n+ this.layerStates[i] = {\n+ 'name': layer.name,\n+ 'visibility': layer.visibility,\n+ 'inRange': layer.inRange,\n+ 'id': layer.id\n+ };\n }\n \n- //get all additions from superclasses\n- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);\n+ var layers = this.map.layers.slice();\n+ if (!this.ascending) {\n+ layers.reverse();\n+ }\n+ for (var i = 0, len = layers.length; i < len; i++) {\n+ var layer = layers[i];\n+ var baseLayer = layer.isBaseLayer;\n \n- // copy/set any non-init, non-simple values here\n+ if (layer.displayInLayerSwitcher) {\n \n- return obj;\n- },\n+ if (baseLayer) {\n+ containsBaseLayers = true;\n+ } else {\n+ containsOverlays = true;\n+ }\n \n+ // only check a baselayer if it is *the* baselayer, check data\n+ // layers if they are visible\n+ var checked = (baseLayer) ? (layer == this.map.baseLayer) :\n+ layer.getVisibility();\n \n- /**\n- * Method: getURL\n- * Return an image url this layer.\n- *\n- * Parameters:\n- * bounds - {} A bounds representing the bbox for the\n- * request.\n- *\n- * Returns:\n- * {String} A string with the map image's url.\n- */\n- getURL: function(bounds) {\n- bounds = this.adjustBounds(bounds);\n+ // create input element\n+ var inputElem = document.createElement(\"input\"),\n+ // The input shall have an id attribute so we can use\n+ // labels to interact with them.\n+ inputId = OpenLayers.Util.createUniqueID(\n+ this.id + \"_input_\"\n+ );\n \n- // ArcGIS Server only wants the numeric portion of the projection ID.\n- var projWords = this.projection.getCode().split(\":\");\n- var srid = projWords[projWords.length - 1];\n+ inputElem.id = inputId;\n+ inputElem.name = (baseLayer) ? this.id + \"_baseLayers\" : layer.name;\n+ inputElem.type = (baseLayer) ? \"radio\" : \"checkbox\";\n+ inputElem.value = layer.name;\n+ inputElem.checked = checked;\n+ inputElem.defaultChecked = checked;\n+ inputElem.className = \"olButton\";\n+ inputElem._layer = layer.id;\n+ inputElem._layerSwitcher = this.id;\n \n- var imageSize = this.getImageSize();\n- var newParams = {\n- 'BBOX': bounds.toBBOX(),\n- 'SIZE': imageSize.w + \",\" + imageSize.h,\n- // We always want image, the other options were json, image with a whole lotta html around it, etc.\n- 'F': \"image\",\n- 'BBOXSR': srid,\n- 'IMAGESR': srid\n- };\n+ if (!baseLayer && !layer.inRange) {\n+ inputElem.disabled = true;\n+ }\n \n- // Now add the filter parameters.\n- if (this.layerDefs) {\n- var layerDefStrList = [];\n- var layerID;\n- for (layerID in this.layerDefs) {\n- if (this.layerDefs.hasOwnProperty(layerID)) {\n- if (this.layerDefs[layerID]) {\n- layerDefStrList.push(layerID);\n- layerDefStrList.push(\":\");\n- layerDefStrList.push(this.layerDefs[layerID]);\n- layerDefStrList.push(\";\");\n- }\n+ // create span\n+ var labelSpan = document.createElement(\"label\");\n+ // this isn't the DOM attribute 'for', but an arbitrary name we\n+ // use to find the appropriate input element in \n+ labelSpan[\"for\"] = inputElem.id;\n+ OpenLayers.Element.addClass(labelSpan, \"labelSpan olButton\");\n+ labelSpan._layer = layer.id;\n+ labelSpan._layerSwitcher = this.id;\n+ if (!baseLayer && !layer.inRange) {\n+ labelSpan.style.color = \"gray\";\n }\n+ labelSpan.innerHTML = layer.name;\n+ labelSpan.style.verticalAlign = (baseLayer) ? \"bottom\" :\n+ \"baseline\";\n+ // create line break\n+ var br = document.createElement(\"br\");\n+\n+\n+ var groupArray = (baseLayer) ? this.baseLayers :\n+ this.dataLayers;\n+ groupArray.push({\n+ 'layer': layer,\n+ 'inputElem': inputElem,\n+ 'labelSpan': labelSpan\n+ });\n+\n+\n+ var groupDiv = (baseLayer) ? this.baseLayersDiv :\n+ this.dataLayersDiv;\n+ groupDiv.appendChild(inputElem);\n+ groupDiv.appendChild(labelSpan);\n+ groupDiv.appendChild(br);\n }\n- if (layerDefStrList.length > 0) {\n- newParams['LAYERDEFS'] = layerDefStrList.join(\"\");\n+ }\n+\n+ // if no overlays, dont display the overlay label\n+ this.dataLbl.style.display = (containsOverlays) ? \"\" : \"none\";\n+\n+ // if no baselayers, dont display the baselayer label\n+ this.baseLbl.style.display = (containsBaseLayers) ? \"\" : \"none\";\n+\n+ return this.div;\n+ },\n+\n+ /**\n+ * Method: updateMap\n+ * Cycles through the loaded data and base layer input arrays and makes\n+ * the necessary calls to the Map object such that that the map's\n+ * visual state corresponds to what the user has selected in\n+ * the control.\n+ */\n+ updateMap: function() {\n+\n+ // set the newly selected base layer\n+ for (var i = 0, len = this.baseLayers.length; i < len; i++) {\n+ var layerEntry = this.baseLayers[i];\n+ if (layerEntry.inputElem.checked) {\n+ this.map.setBaseLayer(layerEntry.layer, false);\n }\n }\n- var requestString = this.getFullRequestString(newParams);\n- return requestString;\n+\n+ // set the correct visibilities for the overlays\n+ for (var i = 0, len = this.dataLayers.length; i < len; i++) {\n+ var layerEntry = this.dataLayers[i];\n+ layerEntry.layer.setVisibility(layerEntry.inputElem.checked);\n+ }\n+\n },\n \n /**\n- * Method: setLayerFilter\n- * addTile creates a tile, initializes it, and adds it to the layer div. \n+ * Method: maximizeControl\n+ * Set up the labels and divs for the control\n *\n * Parameters:\n- * id - {String} The id of the layer to which the filter applies.\n- * queryDef - {String} A sql-ish query filter, for more detail see the ESRI\n- * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html\n+ * e - {Event}\n */\n- setLayerFilter: function(id, queryDef) {\n- if (!this.layerDefs) {\n- this.layerDefs = {};\n- }\n- if (queryDef) {\n- this.layerDefs[id] = queryDef;\n- } else {\n- delete this.layerDefs[id];\n+ maximizeControl: function(e) {\n+\n+ // set the div's width and height to empty values, so\n+ // the div dimensions can be controlled by CSS\n+ this.div.style.width = \"\";\n+ this.div.style.height = \"\";\n+\n+ this.showControls(false);\n+\n+ if (e != null) {\n+ OpenLayers.Event.stop(e);\n }\n },\n \n /**\n- * Method: clearLayerFilter\n- * Clears layer filters, either from a specific layer,\n- * or all of them.\n+ * Method: minimizeControl\n+ * Hide all the contents of the control, shrink the size,\n+ * add the maximize icon\n *\n * Parameters:\n- * id - {String} The id of the layer from which to remove any\n- * filter. If unspecified/blank, all filters\n- * will be removed.\n+ * e - {Event}\n */\n- clearLayerFilter: function(id) {\n- if (id) {\n- delete this.layerDefs[id];\n- } else {\n- delete this.layerDefs;\n+ minimizeControl: function(e) {\n+\n+ // to minimize the control we set its div's width\n+ // and height to 0px, we cannot just set \"display\"\n+ // to \"none\" because it would hide the maximize\n+ // div\n+ this.div.style.width = \"0px\";\n+ this.div.style.height = \"0px\";\n+\n+ this.showControls(true);\n+\n+ if (e != null) {\n+ OpenLayers.Event.stop(e);\n }\n },\n \n /**\n- * APIMethod: mergeNewParams\n- * Catch changeParams and uppercase the new params to be merged in\n- * before calling changeParams on the super class.\n- * \n- * Once params have been changed, the tiles will be reloaded with\n- * the new parameters.\n- * \n+ * Method: showControls\n+ * Hide/Show all LayerSwitcher controls depending on whether we are\n+ * minimized or not\n+ *\n * Parameters:\n- * newParams - {Object} Hashtable of new params to use\n+ * minimize - {Boolean}\n */\n- mergeNewParams: function(newParams) {\n- var upperParams = OpenLayers.Util.upperCaseObject(newParams);\n- var newArguments = [upperParams];\n- return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,\n- newArguments);\n+ showControls: function(minimize) {\n+\n+ this.maximizeDiv.style.display = minimize ? \"\" : \"none\";\n+ this.minimizeDiv.style.display = minimize ? \"none\" : \"\";\n+\n+ this.layersDiv.style.display = minimize ? \"none\" : \"\";\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.ArcGIS93Rest\"\n+ /**\n+ * Method: loadContents\n+ * Set up the labels and divs for the control\n+ */\n+ loadContents: function() {\n+\n+ // layers list div\n+ this.layersDiv = document.createElement(\"div\");\n+ this.layersDiv.id = this.id + \"_layersDiv\";\n+ OpenLayers.Element.addClass(this.layersDiv, \"layersDiv\");\n+\n+ this.baseLbl = document.createElement(\"div\");\n+ this.baseLbl.innerHTML = OpenLayers.i18n(\"Base Layer\");\n+ OpenLayers.Element.addClass(this.baseLbl, \"baseLbl\");\n+\n+ this.baseLayersDiv = document.createElement(\"div\");\n+ OpenLayers.Element.addClass(this.baseLayersDiv, \"baseLayersDiv\");\n+\n+ this.dataLbl = document.createElement(\"div\");\n+ this.dataLbl.innerHTML = OpenLayers.i18n(\"Overlays\");\n+ OpenLayers.Element.addClass(this.dataLbl, \"dataLbl\");\n+\n+ this.dataLayersDiv = document.createElement(\"div\");\n+ OpenLayers.Element.addClass(this.dataLayersDiv, \"dataLayersDiv\");\n+\n+ if (this.ascending) {\n+ this.layersDiv.appendChild(this.baseLbl);\n+ this.layersDiv.appendChild(this.baseLayersDiv);\n+ this.layersDiv.appendChild(this.dataLbl);\n+ this.layersDiv.appendChild(this.dataLayersDiv);\n+ } else {\n+ this.layersDiv.appendChild(this.dataLbl);\n+ this.layersDiv.appendChild(this.dataLayersDiv);\n+ this.layersDiv.appendChild(this.baseLbl);\n+ this.layersDiv.appendChild(this.baseLayersDiv);\n+ }\n+\n+ this.div.appendChild(this.layersDiv);\n+\n+ // maximize button div\n+ var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');\n+ this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(\n+ \"OpenLayers_Control_MaximizeDiv\",\n+ null,\n+ null,\n+ img,\n+ \"absolute\");\n+ OpenLayers.Element.addClass(this.maximizeDiv, \"maximizeDiv olButton\");\n+ this.maximizeDiv.style.display = \"none\";\n+\n+ this.div.appendChild(this.maximizeDiv);\n+\n+ // minimize button div\n+ var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');\n+ this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(\n+ \"OpenLayers_Control_MinimizeDiv\",\n+ null,\n+ null,\n+ img,\n+ \"absolute\");\n+ OpenLayers.Element.addClass(this.minimizeDiv, \"minimizeDiv olButton\");\n+ this.minimizeDiv.style.display = \"none\";\n+\n+ this.div.appendChild(this.minimizeDiv);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control.LayerSwitcher\"\n });\n /* ======================================================================\n- OpenLayers/Layer/XYZ.js\n+ OpenLayers/Control/ArgParser.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n- * @requires OpenLayers/Layer/Grid.js\n+ * @requires OpenLayers/Control.js\n */\n \n-/** \n- * Class: OpenLayers.Layer.XYZ\n- * The XYZ class is designed to make it easier for people who have tiles\n- * arranged by a standard XYZ grid. \n- * \n+/**\n+ * Class: OpenLayers.Control.ArgParser\n+ * The ArgParser control adds location bar query string parsing functionality \n+ * to an OpenLayers Map.\n+ * When added to a Map control, on a page load/refresh, the Map will \n+ * automatically take the href string and parse it for lon, lat, zoom, and \n+ * layers information. \n+ *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {\n+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {\n \n /**\n- * APIProperty: isBaseLayer\n- * Default is true, as this is designed to be a base tile source. \n+ * Property: center\n+ * {}\n */\n- isBaseLayer: true,\n+ center: null,\n \n /**\n- * APIProperty: sphericalMercator\n- * Whether the tile extents should be set to the defaults for \n- * spherical mercator. Useful for things like OpenStreetMap.\n- * Default is false, except for the OSM subclass.\n+ * Property: zoom\n+ * {int}\n */\n- sphericalMercator: false,\n+ zoom: null,\n \n /**\n- * APIProperty: zoomOffset\n- * {Number} If your cache has more zoom levels than you want to provide\n- * access to with this layer, supply a zoomOffset. This zoom offset\n- * is added to the current map zoom level to determine the level\n- * for a requested tile. For example, if you supply a zoomOffset\n- * of 3, when the map is at the zoom 0, tiles will be requested from\n- * level 3 of your cache. Default is 0 (assumes cache level and map\n- * zoom are equivalent). Using is an alternative to\n- * setting if you only want to expose a subset\n- * of the server resolutions.\n+ * Property: layers\n+ * {String} Each character represents the state of the corresponding layer \n+ * on the map.\n */\n- zoomOffset: 0,\n+ layers: null,\n \n- /**\n- * APIProperty: serverResolutions\n- * {Array} A list of all resolutions available on the server. Only set this\n- * property if the map resolutions differ from the server. This\n- * property serves two purposes. (a) can include\n- * resolutions that the server supports and that you don't want to\n- * provide with this layer; you can also look at , which is\n- * an alternative to for that specific purpose.\n- * (b) The map can work with resolutions that aren't supported by\n- * the server, i.e. that aren't in . When the\n- * map is displayed in such a resolution data for the closest\n- * server-supported resolution is loaded and the layer div is\n- * stretched as necessary.\n+ /** \n+ * APIProperty: displayProjection\n+ * {} Requires proj4js support. \n+ * Projection used when reading the coordinates from the URL. This will\n+ * reproject the map coordinates from the URL into the map's\n+ * projection.\n+ *\n+ * If you are using this functionality, be aware that any permalink\n+ * which is added to the map will determine the coordinate type which\n+ * is read from the URL, which means you should not add permalinks with\n+ * different displayProjections to the same map. \n */\n- serverResolutions: null,\n+ displayProjection: null,\n \n /**\n- * Constructor: OpenLayers.Layer.XYZ\n+ * Constructor: OpenLayers.Control.ArgParser\n *\n * Parameters:\n- * name - {String}\n- * url - {String}\n- * options - {Object} Hashtable of extra options to tag onto the layer\n+ * options - {Object}\n */\n- initialize: function(name, url, options) {\n- if (options && options.sphericalMercator || this.sphericalMercator) {\n- options = OpenLayers.Util.extend({\n- projection: \"EPSG:900913\",\n- numZoomLevels: 19\n- }, options);\n- }\n- OpenLayers.Layer.Grid.prototype.initialize.apply(this, [\n- name || this.name, url || this.url, {},\n- options\n- ]);\n- },\n \n /**\n- * APIMethod: clone\n- * Create a clone of this layer\n- *\n- * Parameters:\n- * obj - {Object} Is this ever used?\n- * \n- * Returns:\n- * {} An exact clone of this OpenLayers.Layer.XYZ\n+ * Method: getParameters\n */\n- clone: function(obj) {\n-\n- if (obj == null) {\n- obj = new OpenLayers.Layer.XYZ(this.name,\n- this.url,\n- this.getOptions());\n- }\n+ getParameters: function(url) {\n+ url = url || window.location.href;\n+ var parameters = OpenLayers.Util.getParameters(url);\n \n- //get all additions from superclasses\n- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);\n+ // If we have an anchor in the url use it to split the url\n+ var index = url.indexOf('#');\n+ if (index > 0) {\n+ // create an url to parse on the getParameters\n+ url = '?' + url.substring(index + 1, url.length);\n \n- return obj;\n+ OpenLayers.Util.extend(parameters,\n+ OpenLayers.Util.getParameters(url));\n+ }\n+ return parameters;\n },\n \n /**\n- * Method: getURL\n- *\n+ * Method: setMap\n+ * Set the map property for the control. \n+ * \n * Parameters:\n- * bounds - {}\n- *\n- * Returns:\n- * {String} A string with the layer's url and parameters and also the\n- * passed-in bounds and appropriate tile size specified as\n- * parameters\n+ * map - {} \n */\n- getURL: function(bounds) {\n- var xyz = this.getXYZ(bounds);\n- var url = this.url;\n- if (OpenLayers.Util.isArray(url)) {\n- var s = '' + xyz.x + xyz.y + xyz.z;\n- url = this.selectUrl(s, url);\n+ setMap: function(map) {\n+ OpenLayers.Control.prototype.setMap.apply(this, arguments);\n+\n+ //make sure we dont already have an arg parser attached\n+ for (var i = 0, len = this.map.controls.length; i < len; i++) {\n+ var control = this.map.controls[i];\n+ if ((control != this) &&\n+ (control.CLASS_NAME == \"OpenLayers.Control.ArgParser\")) {\n+\n+ // If a second argparser is added to the map, then we \n+ // override the displayProjection to be the one added to the\n+ // map. \n+ if (control.displayProjection != this.displayProjection) {\n+ this.displayProjection = control.displayProjection;\n+ }\n+\n+ break;\n+ }\n }\n+ if (i == this.map.controls.length) {\n \n- return OpenLayers.String.format(url, xyz);\n+ var args = this.getParameters();\n+ // Be careful to set layer first, to not trigger unnecessary layer loads\n+ if (args.layers) {\n+ this.layers = args.layers;\n+\n+ // when we add a new layer, set its visibility \n+ this.map.events.register('addlayer', this,\n+ this.configureLayers);\n+ this.configureLayers();\n+ }\n+ if (args.lat && args.lon) {\n+ this.center = new OpenLayers.LonLat(parseFloat(args.lon),\n+ parseFloat(args.lat));\n+ if (args.zoom) {\n+ this.zoom = parseFloat(args.zoom);\n+ }\n+\n+ // when we add a new baselayer to see when we can set the center\n+ this.map.events.register('changebaselayer', this,\n+ this.setCenter);\n+ this.setCenter();\n+ }\n+ }\n },\n \n- /**\n- * Method: getXYZ\n- * Calculates x, y and z for the given bounds.\n- *\n- * Parameters:\n- * bounds - {}\n- *\n- * Returns:\n- * {Object} - an object with x, y and z properties.\n+ /** \n+ * Method: setCenter\n+ * As soon as a baseLayer has been loaded, we center and zoom\n+ * ...and remove the handler.\n */\n- getXYZ: function(bounds) {\n- var res = this.getServerResolution();\n- var x = Math.round((bounds.left - this.maxExtent.left) /\n- (res * this.tileSize.w));\n- var y = Math.round((this.maxExtent.top - bounds.top) /\n- (res * this.tileSize.h));\n- var z = this.getServerZoom();\n+ setCenter: function() {\n \n- if (this.wrapDateLine) {\n- var limit = Math.pow(2, z);\n- x = ((x % limit) + limit) % limit;\n- }\n+ if (this.map.baseLayer) {\n+ //dont need to listen for this one anymore\n+ this.map.events.unregister('changebaselayer', this,\n+ this.setCenter);\n \n- return {\n- 'x': x,\n- 'y': y,\n- 'z': z\n- };\n+ if (this.displayProjection) {\n+ this.center.transform(this.displayProjection,\n+ this.map.getProjectionObject());\n+ }\n+\n+ this.map.setCenter(this.center, this.zoom);\n+ }\n },\n \n- /* APIMethod: setMap\n- * When the layer is added to a map, then we can fetch our origin \n- * (if we don't have one.) \n- * \n- * Parameters:\n- * map - {}\n+ /** \n+ * Method: configureLayers\n+ * As soon as all the layers are loaded, cycle through them and \n+ * hide or show them. \n */\n- setMap: function(map) {\n- OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);\n- if (!this.tileOrigin) {\n- this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left,\n- this.maxExtent.bottom);\n+ configureLayers: function() {\n+\n+ if (this.layers.length == this.map.layers.length) {\n+ this.map.events.unregister('addlayer', this, this.configureLayers);\n+\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+\n+ var layer = this.map.layers[i];\n+ var c = this.layers.charAt(i);\n+\n+ if (c == \"B\") {\n+ this.map.setBaseLayer(layer);\n+ } else if ((c == \"T\") || (c == \"F\")) {\n+ layer.setVisibility(c == \"T\");\n+ }\n+ }\n }\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.XYZ\"\n+ CLASS_NAME: \"OpenLayers.Control.ArgParser\"\n });\n /* ======================================================================\n- OpenLayers/Tile/UTFGrid.js\n+ OpenLayers/Control/Permalink.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n \n /**\n- * @requires OpenLayers/Tile.js\n- * @requires OpenLayers/Format/JSON.js\n- * @requires OpenLayers/Request.js\n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/Control/ArgParser.js\n+ * @requires OpenLayers/Lang.js\n */\n \n /**\n- * Class: OpenLayers.Tile.UTFGrid\n- * Instances of OpenLayers.Tile.UTFGrid are used to manage \n- * UTFGrids. This is an unusual tile type in that it doesn't have a\n- * rendered image; only a 'hit grid' that can be used to \n- * look up feature attributes.\n- *\n- * See the constructor for details on constructing a\n- * new instance.\n- *\n+ * Class: OpenLayers.Control.Permalink\n+ * The Permalink control is hyperlink that will return the user to the \n+ * current map view. By default it is drawn in the lower right corner of the\n+ * map. The href is updated as the map is zoomed, panned and whilst layers\n+ * are switched.\n+ * \n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, {\n-\n- /** \n- * Property: url\n- * {String}\n- * The URL of the UTFGrid file being requested. Provided by the \n- * method. \n- */\n- url: null,\n+OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {\n \n /**\n- * Property: utfgridResolution\n- * {Number}\n- * Ratio of the pixel width to the width of a UTFGrid data point. If an \n- * entry in the grid represents a 4x4 block of pixels, the \n- * utfgridResolution would be 4. Default is 2.\n+ * APIProperty: argParserClass\n+ * {Class} The ArgParser control class (not instance) to use with this\n+ * control.\n */\n- utfgridResolution: 2,\n+ argParserClass: OpenLayers.Control.ArgParser,\n \n /** \n- * Property: json\n- * {Object}\n- * Stores the parsed JSON tile data structure. \n+ * Property: element \n+ * {DOMElement}\n */\n- json: null,\n+ element: null,\n \n /** \n- * Property: format\n- * {OpenLayers.Format.JSON}\n- * Parser instance used to parse JSON for cross browser support. The native\n- * JSON.parse method will be used where available (all except IE<8).\n+ * APIProperty: anchor\n+ * {Boolean} This option changes 3 things:\n+ * the character '#' is used in place of the character '?',\n+ * the window.href is updated if no element is provided.\n+ * When this option is set to true it's not recommend to provide\n+ * a base without provide an element.\n */\n- format: null,\n+ anchor: false,\n \n /** \n- * Constructor: OpenLayers.Tile.UTFGrid\n- * Constructor for a new instance.\n- * \n- * Parameters:\n- * layer - {} layer that the tile will go in.\n- * position - {}\n- * bounds - {}\n- * url - {} Deprecated. Remove me in 3.0.\n- * size - {}\n- * options - {Object}\n+ * APIProperty: base\n+ * {String}\n */\n+ base: '',\n \n /** \n- * APIMethod: destroy\n- * Clean up.\n+ * APIProperty: displayProjection\n+ * {} Requires proj4js support. Projection used\n+ * when creating the coordinates in the link. This will reproject the\n+ * map coordinates into display coordinates. If you are using this\n+ * functionality, the permalink which is last added to the map will\n+ * determine the coordinate type which is read from the URL, which\n+ * means you should not add permalinks with different\n+ * displayProjections to the same map. \n */\n- destroy: function() {\n- this.clear();\n- OpenLayers.Tile.prototype.destroy.apply(this, arguments);\n- },\n+ displayProjection: null,\n \n /**\n- * Method: draw\n- * Check that a tile should be drawn, and draw it.\n- * In the case of UTFGrids, \"drawing\" it means fetching and\n- * parsing the json. \n- * \n- * Returns:\n- * {Boolean} Was a tile drawn?\n+ * Constructor: OpenLayers.Control.Permalink\n+ *\n+ * Parameters: \n+ * element - {DOMElement} \n+ * base - {String} \n+ * options - {Object} options to the control.\n+ *\n+ * Or for anchor:\n+ * options - {Object} options to the control.\n */\n- draw: function() {\n- var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments);\n- if (drawn) {\n- if (this.isLoading) {\n- this.abortLoading();\n- //if we're already loading, send 'reload' instead of 'loadstart'.\n- this.events.triggerEvent(\"reload\");\n- } else {\n- this.isLoading = true;\n- this.events.triggerEvent(\"loadstart\");\n- }\n- this.url = this.layer.getURL(this.bounds);\n-\n- if (this.layer.useJSONP) {\n- // Use JSONP method to avoid xbrowser policy\n- var ols = new OpenLayers.Protocol.Script({\n- url: this.url,\n- callback: function(response) {\n- this.isLoading = false;\n- this.events.triggerEvent(\"loadend\");\n- this.json = response.data;\n- },\n- scope: this\n- });\n- ols.read();\n- this.request = ols;\n- } else {\n- // Use standard XHR\n- this.request = OpenLayers.Request.GET({\n- url: this.url,\n- callback: function(response) {\n- this.isLoading = false;\n- this.events.triggerEvent(\"loadend\");\n- if (response.status === 200) {\n- this.parseData(response.responseText);\n- }\n- },\n- scope: this\n- });\n+ initialize: function(element, base, options) {\n+ if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) {\n+ options = element;\n+ this.base = document.location.href;\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ if (this.element != null) {\n+ this.element = OpenLayers.Util.getElement(this.element);\n }\n } else {\n- this.unload();\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n+ this.element = OpenLayers.Util.getElement(element);\n+ this.base = base || document.location.href;\n }\n- return drawn;\n },\n \n /**\n- * Method: abortLoading\n- * Cancel a pending request.\n+ * APIMethod: destroy\n */\n- abortLoading: function() {\n- if (this.request) {\n- this.request.abort();\n- delete this.request;\n+ destroy: function() {\n+ if (this.element && this.element.parentNode == this.div) {\n+ this.div.removeChild(this.element);\n+ this.element = null;\n }\n- this.isLoading = false;\n+ if (this.map) {\n+ this.map.events.unregister('moveend', this, this.updateLink);\n+ }\n+\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n },\n \n /**\n- * Method: getFeatureInfo\n- * Get feature information associated with a pixel offset. If the pixel\n- * offset corresponds to a feature, the returned object will have id\n- * and data properties. Otherwise, null will be returned.\n- * \n- *\n+ * Method: setMap\n+ * Set the map property for the control. \n+ * \n * Parameters:\n- * i - {Number} X-axis pixel offset (from top left of tile)\n- * j - {Number} Y-axis pixel offset (from top left of tile)\n- *\n- * Returns:\n- * {Object} Object with feature id and data properties corresponding to the \n- * given pixel offset.\n+ * map - {} \n */\n- getFeatureInfo: function(i, j) {\n- var info = null;\n- if (this.json) {\n- var id = this.getFeatureId(i, j);\n- if (id !== null) {\n- info = {\n- id: id,\n- data: this.json.data[id]\n- };\n+ setMap: function(map) {\n+ OpenLayers.Control.prototype.setMap.apply(this, arguments);\n+\n+ //make sure we have an arg parser attached\n+ for (var i = 0, len = this.map.controls.length; i < len; i++) {\n+ var control = this.map.controls[i];\n+ if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) {\n+\n+ // If a permalink is added to the map, and an ArgParser already\n+ // exists, we override the displayProjection to be the one\n+ // on the permalink. \n+ if (control.displayProjection != this.displayProjection) {\n+ this.displayProjection = control.displayProjection;\n+ }\n+\n+ break;\n }\n }\n- return info;\n+ if (i == this.map.controls.length) {\n+ this.map.addControl(new this.argParserClass({\n+ 'displayProjection': this.displayProjection\n+ }));\n+ }\n+\n },\n \n /**\n- * Method: getFeatureId\n- * Get the identifier for the feature associated with a pixel offset.\n- *\n- * Parameters:\n- * i - {Number} X-axis pixel offset (from top left of tile)\n- * j - {Number} Y-axis pixel offset (from top left of tile)\n+ * Method: draw\n *\n * Returns:\n- * {Object} The feature identifier corresponding to the given pixel offset.\n- * Returns null if pixel doesn't correspond to a feature.\n+ * {DOMElement}\n */\n- getFeatureId: function(i, j) {\n- var id = null;\n- if (this.json) {\n- var resolution = this.utfgridResolution;\n- var row = Math.floor(j / resolution);\n- var col = Math.floor(i / resolution);\n- var charCode = this.json.grid[row].charCodeAt(col);\n- var index = this.indexFromCharCode(charCode);\n- var keys = this.json.keys;\n- if (!isNaN(index) && (index in keys)) {\n- id = keys[index];\n- }\n+ draw: function() {\n+ OpenLayers.Control.prototype.draw.apply(this, arguments);\n+\n+ if (!this.element && !this.anchor) {\n+ this.element = document.createElement(\"a\");\n+ this.element.innerHTML = OpenLayers.i18n(\"Permalink\");\n+ this.element.href = \"\";\n+ this.div.appendChild(this.element);\n }\n- return id;\n+ this.map.events.on({\n+ 'moveend': this.updateLink,\n+ 'changelayer': this.updateLink,\n+ 'changebaselayer': this.updateLink,\n+ scope: this\n+ });\n+\n+ // Make it so there is at least a link even though the map may not have\n+ // moved yet.\n+ this.updateLink();\n+\n+ return this.div;\n },\n \n /**\n- * Method: indexFromCharCode\n- * Given a character code for one of the UTFGrid \"grid\" characters, \n- * resolve the integer index for the feature id in the UTFGrid \"keys\"\n- * array.\n- *\n- * Parameters:\n- * charCode - {Integer}\n- *\n- * Returns:\n- * {Integer} Index for the feature id from the keys array.\n+ * Method: updateLink \n */\n- indexFromCharCode: function(charCode) {\n- if (charCode >= 93) {\n- charCode--;\n+ updateLink: function() {\n+ var separator = this.anchor ? '#' : '?';\n+ var href = this.base;\n+ var anchor = null;\n+ if (href.indexOf(\"#\") != -1 && this.anchor == false) {\n+ anchor = href.substring(href.indexOf(\"#\"), href.length);\n }\n- if (charCode >= 35) {\n- charCode--;\n+ if (href.indexOf(separator) != -1) {\n+ href = href.substring(0, href.indexOf(separator));\n+ }\n+ var splits = href.split(\"#\");\n+ href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams());\n+ if (anchor) {\n+ href += anchor;\n+ }\n+ if (this.anchor && !this.element) {\n+ window.location.href = href;\n+ } else {\n+ this.element.href = href;\n }\n- return charCode - 32;\n },\n \n /**\n- * Method: parseData\n- * Parse the JSON from a request\n- *\n+ * APIMethod: createParams\n+ * Creates the parameters that need to be encoded into the permalink url.\n+ * \n * Parameters:\n- * str - {String} UTFGrid as a JSON string. \n+ * center - {} center to encode in the permalink.\n+ * Defaults to the current map center.\n+ * zoom - {Integer} zoom level to encode in the permalink. Defaults to the\n+ * current map zoom level.\n+ * layers - {Array()} layers to encode in the permalink.\n+ * Defaults to the current map layers.\n * \n * Returns:\n- * {Object} parsed javascript data\n+ * {Object} Hash of parameters that will be url-encoded into the\n+ * permalink.\n */\n- parseData: function(str) {\n- if (!this.format) {\n- this.format = new OpenLayers.Format.JSON();\n+ createParams: function(center, zoom, layers) {\n+ center = center || this.map.getCenter();\n+\n+ var params = OpenLayers.Util.getParameters(this.base);\n+\n+ // If there's still no center, map is not initialized yet. \n+ // Break out of this function, and simply return the params from the\n+ // base link.\n+ if (center) {\n+\n+ //zoom\n+ params.zoom = zoom || this.map.getZoom();\n+\n+ //lon,lat\n+ var lat = center.lat;\n+ var lon = center.lon;\n+\n+ if (this.displayProjection) {\n+ var mapPosition = OpenLayers.Projection.transform({\n+ x: lon,\n+ y: lat\n+ },\n+ this.map.getProjectionObject(),\n+ this.displayProjection);\n+ lon = mapPosition.x;\n+ lat = mapPosition.y;\n+ }\n+ params.lat = Math.round(lat * 100000) / 100000;\n+ params.lon = Math.round(lon * 100000) / 100000;\n+\n+ //layers \n+ layers = layers || this.map.layers;\n+ params.layers = '';\n+ for (var i = 0, len = layers.length; i < len; i++) {\n+ var layer = layers[i];\n+\n+ if (layer.isBaseLayer) {\n+ params.layers += (layer == this.map.baseLayer) ? \"B\" : \"0\";\n+ } else {\n+ params.layers += (layer.getVisibility()) ? \"T\" : \"F\";\n+ }\n+ }\n }\n- this.json = this.format.read(str);\n- },\n \n- /** \n- * Method: clear\n- * Delete data stored with this tile.\n- */\n- clear: function() {\n- this.json = null;\n+ return params;\n },\n \n- CLASS_NAME: \"OpenLayers.Tile.UTFGrid\"\n-\n+ CLASS_NAME: \"OpenLayers.Control.Permalink\"\n });\n /* ======================================================================\n- OpenLayers/Layer/UTFGrid.js\n+ OpenLayers/Handler/MouseWheel.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Layer/XYZ.js\n- * @requires OpenLayers/Tile/UTFGrid.js\n+ * @requires OpenLayers/Handler.js\n */\n \n-/** \n- * Class: OpenLayers.Layer.UTFGrid\n- * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are \n- * essentially JSON-based ASCII art with attached attributes, they are not \n- * visibly rendered. In order to use them in the map, you must add a \n- * control as well.\n- *\n- * Example:\n- *\n- * (start code)\n- * var world_utfgrid = new OpenLayers.Layer.UTFGrid({\n- * url: \"/tiles/world_utfgrid/${z}/${x}/${y}.json\",\n- * utfgridResolution: 4,\n- * displayInLayerSwitcher: false\n- * );\n- * map.addLayer(world_utfgrid);\n- * \n- * var control = new OpenLayers.Control.UTFGrid({\n- * layers: [world_utfgrid],\n- * handlerMode: 'move',\n- * callback: function(dataLookup) {\n- * // do something with returned data\n- * }\n- * })\n- * (end code)\n- *\n+/**\n+ * Class: OpenLayers.Handler.MouseWheel\n+ * Handler for wheel up/down events.\n * \n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, {\n-\n- /**\n- * APIProperty: isBaseLayer\n- * Default is false, as UTFGrids are designed to be a transparent overlay layer. \n- */\n- isBaseLayer: false,\n-\n- /**\n- * APIProperty: projection\n- * {}\n- * Source projection for the UTFGrids. Default is \"EPSG:900913\".\n+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {\n+ /** \n+ * Property: wheelListener \n+ * {function} \n */\n- projection: new OpenLayers.Projection(\"EPSG:900913\"),\n+ wheelListener: null,\n \n /**\n- * Property: useJSONP\n- * {Boolean}\n- * Should we use a JSONP script approach instead of a standard AJAX call?\n- *\n- * Set to true for using utfgrids from another server. \n- * Avoids same-domain policy restrictions. \n- * Note that this only works if the server accepts \n- * the callback GET parameter and dynamically \n- * wraps the returned json in a function call.\n- * \n- * Default is false\n+ * Property: interval\n+ * {Integer} In order to increase server performance, an interval (in \n+ * milliseconds) can be set to reduce the number of up/down events \n+ * called. If set, a new up/down event will not be set until the \n+ * interval has passed. \n+ * Defaults to 0, meaning no interval. \n */\n- useJSONP: false,\n+ interval: 0,\n \n /**\n- * APIProperty: url\n- * {String}\n- * URL tempate for UTFGrid tiles. Include x, y, and z parameters.\n- * E.g. \"/tiles/${z}/${x}/${y}.json\"\n+ * Property: maxDelta\n+ * {Integer} Maximum delta to collect before breaking from the current\n+ * interval. In cumulative mode, this also limits the maximum delta\n+ * returned from the handler. Default is Number.POSITIVE_INFINITY.\n */\n+ maxDelta: Number.POSITIVE_INFINITY,\n \n /**\n- * APIProperty: utfgridResolution\n- * {Number}\n- * Ratio of the pixel width to the width of a UTFGrid data point. If an \n- * entry in the grid represents a 4x4 block of pixels, the \n- * utfgridResolution would be 4. Default is 2 (specified in \n- * ).\n+ * Property: delta\n+ * {Integer} When interval is set, delta collects the mousewheel z-deltas\n+ * of the events that occur within the interval.\n+ * See also the cumulative option\n */\n+ delta: 0,\n \n /**\n- * Property: tileClass\n- * {} The tile class to use for this layer.\n- * Defaults is .\n+ * Property: cumulative\n+ * {Boolean} When interval is set: true to collect all the mousewheel \n+ * z-deltas, false to only record the delta direction (positive or\n+ * negative)\n */\n- tileClass: OpenLayers.Tile.UTFGrid,\n+ cumulative: true,\n \n /**\n- * Constructor: OpenLayers.Layer.UTFGrid\n- * Create a new UTFGrid layer.\n+ * Constructor: OpenLayers.Handler.MouseWheel\n *\n * Parameters:\n- * config - {Object} Configuration properties for the layer.\n- *\n- * Required configuration properties:\n- * url - {String} The url template for UTFGrid tiles. See the property.\n+ * control - {} \n+ * callbacks - {Object} An object containing a single function to be\n+ * called when the drag operation is finished.\n+ * The callback should expect to recieve a single\n+ * argument, the point geometry.\n+ * options - {Object} \n */\n- initialize: function(options) {\n- OpenLayers.Layer.Grid.prototype.initialize.apply(\n- this, [options.name, options.url, {}, options]\n+ initialize: function(control, callbacks, options) {\n+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);\n+ this.wheelListener = OpenLayers.Function.bindAsEventListener(\n+ this.onWheelEvent, this\n );\n- this.tileOptions = OpenLayers.Util.extend({\n- utfgridResolution: this.utfgridResolution\n- }, this.tileOptions);\n },\n \n /**\n- * Method: createBackBuffer\n- * The UTFGrid cannot create a back buffer, so this method is overriden.\n+ * Method: destroy\n */\n- createBackBuffer: function() {},\n+ destroy: function() {\n+ OpenLayers.Handler.prototype.destroy.apply(this, arguments);\n+ this.wheelListener = null;\n+ },\n \n /**\n- * APIMethod: clone\n- * Create a clone of this layer\n- *\n- * Parameters:\n- * obj - {Object} Only used by a subclass of this layer.\n+ * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/\n+ */\n+\n+ /** \n+ * Method: onWheelEvent\n+ * Catch the wheel event and handle it xbrowserly\n * \n- * Returns:\n- * {} An exact clone of this OpenLayers.Layer.UTFGrid\n+ * Parameters:\n+ * e - {Event} \n */\n- clone: function(obj) {\n- if (obj == null) {\n- obj = new OpenLayers.Layer.UTFGrid(this.getOptions());\n+ onWheelEvent: function(e) {\n+\n+ // make sure we have a map and check keyboard modifiers\n+ if (!this.map || !this.checkModifiers(e)) {\n+ return;\n }\n \n- // get all additions from superclasses\n- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);\n+ // Ride up the element's DOM hierarchy to determine if it or any of \n+ // its ancestors was: \n+ // * specifically marked as scrollable (CSS overflow property)\n+ // * one of our layer divs or a div marked as scrollable\n+ // ('olScrollable' CSS class)\n+ // * the map div\n+ //\n+ var overScrollableDiv = false;\n+ var allowScroll = false;\n+ var overMapDiv = false;\n \n- return obj;\n+ var elem = OpenLayers.Event.element(e);\n+ while ((elem != null) && !overMapDiv && !overScrollableDiv) {\n+\n+ if (!overScrollableDiv) {\n+ try {\n+ var overflow;\n+ if (elem.currentStyle) {\n+ overflow = elem.currentStyle[\"overflow\"];\n+ } else {\n+ var style =\n+ document.defaultView.getComputedStyle(elem, null);\n+ overflow = style.getPropertyValue(\"overflow\");\n+ }\n+ overScrollableDiv = (overflow &&\n+ (overflow == \"auto\") || (overflow == \"scroll\"));\n+ } catch (err) {\n+ //sometimes when scrolling in a popup, this causes \n+ // obscure browser error\n+ }\n+ }\n+\n+ if (!allowScroll) {\n+ allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable');\n+ if (!allowScroll) {\n+ for (var i = 0, len = this.map.layers.length; i < len; i++) {\n+ // Are we in the layer div? Note that we have two cases\n+ // here: one is to catch EventPane layers, which have a\n+ // pane above the layer (layer.pane)\n+ var layer = this.map.layers[i];\n+ if (elem == layer.div || elem == layer.pane) {\n+ allowScroll = true;\n+ break;\n+ }\n+ }\n+ }\n+ }\n+ overMapDiv = (elem == this.map.div);\n+\n+ elem = elem.parentNode;\n+ }\n+\n+ // Logic below is the following:\n+ //\n+ // If we are over a scrollable div or not over the map div:\n+ // * do nothing (let the browser handle scrolling)\n+ //\n+ // otherwise \n+ // \n+ // If we are over the layer div or a 'olScrollable' div:\n+ // * zoom/in out\n+ // then\n+ // * kill event (so as not to also scroll the page after zooming)\n+ //\n+ // otherwise\n+ //\n+ // Kill the event (dont scroll the page if we wheel over the \n+ // layerswitcher or the pan/zoom control)\n+ //\n+ if (!overScrollableDiv && overMapDiv) {\n+ if (allowScroll) {\n+ var delta = 0;\n+\n+ if (e.wheelDelta) {\n+ delta = e.wheelDelta;\n+ if (delta % 160 === 0) {\n+ // opera have steps of 160 instead of 120\n+ delta = delta * 0.75;\n+ }\n+ delta = delta / 120;\n+ } else if (e.detail) {\n+ // detail in Firefox on OS X is 1/3 of Windows\n+ // so force delta 1 / -1\n+ delta = -(e.detail / Math.abs(e.detail));\n+ }\n+ this.delta += delta;\n+\n+ window.clearTimeout(this._timeoutId);\n+ if (this.interval && Math.abs(this.delta) < this.maxDelta) {\n+ // store e because window.event might change during delay\n+ var evt = OpenLayers.Util.extend({}, e);\n+ this._timeoutId = window.setTimeout(\n+ OpenLayers.Function.bind(function() {\n+ this.wheelZoom(evt);\n+ }, this),\n+ this.interval\n+ );\n+ } else {\n+ this.wheelZoom(e);\n+ }\n+ }\n+ OpenLayers.Event.stop(e);\n+ }\n },\n \n /**\n- * APIProperty: getFeatureInfo\n- * Get details about a feature associated with a map location. The object\n- * returned will have id and data properties. If the given location\n- * doesn't correspond to a feature, null will be returned.\n- *\n+ * Method: wheelZoom\n+ * Given the wheel event, we carry out the appropriate zooming in or out,\n+ * based on the 'wheelDelta' or 'detail' property of the event.\n+ * \n * Parameters:\n- * location - {} map location\n- *\n- * Returns:\n- * {Object} Object representing the feature id and UTFGrid data \n- * corresponding to the given map location. Returns null if the given\n- * location doesn't hit a feature.\n+ * e - {Event}\n */\n- getFeatureInfo: function(location) {\n- var info = null;\n- var tileInfo = this.getTileData(location);\n- if (tileInfo && tileInfo.tile) {\n- info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j);\n+ wheelZoom: function(e) {\n+ var delta = this.delta;\n+ this.delta = 0;\n+\n+ if (delta) {\n+ e.xy = this.map.events.getMousePosition(e);\n+ if (delta < 0) {\n+ this.callback(\"down\",\n+ [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]);\n+ } else {\n+ this.callback(\"up\",\n+ [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]);\n+ }\n }\n- return info;\n },\n \n /**\n- * APIMethod: getFeatureId\n- * Get the identifier for the feature associated with a map location.\n- *\n- * Parameters:\n- * location - {} map location\n- *\n- * Returns:\n- * {String} The feature identifier corresponding to the given map location.\n- * Returns null if the location doesn't hit a feature.\n+ * Method: activate \n */\n- getFeatureId: function(location) {\n- var id = null;\n- var info = this.getTileData(location);\n- if (info.tile) {\n- id = info.tile.getFeatureId(info.i, info.j);\n+ activate: function(evt) {\n+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {\n+ //register mousewheel events specifically on the window and document\n+ var wheelListener = this.wheelListener;\n+ OpenLayers.Event.observe(window, \"DOMMouseScroll\", wheelListener);\n+ OpenLayers.Event.observe(window, \"mousewheel\", wheelListener);\n+ OpenLayers.Event.observe(document, \"mousewheel\", wheelListener);\n+ return true;\n+ } else {\n+ return false;\n }\n- return id;\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.UTFGrid\"\n+ /**\n+ * Method: deactivate \n+ */\n+ deactivate: function(evt) {\n+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {\n+ // unregister mousewheel events specifically on the window and document\n+ var wheelListener = this.wheelListener;\n+ OpenLayers.Event.stopObserving(window, \"DOMMouseScroll\", wheelListener);\n+ OpenLayers.Event.stopObserving(window, \"mousewheel\", wheelListener);\n+ OpenLayers.Event.stopObserving(document, \"mousewheel\", wheelListener);\n+ return true;\n+ } else {\n+ return false;\n+ }\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Handler.MouseWheel\"\n });\n /* ======================================================================\n- OpenLayers/Layer/Bing.js\n+ OpenLayers/Control/Navigation.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Layer/XYZ.js\n+ * @requires OpenLayers/Control/ZoomBox.js\n+ * @requires OpenLayers/Control/DragPan.js\n+ * @requires OpenLayers/Handler/MouseWheel.js\n+ * @requires OpenLayers/Handler/Click.js\n */\n \n-/** \n- * Class: OpenLayers.Layer.Bing\n- * Bing layer using direct tile access as provided by Bing Maps REST Services.\n- * See http://msdn.microsoft.com/en-us/library/ff701713.aspx for more\n- * information. Note: Terms of Service compliant use requires the map to be\n- * configured with an control and the\n- * attribution placed on or near the map.\n+/**\n+ * Class: OpenLayers.Control.Navigation\n+ * The navigation control handles map browsing with mouse events (dragging,\n+ * double-clicking, and scrolling the wheel). Create a new navigation \n+ * control with the control. \n * \n- * Inherits from:\n- * - \n+ * Note that this control is added to the map by default (if no controls \n+ * array is sent in the options object to the \n+ * constructor).\n+ * \n+ * Inherits:\n+ * - \n */\n-OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {\n+OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {\n+\n+ /** \n+ * Property: dragPan\n+ * {} \n+ */\n+ dragPan: null,\n \n /**\n- * Property: key\n- * {String} API key for Bing maps, get your own key \n- * at http://bingmapsportal.com/ .\n+ * APIProperty: dragPanOptions\n+ * {Object} Options passed to the DragPan control.\n */\n- key: null,\n+ dragPanOptions: null,\n \n /**\n- * Property: serverResolutions\n- * {Array} the resolutions provided by the Bing servers.\n+ * Property: pinchZoom\n+ * {}\n */\n- serverResolutions: [\n- 156543.03390625, 78271.516953125, 39135.7584765625,\n- 19567.87923828125, 9783.939619140625, 4891.9698095703125,\n- 2445.9849047851562, 1222.9924523925781, 611.4962261962891,\n- 305.74811309814453, 152.87405654907226, 76.43702827453613,\n- 38.218514137268066, 19.109257068634033, 9.554628534317017,\n- 4.777314267158508, 2.388657133579254, 1.194328566789627,\n- 0.5971642833948135, 0.29858214169740677, 0.14929107084870338,\n- 0.07464553542435169\n- ],\n+ pinchZoom: null,\n \n /**\n- * Property: attributionTemplate\n- * {String}\n+ * APIProperty: pinchZoomOptions\n+ * {Object} Options passed to the PinchZoom control.\n */\n- attributionTemplate: '' +\n- '${copyrights}' +\n- '' +\n- 'Terms of Use',\n+ pinchZoomOptions: null,\n \n /**\n- * Property: metadata\n- * {Object} Metadata for this layer, as returned by the callback script\n+ * APIProperty: documentDrag\n+ * {Boolean} Allow panning of the map by dragging outside map viewport.\n+ * Default is false.\n */\n- metadata: null,\n+ documentDrag: false,\n+\n+ /** \n+ * Property: zoomBox\n+ * {}\n+ */\n+ zoomBox: null,\n \n /**\n- * Property: protocolRegex\n- * {RegExp} Regular expression to match and replace http: in bing urls\n+ * APIProperty: zoomBoxEnabled\n+ * {Boolean} Whether the user can draw a box to zoom\n */\n- protocolRegex: /^http:/i,\n+ zoomBoxEnabled: true,\n \n /**\n- * APIProperty: type\n- * {String} The layer identifier. Any non-birdseye imageryType\n- * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be\n- * used. Default is \"Road\".\n+ * APIProperty: zoomWheelEnabled\n+ * {Boolean} Whether the mousewheel should zoom the map\n */\n- type: \"Road\",\n+ zoomWheelEnabled: true,\n \n /**\n- * APIProperty: culture\n- * {String} The culture identifier. See http://msdn.microsoft.com/en-us/library/ff701709.aspx\n- * for the definition and the possible values. Default is \"en-US\".\n+ * Property: mouseWheelOptions\n+ * {Object} Options passed to the MouseWheel control (only useful if\n+ * is set to true). Default is no options for maps\n+ * with fractionalZoom set to true, otherwise\n+ * {cumulative: false, interval: 50, maxDelta: 6} \n */\n- culture: \"en-US\",\n+ mouseWheelOptions: null,\n \n /**\n- * APIProperty: metadataParams\n- * {Object} Optional url parameters for the Get Imagery Metadata request\n- * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx\n+ * APIProperty: handleRightClicks\n+ * {Boolean} Whether or not to handle right clicks. Default is false.\n */\n- metadataParams: null,\n+ handleRightClicks: false,\n \n- /** APIProperty: tileOptions\n- * {Object} optional configuration options for instances\n- * created by this Layer. Default is\n- *\n- * (code)\n- * {crossOriginKeyword: 'anonymous'}\n- * (end)\n+ /**\n+ * APIProperty: zoomBoxKeyMask\n+ * {Integer} key code of the key, which has to be\n+ * pressed, while drawing the zoom box with the mouse on the screen. \n+ * You should probably set handleRightClicks to true if you use this\n+ * with MOD_CTRL, to disable the context menu for machines which use\n+ * CTRL-Click as a right click.\n+ * Default: \n */\n- tileOptions: null,\n+ zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT,\n \n- /** APIProperty: protocol\n- * {String} Protocol to use to fetch Imagery Metadata, tiles and bing logo\n- * Can be 'http:' 'https:' or ''\n- *\n- * Warning: tiles may not be available under both HTTP and HTTPS protocols.\n- * Microsoft approved use of both HTTP and HTTPS urls for tiles. However\n- * this is undocumented and the Imagery Metadata API always returns HTTP\n- * urls.\n- *\n- * Default is '', unless when executed from a file:/// uri, in which case\n- * it is 'http:'.\n+ /**\n+ * APIProperty: autoActivate\n+ * {Boolean} Activate the control when it is added to a map. Default is\n+ * true.\n */\n- protocol: ~window.location.href.indexOf('http') ? '' : 'http:',\n+ autoActivate: true,\n \n /**\n- * Constructor: OpenLayers.Layer.Bing\n- * Create a new Bing layer.\n- *\n- * Example:\n- * (code)\n- * var road = new OpenLayers.Layer.Bing({\n- * name: \"My Bing Aerial Layer\",\n- * type: \"Aerial\",\n- * key: \"my-api-key-here\",\n- * });\n- * (end)\n- *\n+ * Constructor: OpenLayers.Control.Navigation\n+ * Create a new navigation control\n+ * \n * Parameters:\n- * options - {Object} Configuration properties for the layer.\n- *\n- * Required configuration properties:\n- * key - {String} Bing Maps API key for your application. Get one at\n- * http://bingmapsportal.com/.\n- * type - {String} The layer identifier. Any non-birdseye imageryType\n- * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be\n- * used.\n- *\n- * Any other documented layer properties can be provided in the config object.\n+ * options - {Object} An optional object whose properties will be set on\n+ * the control\n */\n initialize: function(options) {\n- options = OpenLayers.Util.applyDefaults({\n- sphericalMercator: true\n- }, options);\n- var name = options.name || \"Bing \" + (options.type || this.type);\n-\n- var newArgs = [name, null, options];\n- OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs);\n- this.tileOptions = OpenLayers.Util.extend({\n- crossOriginKeyword: 'anonymous'\n- }, this.options.tileOptions);\n- this.loadMetadata();\n+ this.handlers = {};\n+ OpenLayers.Control.prototype.initialize.apply(this, arguments);\n },\n \n /**\n- * Method: loadMetadata\n+ * Method: destroy\n+ * The destroy method is used to perform any clean up before the control\n+ * is dereferenced. Typically this is where event listeners are removed\n+ * to prevent memory leaks.\n */\n- loadMetadata: function() {\n- this._callbackId = \"_callback_\" + this.id.replace(/\\./g, \"_\");\n- // link the processMetadata method to the global scope and bind it\n- // to this instance\n- window[this._callbackId] = OpenLayers.Function.bind(\n- OpenLayers.Layer.Bing.processMetadata, this\n- );\n- var params = OpenLayers.Util.applyDefaults({\n- key: this.key,\n- jsonp: this._callbackId,\n- include: \"ImageryProviders\"\n- }, this.metadataParams);\n- var url = this.protocol + \"//dev.virtualearth.net/REST/v1/Imagery/Metadata/\" +\n- this.type + \"?\" + OpenLayers.Util.getParameterString(params);\n- var script = document.createElement(\"script\");\n- script.type = \"text/javascript\";\n- script.src = url;\n- script.id = this._callbackId;\n- document.getElementsByTagName(\"head\")[0].appendChild(script);\n+ destroy: function() {\n+ this.deactivate();\n+\n+ if (this.dragPan) {\n+ this.dragPan.destroy();\n+ }\n+ this.dragPan = null;\n+\n+ if (this.zoomBox) {\n+ this.zoomBox.destroy();\n+ }\n+ this.zoomBox = null;\n+\n+ if (this.pinchZoom) {\n+ this.pinchZoom.destroy();\n+ }\n+ this.pinchZoom = null;\n+\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n },\n \n /**\n- * Method: initLayer\n- *\n- * Sets layer properties according to the metadata provided by the API\n+ * Method: activate\n */\n- initLayer: function() {\n- var res = this.metadata.resourceSets[0].resources[0];\n- var url = res.imageUrl.replace(\"{quadkey}\", \"${quadkey}\");\n- url = url.replace(\"{culture}\", this.culture);\n- url = url.replace(this.protocolRegex, this.protocol);\n- this.url = [];\n- for (var i = 0; i < res.imageUrlSubdomains.length; ++i) {\n- this.url.push(url.replace(\"{subdomain}\", res.imageUrlSubdomains[i]));\n+ activate: function() {\n+ this.dragPan.activate();\n+ if (this.zoomWheelEnabled) {\n+ this.handlers.wheel.activate();\n }\n- this.addOptions({\n- maxResolution: Math.min(\n- this.serverResolutions[res.zoomMin],\n- this.maxResolution || Number.POSITIVE_INFINITY\n- ),\n- numZoomLevels: Math.min(\n- res.zoomMax + 1 - res.zoomMin, this.numZoomLevels\n- )\n- }, true);\n- if (!this.isBaseLayer) {\n- this.redraw();\n+ this.handlers.click.activate();\n+ if (this.zoomBoxEnabled) {\n+ this.zoomBox.activate();\n }\n- this.updateAttribution();\n+ if (this.pinchZoom) {\n+ this.pinchZoom.activate();\n+ }\n+ return OpenLayers.Control.prototype.activate.apply(this, arguments);\n },\n \n /**\n- * Method: getURL\n- *\n- * Paramters:\n- * bounds - {}\n+ * Method: deactivate\n */\n- getURL: function(bounds) {\n- if (!this.url) {\n- return;\n- }\n- var xyz = this.getXYZ(bounds),\n- x = xyz.x,\n- y = xyz.y,\n- z = xyz.z;\n- var quadDigits = [];\n- for (var i = z; i > 0; --i) {\n- var digit = '0';\n- var mask = 1 << (i - 1);\n- if ((x & mask) != 0) {\n- digit++;\n- }\n- if ((y & mask) != 0) {\n- digit++;\n- digit++;\n- }\n- quadDigits.push(digit);\n+ deactivate: function() {\n+ if (this.pinchZoom) {\n+ this.pinchZoom.deactivate();\n }\n- var quadKey = quadDigits.join(\"\");\n- var url = this.selectUrl('' + x + y + z, this.url);\n-\n- return OpenLayers.String.format(url, {\n- 'quadkey': quadKey\n- });\n+ this.zoomBox.deactivate();\n+ this.dragPan.deactivate();\n+ this.handlers.click.deactivate();\n+ this.handlers.wheel.deactivate();\n+ return OpenLayers.Control.prototype.deactivate.apply(this, arguments);\n },\n \n /**\n- * Method: updateAttribution\n- * Updates the attribution according to the requirements outlined in\n- * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html\n+ * Method: draw\n */\n- updateAttribution: function() {\n- var metadata = this.metadata;\n- if (!metadata.resourceSets || !this.map || !this.map.center) {\n- return;\n+ draw: function() {\n+ // disable right mouse context menu for support of right click events\n+ if (this.handleRightClicks) {\n+ this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False;\n }\n- var res = metadata.resourceSets[0].resources[0];\n- var extent = this.map.getExtent().transform(\n- this.map.getProjectionObject(),\n- new OpenLayers.Projection(\"EPSG:4326\")\n+\n+ var clickCallbacks = {\n+ 'click': this.defaultClick,\n+ 'dblclick': this.defaultDblClick,\n+ 'dblrightclick': this.defaultDblRightClick\n+ };\n+ var clickOptions = {\n+ 'double': true,\n+ 'stopDouble': true\n+ };\n+ this.handlers.click = new OpenLayers.Handler.Click(\n+ this, clickCallbacks, clickOptions\n );\n- var providers = res.imageryProviders || [],\n- zoom = OpenLayers.Util.indexOf(this.serverResolutions,\n- this.getServerResolution()),\n- copyrights = \"\",\n- provider, i, ii, j, jj, bbox, coverage;\n- for (i = 0, ii = providers.length; i < ii; ++i) {\n- provider = providers[i];\n- for (j = 0, jj = provider.coverageAreas.length; j < jj; ++j) {\n- coverage = provider.coverageAreas[j];\n- // axis order provided is Y,X\n- bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true);\n- if (extent.intersectsBounds(bbox) &&\n- zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) {\n- copyrights += provider.attribution + \" \";\n- }\n- }\n- }\n- var logo = metadata.brandLogoUri.replace(this.protocolRegex, this.protocol);\n- this.attribution = OpenLayers.String.format(this.attributionTemplate, {\n- type: this.type.toLowerCase(),\n- logo: logo,\n- copyrights: copyrights\n- });\n- this.map && this.map.events.triggerEvent(\"changelayer\", {\n- layer: this,\n- property: \"attribution\"\n+ this.dragPan = new OpenLayers.Control.DragPan(\n+ OpenLayers.Util.extend({\n+ map: this.map,\n+ documentDrag: this.documentDrag\n+ }, this.dragPanOptions)\n+ );\n+ this.zoomBox = new OpenLayers.Control.ZoomBox({\n+ map: this.map,\n+ keyMask: this.zoomBoxKeyMask\n });\n+ this.dragPan.draw();\n+ this.zoomBox.draw();\n+ var wheelOptions = this.map.fractionalZoom ? {} : {\n+ cumulative: false,\n+ interval: 50,\n+ maxDelta: 6\n+ };\n+ this.handlers.wheel = new OpenLayers.Handler.MouseWheel(\n+ this, {\n+ up: this.wheelUp,\n+ down: this.wheelDown\n+ },\n+ OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions)\n+ );\n+ if (OpenLayers.Control.PinchZoom) {\n+ this.pinchZoom = new OpenLayers.Control.PinchZoom(\n+ OpenLayers.Util.extend({\n+ map: this.map\n+ }, this.pinchZoomOptions));\n+ }\n },\n \n /**\n- * Method: setMap\n+ * Method: defaultClick\n+ *\n+ * Parameters:\n+ * evt - {Event}\n */\n- setMap: function() {\n- OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments);\n- this.map.events.register(\"moveend\", this, this.updateAttribution);\n+ defaultClick: function(evt) {\n+ if (evt.lastTouches && evt.lastTouches.length == 2) {\n+ this.map.zoomOut();\n+ }\n },\n \n /**\n- * APIMethod: clone\n+ * Method: defaultDblClick \n * \n * Parameters:\n- * obj - {Object}\n- * \n- * Returns:\n- * {} An exact clone of this \n+ * evt - {Event} \n */\n- clone: function(obj) {\n- if (obj == null) {\n- obj = new OpenLayers.Layer.Bing(this.options);\n- }\n- //get all additions from superclasses\n- obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);\n- // copy/set any non-init, non-simple values here\n- return obj;\n+ defaultDblClick: function(evt) {\n+ this.map.zoomTo(this.map.zoom + 1, evt.xy);\n },\n \n /**\n- * Method: destroy\n+ * Method: defaultDblRightClick \n+ * \n+ * Parameters:\n+ * evt - {Event} \n */\n- destroy: function() {\n- this.map &&\n- this.map.events.unregister(\"moveend\", this, this.updateAttribution);\n- OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments);\n+ defaultDblRightClick: function(evt) {\n+ this.map.zoomTo(this.map.zoom - 1, evt.xy);\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.Bing\"\n-});\n-\n-/**\n- * Function: OpenLayers.Layer.Bing.processMetadata\n- * This function will be bound to an instance, linked to the global scope with\n- * an id, and called by the JSONP script returned by the API.\n- *\n- * Parameters:\n- * metadata - {Object} metadata as returned by the API\n- */\n-OpenLayers.Layer.Bing.processMetadata = function(metadata) {\n- this.metadata = metadata;\n- this.initLayer();\n- var script = document.getElementById(this._callbackId);\n- script.parentNode.removeChild(script);\n- window[this._callbackId] = undefined; // cannot delete from window in IE\n- delete this._callbackId;\n-};\n-/* ======================================================================\n- OpenLayers/Layer/Markers.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Layer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Layer.Markers\n- * \n- * Inherits from:\n- * - \n- */\n-OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {\n-\n- /** \n- * APIProperty: isBaseLayer \n- * {Boolean} Markers layer is never a base layer. \n- */\n- isBaseLayer: false,\n-\n- /** \n- * APIProperty: markers \n- * {Array()} internal marker list \n- */\n- markers: null,\n-\n-\n- /** \n- * Property: drawn \n- * {Boolean} internal state of drawing. This is a workaround for the fact\n- * that the map does not call moveTo with a zoomChanged when the map is\n- * first starting up. This lets us catch the case where we have *never*\n- * drawn the layer, and draw it even if the zoom hasn't changed.\n- */\n- drawn: false,\n-\n /**\n- * Constructor: OpenLayers.Layer.Markers \n- * Create a Markers layer.\n+ * Method: wheelChange \n *\n * Parameters:\n- * name - {String} \n- * options - {Object} Hashtable of extra options to tag onto the layer\n- */\n- initialize: function(name, options) {\n- OpenLayers.Layer.prototype.initialize.apply(this, arguments);\n- this.markers = [];\n- },\n-\n- /**\n- * APIMethod: destroy \n+ * evt - {Event}\n+ * deltaZ - {Integer}\n */\n- destroy: function() {\n- this.clearMarkers();\n- this.markers = null;\n- OpenLayers.Layer.prototype.destroy.apply(this, arguments);\n+ wheelChange: function(evt, deltaZ) {\n+ if (!this.map.fractionalZoom) {\n+ deltaZ = Math.round(deltaZ);\n+ }\n+ var currentZoom = this.map.getZoom(),\n+ newZoom = currentZoom + deltaZ;\n+ newZoom = Math.max(newZoom, 0);\n+ newZoom = Math.min(newZoom, this.map.getNumZoomLevels());\n+ if (newZoom === currentZoom) {\n+ return;\n+ }\n+ this.map.zoomTo(newZoom, evt.xy);\n },\n \n- /**\n- * APIMethod: setOpacity\n- * Sets the opacity for all the markers.\n+ /** \n+ * Method: wheelUp\n+ * User spun scroll wheel up\n * \n * Parameters:\n- * opacity - {Float}\n+ * evt - {Event}\n+ * delta - {Integer}\n */\n- setOpacity: function(opacity) {\n- if (opacity != this.opacity) {\n- this.opacity = opacity;\n- for (var i = 0, len = this.markers.length; i < len; i++) {\n- this.markers[i].setOpacity(this.opacity);\n- }\n- }\n+ wheelUp: function(evt, delta) {\n+ this.wheelChange(evt, delta || 1);\n },\n \n /** \n- * Method: moveTo\n- *\n+ * Method: wheelDown\n+ * User spun scroll wheel down\n+ * \n * Parameters:\n- * bounds - {} \n- * zoomChanged - {Boolean} \n- * dragging - {Boolean} \n+ * evt - {Event}\n+ * delta - {Integer}\n */\n- moveTo: function(bounds, zoomChanged, dragging) {\n- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);\n-\n- if (zoomChanged || !this.drawn) {\n- for (var i = 0, len = this.markers.length; i < len; i++) {\n- this.drawMarker(this.markers[i]);\n- }\n- this.drawn = true;\n- }\n+ wheelDown: function(evt, delta) {\n+ this.wheelChange(evt, delta || -1);\n },\n \n /**\n- * APIMethod: addMarker\n- *\n- * Parameters:\n- * marker - {} \n+ * Method: disableZoomBox\n */\n- addMarker: function(marker) {\n- this.markers.push(marker);\n-\n- if (this.opacity < 1) {\n- marker.setOpacity(this.opacity);\n- }\n-\n- if (this.map && this.map.getExtent()) {\n- marker.map = this.map;\n- this.drawMarker(marker);\n- }\n+ disableZoomBox: function() {\n+ this.zoomBoxEnabled = false;\n+ this.zoomBox.deactivate();\n },\n \n /**\n- * APIMethod: removeMarker\n- *\n- * Parameters:\n- * marker - {} \n+ * Method: enableZoomBox\n */\n- removeMarker: function(marker) {\n- if (this.markers && this.markers.length) {\n- OpenLayers.Util.removeItem(this.markers, marker);\n- marker.erase();\n+ enableZoomBox: function() {\n+ this.zoomBoxEnabled = true;\n+ if (this.active) {\n+ this.zoomBox.activate();\n }\n },\n \n /**\n- * Method: clearMarkers\n- * This method removes all markers from a layer. The markers are not\n- * destroyed by this function, but are removed from the list of markers.\n+ * Method: disableZoomWheel\n */\n- clearMarkers: function() {\n- if (this.markers != null) {\n- while (this.markers.length > 0) {\n- this.removeMarker(this.markers[0]);\n- }\n- }\n- },\n \n- /** \n- * Method: drawMarker\n- * Calculate the pixel location for the marker, create it, and \n- * add it to the layer's div\n- *\n- * Parameters:\n- * marker - {} \n- */\n- drawMarker: function(marker) {\n- var px = this.map.getLayerPxFromLonLat(marker.lonlat);\n- if (px == null) {\n- marker.display(false);\n- } else {\n- if (!marker.isDrawn()) {\n- var markerImg = marker.draw(px);\n- this.div.appendChild(markerImg);\n- } else if (marker.icon) {\n- marker.icon.moveTo(px);\n- }\n- }\n+ disableZoomWheel: function() {\n+ this.zoomWheelEnabled = false;\n+ this.handlers.wheel.deactivate();\n },\n \n- /** \n- * APIMethod: getDataExtent\n- * Calculates the max extent which includes all of the markers.\n- * \n- * Returns:\n- * {}\n+ /**\n+ * Method: enableZoomWheel\n */\n- getDataExtent: function() {\n- var maxExtent = null;\n \n- if (this.markers && (this.markers.length > 0)) {\n- var maxExtent = new OpenLayers.Bounds();\n- for (var i = 0, len = this.markers.length; i < len; i++) {\n- var marker = this.markers[i];\n- maxExtent.extend(marker.lonlat);\n- }\n+ enableZoomWheel: function() {\n+ this.zoomWheelEnabled = true;\n+ if (this.active) {\n+ this.handlers.wheel.activate();\n }\n-\n- return maxExtent;\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.Markers\"\n+ CLASS_NAME: \"OpenLayers.Control.Navigation\"\n });\n /* ======================================================================\n- OpenLayers/Format/Text.js\n+ OpenLayers/Handler/Polygon.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n- * @requires OpenLayers/Feature/Vector.js\n- * @requires OpenLayers/Geometry/Point.js\n+ * @requires OpenLayers/Handler/Path.js\n+ * @requires OpenLayers/Geometry/Polygon.js\n */\n \n /**\n- * Class: OpenLayers.Format.Text\n- * Read Text format. Create a new instance with the \n- * constructor. This reads text which is formatted like CSV text, using\n- * tabs as the seperator by default. It provides parsing of data originally\n- * used in the MapViewerService, described on the wiki. This Format is used\n- * by the class.\n+ * Class: OpenLayers.Handler.Polygon\n+ * Handler to draw a polygon on the map. Polygon is displayed on mouse down,\n+ * moves on mouse move, and is finished on mouse up.\n *\n * Inherits from:\n- * - \n+ * - \n+ * - \n */\n-OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, {\n+OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {\n+\n+ /** \n+ * APIProperty: holeModifier\n+ * {String} Key modifier to trigger hole digitizing. Acceptable values are\n+ * \"altKey\", \"shiftKey\", or \"ctrlKey\". If not set, no hole digitizing\n+ * will take place. Default is null.\n+ */\n+ holeModifier: null,\n \n /**\n- * APIProperty: defaultStyle\n- * defaultStyle allows one to control the default styling of the features.\n- * It should be a symbolizer hash. By default, this is set to match the\n- * Layer.Text behavior, which is to use the default OpenLayers Icon.\n+ * Property: drawingHole\n+ * {Boolean} Currently drawing an interior ring.\n */\n- defaultStyle: null,\n+ drawingHole: false,\n \n /**\n- * APIProperty: extractStyles\n- * set to true to extract styles from the TSV files, using information\n- * from the image or icon, iconSize and iconOffset fields. This will result\n- * in features with a symbolizer (style) property set, using the\n- * default symbolizer specified in . Set to false if you\n- * wish to use a styleMap or OpenLayers.Style options to style your\n- * layer instead.\n+ * Property: polygon\n+ * {}\n */\n- extractStyles: true,\n+ polygon: null,\n \n /**\n- * Constructor: OpenLayers.Format.Text\n- * Create a new parser for TSV Text.\n+ * Constructor: OpenLayers.Handler.Polygon\n+ * Create a Polygon Handler.\n *\n * Parameters:\n- * options - {Object} An optional object whose properties will be set on\n- * this instance.\n+ * control - {} The control that owns this handler\n+ * callbacks - {Object} An object with a properties whose values are\n+ * functions. Various callbacks described below.\n+ * options - {Object} An optional object with properties to be set on the\n+ * handler\n+ *\n+ * Named callbacks:\n+ * create - Called when a sketch is first created. Callback called with\n+ * the creation point geometry and sketch feature.\n+ * modify - Called with each move of a vertex with the vertex (point)\n+ * geometry and the sketch feature.\n+ * point - Called as each point is added. Receives the new point geometry.\n+ * done - Called when the point drawing is finished. The callback will\n+ * recieve a single argument, the polygon geometry.\n+ * cancel - Called when the handler is deactivated while drawing. The\n+ * cancel callback will receive a geometry.\n */\n- initialize: function(options) {\n- options = options || {};\n \n- if (options.extractStyles !== false) {\n- options.defaultStyle = {\n- 'externalGraphic': OpenLayers.Util.getImageLocation(\"marker.png\"),\n- 'graphicWidth': 21,\n- 'graphicHeight': 25,\n- 'graphicXOffset': -10.5,\n- 'graphicYOffset': -12.5\n- };\n- }\n-\n- OpenLayers.Format.prototype.initialize.apply(this, [options]);\n+ /**\n+ * Method: createFeature\n+ * Add temporary geometries\n+ *\n+ * Parameters:\n+ * pixel - {} The initial pixel location for the new\n+ * feature.\n+ */\n+ createFeature: function(pixel) {\n+ var lonlat = this.layer.getLonLatFromViewPortPx(pixel);\n+ var geometry = new OpenLayers.Geometry.Point(\n+ lonlat.lon, lonlat.lat\n+ );\n+ this.point = new OpenLayers.Feature.Vector(geometry);\n+ this.line = new OpenLayers.Feature.Vector(\n+ new OpenLayers.Geometry.LinearRing([this.point.geometry])\n+ );\n+ this.polygon = new OpenLayers.Feature.Vector(\n+ new OpenLayers.Geometry.Polygon([this.line.geometry])\n+ );\n+ this.callback(\"create\", [this.point.geometry, this.getSketch()]);\n+ this.point.geometry.clearBounds();\n+ this.layer.addFeatures([this.polygon, this.point], {\n+ silent: true\n+ });\n },\n \n /**\n- * APIMethod: read\n- * Return a list of features from a Tab Seperated Values text string.\n- * \n- * Parameters:\n- * text - {String} \n+ * Method: addPoint\n+ * Add point to geometry.\n *\n- * Returns:\n- * Array({})\n+ * Parameters:\n+ * pixel - {} The pixel location for the new point.\n */\n- read: function(text) {\n- var lines = text.split('\\n');\n- var columns;\n- var features = [];\n- // length - 1 to allow for trailing new line\n- for (var lcv = 0; lcv < (lines.length - 1); lcv++) {\n- var currLine = lines[lcv].replace(/^\\s*/, '').replace(/\\s*$/, '');\n-\n- if (currLine.charAt(0) != '#') {\n- /* not a comment */\n-\n- if (!columns) {\n- //First line is columns\n- columns = currLine.split('\\t');\n- } else {\n- var vals = currLine.split('\\t');\n- var geometry = new OpenLayers.Geometry.Point(0, 0);\n- var attributes = {};\n- var style = this.defaultStyle ?\n- OpenLayers.Util.applyDefaults({}, this.defaultStyle) :\n- null;\n- var icon, iconSize, iconOffset, overflow;\n- var set = false;\n- for (var valIndex = 0; valIndex < vals.length; valIndex++) {\n- if (vals[valIndex]) {\n- if (columns[valIndex] == 'point') {\n- var coords = vals[valIndex].split(',');\n- geometry.y = parseFloat(coords[0]);\n- geometry.x = parseFloat(coords[1]);\n- set = true;\n- } else if (columns[valIndex] == 'lat') {\n- geometry.y = parseFloat(vals[valIndex]);\n- set = true;\n- } else if (columns[valIndex] == 'lon') {\n- geometry.x = parseFloat(vals[valIndex]);\n- set = true;\n- } else if (columns[valIndex] == 'title')\n- attributes['title'] = vals[valIndex];\n- else if (columns[valIndex] == 'image' ||\n- columns[valIndex] == 'icon' && style) {\n- style['externalGraphic'] = vals[valIndex];\n- } else if (columns[valIndex] == 'iconSize' && style) {\n- var size = vals[valIndex].split(',');\n- style['graphicWidth'] = parseFloat(size[0]);\n- style['graphicHeight'] = parseFloat(size[1]);\n- } else if (columns[valIndex] == 'iconOffset' && style) {\n- var offset = vals[valIndex].split(',');\n- style['graphicXOffset'] = parseFloat(offset[0]);\n- style['graphicYOffset'] = parseFloat(offset[1]);\n- } else if (columns[valIndex] == 'description') {\n- attributes['description'] = vals[valIndex];\n- } else if (columns[valIndex] == 'overflow') {\n- attributes['overflow'] = vals[valIndex];\n- } else {\n- // For StyleMap filtering, allow additional\n- // columns to be stored as attributes.\n- attributes[columns[valIndex]] = vals[valIndex];\n- }\n- }\n- }\n- if (set) {\n- if (this.internalProjection && this.externalProjection) {\n- geometry.transform(this.externalProjection,\n- this.internalProjection);\n- }\n- var feature = new OpenLayers.Feature.Vector(geometry, attributes, style);\n- features.push(feature);\n- }\n+ addPoint: function(pixel) {\n+ if (!this.drawingHole && this.holeModifier &&\n+ this.evt && this.evt[this.holeModifier]) {\n+ var geometry = this.point.geometry;\n+ var features = this.control.layer.features;\n+ var candidate, polygon;\n+ // look for intersections, last drawn gets priority\n+ for (var i = features.length - 1; i >= 0; --i) {\n+ candidate = features[i].geometry;\n+ if ((candidate instanceof OpenLayers.Geometry.Polygon ||\n+ candidate instanceof OpenLayers.Geometry.MultiPolygon) &&\n+ candidate.intersects(geometry)) {\n+ polygon = features[i];\n+ this.control.layer.removeFeatures([polygon], {\n+ silent: true\n+ });\n+ this.control.layer.events.registerPriority(\n+ \"sketchcomplete\", this, this.finalizeInteriorRing\n+ );\n+ this.control.layer.events.registerPriority(\n+ \"sketchmodified\", this, this.enforceTopology\n+ );\n+ polygon.geometry.addComponent(this.line.geometry);\n+ this.polygon = polygon;\n+ this.drawingHole = true;\n+ break;\n }\n }\n }\n- return features;\n+ OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments);\n },\n \n- CLASS_NAME: \"OpenLayers.Format.Text\"\n-});\n-/* ======================================================================\n- OpenLayers/Layer/Text.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Layer/Markers.js\n- * @requires OpenLayers/Format/Text.js\n- * @requires OpenLayers/Request/XMLHttpRequest.js\n- */\n-\n-/**\n- * Class: OpenLayers.Layer.Text\n- * This layer creates markers given data in a text file. The \n- * property of the layer (specified as a property of the options argument\n- * in the constructor) points to a tab delimited\n- * file with data used to create markers.\n- *\n- * The first row of the data file should be a header line with the column names\n- * of the data. Each column should be delimited by a tab space. The\n- * possible columns are:\n- * - *point* lat,lon of the point where a marker is to be placed\n- * - *lat* Latitude of the point where a marker is to be placed\n- * - *lon* Longitude of the point where a marker is to be placed\n- * - *icon* or *image* URL of marker icon to use.\n- * - *iconSize* Size of Icon to use.\n- * - *iconOffset* Where the top-left corner of the icon is to be placed\n- * relative to the latitude and longitude of the point.\n- * - *title* The text of the 'title' is placed inside an 'h2' marker\n- * inside a popup, which opens when the marker is clicked.\n- * - *description* The text of the 'description' is placed below the h2\n- * in the popup. this can be plain text or HTML.\n- *\n- * Example text file:\n- * (code)\n- * lat\tlon\ttitle\tdescription\ticonSize\ticonOffset\ticon\n- * 10\t20\ttitle\tdescription\t21,25\t\t-10,-25\t\thttp://www.openlayers.org/dev/img/marker.png\n- * (end)\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, {\n-\n /**\n- * APIProperty: location \n- * {String} URL of text file. Must be specified in the \"options\" argument\n- * of the constructor. Can not be changed once passed in. \n- */\n- location: null,\n-\n- /** \n- * Property: features\n- * {Array()} \n+ * Method: getCurrentPointIndex\n+ * \n+ * Returns:\n+ * {Number} The index of the most recently drawn point.\n */\n- features: null,\n+ getCurrentPointIndex: function() {\n+ return this.line.geometry.components.length - 2;\n+ },\n \n /**\n- * APIProperty: formatOptions\n- * {Object} Hash of options which should be passed to the format when it is\n- * created. Must be passed in the constructor.\n- */\n- formatOptions: null,\n-\n- /** \n- * Property: selectedFeature\n- * {}\n+ * Method: enforceTopology\n+ * Simple topology enforcement for drawing interior rings. Ensures vertices\n+ * of interior rings are contained by exterior ring. Other topology \n+ * rules are enforced in to allow drawing of \n+ * rings that intersect only during the sketch (e.g. a \"C\" shaped ring\n+ * that nearly encloses another ring).\n */\n- selectedFeature: null,\n+ enforceTopology: function(event) {\n+ var point = event.vertex;\n+ var components = this.line.geometry.components;\n+ // ensure that vertices of interior ring are contained by exterior ring\n+ if (!this.polygon.geometry.intersects(point)) {\n+ var last = components[components.length - 3];\n+ point.x = last.x;\n+ point.y = last.y;\n+ }\n+ },\n \n /**\n- * Constructor: OpenLayers.Layer.Text\n- * Create a text layer.\n- * \n- * Parameters:\n- * name - {String} \n- * options - {Object} Object with properties to be set on the layer.\n- * Must include property.\n+ * Method: finishGeometry\n+ * Finish the geometry and send it back to the control.\n */\n- initialize: function(name, options) {\n- OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments);\n- this.features = [];\n+ finishGeometry: function() {\n+ var index = this.line.geometry.components.length - 2;\n+ this.line.geometry.removeComponent(this.line.geometry.components[index]);\n+ this.removePoint();\n+ this.finalize();\n },\n \n /**\n- * APIMethod: destroy \n+ * Method: finalizeInteriorRing\n+ * Enforces that new ring has some area and doesn't contain vertices of any\n+ * other rings.\n */\n- destroy: function() {\n- // Warning: Layer.Markers.destroy() must be called prior to calling\n- // clearFeatures() here, otherwise we leak memory. Indeed, if\n- // Layer.Markers.destroy() is called after clearFeatures(), it won't be\n- // able to remove the marker image elements from the layer's div since\n- // the markers will have been destroyed by clearFeatures().\n- OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);\n- this.clearFeatures();\n- this.features = null;\n+ finalizeInteriorRing: function() {\n+ var ring = this.line.geometry;\n+ // ensure that ring has some area\n+ var modified = (ring.getArea() !== 0);\n+ if (modified) {\n+ // ensure that new ring doesn't intersect any other rings\n+ var rings = this.polygon.geometry.components;\n+ for (var i = rings.length - 2; i >= 0; --i) {\n+ if (ring.intersects(rings[i])) {\n+ modified = false;\n+ break;\n+ }\n+ }\n+ if (modified) {\n+ // ensure that new ring doesn't contain any other rings\n+ var target;\n+ outer: for (var i = rings.length - 2; i > 0; --i) {\n+ var points = rings[i].components;\n+ for (var j = 0, jj = points.length; j < jj; ++j) {\n+ if (ring.containsPoint(points[j])) {\n+ modified = false;\n+ break outer;\n+ }\n+ }\n+ }\n+ }\n+ }\n+ if (modified) {\n+ if (this.polygon.state !== OpenLayers.State.INSERT) {\n+ this.polygon.state = OpenLayers.State.UPDATE;\n+ }\n+ } else {\n+ this.polygon.geometry.removeComponent(ring);\n+ }\n+ this.restoreFeature();\n+ return false;\n },\n \n /**\n- * Method: loadText\n- * Start the load of the Text data. Don't do this when we first add the layer,\n- * since we may not be visible at any point, and it would therefore be a waste.\n+ * APIMethod: cancel\n+ * Finish the geometry and call the \"cancel\" callback.\n */\n- loadText: function() {\n- if (!this.loaded) {\n- if (this.location != null) {\n-\n- var onFail = function(e) {\n- this.events.triggerEvent(\"loadend\");\n- };\n-\n- this.events.triggerEvent(\"loadstart\");\n- OpenLayers.Request.GET({\n- url: this.location,\n- success: this.parseData,\n- failure: onFail,\n- scope: this\n- });\n- this.loaded = true;\n- }\n+ cancel: function() {\n+ if (this.drawingHole) {\n+ this.polygon.geometry.removeComponent(this.line.geometry);\n+ this.restoreFeature(true);\n }\n+ return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments);\n },\n \n /**\n- * Method: moveTo\n- * If layer is visible and Text has not been loaded, load Text. \n- * \n- * Parameters:\n- * bounds - {Object} \n- * zoomChanged - {Object} \n- * minor - {Object} \n+ * Method: restoreFeature\n+ * Move the feature from the sketch layer to the target layer.\n+ *\n+ * Properties: \n+ * cancel - {Boolean} Cancel drawing. If falsey, the \"sketchcomplete\" event\n+ * will be fired.\n */\n- moveTo: function(bounds, zoomChanged, minor) {\n- OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);\n- if (this.visibility && !this.loaded) {\n- this.loadText();\n+ restoreFeature: function(cancel) {\n+ this.control.layer.events.unregister(\n+ \"sketchcomplete\", this, this.finalizeInteriorRing\n+ );\n+ this.control.layer.events.unregister(\n+ \"sketchmodified\", this, this.enforceTopology\n+ );\n+ this.layer.removeFeatures([this.polygon], {\n+ silent: true\n+ });\n+ this.control.layer.addFeatures([this.polygon], {\n+ silent: true\n+ });\n+ this.drawingHole = false;\n+ if (!cancel) {\n+ // Re-trigger \"sketchcomplete\" so other listeners can do their\n+ // business. While this is somewhat sloppy (if a listener is \n+ // registered with registerPriority - not common - between the start\n+ // and end of a single ring drawing - very uncommon - it will be \n+ // called twice).\n+ // TODO: In 3.0, collapse sketch handlers into geometry specific\n+ // drawing controls.\n+ this.control.layer.events.triggerEvent(\n+ \"sketchcomplete\", {\n+ feature: this.polygon\n+ }\n+ );\n }\n },\n \n /**\n- * Method: parseData\n+ * Method: destroyFeature\n+ * Destroy temporary geometries\n *\n * Parameters:\n- * ajaxRequest - {} \n+ * force - {Boolean} Destroy even if persist is true.\n */\n- parseData: function(ajaxRequest) {\n- var text = ajaxRequest.responseText;\n-\n- var options = {};\n-\n- OpenLayers.Util.extend(options, this.formatOptions);\n-\n- if (this.map && !this.projection.equals(this.map.getProjectionObject())) {\n- options.externalProjection = this.projection;\n- options.internalProjection = this.map.getProjectionObject();\n- }\n-\n- var parser = new OpenLayers.Format.Text(options);\n- var features = parser.read(text);\n- for (var i = 0, len = features.length; i < len; i++) {\n- var data = {};\n- var feature = features[i];\n- var location;\n- var iconSize, iconOffset;\n-\n- location = new OpenLayers.LonLat(feature.geometry.x,\n- feature.geometry.y);\n-\n- if (feature.style.graphicWidth &&\n- feature.style.graphicHeight) {\n- iconSize = new OpenLayers.Size(\n- feature.style.graphicWidth,\n- feature.style.graphicHeight);\n- }\n-\n- // FIXME: At the moment, we only use this if we have an \n- // externalGraphic, because icon has no setOffset API Method.\n- /**\n- * FIXME FIRST!!\n- * The Text format does all sorts of parseFloating\n- * The result of a parseFloat for a bogus string is NaN. That\n- * means the three possible values here are undefined, NaN, or a\n- * number. The previous check was an identity check for null. This\n- * means it was failing for all undefined or NaN. A slightly better\n- * check is for undefined. An even better check is to see if the\n- * value is a number (see #1441).\n- */\n- if (feature.style.graphicXOffset !== undefined &&\n- feature.style.graphicYOffset !== undefined) {\n- iconOffset = new OpenLayers.Pixel(\n- feature.style.graphicXOffset,\n- feature.style.graphicYOffset);\n- }\n-\n- if (feature.style.externalGraphic != null) {\n- data.icon = new OpenLayers.Icon(feature.style.externalGraphic,\n- iconSize,\n- iconOffset);\n- } else {\n- data.icon = OpenLayers.Marker.defaultIcon();\n-\n- //allows for the case where the image url is not \n- // specified but the size is. use a default icon\n- // but change the size\n- if (iconSize != null) {\n- data.icon.setSize(iconSize);\n- }\n- }\n-\n- if ((feature.attributes.title != null) &&\n- (feature.attributes.description != null)) {\n- data['popupContentHTML'] =\n- '

' + feature.attributes.title + '

' +\n- '

' + feature.attributes.description + '

';\n- }\n-\n- data['overflow'] = feature.attributes.overflow || \"auto\";\n+ destroyFeature: function(force) {\n+ OpenLayers.Handler.Path.prototype.destroyFeature.call(\n+ this, force);\n+ this.polygon = null;\n+ },\n \n- var markerFeature = new OpenLayers.Feature(this, location, data);\n- this.features.push(markerFeature);\n- var marker = markerFeature.createMarker();\n- if ((feature.attributes.title != null) &&\n- (feature.attributes.description != null)) {\n- marker.events.register('click', markerFeature, this.markerClick);\n- }\n- this.addMarker(marker);\n- }\n- this.events.triggerEvent(\"loadend\");\n+ /**\n+ * Method: drawFeature\n+ * Render geometries on the temporary layer.\n+ */\n+ drawFeature: function() {\n+ this.layer.drawFeature(this.polygon, this.style);\n+ this.layer.drawFeature(this.point, this.style);\n },\n \n /**\n- * Property: markerClick\n- * \n- * Parameters:\n- * evt - {Event} \n+ * Method: getSketch\n+ * Return the sketch feature.\n *\n- * Context:\n- * - {}\n+ * Returns:\n+ * {}\n */\n- markerClick: function(evt) {\n- var sameMarkerClicked = (this == this.layer.selectedFeature);\n- this.layer.selectedFeature = (!sameMarkerClicked) ? this : null;\n- for (var i = 0, len = this.layer.map.popups.length; i < len; i++) {\n- this.layer.map.removePopup(this.layer.map.popups[i]);\n- }\n- if (!sameMarkerClicked) {\n- this.layer.map.addPopup(this.createPopup());\n- }\n- OpenLayers.Event.stop(evt);\n+ getSketch: function() {\n+ return this.polygon;\n },\n \n /**\n- * Method: clearFeatures\n+ * Method: getGeometry\n+ * Return the sketch geometry. If is true, this will return\n+ * a multi-part geometry.\n+ *\n+ * Returns:\n+ * {}\n */\n- clearFeatures: function() {\n- if (this.features != null) {\n- while (this.features.length > 0) {\n- var feature = this.features[0];\n- OpenLayers.Util.removeItem(this.features, feature);\n- feature.destroy();\n- }\n+ getGeometry: function() {\n+ var geometry = this.polygon && this.polygon.geometry;\n+ if (geometry && this.multi) {\n+ geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);\n }\n+ return geometry;\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.Text\"\n+ CLASS_NAME: \"OpenLayers.Handler.Polygon\"\n });\n /* ======================================================================\n- OpenLayers/Layer/WMTS.js\n+ OpenLayers/Control/EditingToolbar.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Layer/Grid.js\n+ * @requires OpenLayers/Control/Panel.js\n+ * @requires OpenLayers/Control/Navigation.js\n+ * @requires OpenLayers/Control/DrawFeature.js\n+ * @requires OpenLayers/Handler/Point.js\n+ * @requires OpenLayers/Handler/Path.js\n+ * @requires OpenLayers/Handler/Polygon.js\n */\n \n /**\n- * Class: OpenLayers.Layer.WMTS\n- * Instances of the WMTS class allow viewing of tiles from a service that \n- * implements the OGC WMTS specification version 1.0.0.\n+ * Class: OpenLayers.Control.EditingToolbar \n+ * The EditingToolbar is a panel of 4 controls to draw polygons, lines, \n+ * points, or to navigate the map by panning. By default it appears in the \n+ * upper right corner of the map.\n * \n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, {\n+OpenLayers.Control.EditingToolbar = OpenLayers.Class(\n+ OpenLayers.Control.Panel, {\n \n- /**\n- * APIProperty: isBaseLayer\n- * {Boolean} The layer will be considered a base layer. Default is true.\n- */\n- isBaseLayer: true,\n+ /**\n+ * APIProperty: citeCompliant\n+ * {Boolean} If set to true, coordinates of features drawn in a map extent\n+ * crossing the date line won't exceed the world bounds. Default is false.\n+ */\n+ citeCompliant: false,\n+\n+ /**\n+ * Constructor: OpenLayers.Control.EditingToolbar\n+ * Create an editing toolbar for a given layer. \n+ *\n+ * Parameters:\n+ * layer - {} \n+ * options - {Object} \n+ */\n+ initialize: function(layer, options) {\n+ OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);\n+\n+ this.addControls(\n+ [new OpenLayers.Control.Navigation()]\n+ );\n+ var controls = [\n+ new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, {\n+ displayClass: 'olControlDrawFeaturePoint',\n+ handlerOptions: {\n+ citeCompliant: this.citeCompliant\n+ }\n+ }),\n+ new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, {\n+ displayClass: 'olControlDrawFeaturePath',\n+ handlerOptions: {\n+ citeCompliant: this.citeCompliant\n+ }\n+ }),\n+ new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, {\n+ displayClass: 'olControlDrawFeaturePolygon',\n+ handlerOptions: {\n+ citeCompliant: this.citeCompliant\n+ }\n+ })\n+ ];\n+ this.addControls(controls);\n+ },\n+\n+ /**\n+ * Method: draw\n+ * calls the default draw, and then activates mouse defaults.\n+ *\n+ * Returns:\n+ * {DOMElement}\n+ */\n+ draw: function() {\n+ var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments);\n+ if (this.defaultControl === null) {\n+ this.defaultControl = this.controls[0];\n+ }\n+ return div;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Control.EditingToolbar\"\n+ });\n+/* ======================================================================\n+ OpenLayers/Control/OverviewMap.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/** \n+ * @requires OpenLayers/Control.js\n+ * @requires OpenLayers/BaseTypes.js\n+ * @requires OpenLayers/Events/buttonclick.js\n+ * @requires OpenLayers/Map.js\n+ * @requires OpenLayers/Handler/Click.js\n+ * @requires OpenLayers/Handler/Drag.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Control.OverviewMap\n+ * The OverMap control creates a small overview map, useful to display the \n+ * extent of a zoomed map and your main map and provide additional \n+ * navigation options to the User. By default the overview map is drawn in\n+ * the lower right corner of the main map. Create a new overview map with the\n+ * constructor.\n+ *\n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {\n \n /**\n- * Property: version\n- * {String} WMTS version. Default is \"1.0.0\".\n+ * Property: element\n+ * {DOMElement} The DOM element that contains the overview map\n */\n- version: \"1.0.0\",\n+ element: null,\n \n /**\n- * APIProperty: requestEncoding\n- * {String} Request encoding. Can be \"REST\" or \"KVP\". Default is \"KVP\".\n+ * APIProperty: ovmap\n+ * {} A reference to the overview map itself.\n */\n- requestEncoding: \"KVP\",\n+ ovmap: null,\n \n /**\n- * APIProperty: url\n- * {String|Array(String)} The base URL or request URL template for the WMTS\n- * service. Must be provided. Array is only supported for base URLs, not\n- * for request URL templates. URL templates are only supported for\n- * REST .\n+ * APIProperty: size\n+ * {} The overvew map size in pixels. Note that this is\n+ * the size of the map itself - the element that contains the map (default\n+ * class name olControlOverviewMapElement) may have padding or other style\n+ * attributes added via CSS.\n */\n- url: null,\n+ size: {\n+ w: 180,\n+ h: 90\n+ },\n \n /**\n- * APIProperty: layer\n- * {String} The layer identifier advertised by the WMTS service. Must be \n- * provided.\n+ * APIProperty: layers\n+ * {Array()} Ordered list of layers in the overview map.\n+ * If none are sent at construction, the base layer for the main map is used.\n */\n- layer: null,\n+ layers: null,\n \n- /** \n- * APIProperty: matrixSet\n- * {String} One of the advertised matrix set identifiers. Must be provided.\n+ /**\n+ * APIProperty: minRectSize\n+ * {Integer} The minimum width or height (in pixels) of the extent\n+ * rectangle on the overview map. When the extent rectangle reaches\n+ * this size, it will be replaced depending on the value of the\n+ * property. Default is 15 pixels.\n */\n- matrixSet: null,\n+ minRectSize: 15,\n \n- /** \n- * APIProperty: style\n- * {String} One of the advertised layer styles. Must be provided.\n+ /**\n+ * APIProperty: minRectDisplayClass\n+ * {String} Replacement style class name for the extent rectangle when\n+ * is reached. This string will be suffixed on to the\n+ * displayClass. Default is \"RectReplacement\".\n+ *\n+ * Example CSS declaration:\n+ * (code)\n+ * .olControlOverviewMapRectReplacement {\n+ * overflow: hidden;\n+ * cursor: move;\n+ * background-image: url(\"img/overview_replacement.gif\");\n+ * background-repeat: no-repeat;\n+ * background-position: center;\n+ * }\n+ * (end)\n */\n- style: null,\n+ minRectDisplayClass: \"RectReplacement\",\n \n- /** \n- * APIProperty: format\n- * {String} The image MIME type. Default is \"image/jpeg\".\n+ /**\n+ * APIProperty: minRatio\n+ * {Float} The ratio of the overview map resolution to the main map\n+ * resolution at which to zoom farther out on the overview map.\n */\n- format: \"image/jpeg\",\n+ minRatio: 8,\n \n /**\n- * APIProperty: tileOrigin\n- * {} The top-left corner of the tile matrix in map \n- * units. If the tile origin for each matrix in a set is different,\n- * the should include a topLeftCorner property. If\n- * not provided, the tile origin will default to the top left corner\n- * of the layer .\n+ * APIProperty: maxRatio\n+ * {Float} The ratio of the overview map resolution to the main map\n+ * resolution at which to zoom farther in on the overview map.\n */\n- tileOrigin: null,\n+ maxRatio: 32,\n \n /**\n- * APIProperty: tileFullExtent\n- * {} The full extent of the tile set. If not supplied,\n- * the layer's property will be used.\n+ * APIProperty: mapOptions\n+ * {Object} An object containing any non-default properties to be sent to\n+ * the overview map's map constructor. These should include any\n+ * non-default options that the main map was constructed with.\n */\n- tileFullExtent: null,\n+ mapOptions: null,\n \n /**\n- * APIProperty: formatSuffix\n- * {String} For REST request encoding, an image format suffix must be \n- * included in the request. If not provided, the suffix will be derived\n- * from the property.\n+ * APIProperty: autoPan\n+ * {Boolean} Always pan the overview map, so the extent marker remains in\n+ * the center. Default is false. If true, when you drag the extent\n+ * marker, the overview map will update itself so the marker returns\n+ * to the center.\n */\n- formatSuffix: null,\n+ autoPan: false,\n \n /**\n- * APIProperty: matrixIds\n- * {Array} A list of tile matrix identifiers. If not provided, the matrix\n- * identifiers will be assumed to be integers corresponding to the \n- * map zoom level. If a list of strings is provided, each item should\n- * be the matrix identifier that corresponds to the map zoom level.\n- * Additionally, a list of objects can be provided. Each object should\n- * describe the matrix as presented in the WMTS capabilities. These\n- * objects should have the propertes shown below.\n- * \n- * Matrix properties:\n- * identifier - {String} The matrix identifier (required).\n- * scaleDenominator - {Number} The matrix scale denominator.\n- * topLeftCorner - {} The top left corner of the \n- * matrix. Must be provided if different than the layer .\n- * tileWidth - {Number} The tile width for the matrix. Must be provided \n- * if different than the width given in the layer .\n- * tileHeight - {Number} The tile height for the matrix. Must be provided \n- * if different than the height given in the layer .\n+ * Property: handlers\n+ * {Object}\n */\n- matrixIds: null,\n+ handlers: null,\n \n /**\n- * APIProperty: dimensions\n- * {Array} For RESTful request encoding, extra dimensions may be specified.\n- * Items in this list should be property names in the object.\n- * Values of extra dimensions will be determined from the corresponding\n- * values in the object.\n+ * Property: resolutionFactor\n+ * {Object}\n */\n- dimensions: null,\n+ resolutionFactor: 1,\n \n /**\n- * APIProperty: params\n- * {Object} Extra parameters to include in tile requests. For KVP \n- * , these properties will be encoded in the request \n- * query string. For REST , these properties will\n- * become part of the request path, with order determined by the \n- * list.\n+ * APIProperty: maximized\n+ * {Boolean} Start as maximized (visible). Defaults to false.\n */\n- params: null,\n+ maximized: false,\n \n /**\n- * APIProperty: zoomOffset\n- * {Number} If your cache has more levels than you want to provide\n- * access to with this layer, supply a zoomOffset. This zoom offset\n- * is added to the current map zoom level to determine the level\n- * for a requested tile. For example, if you supply a zoomOffset\n- * of 3, when the map is at the zoom 0, tiles will be requested from\n- * level 3 of your cache. Default is 0 (assumes cache level and map\n- * zoom are equivalent). Additionally, if this layer is to be used\n- * as an overlay and the cache has fewer zoom levels than the base\n- * layer, you can supply a negative zoomOffset. For example, if a\n- * map zoom level of 1 corresponds to your cache level zero, you would\n- * supply a -1 zoomOffset (and set the maxResolution of the layer\n- * appropriately). The zoomOffset value has no effect if complete\n- * matrix definitions (including scaleDenominator) are supplied in\n- * the property. Defaults to 0 (no zoom offset).\n+ * APIProperty: maximizeTitle\n+ * {String} This property is used for showing a tooltip over the \n+ * maximize div. Defaults to \"\" (no title).\n */\n- zoomOffset: 0,\n+ maximizeTitle: \"\",\n \n /**\n- * APIProperty: serverResolutions\n- * {Array} A list of all resolutions available on the server. Only set this\n- * property if the map resolutions differ from the server. This\n- * property serves two purposes. (a) can include\n- * resolutions that the server supports and that you don't want to\n- * provide with this layer; you can also look at , which is\n- * an alternative to for that specific purpose.\n- * (b) The map can work with resolutions that aren't supported by\n- * the server, i.e. that aren't in . When the\n- * map is displayed in such a resolution data for the closest\n- * server-supported resolution is loaded and the layer div is\n- * stretched as necessary.\n+ * APIProperty: minimizeTitle\n+ * {String} This property is used for showing a tooltip over the \n+ * minimize div. Defaults to \"\" (no title).\n */\n- serverResolutions: null,\n+ minimizeTitle: \"\",\n \n /**\n- * Property: formatSuffixMap\n- * {Object} a map between WMTS 'format' request parameter and tile image file suffix\n+ * Constructor: OpenLayers.Control.OverviewMap\n+ * Create a new overview map\n+ *\n+ * Parameters:\n+ * options - {Object} Properties of this object will be set on the overview\n+ * map object. Note, to set options on the map object contained in this\n+ * control, set as one of the options properties.\n */\n- formatSuffixMap: {\n- \"image/png\": \"png\",\n- \"image/png8\": \"png\",\n- \"image/png24\": \"png\",\n- \"image/png32\": \"png\",\n- \"png\": \"png\",\n- \"image/jpeg\": \"jpg\",\n- \"image/jpg\": \"jpg\",\n- \"jpeg\": \"jpg\",\n- \"jpg\": \"jpg\"\n+ initialize: function(options) {\n+ this.layers = [];\n+ this.handlers = {};\n+ OpenLayers.Control.prototype.initialize.apply(this, [options]);\n },\n \n /**\n- * Property: matrix\n- * {Object} Matrix definition for the current map resolution. Updated by\n- * the method.\n+ * APIMethod: destroy\n+ * Deconstruct the control\n */\n- matrix: null,\n+ destroy: function() {\n+ if (!this.mapDiv) { // we've already been destroyed\n+ return;\n+ }\n+ if (this.handlers.click) {\n+ this.handlers.click.destroy();\n+ }\n+ if (this.handlers.drag) {\n+ this.handlers.drag.destroy();\n+ }\n+\n+ this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle);\n+ this.extentRectangle = null;\n+\n+ if (this.rectEvents) {\n+ this.rectEvents.destroy();\n+ this.rectEvents = null;\n+ }\n+\n+ if (this.ovmap) {\n+ this.ovmap.destroy();\n+ this.ovmap = null;\n+ }\n+\n+ this.element.removeChild(this.mapDiv);\n+ this.mapDiv = null;\n+\n+ this.div.removeChild(this.element);\n+ this.element = null;\n+\n+ if (this.maximizeDiv) {\n+ this.div.removeChild(this.maximizeDiv);\n+ this.maximizeDiv = null;\n+ }\n+\n+ if (this.minimizeDiv) {\n+ this.div.removeChild(this.minimizeDiv);\n+ this.minimizeDiv = null;\n+ }\n+\n+ this.map.events.un({\n+ buttonclick: this.onButtonClick,\n+ moveend: this.update,\n+ changebaselayer: this.baseLayerDraw,\n+ scope: this\n+ });\n+\n+ OpenLayers.Control.prototype.destroy.apply(this, arguments);\n+ },\n \n /**\n- * Constructor: OpenLayers.Layer.WMTS\n- * Create a new WMTS layer.\n- *\n- * Example:\n- * (code)\n- * var wmts = new OpenLayers.Layer.WMTS({\n- * name: \"My WMTS Layer\",\n- * url: \"http://example.com/wmts\", \n- * layer: \"layer_id\",\n- * style: \"default\",\n- * matrixSet: \"matrix_id\"\n- * });\n- * (end)\n- *\n- * Parameters:\n- * config - {Object} Configuration properties for the layer.\n- *\n- * Required configuration properties:\n- * url - {String} The base url for the service. See the property.\n- * layer - {String} The layer identifier. See the property.\n- * style - {String} The layer style identifier. See the