diff --git a/pandora_console/ChangeLog b/pandora_console/ChangeLog index a3a0ad42bc..498c1d4420 100644 --- a/pandora_console/ChangeLog +++ b/pandora_console/ChangeLog @@ -1,3 +1,7 @@ +2010-01-18 Miguel de Dios + + * include/javascript/OpenLayers/*: commit lost files of OpenLayer library. + 2010-01-20 Ramon Novoa * godmode/setup/file_manager.php: Added support for file and empty diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Ajax.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Ajax.js new file mode 100755 index 0000000000..407a6d0cfa --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Ajax.js @@ -0,0 +1,677 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Request/XMLHttpRequest.js + * @requires OpenLayers/Console.js + */ + +OpenLayers.ProxyHost = ""; +//OpenLayers.ProxyHost = "examples/proxy.cgi?url="; + +/** + * Ajax reader for OpenLayers + * + * @uri url to do remote XML http get + * @param {String} 'get' format params (x=y&a=b...) + * @who object to handle callbacks for this request + * @complete the function to be called on success + * @failure the function to be called on failure + * + * example usage from a caller: + * + * caps: function(request) { + * -blah- + * }, + * + * OpenLayers.loadURL(url,params,this,caps); + * + * Notice the above example does not provide an error handler; a default empty + * handler is provided which merely logs the error if a failure handler is not + * supplied + * + */ + + +/** + * Function: OpenLayers.nullHandler + * @param {} request + */ +OpenLayers.nullHandler = function(request) { + OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText})); +}; + +/** + * APIFunction: loadURL + * Background load a document. For more flexibility in using XMLHttpRequest, + * see the methods. + * + * Parameters: + * uri - {String} URI of source doc + * params - {String} or {Object} GET params. Either a string in the form + * "?hello=world&foo=bar" (do not forget the leading question mark) + * or an object in the form {'hello': 'world', 'foo': 'bar} + * caller - {Object} object which gets callbacks + * onComplete - {Function} Optional callback for success. The callback + * will be called with this set to caller and will receive the request + * object as an argument. Note that if you do not specify an onComplete + * function, will be called (which pops up a + * user friendly error message dialog). + * onFailure - {Function} Optional callback for failure. In the event of + * a failure, the callback will be called with this set to caller and will + * receive the request object as an argument. Note that if you do not + * specify an onComplete function, will be called + * (which pops up a user friendly error message dialog). + * + * Returns: + * {} The request object. To abort loading, + * call request.abort(). + */ +OpenLayers.loadURL = function(uri, params, caller, + onComplete, onFailure) { + + if(typeof params == 'string') { + params = OpenLayers.Util.getParameters(params); + } + var success = (onComplete) ? onComplete : OpenLayers.nullHandler; + var failure = (onFailure) ? onFailure : OpenLayers.nullHandler; + + return OpenLayers.Request.GET({ + url: uri, params: params, + success: success, failure: failure, scope: caller + }); +}; + +/** + * Function: parseXMLString + * Parse XML into a doc structure + * + * Parameters: + * text - {String} + * + * Returns: + * {?} Parsed AJAX Responsev + */ +OpenLayers.parseXMLString = function(text) { + + //MS sucks, if the server is bad it dies + var index = text.indexOf('<'); + if (index > 0) { + text = text.substring(index); + } + + var ajaxResponse = OpenLayers.Util.Try( + function() { + var xmldom = new ActiveXObject('Microsoft.XMLDOM'); + xmldom.loadXML(text); + return xmldom; + }, + function() { + return new DOMParser().parseFromString(text, 'text/xml'); + }, + function() { + var req = new XMLHttpRequest(); + req.open("GET", "data:" + "text/xml" + + ";charset=utf-8," + encodeURIComponent(text), false); + if (req.overrideMimeType) { + req.overrideMimeType("text/xml"); + } + req.send(null); + return req.responseXML; + } + ); + + return ajaxResponse; +}; + + +/** + * Namespace: OpenLayers.Ajax + */ +OpenLayers.Ajax = { + + /** + * Method: emptyFunction + */ + emptyFunction: function () {}, + + /** + * Method: getTransport + * + * Returns: + * {Object} Transport mechanism for whichever browser we're in, or false if + * none available. + */ + getTransport: function() { + return OpenLayers.Util.Try( + function() {return new XMLHttpRequest();}, + function() {return new ActiveXObject('Msxml2.XMLHTTP');}, + function() {return new ActiveXObject('Microsoft.XMLHTTP');} + ) || false; + }, + + /** + * Property: activeRequestCount + * {Integer} + */ + activeRequestCount: 0 +}; + +/** + * Namespace: OpenLayers.Ajax.Responders + * {Object} + */ +OpenLayers.Ajax.Responders = { + + /** + * Property: responders + * {Array} + */ + responders: [], + + /** + * Method: register + * + * Parameters: + * responderToAdd - {?} + */ + register: function(responderToAdd) { + for (var i = 0; i < this.responders.length; i++){ + if (responderToAdd == this.responders[i]){ + return; + } + } + this.responders.push(responderToAdd); + }, + + /** + * Method: unregister + * + * Parameters: + * responderToRemove - {?} + */ + unregister: function(responderToRemove) { + OpenLayers.Util.removeItem(this.reponders, responderToRemove); + }, + + /** + * Method: dispatch + * + * Parameters: + * callback - {?} + * request - {?} + * transport - {?} + */ + dispatch: function(callback, request, transport) { + var responder; + for (var i = 0; i < this.responders.length; i++) { + responder = this.responders[i]; + + if (responder[callback] && + typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, + [request, transport]); + } catch (e) {} + } + } + } +}; + +OpenLayers.Ajax.Responders.register({ + /** + * Function: onCreate + */ + onCreate: function() { + OpenLayers.Ajax.activeRequestCount++; + }, + + /** + * Function: onComplete + */ + onComplete: function() { + OpenLayers.Ajax.activeRequestCount--; + } +}); + +/** + * Class: OpenLayers.Ajax.Base + */ +OpenLayers.Ajax.Base = OpenLayers.Class({ + + /** + * Constructor: OpenLayers.Ajax.Base + * + * Parameters: + * options - {Object} + */ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/xml', + parameters: '' + }; + OpenLayers.Util.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + + if (typeof this.options.parameters == 'string') { + this.options.parameters = + OpenLayers.Util.getParameters(this.options.parameters); + } + } +}); + +/** + * Class: OpenLayers.Ajax.Request + * *Deprecated*. Use method instead. + * + * Inherit: + * - + */ +OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, { + + /** + * Property: _complete + * + * {Boolean} + */ + _complete: false, + + /** + * Constructor: OpenLayers.Ajax.Request + * + * Parameters: + * url - {String} + * options - {Object} + */ + initialize: function(url, options) { + OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]); + + if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) { + url = OpenLayers.ProxyHost + encodeURIComponent(url); + } + + this.transport = OpenLayers.Ajax.getTransport(); + this.request(url); + }, + + /** + * Method: request + * + * Parameters: + * url - {String} + */ + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = OpenLayers.Util.extend({}, this.options.parameters); + + if (this.method != 'get' && this.method != 'post') { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = OpenLayers.Util.getParameterString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') { + this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params; + } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + params += '&_='; + } + } + try { + var response = new OpenLayers.Ajax.Response(this); + if (this.options.onCreate) { + this.options.onCreate(response); + } + + OpenLayers.Ajax.Responders.dispatch('onCreate', + this, + response); + + this.transport.open(this.method.toUpperCase(), + this.url, + this.options.asynchronous); + + if (this.options.asynchronous) { + window.setTimeout( + OpenLayers.Function.bind(this.respondToReadyState, this, 1), + 10); + } + + this.transport.onreadystatechange = + OpenLayers.Function.bind(this.onStateChange, this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? + (this.options.postBody || params) : null; + this.transport.send(this.body); + + // Force Firefox to handle ready state 4 for synchronous requests + if (!this.options.asynchronous && + this.transport.overrideMimeType) { + this.onStateChange(); + } + } catch (e) { + this.dispatchException(e); + } + }, + + /** + * Method: onStateChange + */ + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) { + this.respondToReadyState(this.transport.readyState); + } + }, + + /** + * Method: setRequestHeaders + */ + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*', + 'OpenLayers': true + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) { + headers['Connection'] = 'close'; + } + } + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') { + for (var i = 0, length = extras.length; i < length; i += 2) { + headers[extras[i]] = extras[i+1]; + } + } else { + for (var i in extras) { + headers[i] = extras[i]; + } + } + } + + for (var name in headers) { + this.transport.setRequestHeader(name, headers[name]); + } + }, + + /** + * Method: success + * + * Returns: + * {Boolean} - + */ + success: function() { + var status = this.getStatus(); + return !status || (status >=200 && status < 300); + }, + + /** + * Method: getStatus + * + * Returns: + * {Integer} - Status + */ + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { + return 0; + } + }, + + /** + * Method: respondToReadyState + * + * Parameters: + * readyState - {?} + */ + respondToReadyState: function(readyState) { + var state = OpenLayers.Ajax.Request.Events[readyState]; + var response = new OpenLayers.Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] || + this.options['on' + (this.success() ? 'Success' : 'Failure')] || + OpenLayers.Ajax.emptyFunction)(response); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + } + + try { + (this.options['on' + state] || + OpenLayers.Ajax.emptyFunction)(response); + OpenLayers.Ajax.Responders.dispatch('on' + state, + this, + response); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction; + } + }, + + /** + * Method: getHeader + * + * Parameters: + * name - {String} Header name + * + * Returns: + * {?} - response header for the given name + */ + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { + return null; + } + }, + + /** + * Method: dispatchException + * If the optional onException function is set, execute it + * and then dispatch the call to any other listener registered + * for onException. + * + * If no optional onException function is set, we suspect that + * the user may have also not used + * OpenLayers.Ajax.Responders.register to register a listener + * for the onException call. To make sure that something + * gets done with this exception, only dispatch the call if there + * are listeners. + * + * If you explicitly want to swallow exceptions, set + * request.options.onException to an empty function (function(){}) + * or register an empty function with + * for onException. + * + * Parameters: + * exception - {?} + */ + dispatchException: function(exception) { + var handler = this.options.onException; + if(handler) { + // call options.onException and alert any other listeners + handler(this, exception); + OpenLayers.Ajax.Responders.dispatch('onException', this, exception); + } else { + // check if there are any other listeners + var listener = false; + var responders = OpenLayers.Ajax.Responders.responders; + for (var i = 0; i < responders.length; i++) { + if(responders[i].onException) { + listener = true; + break; + } + } + if(listener) { + // call all listeners + OpenLayers.Ajax.Responders.dispatch('onException', this, exception); + } else { + // let the exception through + throw exception; + } + } + } +}); + +/** + * Property: Events + * {Array(String)} + */ +OpenLayers.Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +/** + * Class: OpenLayers.Ajax.Response + */ +OpenLayers.Ajax.Response = OpenLayers.Class({ + + /** + * Property: status + * + * {Integer} + */ + status: 0, + + + /** + * Property: statusText + * + * {String} + */ + statusText: '', + + /** + * Constructor: OpenLayers.Ajax.Response + * + * Parameters: + * request - {Object} + */ + initialize: function(request) { + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if ((readyState > 2 && + !(!!(window.attachEvent && !window.opera))) || + readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = transport.responseText == null ? + '' : String(transport.responseText); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = xml === undefined ? null : xml; + } + }, + + /** + * Method: getStatus + */ + getStatus: OpenLayers.Ajax.Request.prototype.getStatus, + + /** + * Method: getStatustext + * + * Returns: + * {String} - statusText + */ + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { + return ''; + } + }, + + /** + * Method: getHeader + */ + getHeader: OpenLayers.Ajax.Request.prototype.getHeader, + + /** + * Method: getResponseHeader + * + * Returns: + * {?} - response header for given name + */ + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + } +}); + + +/** + * Function: getElementsByTagNameNS + * + * Parameters: + * parentnode - {?} + * nsuri - {?} + * nsprefix - {?} + * tagname - {?} + * + * Returns: + * {?} + */ +OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri, + nsprefix, tagname) { + var elem = null; + if (parentnode.getElementsByTagNameNS) { + elem = parentnode.getElementsByTagNameNS(nsuri, tagname); + } else { + elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname); + } + return elem; +}; + + +/** + * Function: serializeXMLToString + * Wrapper function around XMLSerializer, which doesn't exist/work in + * IE/Safari. We need to come up with a way to serialize in those browser: + * for now, these browsers will just fail. #535, #536 + * + * Parameters: + * xmldom {XMLNode} xml dom to serialize + * + * Returns: + * {?} + */ +OpenLayers.Ajax.serializeXMLToString = function(xmldom) { + var serializer = new XMLSerializer(); + var data = serializer.serializeToString(xmldom); + return data; +}; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/BaseTypes.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/BaseTypes.js new file mode 100755 index 0000000000..615ef1de3e --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/BaseTypes.js @@ -0,0 +1,529 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/BaseTypes/Class.js + * @requires OpenLayers/BaseTypes/LonLat.js + * @requires OpenLayers/BaseTypes/Size.js + * @requires OpenLayers/BaseTypes/Pixel.js + * @requires OpenLayers/BaseTypes/Bounds.js + * @requires OpenLayers/BaseTypes/Element.js + * @requires OpenLayers/Lang/en.js + * @requires OpenLayers/Console.js + */ + +/** + * Header: OpenLayers Base Types + * OpenLayers custom string, number and function functions are described here. + */ + +/** + * Namespace: OpenLayers.String + * Contains convenience functions for string manipulation. + */ +OpenLayers.String = { + + /** + * APIFunction: startsWith + * Test whether a string starts with another string. + * + * Parameters: + * str - {String} The string to test. + * sub - {Sring} The substring to look for. + * + * Returns: + * {Boolean} The first string starts with the second. + */ + startsWith: function(str, sub) { + return (str.indexOf(sub) == 0); + }, + + /** + * APIFunction: contains + * Test whether a string contains another string. + * + * Parameters: + * str - {String} The string to test. + * sub - {String} The substring to look for. + * + * Returns: + * {Boolean} The first string contains the second. + */ + contains: function(str, sub) { + return (str.indexOf(sub) != -1); + }, + + /** + * APIFunction: trim + * Removes leading and trailing whitespace characters from a string. + * + * Parameters: + * str - {String} The (potentially) space padded string. This string is not + * modified. + * + * Returns: + * {String} A trimmed version of the string with all leading and + * trailing spaces removed. + */ + trim: function(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + }, + + /** + * APIFunction: camelize + * Camel-case a hyphenated string. + * Ex. "chicken-head" becomes "chickenHead", and + * "-chicken-head" becomes "ChickenHead". + * + * Parameters: + * str - {String} The string to be camelized. The original is not modified. + * + * Returns: + * {String} The string, camelized + */ + camelize: function(str) { + var oStringList = str.split('-'); + var camelizedString = oStringList[0]; + for (var i=1, len=oStringList.length; i replacement = context[a]; + // 1 -> replacement = context[a][b]; + // 2 -> replacement = context[a][b][c]; + var subs = match.split(/\.+/); + for (var i=0; i< subs.length; i++) { + if (i == 0) { + replacement = context; + } + + replacement = replacement[subs[i]]; + } + + if(typeof replacement == "function") { + replacement = args ? + replacement.apply(null, args) : + replacement(); + } + + // If replacement is undefined, return the string 'undefined'. + // This is a workaround for a bugs in browsers not properly + // dealing with non-participating groups in regular expressions: + // http://blog.stevenlevithan.com/archives/npcg-javascript + if (typeof replacement == 'undefined') { + return 'undefined'; + } else { + return replacement; + } + }; + + return template.replace(OpenLayers.String.tokenRegEx, replacer); + }, + + /** + * Property: OpenLayers.String.tokenRegEx + * Used to find tokens in a string. + * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} + */ + tokenRegEx: /\$\{([\w.]+?)\}/g, + + /** + * Property: OpenLayers.String.numberRegEx + * Used to test strings as numbers. + */ + numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, + + /** + * APIFunction: OpenLayers.String.isNumeric + * Determine whether a string contains only a numeric value. + * + * Examples: + * (code) + * OpenLayers.String.isNumeric("6.02e23") // true + * OpenLayers.String.isNumeric("12 dozen") // false + * OpenLayers.String.isNumeric("4") // true + * OpenLayers.String.isNumeric(" 4 ") // false + * (end) + * + * Returns: + * {Boolean} String contains only a number. + */ + isNumeric: function(value) { + return OpenLayers.String.numberRegEx.test(value); + }, + + /** + * APIFunction: numericIf + * Converts a string that appears to be a numeric value into a number. + * + * Returns + * {Number|String} a Number if the passed value is a number, a String + * otherwise. + */ + numericIf: function(value) { + return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value; + } + +}; + +if (!String.prototype.startsWith) { + /** + * APIMethod: String.startsWith + * *Deprecated*. Whether or not a string starts with another string. + * + * Parameters: + * sStart - {Sring} The string we're testing for. + * + * Returns: + * {Boolean} Whether or not this string starts with the string passed in. + */ + String.prototype.startsWith = function(sStart) { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.String.startsWith'})); + return OpenLayers.String.startsWith(this, sStart); + }; +} + +if (!String.prototype.contains) { + /** + * APIMethod: String.contains + * *Deprecated*. Whether or not a string contains another string. + * + * Parameters: + * str - {String} The string that we're testing for. + * + * Returns: + * {Boolean} Whether or not this string contains with the string passed in. + */ + String.prototype.contains = function(str) { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.String.contains'})); + return OpenLayers.String.contains(this, str); + }; +} + +if (!String.prototype.trim) { + /** + * APIMethod: String.trim + * *Deprecated*. Removes leading and trailing whitespace characters from a string. + * + * Returns: + * {String} A trimmed version of the string - all leading and + * trailing spaces removed + */ + String.prototype.trim = function() { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.String.trim'})); + return OpenLayers.String.trim(this); + }; +} + +if (!String.prototype.camelize) { + /** + * APIMethod: String.camelize + * *Deprecated*. Camel-case a hyphenated string. + * Ex. "chicken-head" becomes "chickenHead", and + * "-chicken-head" becomes "ChickenHead". + * + * Returns: + * {String} The string, camelized + */ + String.prototype.camelize = function() { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.String.camelize'})); + return OpenLayers.String.camelize(this); + }; +} + +/** + * Namespace: OpenLayers.Number + * Contains convenience functions for manipulating numbers. + */ +OpenLayers.Number = { + + /** + * Property: decimalSeparator + * Decimal separator to use when formatting numbers. + */ + decimalSeparator: ".", + + /** + * Property: thousandsSeparator + * Thousands separator to use when formatting numbers. + */ + thousandsSeparator: ",", + + /** + * APIFunction: limitSigDigs + * Limit the number of significant digits on a float. + * + * Parameters: + * num - {Float} + * sig - {Integer} + * + * Returns: + * {Float} The number, rounded to the specified number of significant + * digits. + */ + limitSigDigs: function(num, sig) { + var fig = 0; + if (sig > 0) { + fig = parseFloat(num.toPrecision(sig)); + } + return fig; + }, + + /** + * APIFunction: format + * Formats a number for output. + * + * Parameters: + * num - {Float} + * dec - {Integer} Number of decimal places to round to. + * Defaults to 0. Set to null to leave decimal places unchanged. + * tsep - {String} Thousands separator. + * Default is ",". + * dsep - {String} Decimal separator. + * Default is ".". + * + * Returns: + * {String} A string representing the formatted number. + */ + format: function(num, dec, tsep, dsep) { + dec = (typeof dec != "undefined") ? dec : 0; + tsep = (typeof tsep != "undefined") ? tsep : + OpenLayers.Number.thousandsSeparator; + dsep = (typeof dsep != "undefined") ? dsep : + OpenLayers.Number.decimalSeparator; + + if (dec != null) { + num = parseFloat(num.toFixed(dec)); + } + + var parts = num.toString().split("."); + if (parts.length == 1 && dec == null) { + // integer where we do not want to touch the decimals + dec = 0; + } + + var integer = parts[0]; + if (tsep) { + var thousands = /(-?[0-9]+)([0-9]{3})/; + while(thousands.test(integer)) { + integer = integer.replace(thousands, "$1" + tsep + "$2"); + } + } + + var str; + if (dec == 0) { + str = integer; + } else { + var rem = parts.length > 1 ? parts[1] : "0"; + if (dec != null) { + rem = rem + new Array(dec - rem.length + 1).join("0"); + } + str = integer + dsep + rem; + } + return str; + } +}; + +if (!Number.prototype.limitSigDigs) { + /** + * APIMethod: Number.limitSigDigs + * *Deprecated*. Limit the number of significant digits on an integer. Does *not* + * work with floats! + * + * Parameters: + * sig - {Integer} + * + * Returns: + * {Integer} The number, rounded to the specified number of significant digits. + * If null, 0, or negative value passed in, returns 0 + */ + Number.prototype.limitSigDigs = function(sig) { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.Number.limitSigDigs'})); + return OpenLayers.Number.limitSigDigs(this, sig); + }; +} + +/** + * Namespace: OpenLayers.Function + * Contains convenience functions for function manipulation. + */ +OpenLayers.Function = { + /** + * APIFunction: bind + * Bind a function to an object. Method to easily create closures with + * 'this' altered. + * + * Parameters: + * func - {Function} Input function. + * object - {Object} The object to bind to the input function (as this). + * + * Returns: + * {Function} A closure with 'this' set to the passed in object. + */ + bind: function(func, object) { + // create a reference to all arguments past the second one + var args = Array.prototype.slice.apply(arguments, [2]); + return function() { + // Push on any additional arguments from the actual function call. + // These will come after those sent to the bind call. + var newArgs = args.concat( + Array.prototype.slice.apply(arguments, [0]) + ); + return func.apply(object, newArgs); + }; + }, + + /** + * APIFunction: bindAsEventListener + * Bind a function to an object, and configure it to receive the event + * object as first parameter when called. + * + * Parameters: + * func - {Function} Input function to serve as an event listener. + * object - {Object} A reference to this. + * + * Returns: + * {Function} + */ + bindAsEventListener: function(func, object) { + return function(event) { + return func.call(object, event || window.event); + }; + } +}; + +if (!Function.prototype.bind) { + /** + * APIMethod: Function.bind + * *Deprecated*. Bind a function to an object. + * Method to easily create closures with 'this' altered. + * + * Parameters: + * object - {Object} the this parameter + * + * Returns: + * {Function} A closure with 'this' altered to the first + * argument. + */ + Function.prototype.bind = function() { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.Function.bind'})); + // new function takes the same arguments with this function up front + Array.prototype.unshift.apply(arguments, [this]); + return OpenLayers.Function.bind.apply(null, arguments); + }; +} + +if (!Function.prototype.bindAsEventListener) { + /** + * APIMethod: Function.bindAsEventListener + * *Deprecated*. Bind a function to an object, and configure it to receive the + * event object as first parameter when called. + * + * Parameters: + * object - {Object} A reference to this. + * + * Returns: + * {Function} + */ + Function.prototype.bindAsEventListener = function(object) { + OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", + {'newMethod':'OpenLayers.Function.bindAsEventListener'})); + return OpenLayers.Function.bindAsEventListener(this, object); + }; +} + +/** + * Namespace: OpenLayers.Array + * Contains convenience functions for array manipulation. + */ +OpenLayers.Array = { + + /** + * APIMethod: filter + * Filter an array. Provides the functionality of the + * Array.prototype.filter extension to the ECMA-262 standard. Where + * available, Array.prototype.filter will be used. + * + * Based on well known example from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter + * + * Parameters: + * array - {Array} The array to be filtered. This array is not mutated. + * Elements added to this array by the callback will not be visited. + * callback - {Function} A function that is called for each element in + * the array. If this function returns true, the element will be + * included in the return. The function will be called with three + * arguments: the element in the array, the index of that element, and + * the array itself. If the optional caller parameter is specified + * the callback will be called with this set to caller. + * caller - {Object} Optional object to be set as this when the callback + * is called. + * + * Returns: + * {Array} An array of elements from the passed in array for which the + * callback returns true. + */ + filter: function(array, callback, caller) { + var selected = []; + if (Array.prototype.filter) { + selected = array.filter(callback, caller); + } else { + var len = array.length; + if (typeof callback != "function") { + throw new TypeError(); + } + for(var i=0; i var map = new OpenLayers.Map('map', { controls: [] }); + * > + * > map.addControl(new OpenLayers.Control.PanZoomBar()); + * > map.addControl(new OpenLayers.Control.MouseToolbar()); + * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false})); + * > map.addControl(new OpenLayers.Control.Permalink()); + * > map.addControl(new OpenLayers.Control.Permalink('permalink')); + * > map.addControl(new OpenLayers.Control.MousePosition()); + * > map.addControl(new OpenLayers.Control.OverviewMap()); + * > map.addControl(new OpenLayers.Control.KeyboardDefaults()); + * + * The next code fragment is a quick example of how to intercept + * shift-mouse click to display the extent of the bounding box + * dragged out by the user. Usually controls are not created + * in exactly this manner. See the source for a more complete + * example: + * + * > var control = new OpenLayers.Control(); + * > OpenLayers.Util.extend(control, { + * > draw: function () { + * > // this Handler.Box will intercept the shift-mousedown + * > // before Control.MouseDefault gets to see it + * > this.box = new OpenLayers.Handler.Box( control, + * > {"done": this.notice}, + * > {keyMask: OpenLayers.Handler.MOD_SHIFT}); + * > this.box.activate(); + * > }, + * > + * > notice: function (bounds) { + * > OpenLayers.Console.userError(bounds); + * > } + * > }); + * > map.addControl(control); + * + */ +OpenLayers.Control = OpenLayers.Class({ + + /** + * Property: id + * {String} + */ + id: null, + + /** + * Property: map + * {} this gets set in the addControl() function in + * OpenLayers.Map + */ + map: null, + + /** + * Property: div + * {DOMElement} + */ + div: null, + + /** + * Property: type + * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type + * determines the type of interactions which are possible with them when + * they are placed into a toolbar. + */ + type: null, + + /** + * Property: allowSelection + * {Boolean} By deafault, controls do not allow selection, because + * it may interfere with map dragging. If this is true, OpenLayers + * will not prevent selection of the control. + * Default is false. + */ + allowSelection: false, + + /** + * Property: displayClass + * {string} This property is used for CSS related to the drawing of the + * Control. + */ + displayClass: "", + + /** + * Property: title + * {string} This property is used for showing a tooltip over the + * Control. + */ + title: "", + + /** + * Property: active + * {Boolean} The control is active. + */ + active: null, + + /** + * Property: handler + * {} null + */ + handler: null, + + /** + * APIProperty: eventListeners + * {Object} If set as an option at construction, the eventListeners + * object will be registered with . Object + * structure must be a listeners object as shown in the example for + * the events.on method. + */ + eventListeners: null, + + /** + * Property: events + * {} Events instance for triggering control specific + * events. + */ + events: null, + + /** + * Constant: EVENT_TYPES + * {Array(String)} Supported application event types. Register a listener + * for a particular event with the following syntax: + * (code) + * control.events.register(type, obj, listener); + * (end) + * + * Listeners will be called with a reference to an event object. The + * properties of this event depends on exactly what happened. + * + * All event objects have at least the following properties: + * object - {Object} A reference to control.events.object (a reference + * to the control). + * element - {DOMElement} A reference to control.events.element (which + * will be null unless documented otherwise). + * + * Supported map event types: + * activate - Triggered when activated. + * deactivate - Triggered when deactivated. + */ + EVENT_TYPES: ["activate", "deactivate"], + + /** + * Constructor: OpenLayers.Control + * Create an OpenLayers Control. The options passed as a parameter + * directly extend the control. For example passing the following: + * + * > var control = new OpenLayers.Control({div: myDiv}); + * + * Overrides the default div attribute value of null. + * + * Parameters: + * options - {Object} + */ + initialize: function (options) { + // We do this before the extend so that instances can override + // className in options. + this.displayClass = + this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, ""); + + OpenLayers.Util.extend(this, options); + + this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES); + if(this.eventListeners instanceof Object) { + this.events.on(this.eventListeners); + } + if (this.id == null) { + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + } + }, + + /** + * Method: destroy + * The destroy method is used to perform any clean up before the control + * is dereferenced. Typically this is where event listeners are removed + * to prevent memory leaks. + */ + destroy: function () { + if(this.events) { + if(this.eventListeners) { + this.events.un(this.eventListeners); + } + this.events.destroy(); + this.events = null; + } + this.eventListeners = null; + + // eliminate circular references + if (this.handler) { + this.handler.destroy(); + this.handler = null; + } + if(this.handlers) { + for(var key in this.handlers) { + if(this.handlers.hasOwnProperty(key) && + typeof this.handlers[key].destroy == "function") { + this.handlers[key].destroy(); + } + } + this.handlers = null; + } + if (this.map) { + this.map.removeControl(this); + this.map = null; + } + }, + + /** + * Method: setMap + * Set the map property for the control. This is done through an accessor + * so that subclasses can override this and take special action once + * they have their map variable set. + * + * Parameters: + * map - {} + */ + setMap: function(map) { + this.map = map; + if (this.handler) { + this.handler.setMap(map); + } + }, + + /** + * Method: draw + * The draw method is called when the control is ready to be displayed + * on the page. If a div has not been created one is created. Controls + * with a visual component will almost always want to override this method + * to customize the look of control. + * + * Parameters: + * px - {} The top-left pixel position of the control + * or null. + * + * Returns: + * {DOMElement} A reference to the DIV DOMElement containing the control + */ + draw: function (px) { + if (this.div == null) { + this.div = OpenLayers.Util.createDiv(this.id); + this.div.className = this.displayClass; + if (!this.allowSelection) { + this.div.className += " olControlNoSelect"; + this.div.setAttribute("unselectable", "on", 0); + this.div.onselectstart = function() { return(false); }; + } + if (this.title != "") { + this.div.title = this.title; + } + } + if (px != null) { + this.position = px.clone(); + } + this.moveTo(this.position); + return this.div; + }, + + /** + * Method: moveTo + * Sets the left and top style attributes to the passed in pixel + * coordinates. + * + * Parameters: + * px - {} + */ + moveTo: function (px) { + if ((px != null) && (this.div != null)) { + this.div.style.left = px.x + "px"; + this.div.style.top = px.y + "px"; + } + }, + + /** + * Method: activate + * Explicitly activates a control and it's associated + * handler if one has been set. Controls can be + * deactivated by calling the deactivate() method. + * + * Returns: + * {Boolean} True if the control was successfully activated or + * false if the control was already active. + */ + activate: function () { + if (this.active) { + return false; + } + if (this.handler) { + this.handler.activate(); + } + this.active = true; + if(this.map) { + OpenLayers.Element.addClass( + this.map.viewPortDiv, + this.displayClass.replace(/ /g, "") + "Active" + ); + } + this.events.triggerEvent("activate"); + return true; + }, + + /** + * Method: deactivate + * Deactivates a control and it's associated handler if any. The exact + * effect of this depends on the control itself. + * + * Returns: + * {Boolean} True if the control was effectively deactivated or false + * if the control was already inactive. + */ + deactivate: function () { + if (this.active) { + if (this.handler) { + this.handler.deactivate(); + } + this.active = false; + if(this.map) { + OpenLayers.Element.removeClass( + this.map.viewPortDiv, + this.displayClass.replace(/ /g, "") + "Active" + ); + } + this.events.triggerEvent("deactivate"); + return true; + } + return false; + }, + + CLASS_NAME: "OpenLayers.Control" +}); + +OpenLayers.Control.TYPE_BUTTON = 1; +OpenLayers.Control.TYPE_TOGGLE = 2; +OpenLayers.Control.TYPE_TOOL = 3; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Events.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Events.js new file mode 100755 index 0000000000..bb0d954bf2 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Events.js @@ -0,0 +1,828 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + */ + +/** + * Namespace: OpenLayers.Event + * Utility functions for event handling. + */ +OpenLayers.Event = { + + /** + * Property: observers + * {Object} A hashtable cache of the event observers. Keyed by + * element._eventCacheID + */ + observers: false, + + /** + * Constant: KEY_BACKSPACE + * {int} + */ + KEY_BACKSPACE: 8, + + /** + * Constant: KEY_TAB + * {int} + */ + KEY_TAB: 9, + + /** + * Constant: KEY_RETURN + * {int} + */ + KEY_RETURN: 13, + + /** + * Constant: KEY_ESC + * {int} + */ + KEY_ESC: 27, + + /** + * Constant: KEY_LEFT + * {int} + */ + KEY_LEFT: 37, + + /** + * Constant: KEY_UP + * {int} + */ + KEY_UP: 38, + + /** + * Constant: KEY_RIGHT + * {int} + */ + KEY_RIGHT: 39, + + /** + * Constant: KEY_DOWN + * {int} + */ + KEY_DOWN: 40, + + /** + * Constant: KEY_DELETE + * {int} + */ + KEY_DELETE: 46, + + + /** + * Method: element + * Cross browser event element detection. + * + * Parameters: + * event - {Event} + * + * Returns: + * {DOMElement} The element that caused the event + */ + element: function(event) { + return event.target || event.srcElement; + }, + + /** + * Method: isLeftClick + * Determine whether event was caused by a left click. + * + * Parameters: + * event - {Event} + * + * Returns: + * {Boolean} + */ + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + /** + * Method: isRightClick + * Determine whether event was caused by a right mouse click. + * + * Parameters: + * event - {Event} + * + * Returns: + * {Boolean} + */ + isRightClick: function(event) { + return (((event.which) && (event.which == 3)) || + ((event.button) && (event.button == 2))); + }, + + /** + * Method: stop + * Stops an event from propagating. + * + * Parameters: + * event - {Event} + * allowDefault - {Boolean} If true, we stop the event chain but + * still allow the default browser + * behaviour (text selection, radio-button + * clicking, etc) + * Default false + */ + stop: function(event, allowDefault) { + + if (!allowDefault) { + if (event.preventDefault) { + event.preventDefault(); + } else { + event.returnValue = false; + } + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else { + event.cancelBubble = true; + } + }, + + /** + * Method: findElement + * + * Parameters: + * event - {Event} + * tagName - {String} + * + * Returns: + * {DOMElement} The first node with the given tagName, starting from the + * node the event was triggered on and traversing the DOM upwards + */ + findElement: function(event, tagName) { + var element = OpenLayers.Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))){ + element = element.parentNode; + } + return element; + }, + + /** + * Method: observe + * + * Parameters: + * elementParam - {DOMElement || String} + * name - {String} + * observer - {function} + * useCapture - {Boolean} + */ + observe: function(elementParam, name, observer, useCapture) { + var element = OpenLayers.Util.getElement(elementParam); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) { + name = 'keydown'; + } + + //if observers cache has not yet been created, create it + if (!this.observers) { + this.observers = {}; + } + + //if not already assigned, make a new unique cache ID + if (!element._eventCacheID) { + var idPrefix = "eventCacheID_"; + if (element.id) { + idPrefix = element.id + "_" + idPrefix; + } + element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix); + } + + var cacheID = element._eventCacheID; + + //if there is not yet a hash entry for this element, add one + if (!this.observers[cacheID]) { + this.observers[cacheID] = []; + } + + //add a new observer to this element's list + this.observers[cacheID].push({ + 'element': element, + 'name': name, + 'observer': observer, + 'useCapture': useCapture + }); + + //add the actual browser event listener + if (element.addEventListener) { + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + element.attachEvent('on' + name, observer); + } + }, + + /** + * Method: stopObservingElement + * Given the id of an element to stop observing, cycle through the + * element's cached observers, calling stopObserving on each one, + * skipping those entries which can no longer be removed. + * + * parameters: + * elementParam - {DOMElement || String} + */ + stopObservingElement: function(elementParam) { + var element = OpenLayers.Util.getElement(elementParam); + var cacheID = element._eventCacheID; + + this._removeElementObservers(OpenLayers.Event.observers[cacheID]); + }, + + /** + * Method: _removeElementObservers + * + * Parameters: + * elementObservers - {Array(Object)} Array of (element, name, + * observer, usecapture) objects, + * taken directly from hashtable + */ + _removeElementObservers: function(elementObservers) { + if (elementObservers) { + for(var i = elementObservers.length-1; i >= 0; i--) { + var entry = elementObservers[i]; + var args = new Array(entry.element, + entry.name, + entry.observer, + entry.useCapture); + var removed = OpenLayers.Event.stopObserving.apply(this, args); + } + } + }, + + /** + * Method: stopObserving + * + * Parameters: + * elementParam - {DOMElement || String} + * name - {String} + * observer - {function} + * useCapture - {Boolean} + * + * Returns: + * {Boolean} Whether or not the event observer was removed + */ + stopObserving: function(elementParam, name, observer, useCapture) { + useCapture = useCapture || false; + + var element = OpenLayers.Util.getElement(elementParam); + var cacheID = element._eventCacheID; + + if (name == 'keypress') { + if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || + element.detachEvent) { + name = 'keydown'; + } + } + + // find element's entry in this.observers cache and remove it + var foundEntry = false; + var elementObservers = OpenLayers.Event.observers[cacheID]; + if (elementObservers) { + + // find the specific event type in the element's list + var i=0; + while(!foundEntry && i < elementObservers.length) { + var cacheEntry = elementObservers[i]; + + if ((cacheEntry.name == name) && + (cacheEntry.observer == observer) && + (cacheEntry.useCapture == useCapture)) { + + elementObservers.splice(i, 1); + if (elementObservers.length == 0) { + delete OpenLayers.Event.observers[cacheID]; + } + foundEntry = true; + break; + } + i++; + } + } + + //actually remove the event listener from browser + if (foundEntry) { + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element && element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } + return foundEntry; + }, + + /** + * Method: unloadCache + * Cycle through all the element entries in the events cache and call + * stopObservingElement on each. + */ + unloadCache: function() { + // check for OpenLayers.Event before checking for observers, because + // OpenLayers.Event may be undefined in IE if no map instance was + // created + if (OpenLayers.Event && OpenLayers.Event.observers) { + for (var cacheID in OpenLayers.Event.observers) { + var elementObservers = OpenLayers.Event.observers[cacheID]; + OpenLayers.Event._removeElementObservers.apply(this, + [elementObservers]); + } + OpenLayers.Event.observers = false; + } + }, + + CLASS_NAME: "OpenLayers.Event" +}; + +/* prevent memory leaks in IE */ +OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false); + +// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided +// by OpenLayers. +if (window.Event) { + OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event); +} else { + var Event = OpenLayers.Event; +} + +/** + * Class: OpenLayers.Events + */ +OpenLayers.Events = OpenLayers.Class({ + + /** + * Constant: BROWSER_EVENTS + * {Array(String)} supported events + */ + BROWSER_EVENTS: [ + "mouseover", "mouseout", + "mousedown", "mouseup", "mousemove", + "click", "dblclick", "rightclick", "dblrightclick", + "resize", "focus", "blur" + ], + + /** + * Property: listeners + * {Object} Hashtable of Array(Function): events listener functions + */ + listeners: null, + + /** + * Property: object + * {Object} the code object issuing application events + */ + object: null, + + /** + * Property: element + * {DOMElement} the DOM element receiving browser events + */ + element: null, + + /** + * Property: eventTypes + * {Array(String)} list of support application events + */ + eventTypes: null, + + /** + * Property: eventHandler + * {Function} bound event handler attached to elements + */ + eventHandler: null, + + /** + * APIProperty: fallThrough + * {Boolean} + */ + fallThrough: null, + + /** + * APIProperty: includeXY + * {Boolean} Should the .xy property automatically be created for browser + * mouse events? In general, this should be false. If it is true, then + * mouse events will automatically generate a '.xy' property on the + * event object that is passed. (Prior to OpenLayers 2.7, this was true + * by default.) Otherwise, you can call the getMousePosition on the + * relevant events handler on the object available via the 'evt.object' + * property of the evt object. So, for most events, you can call: + * function named(evt) { + * this.xy = this.object.events.getMousePosition(evt) + * } + * + * This option typically defaults to false for performance reasons: + * when creating an events object whose primary purpose is to manage + * relatively positioned mouse events within a div, it may make + * sense to set it to true. + * + * This option is also used to control whether the events object caches + * offsets. If this is false, it will not: the reason for this is that + * it is only expected to be called many times if the includeXY property + * is set to true. If you set this to true, you are expected to clear + * the offset cache manually (using this.clearMouseCache()) if: + * the border of the element changes + * the location of the element in the page changes + */ + includeXY: false, + + /** + * Method: clearMouseListener + * A version of that is bound to this instance so that + * it can be used with and + * . + */ + clearMouseListener: null, + + /** + * Constructor: OpenLayers.Events + * Construct an OpenLayers.Events object. + * + * Parameters: + * object - {Object} The js object to which this Events object is being + * added element - {DOMElement} A dom element to respond to browser events + * eventTypes - {Array(String)} Array of custom application events + * fallThrough - {Boolean} Allow events to fall through after these have + * been handled? + * options - {Object} Options for the events object. + */ + initialize: function (object, element, eventTypes, fallThrough, options) { + OpenLayers.Util.extend(this, options); + this.object = object; + this.fallThrough = fallThrough; + this.listeners = {}; + + // keep a bound copy of handleBrowserEvent() so that we can + // pass the same function to both Event.observe() and .stopObserving() + this.eventHandler = OpenLayers.Function.bindAsEventListener( + this.handleBrowserEvent, this + ); + + // to be used with observe and stopObserving + this.clearMouseListener = OpenLayers.Function.bind( + this.clearMouseCache, this + ); + + // if eventTypes is specified, create a listeners list for each + // custom application event. + this.eventTypes = []; + if (eventTypes != null) { + for (var i=0, len=eventTypes.length; i} The current xy coordinate of the mouse, adjusted + * for offsets + */ + getMousePosition: function (evt) { + if (!this.includeXY) { + this.clearMouseCache(); + } else if (!this.element.hasScrollEvent) { + OpenLayers.Event.observe(window, "scroll", this.clearMouseListener); + this.element.hasScrollEvent = true; + } + + if (!this.element.scrolls) { + this.element.scrolls = [ + (document.documentElement.scrollLeft + || document.body.scrollLeft), + (document.documentElement.scrollTop + || document.body.scrollTop) + ]; + } + + if (!this.element.lefttop) { + this.element.lefttop = [ + (document.documentElement.clientLeft || 0), + (document.documentElement.clientTop || 0) + ]; + } + + if (!this.element.offsets) { + this.element.offsets = OpenLayers.Util.pagePosition(this.element); + this.element.offsets[0] += this.element.scrolls[0]; + this.element.offsets[1] += this.element.scrolls[1]; + } + return new OpenLayers.Pixel( + (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0] + - this.element.lefttop[0], + (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1] + - this.element.lefttop[1] + ); + }, + + CLASS_NAME: "OpenLayers.Events" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Feature.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Feature.js new file mode 100755 index 0000000000..2eaafbdba5 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Feature.js @@ -0,0 +1,222 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Marker.js + * @requires OpenLayers/Popup/AnchoredBubble.js + */ + +/** + * Class: OpenLayers.Feature + * Features are combinations of geography and attributes. The OpenLayers.Feature + * class specifically combines a marker and a lonlat. + */ +OpenLayers.Feature = OpenLayers.Class({ + + /** + * Property: layer + * {} + */ + layer: null, + + /** + * Property: id + * {String} + */ + id: null, + + /** + * Property: lonlat + * {} + */ + lonlat: null, + + /** + * Property: data + * {Object} + */ + data: null, + + /** + * Property: marker + * {} + */ + marker: null, + + /** + * APIProperty: popupClass + * {} The class which will be used to instantiate + * a new Popup. Default is . + */ + popupClass: OpenLayers.Popup.AnchoredBubble, + + /** + * Property: popup + * {} + */ + popup: null, + + /** + * Constructor: OpenLayers.Feature + * Constructor for features. + * + * Parameters: + * layer - {} + * lonlat - {} + * data - {Object} + * + * Returns: + * {} + */ + initialize: function(layer, lonlat, data) { + this.layer = layer; + this.lonlat = lonlat; + this.data = (data != null) ? data : {}; + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + }, + + /** + * Method: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + + //remove the popup from the map + if ((this.layer != null) && (this.layer.map != null)) { + if (this.popup != null) { + this.layer.map.removePopup(this.popup); + } + } + + this.layer = null; + this.id = null; + this.lonlat = null; + this.data = null; + if (this.marker != null) { + this.destroyMarker(this.marker); + this.marker = null; + } + if (this.popup != null) { + this.destroyPopup(this.popup); + this.popup = null; + } + }, + + /** + * Method: onScreen + * + * Returns: + * {Boolean} Whether or not the feature is currently visible on screen + * (based on its 'lonlat' property) + */ + onScreen:function() { + + var onScreen = false; + if ((this.layer != null) && (this.layer.map != null)) { + var screenBounds = this.layer.map.getExtent(); + onScreen = screenBounds.containsLonLat(this.lonlat); + } + return onScreen; + }, + + + /** + * Method: createMarker + * Based on the data associated with the Feature, create and return a marker object. + * + * Returns: + * {} A Marker Object created from the 'lonlat' and 'icon' properties + * set in this.data. If no 'lonlat' is set, returns null. If no + * 'icon' is set, OpenLayers.Marker() will load the default image. + * + * Note - this.marker is set to return value + * + */ + createMarker: function() { + + if (this.lonlat != null) { + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); + } + return this.marker; + }, + + /** + * Method: destroyMarker + * Destroys marker. + * If user overrides the createMarker() function, s/he should be able + * to also specify an alternative function for destroying it + */ + destroyMarker: function() { + this.marker.destroy(); + }, + + /** + * Method: createPopup + * Creates a popup object created from the 'lonlat', 'popupSize', + * and 'popupContentHTML' properties set in this.data. It uses + * this.marker.icon as default anchor. + * + * If no 'lonlat' is set, returns null. + * If no this.marker has been created, no anchor is sent. + * + * Note - the returned popup object is 'owned' by the feature, so you + * cannot use the popup's destroy method to discard the popup. + * Instead, you must use the feature's destroyPopup + * + * Note - this.popup is set to return value + * + * Parameters: + * closeBox - {Boolean} create popup with closebox or not + * + * Returns: + * {} Returns the created popup, which is also set + * as 'popup' property of this feature. Will be of whatever type + * specified by this feature's 'popupClass' property, but must be + * of type . + * + */ + createPopup: function(closeBox) { + + if (this.lonlat != null) { + + var id = this.id + "_popup"; + var anchor = (this.marker) ? this.marker.icon : null; + + if (!this.popup) { + this.popup = new this.popupClass(id, + this.lonlat, + this.data.popupSize, + this.data.popupContentHTML, + anchor, + closeBox); + } + if (this.data.overflow != null) { + this.popup.contentDiv.style.overflow = this.data.overflow; + } + + this.popup.feature = this; + } + return this.popup; + }, + + + /** + * Method: destroyPopup + * Destroys the popup created via createPopup. + * + * As with the marker, if user overrides the createPopup() function, s/he + * should also be able to override the destruction + */ + destroyPopup: function() { + if (this.popup) { + this.popup.feature = null; + this.popup.destroy(); + this.popup = null; + } + }, + + CLASS_NAME: "OpenLayers.Feature" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Filter.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Filter.js new file mode 100755 index 0000000000..31cbcd36ba --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Filter.js @@ -0,0 +1,66 @@ +/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. + * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt + * for the full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Style.js + */ + +/** + * Class: OpenLayers.Filter + * This class represents an OGC Filter. + */ +OpenLayers.Filter = OpenLayers.Class({ + + /** + * Constructor: OpenLayers.Filter + * This is an abstract class. Create an instance of a filter subclass. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Returns: + * {} + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + }, + + /** + * APIMethod: destroy + * Remove reference to anything added. + */ + destroy: function() { + }, + + /** + * APIMethod: evaluate + * Evaluates this filter in a specific context. Should be implemented by + * subclasses. + * + * Parameters: + * context - {Object} Context to use in evaluating the filter. + * + * Returns: + * {Boolean} The filter applies. + */ + evaluate: function(context) { + return true; + }, + + /** + * APIMethod: clone + * Clones this filter. Should be implementted by subclasses. + * + * Returns: + * {} Clone of this filter. + */ + clone: function() { + return null; + }, + + CLASS_NAME: "OpenLayers.Filter" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format.js new file mode 100755 index 0000000000..0a11e39e3f --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format.js @@ -0,0 +1,122 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Console.js + */ + +/** + * Class: OpenLayers.Format + * Base class for format reading/writing a variety of formats. Subclasses + * of OpenLayers.Format are expected to have read and write methods. + */ +OpenLayers.Format = OpenLayers.Class({ + + /** + * Property: options + * {Object} A reference to options passed to the constructor. + */ + options: null, + + /** + * APIProperty: externalProjection + * {} When passed a externalProjection and + * internalProjection, the format will reproject the geometries it + * reads or writes. The externalProjection is the projection used by + * the content which is passed into read or which comes out of write. + * In order to reproject, a projection transformation function for the + * specified projections must be available. This support may be + * provided via proj4js or via a custom transformation function. See + * {} for more information on + * custom transformations. + */ + externalProjection: null, + + /** + * APIProperty: internalProjection + * {} When passed a externalProjection and + * internalProjection, the format will reproject the geometries it + * reads or writes. The internalProjection is the projection used by + * the geometries which are returned by read or which are passed into + * write. In order to reproject, a projection transformation function + * for the specified projections must be available. This support may be + * provided via proj4js or via a custom transformation function. See + * {} for more information on + * custom transformations. + */ + internalProjection: null, + + /** + * APIProperty: data + * {Object} When is true, this is the parsed string sent to + * . + */ + data: null, + + /** + * APIProperty: keepData + * {Object} Maintain a reference () to the most recently read data. + * Default is false. + */ + keepData: false, + + /** + * Constructor: OpenLayers.Format + * Instances of this class are not useful. See one of the subclasses. + * + * Parameters: + * options - {Object} An optional object with properties to set on the + * format + * + * Valid options: + * keepData - {Boolean} If true, upon , the data property will be + * set to the parsed object (e.g. the json or xml object). + * + * Returns: + * An instance of OpenLayers.Format + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + this.options = options; + }, + + /** + * APIMethod: destroy + * Clean up. + */ + destroy: function() { + }, + + /** + * Method: read + * Read data from a string, and return an object whose type depends on the + * subclass. + * + * Parameters: + * data - {string} Data to read/parse. + * + * Returns: + * Depends on the subclass + */ + read: function(data) { + OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented")); + }, + + /** + * Method: write + * Accept an object, and return a string. + * + * Parameters: + * object - {Object} Object to be serialized + * + * Returns: + * {String} A string representation of the object. + */ + write: function(object) { + OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented")); + }, + + CLASS_NAME: "OpenLayers.Format" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1.js new file mode 100755 index 0000000000..29f546bdbc --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1.js @@ -0,0 +1,883 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Rule.js + * @requires OpenLayers/Format/SLD.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.SLD.v1 + * Superclass for SLD version 1 parsers. + * + * Inherits from: + * - + */ +OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + sld: "http://www.opengis.net/sld", + ogc: "http://www.opengis.net/ogc", + gml: "http://www.opengis.net/gml", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "sld", + + /** + * Property: schemaLocation + * {String} Schema location for a particular minor version. + */ + schemaLocation: null, + + /** + * APIProperty: defaultSymbolizer. + * {Object} A symbolizer with the SLD defaults. + */ + defaultSymbolizer: { + fillColor: "#808080", + fillOpacity: 1, + strokeColor: "#000000", + strokeOpacity: 1, + strokeWidth: 1, + strokeDashstyle: "solid", + pointRadius: 3, + graphicName: "square" + }, + + /** + * Constructor: OpenLayers.Format.SLD.v1 + * Instances of this class are not created directly. Use the + * constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); + }, + + /** + * Method: read + * + * Parameters: + * data - {DOMElement} An SLD document element. + * options - {Object} Options for the reader. + * + * Valid options: + * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, + * the namedLayers property value will be an object keyed by layer name. + * Default is false. + * + * Returns: + * {Object} An object representing the SLD. + */ + read: function(data, options) { + options = OpenLayers.Util.applyDefaults(options, this.options); + var sld = { + namedLayers: options.namedLayersAsArray === true ? [] : {} + }; + this.readChildNodes(data, sld); + return sld; + }, + + /** + * Property: readers + * Contains public functions, grouped by namespace prefix, that will + * be applied when a namespaced node is found matching the function + * name. The function will be applied in the scope of this parser + * with two arguments: the node being read and a context object passed + * from the parent. + */ + readers: OpenLayers.Util.applyDefaults({ + "sld": { + "StyledLayerDescriptor": function(node, sld) { + sld.version = node.getAttribute("version"); + this.readChildNodes(node, sld); + }, + "Name": function(node, obj) { + obj.name = this.getChildValue(node); + }, + "Title": function(node, obj) { + obj.title = this.getChildValue(node); + }, + "Abstract": function(node, obj) { + obj.description = this.getChildValue(node); + }, + "NamedLayer": function(node, sld) { + var layer = { + userStyles: [], + namedStyles: [] + }; + this.readChildNodes(node, layer); + // give each of the user styles this layer name + for(var i=0, len=layer.userStyles.length; i. + * + * Parameters: + * sym - {String} A symbolizer property name. + * + * Returns: + * {String} A CSS property name or null if none found. + */ + getCssProperty: function(sym) { + var css = null; + for(var prop in this.cssMap) { + if(this.cssMap[prop] == sym) { + css = prop; + break; + } + } + return css; + }, + + /** + * Method: getGraphicFormat + * Given a href for an external graphic, try to determine the mime-type. + * This method doesn't try too hard, and will fall back to + * if one of the known is not + * the file extension of the provided href. + * + * Parameters: + * href - {String} + * + * Returns: + * {String} The graphic format. + */ + getGraphicFormat: function(href) { + var format, regex; + for(var key in this.graphicFormats) { + if(this.graphicFormats[key].test(href)) { + format = key; + break; + } + } + return format || this.defautlGraphicFormat; + }, + + /** + * Property: defaultGraphicFormat + * {String} If none other can be determined from , this + * default will be returned. + */ + defaultGraphicFormat: "image/png", + + /** + * Property: graphicFormats + * {Object} Mapping of image mime-types to regular extensions matching + * well-known file extensions. + */ + graphicFormats: { + "image/jpeg": /\.jpe?g$/i, + "image/gif": /\.gif$/i, + "image/png": /\.png$/i + }, + + /** + * Method: write + * + * Parameters: + * sld - {Object} An object representing the SLD. + * + * Returns: + * {DOMElement} The root of an SLD document. + */ + write: function(sld) { + return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); + }, + + /** + * Property: writers + * As a compliment to the readers property, this structure contains public + * writing functions grouped by namespace alias and named like the + * node names they produce. + */ + writers: OpenLayers.Util.applyDefaults({ + "sld": { + "StyledLayerDescriptor": function(sld) { + var root = this.createElementNSPlus( + "StyledLayerDescriptor", + {attributes: { + "version": this.VERSION, + "xsi:schemaLocation": this.schemaLocation + }} + ); + // add in optional name + if(sld.name) { + this.writeNode("Name", sld.name, root); + } + // add in optional title + if(sld.title) { + this.writeNode("Title", sld.title, root); + } + // add in optional description + if(sld.description) { + this.writeNode("Abstract", sld.description, root); + } + // add in named layers + // allow namedLayers to be an array + if(sld.namedLayers instanceof Array) { + for(var i=0, len=sld.namedLayers.length; i 0) { + this.writeNode( + "ogc:PropertyName", + {property: item.substring(0, last)}, + node + ); + node.appendChild( + this.createTextNode(item.substring(++last)) + ); + } else { + // no ending }, so this is a literal ${ + node.appendChild( + this.createTextNode("${" + item) + ); + } + } + return node; + }, + "Halo": function(symbolizer) { + var node = this.createElementNSPlus("Halo"); + if(symbolizer.haloRadius) { + this.writeNode("Radius", symbolizer.haloRadius, node); + } + if(symbolizer.haloColor || symbolizer.haloOpacity) { + this.writeNode("Fill", { + fillColor: symbolizer.haloColor, + fillOpacity: symbolizer.haloOpacity + }, node); + } + return node; + }, + "Radius": function(value) { + return node = this.createElementNSPlus("Radius", { + value: value + }); + }, + "PolygonSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("PolygonSymbolizer"); + if(symbolizer.fillColor != undefined || + symbolizer.fillOpacity != undefined) { + this.writeNode("Fill", symbolizer, node); + } + if(symbolizer.strokeWidth != undefined || + symbolizer.strokeColor != undefined || + symbolizer.strokeOpacity != undefined || + symbolizer.strokeDashstyle != undefined) { + this.writeNode("Stroke", symbolizer, node); + } + return node; + }, + "Fill": function(symbolizer) { + var node = this.createElementNSPlus("Fill"); + + // GraphicFill here + + // add in CssParameters + if(symbolizer.fillColor) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fillColor"}, + node + ); + } + if(symbolizer.fillOpacity != null) { + this.writeNode( + "CssParameter", + {symbolizer: symbolizer, key: "fillOpacity"}, + node + ); + } + return node; + }, + "PointSymbolizer": function(symbolizer) { + var node = this.createElementNSPlus("PointSymbolizer"); + this.writeNode("Graphic", symbolizer, node); + return node; + }, + "Graphic": function(symbolizer) { + var node = this.createElementNSPlus("Graphic"); + if(symbolizer.externalGraphic != undefined) { + this.writeNode("ExternalGraphic", symbolizer, node); + } else { + this.writeNode("Mark", symbolizer, node); + } + + if(symbolizer.graphicOpacity != undefined) { + this.writeNode("Opacity", symbolizer.graphicOpacity, node); + } + if(symbolizer.pointRadius != undefined) { + this.writeNode("Size", symbolizer.pointRadius * 2, node); + } + if(symbolizer.rotation != undefined) { + this.writeNode("Rotation", symbolizer.rotation, node); + } + return node; + }, + "ExternalGraphic": function(symbolizer) { + var node = this.createElementNSPlus("ExternalGraphic"); + this.writeNode( + "OnlineResource", symbolizer.externalGraphic, node + ); + var format = symbolizer.graphicFormat || + this.getGraphicFormat(symbolizer.externalGraphic); + this.writeNode("Format", format, node); + return node; + }, + "Mark": function(symbolizer) { + var node = this.createElementNSPlus("Mark"); + if(symbolizer.graphicName) { + this.writeNode("WellKnownName", symbolizer.graphicName, node); + } + this.writeNode("Fill", symbolizer, node); + this.writeNode("Stroke", symbolizer, node); + return node; + }, + "WellKnownName": function(name) { + return this.createElementNSPlus("WellKnownName", { + value: name + }); + }, + "Opacity": function(value) { + return this.createElementNSPlus("Opacity", { + value: value + }); + }, + "Size": function(value) { + return this.createElementNSPlus("Size", { + value: value + }); + }, + "Rotation": function(value) { + return this.createElementNSPlus("Rotation", { + value: value + }); + }, + "OnlineResource": function(href) { + return this.createElementNSPlus("OnlineResource", { + attributes: { + "xlink:type": "simple", + "xlink:href": href + } + }); + }, + "Format": function(format) { + return this.createElementNSPlus("Format", { + value: format + }); + } + } + }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), + + CLASS_NAME: "OpenLayers.Format.SLD.v1" + +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1_0_0.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1_0_0.js new file mode 100755 index 0000000000..4d9a1fe22c --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/SLD/v1_0_0.js @@ -0,0 +1,50 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/SLD/v1.js + * @requires OpenLayers/Format/Filter/v1_0_0.js + */ + +/** + * Class: OpenLayers.Format.SLD.v1_0_0 + * Write SLD version 1.0.0. + * + * Inherits from: + * - + */ +OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.SLD.v1, { + + /** + * Constant: VERSION + * {String} 1.0.0 + */ + VERSION: "1.0.0", + + /** + * Property: schemaLocation + * {String} http://www.opengis.net/sld + * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd + */ + schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", + + /** + * Constructor: OpenLayers.Format.SLD.v1_0_0 + * Instances of this class are not created directly. Use the + * constructor instead. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.SLD.v1.prototype.initialize.apply( + this, [options] + ); + }, + + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" + +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1.js new file mode 100755 index 0000000000..4402a262e5 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1.js @@ -0,0 +1,117 @@ +/** + * @requires OpenLayers/Format/WFSCapabilities.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - + */ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.WFSCapabilities, { + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + this.options = options; + }, + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var capabilities = {}; + var root = data.documentElement; + this.runChildNodes(capabilities, root); + return capabilities; + }, + + /** + * Method: runChildNodes + */ + runChildNodes: function(obj, node) { + var children = node.childNodes; + var childNode, processor; + for(var i=0; i + */ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WFSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 + * Create a new parser for WFS capabilities version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply( + this, [options] + ); + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" + +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js new file mode 100755 index 0000000000..4ef24e184b --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WFSCapabilities/v1_1_0.js @@ -0,0 +1,31 @@ +/** + * @requires OpenLayers/Format/WFSCapabilities/v1.js + */ + +/** + * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 + * Read WFS Capabilities version 1.1.0. + * + * Inherits from: + * - + */ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WFSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 + * Create a new parser for WFS capabilities version 1.1.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply( + this, [options] + ); + }, + + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" + +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js new file mode 100755 index 0000000000..9e7392af18 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js @@ -0,0 +1,266 @@ +/** + * @requires OpenLayers/Format/WMSCapabilities.js + * @requires OpenLayers/Format/XML.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities.v1_1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - + */ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + this.options = options; + }, + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var capabilities = {}; + var root = data.documentElement; + this.runChildNodes(capabilities, root); + return capabilities; + }, + + /** + * Method: runChildNodes + */ + runChildNodes: function(obj, node) { + var children = node.childNodes; + var childNode, processor; + for(var i=0; i 0) { + this.read_cap_OnlineResource(obj, children[0]); + } + }, + + /** + * Method: read_cap_Service + */ + read_cap_Service: function(capabilities, node) { + var service = {}; + this.runChildNodes(service, node); + capabilities.service = service; + }, + + /** + * Method: read_cap_Layer + */ + read_cap_Layer: function(capability, node, parentLayer) { + var layer = { + formats: capability.request.getmap.formats || [], + styles: [], + queryable: (node.getAttribute("queryable") === "1" + || node.getAttribute("queryable") === "true") + }; + // deal with property inheritance + if(parentLayer) { + // add style + layer.styles = layer.styles.concat(parentLayer.styles); + // use llbbox + layer.llbbox = parentLayer.llbbox; + // use min/maxScale + layer.minScale = parentLayer.minScale; + layer.maxScale = parentLayer.maxScale; + } + var children = node.childNodes; + var childNode, nodeName, processor; + for(var i=0; i 0) { + layer.prefix = layer.name.substring(0, index); + } + capability.layers.push(layer); + } + }, + + /** + * Method: read_cap_ScaleHint + * The Layer ScaleHint element has min and max attributes that relate to + * the minimum and maximum resolution that the server supports. The + * values are pixel diagonals measured in meters (on the ground). + */ + read_cap_ScaleHint: function(layer, node) { + var min = node.getAttribute("min"); + var max = node.getAttribute("max"); + var rad2 = Math.pow(2, 0.5); + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; + layer.maxScale = parseFloat( + ((rad2 * min) * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13) + ); + layer.minScale = parseFloat( + ((rad2 * max) * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13) + ); + }, + + /** + * Method: read_cap_Name + */ + read_cap_Name: function(obj, node) { + var name = this.getChildValue(node); + if(name) { + obj.name = name; + } + }, + + /** + * Method: read_cap_Title + */ + read_cap_Title: function(obj, node) { + var title = this.getChildValue(node); + if(title) { + obj.title = title; + } + }, + + /** + * Method: read_cap_Abstract + */ + read_cap_Abstract: function(obj, node) { + var abst = this.getChildValue(node); + if(abst) { + obj["abstract"] = abst; + } + }, + + /** + * Method: read_cap_LatLonBoundingBox + */ + read_cap_LatLonBoundingBox: function(layer, node) { + layer.llbbox = [ + parseFloat(node.getAttribute("minx")), + parseFloat(node.getAttribute("miny")), + parseFloat(node.getAttribute("maxx")), + parseFloat(node.getAttribute("maxy")) + ]; + }, + + /** + * Method: read_cap_Style + */ + read_cap_Style: function(layer, node) { + var style = {}; + this.runChildNodes(style, node); + layer.styles.push(style); + }, + + /** + * Method: read_cap_LegendURL + */ + read_cap_LegendURL: function(style, node) { + var legend = { + width: node.getAttribute('width'), + height: node.getAttribute('height') + }; + var links = node.getElementsByTagName("OnlineResource"); + if(links.length > 0) { + this.read_cap_OnlineResource(legend, links[0]); + } + style.legend = legend; + }, + + /** + * Method: read_cap_OnlineResource + */ + read_cap_OnlineResource: function(obj, node) { + obj.href = this.getAttributeNS( + node, "http://www.w3.org/1999/xlink", "href" + ); + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" + +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js new file mode 100755 index 0000000000..87461964bc --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js @@ -0,0 +1,37 @@ +/** + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 + * Read WMS Capabilities version 1.1.0. + * + * Inherits from: + * - + */ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1_1, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.1.0", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 + * Create a new parser for WMS capabilities version 1.1.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply( + this, [options] + ); + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" + +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js new file mode 100755 index 0000000000..aa1053a491 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js @@ -0,0 +1,37 @@ +/** + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js + */ + +/** + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 + * Read WMS Capabilities version 1.1.1. + * + * Inherits from: + * - + */ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( + OpenLayers.Format.WMSCapabilities.v1_1, { + + /** + * Property: version + * {String} The specific parser version. + */ + version: "1.1.1", + + /** + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 + * Create a new parser for WMS capabilities version 1.1.1. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.WMSCapabilities.v1_1.prototype.initialize.apply( + this, [options] + ); + }, + + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" + +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Geometry.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Geometry.js new file mode 100755 index 0000000000..d9d19a9281 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Geometry.js @@ -0,0 +1,455 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WKT.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Geometry + * A Geometry is a description of a geographic object. Create an instance of + * this class with the constructor. This is a base class, + * typical geometry types are described by subclasses of this class. + */ +OpenLayers.Geometry = OpenLayers.Class({ + + /** + * Property: id + * {String} A unique identifier for this geometry. + */ + id: null, + + /** + * Property: parent + * {}This is set when a Geometry is added as component + * of another geometry + */ + parent: null, + + /** + * Property: bounds + * {} The bounds of this geometry + */ + bounds: null, + + /** + * Constructor: OpenLayers.Geometry + * Creates a geometry object. + */ + initialize: function() { + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_"); + }, + + /** + * Method: destroy + * Destroy this geometry. + */ + destroy: function() { + this.id = null; + this.bounds = null; + }, + + /** + * APIMethod: clone + * Create a clone of this geometry. Does not set any non-standard + * properties of the cloned geometry. + * + * Returns: + * {} An exact clone of this geometry. + */ + clone: function() { + return new OpenLayers.Geometry(); + }, + + /** + * Set the bounds for this Geometry. + * + * Parameters: + * object - {} + */ + setBounds: function(bounds) { + if (bounds) { + this.bounds = bounds.clone(); + } + }, + + /** + * Method: clearBounds + * Nullify this components bounds and that of its parent as well. + */ + clearBounds: function() { + this.bounds = null; + if (this.parent) { + this.parent.clearBounds(); + } + }, + + /** + * Method: extendBounds + * Extend the existing bounds to include the new bounds. + * If geometry's bounds is not yet set, then set a new Bounds. + * + * Parameters: + * newBounds - {} + */ + extendBounds: function(newBounds){ + var bounds = this.getBounds(); + if (!bounds) { + this.setBounds(newBounds); + } else { + this.bounds.extend(newBounds); + } + }, + + /** + * APIMethod: getBounds + * Get the bounds for this Geometry. If bounds is not set, it + * is calculated again, this makes queries faster. + * + * Returns: + * {} + */ + getBounds: function() { + if (this.bounds == null) { + this.calculateBounds(); + } + return this.bounds; + }, + + /** + * APIMethod: calculateBounds + * Recalculate the bounds for the geometry. + */ + calculateBounds: function() { + // + // This should be overridden by subclasses. + // + }, + + /** + * APIMethod: distanceTo + * Calculate the closest distance between two geometries (on the x-y plane). + * + * Parameters: + * geometry - {} The target geometry. + * options - {Object} Optional properties for configuring the distance + * calculation. + * + * Valid options depend on the specific geometry type. + * + * Returns: + * {Number | Object} The distance between this geometry and the target. + * If details is true, the return will be an object with distance, + * x0, y0, x1, and x2 properties. The x0 and y0 properties represent + * the coordinates of the closest point on this geometry. The x1 and y1 + * properties represent the coordinates of the closest point on the + * target geometry. + */ + distanceTo: function(geometry, options) { + }, + + /** + * APIMethod: getVertices + * Return a list of all points in this geometry. + * + * Parameters: + * nodes - {Boolean} For lines, only return vertices that are + * endpoints. If false, for lines, only vertices that are not + * endpoints will be returned. If not provided, all vertices will + * be returned. + * + * Returns: + * {Array} A list of all vertices in the geometry. + */ + getVertices: function(nodes) { + }, + + /** + * Method: atPoint + * Note - This is only an approximation based on the bounds of the + * geometry. + * + * Parameters: + * lonlat - {} + * toleranceLon - {float} Optional tolerance in Geometric Coords + * toleranceLat - {float} Optional tolerance in Geographic Coords + * + * Returns: + * {Boolean} Whether or not the geometry is at the specified location + */ + atPoint: function(lonlat, toleranceLon, toleranceLat) { + var atPoint = false; + var bounds = this.getBounds(); + if ((bounds != null) && (lonlat != null)) { + + var dX = (toleranceLon != null) ? toleranceLon : 0; + var dY = (toleranceLat != null) ? toleranceLat : 0; + + var toleranceBounds = + new OpenLayers.Bounds(this.bounds.left - dX, + this.bounds.bottom - dY, + this.bounds.right + dX, + this.bounds.top + dY); + + atPoint = toleranceBounds.containsLonLat(lonlat); + } + return atPoint; + }, + + /** + * Method: getLength + * Calculate the length of this geometry. This method is defined in + * subclasses. + * + * Returns: + * {Float} The length of the collection by summing its parts + */ + getLength: function() { + //to be overridden by geometries that actually have a length + // + return 0.0; + }, + + /** + * Method: getArea + * Calculate the area of this geometry. This method is defined in subclasses. + * + * Returns: + * {Float} The area of the collection by summing its parts + */ + getArea: function() { + //to be overridden by geometries that actually have an area + // + return 0.0; + }, + + /** + * APIMethod: getCentroid + * Calculate the centroid of this geometry. This method is defined in subclasses. + * + * Returns: + * {} The centroid of the collection + */ + getCentroid: function() { + return null; + }, + + /** + * Method: toString + * Returns the Well-Known Text representation of a geometry + * + * Returns: + * {String} Well-Known Text + */ + toString: function() { + return OpenLayers.Format.WKT.prototype.write( + new OpenLayers.Feature.Vector(this) + ); + }, + + CLASS_NAME: "OpenLayers.Geometry" +}); + +/** + * Function: OpenLayers.Geometry.fromWKT + * Generate a geometry given a Well-Known Text string. + * + * Parameters: + * wkt - {String} A string representing the geometry in Well-Known Text. + * + * Returns: + * {} A geometry of the appropriate class. + */ +OpenLayers.Geometry.fromWKT = function(wkt) { + var format = arguments.callee.format; + if(!format) { + format = new OpenLayers.Format.WKT(); + arguments.callee.format = format; + } + var geom; + var result = format.read(wkt); + if(result instanceof OpenLayers.Feature.Vector) { + geom = result.geometry; + } else if(result instanceof Array) { + var len = result.length; + var components = new Array(len); + for(var i=0; i= seg2.x1 || seg2.x2 >= seg1.x1. In those + * obvious cases where there is no intersection, the function should + * not be called. + * + * Parameters: + * seg1 - {Object} Object representing a segment with properties x1, y1, x2, + * and y2. The start point is represented by x1 and y1. The end point + * is represented by x2 and y2. Start and end are ordered so that x1 < x2. + * seg2 - {Object} Object representing a segment with properties x1, y1, x2, + * and y2. The start point is represented by x1 and y1. The end point + * is represented by x2 and y2. Start and end are ordered so that x1 < x2. + * options - {Object} Optional properties for calculating the intersection. + * + * Valid options: + * point - {Boolean} Return the intersection point. If false, the actual + * intersection point will not be calculated. If true and the segments + * intersect, the intersection point will be returned. If true and + * the segments do not intersect, false will be returned. If true and + * the segments are coincident, true will be returned. + * tolerance - {Number} If a non-null value is provided, if the segments are + * within the tolerance distance, this will be considered an intersection. + * In addition, if the point option is true and the calculated intersection + * is within the tolerance distance of an end point, the endpoint will be + * returned instead of the calculated intersection. Further, if the + * intersection is within the tolerance of endpoints on both segments, or + * if two segment endpoints are within the tolerance distance of eachother + * (but no intersection is otherwise calculated), an endpoint on the + * first segment provided will be returned. + * + * Returns: + * {Boolean | } The two segments intersect. + * If the point argument is true, the return will be the intersection + * point or false if none exists. If point is true and the segments + * are coincident, return will be true (and the instersection is equal + * to the shorter segment). + */ +OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, options) { + var point = options && options.point; + var tolerance = options && options.tolerance; + var intersection = false; + var x11_21 = seg1.x1 - seg2.x1; + var y11_21 = seg1.y1 - seg2.y1; + var x12_11 = seg1.x2 - seg1.x1; + var y12_11 = seg1.y2 - seg1.y1; + var y22_21 = seg2.y2 - seg2.y1; + var x22_21 = seg2.x2 - seg2.x1; + var d = (y22_21 * x12_11) - (x22_21 * y12_11); + var n1 = (x22_21 * y11_21) - (y22_21 * x11_21); + var n2 = (x12_11 * y11_21) - (y12_11 * x11_21); + if(d == 0) { + // parallel + if(n1 == 0 && n2 == 0) { + // coincident + intersection = true; + } + } else { + var along1 = n1 / d; + var along2 = n2 / d; + if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) { + // intersect + if(!point) { + intersection = true; + } else { + // calculate the intersection point + var x = seg1.x1 + (along1 * x12_11); + var y = seg1.y1 + (along1 * y12_11); + intersection = new OpenLayers.Geometry.Point(x, y); + } + } + } + if(tolerance) { + var dist; + if(intersection) { + if(point) { + var segs = [seg1, seg2]; + var seg, x, y; + // check segment endpoints for proximity to intersection + // set intersection to first endpoint within the tolerance + outer: for(var i=0; i<2; ++i) { + seg = segs[i]; + for(var j=1; j<3; ++j) { + x = seg["x" + j]; + y = seg["y" + j]; + dist = Math.sqrt( + Math.pow(x - intersection.x, 2) + + Math.pow(y - intersection.y, 2) + ); + if(dist < tolerance) { + intersection.x = x; + intersection.y = y; + break outer; + } + } + } + + } + } else { + // no calculated intersection, but segments could be within + // the tolerance of one another + var segs = [seg1, seg2]; + var source, target, x, y, p, result; + // check segment endpoints for proximity to intersection + // set intersection to first endpoint within the tolerance + outer: for(var i=0; i<2; ++i) { + source = segs[i]; + target = segs[(i+1)%2]; + for(var j=1; j<3; ++j) { + p = {x: source["x"+j], y: source["y"+j]}; + result = OpenLayers.Geometry.distanceToSegment(p, target); + if(result.distance < tolerance) { + if(point) { + intersection = new OpenLayers.Geometry.Point(p.x, p.y); + } else { + intersection = true; + } + break outer; + } + } + } + } + } + return intersection; +}; + +/** + * Function: OpenLayers.Geometry.distanceToSegment + * + * Parameters: + * point - {Object} An object with x and y properties representing the + * point coordinates. + * segment - {Object} An object with x1, y1, x2, and y2 properties + * representing endpoint coordinates. + * + * Returns: + * {Object} An object with distance, x, and y properties. The distance + * will be the shortest distance between the input point and segment. + * The x and y properties represent the coordinates along the segment + * where the shortest distance meets the segment. + */ +OpenLayers.Geometry.distanceToSegment = function(point, segment) { + var x0 = point.x; + var y0 = point.y; + var x1 = segment.x1; + var y1 = segment.y1; + var x2 = segment.x2; + var y2 = segment.y2; + var dx = x2 - x1; + var dy = y2 - y1; + var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / + (Math.pow(dx, 2) + Math.pow(dy, 2)); + var x, y; + if(along <= 0.0) { + x = x1; + y = y1; + } else if(along >= 1.0) { + x = x2; + y = y2; + } else { + x = x1 + along * dx; + y = y1 + along * dy; + } + return { + distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)), + x: x, y: y + }; +}; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Handler.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Handler.js new file mode 100755 index 0000000000..b886ac72dd --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Handler.js @@ -0,0 +1,285 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Events.js + */ + +/** + * Class: OpenLayers.Handler + * Base class to construct a higher-level handler for event sequences. All + * handlers have activate and deactivate methods. In addition, they have + * methods named like browser events. When a handler is activated, any + * additional methods named like a browser event is registered as a + * listener for the corresponding event. When a handler is deactivated, + * those same methods are unregistered as event listeners. + * + * Handlers also typically have a callbacks object with keys named like + * the abstracted events or event sequences that they are in charge of + * handling. The controls that wrap handlers define the methods that + * correspond to these abstract events - so instead of listening for + * individual browser events, they only listen for the abstract events + * defined by the handler. + * + * Handlers are created by controls, which ultimately have the responsibility + * of making changes to the the state of the application. Handlers + * themselves may make temporary changes, but in general are expected to + * return the application in the same state that they found it. + */ +OpenLayers.Handler = OpenLayers.Class({ + + /** + * Property: id + * {String} + */ + id: null, + + /** + * APIProperty: control + * {}. The control that initialized this handler. The + * control is assumed to have a valid map property - that map is used + * in the handler's own setMap method. + */ + control: null, + + /** + * Property: map + * {} + */ + map: null, + + /** + * APIProperty: keyMask + * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler + * constants to construct a keyMask. The keyMask is used by + * . If the keyMask matches the combination of keys + * down on an event, checkModifiers returns true. + * + * Example: + * (code) + * // handler only responds if the Shift key is down + * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; + * + * // handler only responds if Ctrl-Shift is down + * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | + * OpenLayers.Handler.MOD_CTRL; + * (end) + */ + keyMask: null, + + /** + * Property: active + * {Boolean} + */ + active: false, + + /** + * Property: evt + * {Event} This property references the last event handled by the handler. + * Note that this property is not part of the stable API. Use of the + * evt property should be restricted to controls in the library + * or other applications that are willing to update with changes to + * the OpenLayers code. + */ + evt: null, + + /** + * Constructor: OpenLayers.Handler + * Construct a handler. + * + * Parameters: + * control - {} The control that initialized this + * handler. The control is assumed to have a valid map property; that + * map is used in the handler's own setMap method. + * callbacks - {Object} An object whose properties correspond to abstracted + * events or sequences of browser events. The values for these + * properties are functions defined by the control that get called by + * the handler. + * options - {Object} An optional object whose properties will be set on + * the handler. + */ + initialize: function(control, callbacks, options) { + OpenLayers.Util.extend(this, options); + this.control = control; + this.callbacks = callbacks; + if (control.map) { + this.setMap(control.map); + } + + OpenLayers.Util.extend(this, options); + + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + }, + + /** + * Method: setMap + */ + setMap: function (map) { + this.map = map; + }, + + /** + * Method: checkModifiers + * Check the keyMask on the handler. If no is set, this always + * returns true. If a is set and it matches the combination + * of keys down on an event, this returns true. + * + * Returns: + * {Boolean} The keyMask matches the keys down on an event. + */ + checkModifiers: function (evt) { + if(this.keyMask == null) { + return true; + } + /* calculate the keyboard modifier mask for this event */ + var keyModifiers = + (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) | + (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) | + (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0); + + /* if it differs from the handler object's key mask, + bail out of the event handler */ + return (keyModifiers == this.keyMask); + }, + + /** + * APIMethod: activate + * Turn on the handler. Returns false if the handler was already active. + * + * Returns: + * {Boolean} The handler was activated. + */ + activate: function() { + if(this.active) { + return false; + } + // register for event handlers defined on this class. + var events = OpenLayers.Events.prototype.BROWSER_EVENTS; + for (var i=0, len=events.length; i, returns false if any key is down. + */ +OpenLayers.Handler.MOD_NONE = 0; + +/** + * Constant: OpenLayers.Handler.MOD_SHIFT + * If set as the , returns false if Shift is down. + */ +OpenLayers.Handler.MOD_SHIFT = 1; + +/** + * Constant: OpenLayers.Handler.MOD_CTRL + * If set as the , returns false if Ctrl is down. + */ +OpenLayers.Handler.MOD_CTRL = 2; + +/** + * Constant: OpenLayers.Handler.MOD_ALT + * If set as the , returns false if Alt is down. + */ +OpenLayers.Handler.MOD_ALT = 4; + + diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Icon.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Icon.js new file mode 100755 index 0000000000..5dd8537bef --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Icon.js @@ -0,0 +1,227 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * Class: OpenLayers.Icon + * + * The icon represents a graphical icon on the screen. Typically used in + * conjunction with a to represent markers on a screen. + * + * An icon has a url, size and position. It also contains an offset which + * allows the center point to be represented correctly. This can be + * provided either as a fixed offset or a function provided to calculate + * the desired offset. + * + */ +OpenLayers.Icon = OpenLayers.Class({ + + /** + * Property: url + * {String} image url + */ + url: null, + + /** + * Property: size + * {} + */ + size: null, + + /** + * Property: offset + * {} distance in pixels to offset the image when being rendered + */ + offset: null, + + /** + * Property: calculateOffset + * {} Function to calculate the offset (based on the size) + */ + calculateOffset: null, + + /** + * Property: imageDiv + * {DOMElement} + */ + imageDiv: null, + + /** + * Property: px + * {} + */ + px: null, + + /** + * Constructor: OpenLayers.Icon + * Creates an icon, which is an image tag in a div. + * + * url - {String} + * size - {} + * offset - {} + * calculateOffset - {Function} + */ + initialize: function(url, size, offset, calculateOffset) { + this.url = url; + this.size = (size) ? size : new OpenLayers.Size(20,20); + this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2)); + this.calculateOffset = calculateOffset; + + var id = OpenLayers.Util.createUniqueID("OL_Icon_"); + this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); + }, + + /** + * Method: destroy + * Nullify references and remove event listeners to prevent circular + * references and memory leaks + */ + destroy: function() { + // erase any drawn elements + this.erase(); + + OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); + this.imageDiv.innerHTML = ""; + this.imageDiv = null; + }, + + /** + * Method: clone + * + * Returns: + * {} A fresh copy of the icon. + */ + clone: function() { + return new OpenLayers.Icon(this.url, + this.size, + this.offset, + this.calculateOffset); + }, + + /** + * Method: setSize + * + * Parameters: + * size - {} + */ + setSize: function(size) { + if (size != null) { + this.size = size; + } + this.draw(); + }, + + /** + * Method: setUrl + * + * Parameters: + * url - {String} + */ + setUrl: function(url) { + if (url != null) { + this.url = url; + } + this.draw(); + }, + + /** + * Method: draw + * Move the div to the given pixel. + * + * Parameters: + * px - {} + * + * Returns: + * {DOMElement} A new DOM Image of this icon set at the location passed-in + */ + draw: function(px) { + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, + null, + null, + this.size, + this.url, + "absolute"); + this.moveTo(px); + return this.imageDiv; + }, + + /** + * Method: erase + * Erase the underlying image element. + * + */ + erase: function() { + if (this.imageDiv != null && this.imageDiv.parentNode != null) { + OpenLayers.Element.remove(this.imageDiv); + } + }, + + /** + * Method: setOpacity + * Change the icon's opacity + * + * Parameters: + * opacity - {float} + */ + setOpacity: function(opacity) { + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, + null, null, null, null, opacity); + + }, + + /** + * Method: moveTo + * move icon to passed in px. + * + * Parameters: + * px - {} + */ + moveTo: function (px) { + //if no px passed in, use stored location + if (px != null) { + this.px = px; + } + + if (this.imageDiv != null) { + if (this.px == null) { + this.display(false); + } else { + if (this.calculateOffset) { + this.offset = this.calculateOffset(this.size); + } + var offsetPx = this.px.offset(this.offset); + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx); + } + } + }, + + /** + * Method: display + * Hide or show the icon + * + * Parameters: + * display - {Boolean} + */ + display: function(display) { + this.imageDiv.style.display = (display) ? "" : "none"; + }, + + + /** + * APIMethod: isDrawn + * + * Returns: + * {Boolean} Whether or not the icon is drawn. + */ + isDrawn: function() { + // nodeType 11 for ie, whose nodes *always* have a parentNode + // (of type document fragment) + var isDrawn = (this.imageDiv && this.imageDiv.parentNode && + (this.imageDiv.parentNode.nodeType != 11)); + + return isDrawn; + }, + + CLASS_NAME: "OpenLayers.Icon" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Lang.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Lang.js new file mode 100755 index 0000000000..e343a4140d --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Lang.js @@ -0,0 +1,132 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Console.js + */ + +/** + * Namespace: OpenLayers.Lang + * Internationalization namespace. Contains dictionaries in various languages + * and methods to set and get the current language. + */ +OpenLayers.Lang = { + + /** + * Property: code + * {String} Current language code to use in OpenLayers. Use the + * method to set this value and the method to + * retrieve it. + */ + code: null, + + /** + * APIProperty: defaultCode + * {String} Default language to use when a specific language can't be + * found. Default is "en". + */ + defaultCode: "en", + + /** + * APIFunction: getCode + * Get the current language code. + * + * Returns: + * The current language code. + */ + getCode: function() { + if(!OpenLayers.Lang.code) { + OpenLayers.Lang.setCode(); + } + return OpenLayers.Lang.code; + }, + + /** + * APIFunction: setCode + * Set the language code for string translation. This code is used by + * the method. + * + * Parameters- + * code - {String} These codes follow the IETF recommendations at + * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the + * browser's language setting will be tested. If no + * dictionary exists for the code, the + * will be used. + */ + setCode: function(code) { + var lang; + if(!code) { + code = (OpenLayers.Util.getBrowserName() == "msie") ? + navigator.userLanguage : navigator.language; + } + var parts = code.split('-'); + parts[0] = parts[0].toLowerCase(); + if(typeof OpenLayers.Lang[parts[0]] == "object") { + lang = parts[0]; + } + + // check for regional extensions + if(parts[1]) { + var testLang = parts[0] + '-' + parts[1].toUpperCase(); + if(typeof OpenLayers.Lang[testLang] == "object") { + lang = testLang; + } + } + if(!lang) { + OpenLayers.Console.warn( + 'Failed to find OpenLayers.Lang.' + parts.join("-") + + ' dictionary, falling back to default language' + ); + lang = OpenLayers.Lang.defaultCode; + } + + OpenLayers.Lang.code = lang; + }, + + /** + * APIMethod: translate + * Looks up a key from a dictionary based on the current language string. + * The value of will be used to determine the appropriate + * dictionary. Dictionaries are stored in . + * + * Parameters: + * key - {String} The key for an i18n string value in the dictionary. + * context - {Object} Optional context to be used with + * . + * + * Returns: + * {String} A internationalized string. + */ + translate: function(key, context) { + var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()]; + var message = dictionary[key]; + if(!message) { + // Message not found, fall back to message key + message = key; + } + if(context) { + message = OpenLayers.String.format(message, context); + } + return message; + } + +}; + + +/** + * APIMethod: OpenLayers.i18n + * Alias for . Looks up a key from a dictionary + * based on the current language string. The value of + * will be used to determine the appropriate + * dictionary. Dictionaries are stored in . + * + * Parameters: + * key - {String} The key for an i18n string value in the dictionary. + * context - {Object} Optional context to be used with + * . + * + * Returns: + * {String} A internationalized string. + */ +OpenLayers.i18n = OpenLayers.Lang.translate; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer.js new file mode 100755 index 0000000000..47ec65b375 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer.js @@ -0,0 +1,1170 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Map.js + * @requires OpenLayers/Projection.js + */ + +/** + * Class: OpenLayers.Layer + */ +OpenLayers.Layer = OpenLayers.Class({ + + /** + * APIProperty: id + * {String} + */ + id: null, + + /** + * APIProperty: name + * {String} + */ + name: null, + + /** + * APIProperty: div + * {DOMElement} + */ + div: null, + + /** + * Property: opacity + * {Float} The layer's opacity. Float number between 0.0 and 1.0. + */ + opacity: null, + + /** + * APIProperty: alwaysInRange + * {Boolean} If a layer's display should not be scale-based, this should + * be set to true. This will cause the layer, as an overlay, to always + * be 'active', by always returning true from the calculateInRange() + * function. + * + * If not explicitly specified for a layer, its value will be + * determined on startup in initResolutions() based on whether or not + * any scale-specific properties have been set as options on the + * layer. If no scale-specific options have been set on the layer, we + * assume that it should always be in range. + * + * See #987 for more info. + */ + alwaysInRange: null, + + /** + * Constant: EVENT_TYPES + * {Array(String)} Supported application event types. Register a listener + * for a particular event with the following syntax: + * (code) + * layer.events.register(type, obj, listener); + * (end) + * + * Listeners will be called with a reference to an event object. The + * properties of this event depends on exactly what happened. + * + * All event objects have at least the following properties: + * object - {Object} A reference to layer.events.object. + * element - {DOMElement} A reference to layer.events.element. + * + * Supported map event types: + * loadstart - Triggered when layer loading starts. + * loadend - Triggered when layer loading ends. + * loadcancel - Triggered when layer loading is canceled. + * visibilitychanged - Triggered when layer visibility is changed. + * move - Triggered when layer moves (triggered with every mousemove + * during a drag). + * moveend - Triggered when layer is done moving, object passed as + * argument has a zoomChanged boolean property which tells that the + * zoom has changed. + */ + EVENT_TYPES: ["loadstart", "loadend", "loadcancel", "visibilitychanged", + "move", "moveend"], + + /** + * APIProperty: events + * {} + */ + events: null, + + /** + * APIProperty: map + * {} This variable is set when the layer is added to + * the map, via the accessor function setMap(). + */ + map: null, + + /** + * APIProperty: isBaseLayer + * {Boolean} Whether or not the layer is a base layer. This should be set + * individually by all subclasses. Default is false + */ + isBaseLayer: false, + + /** + * Property: alpha + * {Boolean} The layer's images have an alpha channel. Default is false. + */ + alpha: false, + + /** + * APIProperty: displayInLayerSwitcher + * {Boolean} Display the layer's name in the layer switcher. Default is + * true. + */ + displayInLayerSwitcher: true, + + /** + * APIProperty: visibility + * {Boolean} The layer should be displayed in the map. Default is true. + */ + visibility: true, + + /** + * APIProperty: attribution + * {String} Attribution string, displayed when an + * has been added to the map. + */ + attribution: null, + + /** + * Property: inRange + * {Boolean} The current map resolution is within the layer's min/max + * range. This is set in whenever the zoom + * changes. + */ + inRange: false, + + /** + * Propery: imageSize + * {} For layers with a gutter, the image is larger than + * the tile by twice the gutter in each dimension. + */ + imageSize: null, + + /** + * Property: imageOffset + * {} For layers with a gutter, the image offset + * represents displacement due to the gutter. + */ + imageOffset: null, + + // OPTIONS + + /** + * Property: options + * {Object} An optional object whose properties will be set on the layer. + * Any of the layer properties can be set as a property of the options + * object and sent to the constructor when the layer is created. + */ + options: null, + + /** + * APIProperty: eventListeners + * {Object} If set as an option at construction, the eventListeners + * object will be registered with . Object + * structure must be a listeners object as shown in the example for + * the events.on method. + */ + eventListeners: null, + + /** + * APIProperty: gutter + * {Integer} Determines the width (in pixels) of the gutter around image + * tiles to ignore. By setting this property to a non-zero value, + * images will be requested that are wider and taller than the tile + * size by a value of 2 x gutter. This allows artifacts of rendering + * at tile edges to be ignored. Set a gutter value that is equal to + * half the size of the widest symbol that needs to be displayed. + * Defaults to zero. Non-tiled layers always have zero gutter. + */ + gutter: 0, + + /** + * APIProperty: projection + * {} or {} Set in the layer options to + * override the default projection string this layer - also set maxExtent, + * maxResolution, and units if appropriate. Can be either a string or + * an object when created -- will be converted + * to an object when setMap is called if a string is passed. + */ + projection: null, + + /** + * APIProperty: units + * {String} The layer map units. Defaults to 'degrees'. Possible values + * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'. + */ + units: null, + + /** + * APIProperty: scales + * {Array} An array of map scales in descending order. The values in the + * array correspond to the map scale denominator. Note that these + * values only make sense if the display (monitor) resolution of the + * client is correctly guessed by whomever is configuring the + * application. In addition, the units property must also be set. + * Use instead wherever possible. + */ + scales: null, + + /** + * APIProperty: resolutions + * {Array} A list of map resolutions (map units per pixel) in descending + * order. If this is not set in the layer constructor, it will be set + * based on other resolution related properties (maxExtent, + * maxResolution, maxScale, etc.). + */ + resolutions: null, + + /** + * APIProperty: maxExtent + * {} The center of these bounds will not stray outside + * of the viewport extent during panning. In addition, if + * is set to false, data will not be + * requested that falls completely outside of these bounds. + */ + maxExtent: null, + + /** + * APIProperty: minExtent + * {} + */ + minExtent: null, + + /** + * APIProperty: maxResolution + * {Float} Default max is 360 deg / 256 px, which corresponds to + * zoom level 0 on gmaps. Specify a different value in the layer + * options if you are not using a geographic projection and + * displaying the whole world. + */ + maxResolution: null, + + /** + * APIProperty: minResolution + * {Float} + */ + minResolution: null, + + /** + * APIProperty: numZoomLevels + * {Integer} + */ + numZoomLevels: null, + + /** + * APIProperty: minScale + * {Float} + */ + minScale: null, + + /** + * APIProperty: maxScale + * {Float} + */ + maxScale: null, + + /** + * APIProperty: displayOutsideMaxExtent + * {Boolean} Request map tiles that are completely outside of the max + * extent for this layer. Defaults to false. + */ + displayOutsideMaxExtent: false, + + /** + * APIProperty: wrapDateLine + * {Boolean} #487 for more info. + */ + wrapDateLine: false, + + /** + * APIProperty: transitionEffect + * {String} The transition effect to use when the map is panned or + * zoomed. + * + * There are currently two supported values: + * - *null* No transition effect (the default). + * - *resize* Existing tiles are resized on zoom to provide a visual + * effect of the zoom having taken place immediately. As the + * new tiles become available, they are drawn over top of the + * resized tiles. + */ + transitionEffect: null, + + /** + * Property: SUPPORTED_TRANSITIONS + * {Array} An immutable (that means don't change it!) list of supported + * transitionEffect values. + */ + SUPPORTED_TRANSITIONS: ['resize'], + + /** + * Constructor: OpenLayers.Layer + * + * Parameters: + * name - {String} The layer name + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, options) { + + this.addOptions(options); + + this.name = name; + + if (this.id == null) { + + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + + this.div = OpenLayers.Util.createDiv(this.id); + this.div.style.width = "100%"; + this.div.style.height = "100%"; + this.div.dir = "ltr"; + + this.events = new OpenLayers.Events(this, this.div, + this.EVENT_TYPES); + if(this.eventListeners instanceof Object) { + this.events.on(this.eventListeners); + } + + } + + if (this.wrapDateLine) { + this.displayOutsideMaxExtent = true; + } + }, + + /** + * Method: destroy + * Destroy is a destructor: this is to alleviate cyclic references which + * the Javascript garbage cleaner can not take care of on its own. + * + * Parameters: + * setNewBaseLayer - {Boolean} Set a new base layer when this layer has + * been destroyed. Default is true. + */ + destroy: function(setNewBaseLayer) { + if (setNewBaseLayer == null) { + setNewBaseLayer = true; + } + if (this.map != null) { + this.map.removeLayer(this, setNewBaseLayer); + } + this.projection = null; + this.map = null; + this.name = null; + this.div = null; + this.options = null; + + if (this.events) { + if(this.eventListeners) { + this.events.un(this.eventListeners); + } + this.events.destroy(); + } + this.eventListeners = null; + this.events = null; + }, + + /** + * Method: clone + * + * Parameters: + * obj - {} The layer to be cloned + * + * Returns: + * {} An exact clone of this + */ + clone: function (obj) { + + if (obj == null) { + obj = new OpenLayers.Layer(this.name, this.options); + } + + // catch any randomly tagged-on properties + OpenLayers.Util.applyDefaults(obj, this); + + // a cloned layer should never have its map property set + // because it has not been added to a map yet. + obj.map = null; + + return obj; + }, + + /** + * APIMethod: setName + * Sets the new layer name for this layer. Can trigger a changelayer event + * on the map. + * + * Parameters: + * newName - {String} The new name. + */ + setName: function(newName) { + if (newName != this.name) { + this.name = newName; + if (this.map != null) { + this.map.events.triggerEvent("changelayer", { + layer: this, + property: "name" + }); + } + } + }, + + /** + * APIMethod: addOptions + * + * Parameters: + * newOptions - {Object} + */ + addOptions: function (newOptions) { + + if (this.options == null) { + this.options = {}; + } + + // update our copy for clone + OpenLayers.Util.extend(this.options, newOptions); + + // add new options to this + OpenLayers.Util.extend(this, newOptions); + }, + + /** + * APIMethod: onMapResize + * This function can be implemented by subclasses + */ + onMapResize: function() { + //this function can be implemented by subclasses + }, + + /** + * APIMethod: redraw + * Redraws the layer. Returns true if the layer was redrawn, false if not. + * + * Returns: + * {Boolean} The layer was redrawn. + */ + redraw: function() { + var redrawn = false; + if (this.map) { + + // min/max Range may have changed + this.inRange = this.calculateInRange(); + + // map's center might not yet be set + var extent = this.getExtent(); + + if (extent && this.inRange && this.visibility) { + var zoomChanged = true; + this.moveTo(extent, zoomChanged, false); + this.events.triggerEvent("moveend", + {"zoomChanged": zoomChanged}); + redrawn = true; + } + } + return redrawn; + }, + + /** + * Method: moveTo + * + * Parameters: + * bound - {} + * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to + * do some init work in that case. + * dragging - {Boolean} + */ + moveTo:function(bounds, zoomChanged, dragging) { + var display = this.visibility; + if (!this.isBaseLayer) { + display = display && this.inRange; + } + this.display(display); + }, + + /** + * Method: setMap + * Set the map property for the layer. This is done through an accessor + * so that subclasses can override this and take special action once + * they have their map variable set. + * + * Here we take care to bring over any of the necessary default + * properties from the map. + * + * Parameters: + * map - {} + */ + setMap: function(map) { + if (this.map == null) { + + this.map = map; + + // grab some essential layer data from the map if it hasn't already + // been set + this.maxExtent = this.maxExtent || this.map.maxExtent; + this.projection = this.projection || this.map.projection; + + if (this.projection && typeof this.projection == "string") { + this.projection = new OpenLayers.Projection(this.projection); + } + + // Check the projection to see if we can get units -- if not, refer + // to properties. + this.units = this.projection.getUnits() || + this.units || this.map.units; + + this.initResolutions(); + + if (!this.isBaseLayer) { + this.inRange = this.calculateInRange(); + var show = ((this.visibility) && (this.inRange)); + this.div.style.display = show ? "" : "none"; + } + + // deal with gutters + this.setTileSize(); + } + }, + + /** + * Method: afterAdd + * Called at the end of the map.addLayer sequence. At this point, the map + * will have a base layer. To be overridden by subclasses. + */ + afterAdd: function() { + }, + + /** + * APIMethod: removeMap + * Just as setMap() allows each layer the possibility to take a + * personalized action on being added to the map, removeMap() allows + * each layer to take a personalized action on being removed from it. + * For now, this will be mostly unused, except for the EventPane layer, + * which needs this hook so that it can remove the special invisible + * pane. + * + * Parameters: + * map - {} + */ + removeMap: function(map) { + //to be overridden by subclasses + }, + + /** + * APIMethod: getImageSize + * + * Returns: + * {} The size that the image should be, taking into + * account gutters. + */ + getImageSize: function() { + return (this.imageSize || this.tileSize); + }, + + /** + * APIMethod: setTileSize + * Set the tile size based on the map size. This also sets layer.imageSize + * and layer.imageOffset for use by Tile.Image. + * + * Parameters: + * size - {} + */ + setTileSize: function(size) { + var tileSize = (size) ? size : + ((this.tileSize) ? this.tileSize : + this.map.getTileSize()); + this.tileSize = tileSize; + if(this.gutter) { + // layers with gutters need non-null tile sizes + //if(tileSize == null) { + // OpenLayers.console.error("Error in layer.setMap() for " + + // this.name + ": layers with " + + // "gutters need non-null tile sizes"); + //} + this.imageOffset = new OpenLayers.Pixel(-this.gutter, + -this.gutter); + this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), + tileSize.h + (2*this.gutter)); + } + }, + + /** + * APIMethod: getVisibility + * + * Returns: + * {Boolean} The layer should be displayed (if in range). + */ + getVisibility: function() { + return this.visibility; + }, + + /** + * APIMethod: setVisibility + * Set the visibility flag for the layer and hide/show & redraw + * accordingly. Fire event unless otherwise specified + * + * Note that visibility is no longer simply whether or not the layer's + * style.display is set to "block". Now we store a 'visibility' state + * property on the layer class, this allows us to remember whether or + * not we *desire* for a layer to be visible. In the case where the + * map's resolution is out of the layer's range, this desire may be + * subverted. + * + * Parameters: + * visible - {Boolean} Whether or not to display the layer (if in range) + */ + setVisibility: function(visibility) { + if (visibility != this.visibility) { + this.visibility = visibility; + this.display(visibility); + this.redraw(); + if (this.map != null) { + this.map.events.triggerEvent("changelayer", { + layer: this, + property: "visibility" + }); + } + this.events.triggerEvent("visibilitychanged"); + } + }, + + /** + * APIMethod: display + * Hide or show the Layer + * + * Parameters: + * display - {Boolean} + */ + display: function(display) { + var inRange = this.calculateInRange(); + if (display != (this.div.style.display != "none")) { + this.div.style.display = (display && inRange) ? "block" : "none"; + } + }, + + /** + * APIMethod: calculateInRange + * + * Returns: + * {Boolean} The layer is displayable at the current map's current + * resolution. Note that if 'alwaysInRange' is true for the layer, + * this function will always return true. + */ + calculateInRange: function() { + var inRange = false; + + if (this.alwaysInRange) { + inRange = true; + } else { + if (this.map) { + var resolution = this.map.getResolution(); + inRange = ( (resolution >= this.minResolution) && + (resolution <= this.maxResolution) ); + } + } + return inRange; + }, + + /** + * APIMethod: setIsBaseLayer + * + * Parameters: + * isBaseLayer - {Boolean} + */ + setIsBaseLayer: function(isBaseLayer) { + if (isBaseLayer != this.isBaseLayer) { + this.isBaseLayer = isBaseLayer; + if (this.map != null) { + this.map.events.triggerEvent("changebaselayer", { + layer: this + }); + } + } + }, + + /********************************************************/ + /* */ + /* Baselayer Functions */ + /* */ + /********************************************************/ + + /** + * Method: initResolutions + * This method's responsibility is to set up the 'resolutions' array + * for the layer -- this array is what the layer will use to interface + * between the zoom levels of the map and the resolution display + * of the layer. + * + * The user has several options that determine how the array is set up. + * + * For a detailed explanation, see the following wiki from the + * openlayers.org homepage: + * http://trac.openlayers.org/wiki/SettingZoomLevels + */ + initResolutions: function() { + + // These are the relevant options which are used for calculating + // resolutions information. + // + var props = new Array( + 'projection', 'units', + 'scales', 'resolutions', + 'maxScale', 'minScale', + 'maxResolution', 'minResolution', + 'minExtent', 'maxExtent', + 'numZoomLevels', 'maxZoomLevel' + ); + + //these are the properties which do *not* imply that user wishes + // this layer to be scale-dependant + var notScaleProps = ['projection', 'units']; + + //should the layer be scale-dependant? default is false -- this will + // only be set true if we find that the user has specified a property + // from the 'props' array that is not in 'notScaleProps' + var useInRange = false; + + // First we create a new object where we will store all of the + // resolution-related properties that we find in either the layer's + // 'options' array or from the map. + // + var confProps = {}; + for(var i=0, len=props.length; i 1) { + /** + * If maxResolution and minResolution are set (or related + * scale properties), we calculate the base for exponential + * scaling that starts at maxResolution and ends at + * minResolution in numZoomLevels steps. + */ + base = Math.pow( + (confProps.maxResolution / confProps.minResolution), + (1 / (confProps.numZoomLevels - 1)) + ); + } + for (var i=0; i < confProps.numZoomLevels; i++) { + var res = confProps.maxResolution / Math.pow(base, i); + confProps.resolutions[i] = res; + } + } + + //sort resolutions array ascendingly + // + confProps.resolutions.sort( function(a, b) { return(b-a); } ); + + // now set our newly calculated values back to the layer + // Note: We specifically do *not* set them to layer.options, which we + // will preserve as it was when we added this layer to the map. + // this way cloned layers reset themselves to new map div + // dimensions) + // + + this.resolutions = confProps.resolutions; + this.maxResolution = confProps.resolutions[0]; + var lastIndex = confProps.resolutions.length - 1; + this.minResolution = confProps.resolutions[lastIndex]; + + this.scales = []; + for(var i=0, len=confProps.resolutions.length; i} A Bounds object which represents the lon/lat + * bounds of the current viewPort. + */ + getExtent: function() { + // just use stock map calculateBounds function -- passing no arguments + // means it will user map's current center & resolution + // + return this.map.calculateBounds(); + }, + + /** + * APIMethod: getZoomForExtent + * + * Parameters: + * bounds - {} + * closest - {Boolean} Find the zoom level that most closely fits the + * specified bounds. Note that this may result in a zoom that does + * not exactly contain the entire extent. + * Default is false. + * + * Returns: + * {Integer} The index of the zoomLevel (entry in the resolutions array) + * for the passed-in extent. We do this by calculating the ideal + * resolution for the given extent (based on the map size) and then + * calling getZoomForResolution(), passing along the 'closest' + * parameter. + */ + getZoomForExtent: function(extent, closest) { + var viewSize = this.map.getSize(); + var idealResolution = Math.max( extent.getWidth() / viewSize.w, + extent.getHeight() / viewSize.h ); + + return this.getZoomForResolution(idealResolution, closest); + }, + + /** + * Method: getDataExtent + * Calculates the max extent which includes all of the data for the layer. + * This function is to be implemented by subclasses. + * + * Returns: + * {} + */ + getDataExtent: function () { + //to be implemented by subclasses + }, + + /** + * APIMethod: getResolutionForZoom + * + * Parameter: + * zoom - {Float} + * + * Returns: + * {Float} A suitable resolution for the specified zoom. + */ + getResolutionForZoom: function(zoom) { + zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1)); + var resolution; + if(this.map.fractionalZoom) { + var low = Math.floor(zoom); + var high = Math.ceil(zoom); + resolution = this.resolutions[low] - + ((zoom-low) * (this.resolutions[low]-this.resolutions[high])); + } else { + resolution = this.resolutions[Math.round(zoom)]; + } + return resolution; + }, + + /** + * APIMethod: getZoomForResolution + * + * Parameters: + * resolution - {Float} + * closest - {Boolean} Find the zoom level that corresponds to the absolute + * closest resolution, which may result in a zoom whose corresponding + * resolution is actually smaller than we would have desired (if this + * is being called from a getZoomForExtent() call, then this means that + * the returned zoom index might not actually contain the entire + * extent specified... but it'll be close). + * Default is false. + * + * Returns: + * {Integer} The index of the zoomLevel (entry in the resolutions array) + * that corresponds to the best fit resolution given the passed in + * value and the 'closest' specification. + */ + getZoomForResolution: function(resolution, closest) { + var zoom; + if(this.map.fractionalZoom) { + var lowZoom = 0; + var highZoom = this.resolutions.length - 1; + var highRes = this.resolutions[lowZoom]; + var lowRes = this.resolutions[highZoom]; + var res; + for(var i=0, len=this.resolutions.length; i= resolution) { + highRes = res; + lowZoom = i; + } + if(res <= resolution) { + lowRes = res; + highZoom = i; + break; + } + } + var dRes = highRes - lowRes; + if(dRes > 0) { + zoom = lowZoom + ((highRes - resolution) / dRes); + } else { + zoom = lowZoom; + } + } else { + var diff; + var minDiff = Number.POSITIVE_INFINITY; + for(var i=0, len=this.resolutions.length; i minDiff) { + break; + } + minDiff = diff; + } else { + if (this.resolutions[i] < resolution) { + break; + } + } + } + zoom = Math.max(0, i-1); + } + return zoom; + }, + + /** + * APIMethod: getLonLatFromViewPortPx + * + * Parameters: + * viewPortPx - {} + * + * Returns: + * {} An OpenLayers.LonLat which is the passed-in + * view port , translated into lon/lat by the layer. + */ + getLonLatFromViewPortPx: function (viewPortPx) { + var lonlat = null; + if (viewPortPx != null) { + var size = this.map.getSize(); + var center = this.map.getCenter(); + if (center) { + var res = this.map.getResolution(); + + var delta_x = viewPortPx.x - (size.w / 2); + var delta_y = viewPortPx.y - (size.h / 2); + + lonlat = new OpenLayers.LonLat(center.lon + delta_x * res , + center.lat - delta_y * res); + + if (this.wrapDateLine) { + lonlat = lonlat.wrapDateLine(this.maxExtent); + } + } // else { DEBUG STATEMENT } + } + return lonlat; + }, + + /** + * APIMethod: getViewPortPxFromLonLat + * Returns a pixel location given a map location. This method will return + * fractional pixel values. + * + * Parameters: + * lonlat - {} + * + * Returns: + * {} An which is the passed-in + * ,translated into view port pixels. + */ + getViewPortPxFromLonLat: function (lonlat) { + var px = null; + if (lonlat != null) { + var resolution = this.map.getResolution(); + var extent = this.map.getExtent(); + px = new OpenLayers.Pixel( + (1/resolution * (lonlat.lon - extent.left)), + (1/resolution * (extent.top - lonlat.lat)) + ); + } + return px; + }, + + /** + * APIMethod: setOpacity + * Sets the opacity for the entire layer (all images) + * + * Parameter: + * opacity - {Float} + */ + setOpacity: function(opacity) { + if (opacity != this.opacity) { + this.opacity = opacity; + for(var i=0, len=this.div.childNodes.length; i} + */ + adjustBounds: function (bounds) { + + if (this.gutter) { + // Adjust the extent of a bounds in map units by the + // layer's gutter in pixels. + var mapGutter = this.gutter * this.map.getResolution(); + bounds = new OpenLayers.Bounds(bounds.left - mapGutter, + bounds.bottom - mapGutter, + bounds.right + mapGutter, + bounds.top + mapGutter); + } + + if (this.wrapDateLine) { + // wrap around the date line, within the limits of rounding error + var wrappingOptions = { + 'rightTolerance':this.getResolution() + }; + bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions); + + } + return bounds; + }, + + CLASS_NAME: "OpenLayers.Layer" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/MapServer/Untiled.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/MapServer/Untiled.js new file mode 100755 index 0000000000..cb23f5a35a --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/MapServer/Untiled.js @@ -0,0 +1,71 @@ +/* Copyright 2006-2008 MetaCarta, Inc., published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full text + * of the license. */ + + +/** + * @requires OpenLayers/Layer/MapServer.js + * @requires OpenLayers/Console.js + */ + +/** + * Class: OpenLayers.Layer.MapServer.Untiled + * *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.MapServer + * and pass the option 'singleTile' as true. + * + * Inherits from: + * - + */ +OpenLayers.Layer.MapServer.Untiled = OpenLayers.Class(OpenLayers.Layer.MapServer, { + + /** + * APIProperty: singleTile + * {singleTile} Always true for untiled. + */ + singleTile: true, + + /** + * Constructor: OpenLayers.Layer.MapServer.Untiled + * + * Parameters: + * name - {String} + * url - {String} + * params - {Object} + * options - {Object} + */ + initialize: function(name, url, params, options) { + OpenLayers.Layer.MapServer.prototype.initialize.apply(this, arguments); + + var msg = "The OpenLayers.Layer.MapServer.Untiled class is deprecated and " + + "will be removed in 3.0. Instead, you should use the " + + "normal OpenLayers.Layer.MapServer class, passing it the option " + + "'singleTile' as true."; + OpenLayers.Console.warn(msg); + }, + + /** + * Method: clone + * Create a clone of this layer + * + * Returns: + * {} An exact clone of this layer + */ + clone: function (obj) { + + if (obj == null) { + obj = new OpenLayers.Layer.MapServer.Untiled(this.name, + this.url, + this.params, + this.options); + } + + //get all additions from superclasses + obj = OpenLayers.Layer.MapServer.prototype.clone.apply(this, [obj]); + + // copy/set any non-init, non-simple values here + + return obj; + }, + + CLASS_NAME: "OpenLayers.Layer.MapServer.Untiled" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/Vector/RootContainer.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/Vector/RootContainer.js new file mode 100755 index 0000000000..96b7c2f044 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Layer/Vector/RootContainer.js @@ -0,0 +1,156 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Layer/Vector.js + */ + +/** + * Class: OpenLayers.Layer.Vector.RootContainer + * A special layer type to combine multiple vector layers inside a single + * renderer root container. This class is not supposed to be instantiated + * from user space, it is a helper class for controls that require event + * processing for multiple vector layers. + * + * Inherits from: + * - + */ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { + + /** + * Property: displayInLayerSwitcher + * Set to false for this layer type + */ + displayInLayerSwitcher: false, + + /** + * APIProperty: layers + * Layers that are attached to this container. Required config option. + */ + layers: null, + + /** + * Constructor: OpenLayers.Layer.Vector.RootContainer + * Create a new root container for multiple vector layer. This constructor + * is not supposed to be used from user space, it is only to be used by + * controls that need feature selection across multiple vector layers. + * + * Parameters: + * name - {String} A name for the layer + * options - {Object} Optional object with non-default properties to set on + * the layer. + * + * Required options properties: + * layers - {Array()} The layers managed by this + * container + * + * Returns: + * {} A new vector layer root + * container + */ + initialize: function(name, options) { + OpenLayers.Layer.Vector.prototype.initialize.apply(this, arguments); + }, + + /** + * Method: display + */ + display: function() {}, + + /** + * Method: getFeatureFromEvent + * walk through the layers to find the feature returned by the event + * + * Parameters: + * evt - {Object} event object with a feature property + * + * Returns: + * {} + */ + getFeatureFromEvent: function(evt) { + var layers = this.layers; + var feature; + for(var i=0; i} + */ + setMap: function(map) { + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); + this.collectRoots(); + map.events.register("changelayer", this, this.handleChangeLayer); + }, + + /** + * Method: removeMap + * + * Parameters: + * map - {} + */ + removeMap: function(map) { + map.events.unregister("changelayer", this, this.handleChangeLayer); + this.resetRoots(); + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); + }, + + /** + * Method: collectRoots + * Collects the root nodes of all layers this control is configured with + * and moveswien the nodes to this control's layer + */ + collectRoots: function() { + var layer; + // walk through all map layers, because we want to keep the order + for(var i=0; i + */ +OpenLayers.Layer.WMS.Untiled = OpenLayers.Class(OpenLayers.Layer.WMS, { + + /** + * APIProperty: singleTile + * {singleTile} Always true for untiled. + */ + singleTile: true, + + /** + * Constructor: OpenLayers.Layer.WMS.Untiled + * + * Parameters: + * name - {String} + * url - {String} + * params - {Object} + * options - {Object} + */ + initialize: function(name, url, params, options) { + OpenLayers.Layer.WMS.prototype.initialize.apply(this, arguments); + + var msg = "The OpenLayers.Layer.WMS.Untiled class is deprecated and " + + "will be removed in 3.0. Instead, you should use the " + + "normal OpenLayers.Layer.WMS class, passing it the option " + + "'singleTile' as true."; + OpenLayers.Console.warn(msg); + }, + + /** + * Method: clone + * Create a clone of this layer + * + * Returns: + * {} An exact clone of this layer + */ + clone: function (obj) { + + if (obj == null) { + obj = new OpenLayers.Layer.WMS.Untiled(this.name, + this.url, + this.params, + this.options); + } + + //get all additions from superclasses + obj = OpenLayers.Layer.WMS.prototype.clone.apply(this, [obj]); + + // copy/set any non-init, non-simple values here + + return obj; + }, + + CLASS_NAME: "OpenLayers.Layer.WMS.Untiled" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Map.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Map.js new file mode 100755 index 0000000000..e8ae064108 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Map.js @@ -0,0 +1,2338 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Events.js + * @requires OpenLayers/Tween.js + * @requires OpenLayers/Console.js + */ + +/** + * Class: OpenLayers.Map + * Instances of OpenLayers.Map are interactive maps embedded in a web page. + * Create a new map with the constructor. + * + * On their own maps do not provide much functionality. To extend a map + * it's necessary to add controls () and + * layers () to the map. + */ +OpenLayers.Map = OpenLayers.Class({ + + /** + * Constant: Z_INDEX_BASE + * {Object} Base z-indexes for different classes of thing + */ + Z_INDEX_BASE: { + BaseLayer: 100, + Overlay: 325, + Feature: 725, + Popup: 750, + Control: 1000 + }, + + /** + * Constant: EVENT_TYPES + * {Array(String)} Supported application event types. Register a listener + * for a particular event with the following syntax: + * (code) + * map.events.register(type, obj, listener); + * (end) + * + * Listeners will be called with a reference to an event object. The + * properties of this event depends on exactly what happened. + * + * All event objects have at least the following properties: + * - *object* {Object} A reference to map.events.object. + * - *element* {DOMElement} A reference to map.events.element. + * + * Browser events have the following additional properties: + * - *xy* {} The pixel location of the event (relative + * to the the map viewport). + * - other properties that come with browser events + * + * Supported map event types: + * - *preaddlayer* triggered before a layer has been added. The event + * object will include a *layer* property that references the layer + * to be added. + * - *addlayer* triggered after a layer has been added. The event object + * will include a *layer* property that references the added layer. + * - *removelayer* triggered after a layer has been removed. The event + * object will include a *layer* property that references the removed + * layer. + * - *changelayer* triggered after a layer name change, order change, or + * visibility change (due to resolution thresholds). Listeners will + * receive an event object with *layer* and *property* properties. The + * *layer* property will be a reference to the changed layer. The + * *property* property will be a key to the changed property (name, + * visibility, or order). + * - *movestart* triggered after the start of a drag, pan, or zoom + * - *move* triggered after each drag, pan, or zoom + * - *moveend* triggered after a drag, pan, or zoom completes + * - *zoomend* triggered after a zoom completes + * - *addmarker* triggered after a marker has been added + * - *removemarker* triggered after a marker has been removed + * - *clearmarkers* triggered after markers have been cleared + * - *mouseover* triggered after mouseover the map + * - *mouseout* triggered after mouseout the map + * - *mousemove* triggered after mousemove the map + * - *dragstart* Does not work. Register for movestart instead. + * - *drag* Does not work. Register for move instead. + * - *dragend* Does not work. Register for moveend instead. + * - *changebaselayer* triggered after the base layer changes + */ + EVENT_TYPES: [ + "preaddlayer", "addlayer", "removelayer", "changelayer", "movestart", + "move", "moveend", "zoomend", "popupopen", "popupclose", + "addmarker", "removemarker", "clearmarkers", "mouseover", + "mouseout", "mousemove", "dragstart", "drag", "dragend", + "changebaselayer"], + + /** + * Property: id + * {String} Unique identifier for the map + */ + id: null, + + /** + * Property: fractionalZoom + * {Boolean} For a base layer that supports it, allow the map resolution + * to be set to a value between one of the values in the resolutions + * array. Default is false. + * + * When fractionalZoom is set to true, it is possible to zoom to + * an arbitrary extent. This requires a base layer from a source + * that supports requests for arbitrary extents (i.e. not cached + * tiles on a regular lattice). This means that fractionalZoom + * will not work with commercial layers (Google, Yahoo, VE), layers + * using TileCache, or any other pre-cached data sources. + * + * If you are using fractionalZoom, then you should also use + * instead of layer.resolutions[zoom] as the + * former works for non-integer zoom levels. + */ + fractionalZoom: false, + + /** + * APIProperty: events + * {} An events object that handles all + * events on the map + */ + events: null, + + /** + * APIProperty: allOverlays + * {Boolean} Allow the map to function with "overlays" only. Defaults to + * false. If true, the lowest layer in the draw order will act as + * the base layer. In addition, if set to true, all layers will + * have isBaseLayer set to false when they are added to the map. + * + * Note: + * If you set map.allOverlays to true, then you *cannot* use + * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, + * the lowest layer in the draw layer is the base layer. So, to change + * the base layer, use or to set the layer + * index to 0. + */ + allOverlays: false, + + /** + * APIProperty: div + * {DOMElement|String} The element that contains the map (or an id for + * that element). If the constructor is called + * with two arguments, this should be provided as the first argument. + * Alternatively, the map constructor can be called with the options + * object as the only argument. In this case (one argument), a + * div property may or may not be provided. If the div property + * is not provided, the map can be rendered to a container later + * using the method. + * + * Note: If you calling after map construction, do not use + * auto. Instead, divide your by your + * maximum expected dimension. + */ + div: null, + + /** + * Property: dragging + * {Boolean} The map is currently being dragged. + */ + dragging: false, + + /** + * Property: size + * {} Size of the main div (this.div) + */ + size: null, + + /** + * Property: viewPortDiv + * {HTMLDivElement} The element that represents the map viewport + */ + viewPortDiv: null, + + /** + * Property: layerContainerOrigin + * {} The lonlat at which the later container was + * re-initialized (on-zoom) + */ + layerContainerOrigin: null, + + /** + * Property: layerContainerDiv + * {HTMLDivElement} The element that contains the layers. + */ + layerContainerDiv: null, + + /** + * APIProperty: layers + * {Array()} Ordered list of layers in the map + */ + layers: null, + + /** + * Property: controls + * {Array()} List of controls associated with the map. + * + * If not provided in the map options at construction, the map will + * be given the following controls by default: + * - + * - + * - + * - + */ + controls: null, + + /** + * Property: popups + * {Array()} List of popups associated with the map + */ + popups: null, + + /** + * APIProperty: baseLayer + * {} The currently selected base layer. This determines + * min/max zoom level, projection, etc. + */ + baseLayer: null, + + /** + * Property: center + * {} The current center of the map + */ + center: null, + + /** + * Property: resolution + * {Float} The resolution of the map. + */ + resolution: null, + + /** + * Property: zoom + * {Integer} The current zoom level of the map + */ + zoom: 0, + + /** + * Property: panRatio + * {Float} The ratio of the current extent within + * which panning will tween. + */ + panRatio: 1.5, + + /** + * Property: viewRequestID + * {String} Used to store a unique identifier that changes when the map + * view changes. viewRequestID should be used when adding data + * asynchronously to the map: viewRequestID is incremented when + * you initiate your request (right now during changing of + * baselayers and changing of zooms). It is stored here in the + * map and also in the data that will be coming back + * asynchronously. Before displaying this data on request + * completion, we check that the viewRequestID of the data is + * still the same as that of the map. Fix for #480 + */ + viewRequestID: 0, + + // Options + + /** + * APIProperty: tileSize + * {} Set in the map options to override the default tile + * size for this map. + */ + tileSize: null, + + /** + * APIProperty: projection + * {String} Set in the map options to override the default projection + * string this map - also set maxExtent, maxResolution, and + * units if appropriate. Default is "EPSG:4326". + */ + projection: "EPSG:4326", + + /** + * APIProperty: units + * {String} The map units. Defaults to 'degrees'. Possible values are + * 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'. + */ + units: 'degrees', + + /** + * APIProperty: resolutions + * {Array(Float)} A list of map resolutions (map units per pixel) in + * descending order. If this is not set in the layer constructor, it + * will be set based on other resolution related properties + * (maxExtent, maxResolution, maxScale, etc.). + */ + resolutions: null, + + /** + * APIProperty: maxResolution + * {Float} Default max is 360 deg / 256 px, which corresponds to + * zoom level 0 on gmaps. Specify a different value in the map + * options if you are not using a geographic projection and + * displaying the whole world. + */ + maxResolution: 1.40625, + + /** + * APIProperty: minResolution + * {Float} + */ + minResolution: null, + + /** + * APIProperty: maxScale + * {Float} + */ + maxScale: null, + + /** + * APIProperty: minScale + * {Float} + */ + minScale: null, + + /** + * APIProperty: maxExtent + * {} The maximum extent for the map. Defaults to the + * whole world in decimal degrees + * (-180, -90, 180, 90). Specify a different + * extent in the map options if you are not using a + * geographic projection and displaying the whole + * world. + */ + maxExtent: null, + + /** + * APIProperty: minExtent + * {} + */ + minExtent: null, + + /** + * APIProperty: restrictedExtent + * {} Limit map navigation to this extent where possible. + * If a non-null restrictedExtent is set, panning will be restricted + * to the given bounds. In addition, zooming to a resolution that + * displays more than the restricted extent will center the map + * on the restricted extent. If you wish to limit the zoom level + * or resolution, use maxResolution. + */ + restrictedExtent: null, + + /** + * APIProperty: numZoomLevels + * {Integer} Number of zoom levels for the map. Defaults to 16. Set a + * different value in the map options if needed. + */ + numZoomLevels: 16, + + /** + * APIProperty: theme + * {String} Relative path to a CSS file from which to load theme styles. + * Specify null in the map options (e.g. {theme: null}) if you + * want to get cascading style declarations - by putting links to + * stylesheets or style declarations directly in your page. + */ + theme: null, + + /** + * APIProperty: displayProjection + * {} Requires proj4js support.Projection used by + * several controls to display data to user. If this property is set, + * it will be set on any control which has a null displayProjection + * property at the time the control is added to the map. + */ + displayProjection: null, + + /** + * APIProperty: fallThrough + * {Boolean} Should OpenLayers allow events on the map to fall through to + * other elements on the page, or should it swallow them? (#457) + * Default is to fall through. + */ + fallThrough: true, + + /** + * Property: panTween + * {OpenLayers.Tween} Animated panning tween object, see panTo() + */ + panTween: null, + + /** + * APIProperty: eventListeners + * {Object} If set as an option at construction, the eventListeners + * object will be registered with . Object + * structure must be a listeners object as shown in the example for + * the events.on method. + */ + eventListeners: null, + + /** + * APIProperty: panMethod + * {Function} The Easing function to be used for tweening. Default is + * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off + * animated panning. + */ + panMethod: OpenLayers.Easing.Expo.easeOut, + + /** + * Property: panDuration + * {Integer} The number of steps to be passed to the + * OpenLayers.Tween.start() method when the map is + * panned. + * Default is 50. + */ + panDuration: 50, + + /** + * Property: paddingForPopups + * {} Outside margin of the popup. Used to prevent + * the popup from getting too close to the map border. + */ + paddingForPopups : null, + + /** + * Constructor: OpenLayers.Map + * Constructor for a new OpenLayers.Map instance. There are two possible + * ways to call the map constructor. See the examples below. + * + * Parameters: + * div - {String} Id of an element in your page that will contain the map. + * May be omitted if the
option is provided or if you intend + * to use later. + * options - {Object} Optional object with properties to tag onto the map. + * + * Examples (method one): + * (code) + * // create a map with default options in an element with the id "map1" + * var map = new OpenLayers.Map("map1"); + * + * // create a map with non-default options in an element with id "map2" + * var options = { + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), + * maxResolution: 156543, + * units: 'm', + * projection: "EPSG:41001" + * }; + * var map = new OpenLayers.Map("map2", options); + * (end) + * + * Examples (method two - single argument): + * (code) + * // create a map with non-default options + * var map = new OpenLayers.Map({ + * div: "map_id", + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), + * maxResolution: 156543, + * units: 'm', + * projection: "EPSG:41001" + * }); + * + * // create a map without a reference to a container - call render later + * var map = new OpenLayers.Map({ + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), + * maxResolution: 156543, + * units: 'm', + * projection: "EPSG:41001" + * }); + */ + initialize: function (div, options) { + + // If only one argument is provided, check if it is an object. + if(arguments.length === 1 && typeof div === "object") { + options = div; + div = options && options.div; + } + + // Simple-type defaults are set in class definition. + // Now set complex-type defaults + this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH, + OpenLayers.Map.TILE_HEIGHT); + + this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90); + + this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15); + + this.theme = OpenLayers._getScriptLocation() + + 'theme/default/style.css'; + + // now override default options + OpenLayers.Util.extend(this, options); + + this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_"); + + this.div = OpenLayers.Util.getElement(div); + if(!this.div) { + this.div = document.createElement("div"); + this.div.style.height = "1px"; + this.div.style.width = "1px"; + } + + OpenLayers.Element.addClass(this.div, 'olMap'); + + // the viewPortDiv is the outermost div we modify + var id = this.div.id + "_OpenLayers_ViewPort"; + this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null, + "relative", null, + "hidden"); + this.viewPortDiv.style.width = "100%"; + this.viewPortDiv.style.height = "100%"; + this.viewPortDiv.className = "olMapViewport"; + this.div.appendChild(this.viewPortDiv); + + // the layerContainerDiv is the one that holds all the layers + id = this.div.id + "_OpenLayers_Container"; + this.layerContainerDiv = OpenLayers.Util.createDiv(id); + this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1; + + this.viewPortDiv.appendChild(this.layerContainerDiv); + + this.events = new OpenLayers.Events(this, + this.div, + this.EVENT_TYPES, + this.fallThrough, + {includeXY: true}); + this.updateSize(); + if(this.eventListeners instanceof Object) { + this.events.on(this.eventListeners); + } + + // update the map size and location before the map moves + this.events.register("movestart", this, this.updateSize); + + // Because Mozilla does not support the "resize" event for elements + // other than "window", we need to put a hack here. + if (OpenLayers.String.contains(navigator.appName, "Microsoft")) { + // If IE, register the resize on the div + this.events.register("resize", this, this.updateSize); + } else { + // Else updateSize on catching the window's resize + // Note that this is ok, as updateSize() does nothing if the + // map's size has not actually changed. + this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, + this); + OpenLayers.Event.observe(window, 'resize', + this.updateSizeDestroy); + } + + // only append link stylesheet if the theme property is set + if(this.theme) { + // check existing links for equivalent url + var addNode = true; + var nodes = document.getElementsByTagName('link'); + for(var i=0, len=nodes.length; i=0; --i) { + this.controls[i].destroy(); + } + this.controls = null; + } + if (this.layers != null) { + for (var i = this.layers.length - 1; i>=0; --i) { + //pass 'false' to destroy so that map wont try to set a new + // baselayer after each baselayer is removed + this.layers[i].destroy(false); + } + this.layers = null; + } + if (this.viewPortDiv) { + this.div.removeChild(this.viewPortDiv); + } + this.viewPortDiv = null; + + if(this.eventListeners) { + this.events.un(this.eventListeners); + this.eventListeners = null; + } + this.events.destroy(); + this.events = null; + + }, + + /** + * APIMethod: setOptions + * Change the map options + * + * Parameters: + * options - {Object} Hashtable of options to tag to the map + */ + setOptions: function(options) { + OpenLayers.Util.extend(this, options); + }, + + /** + * APIMethod: getTileSize + * Get the tile size for the map + * + * Returns: + * {} + */ + getTileSize: function() { + return this.tileSize; + }, + + + /** + * APIMethod: getBy + * Get a list of objects given a property and a match item. + * + * Parameters: + * array - {String} A property on the map whose value is an array. + * property - {String} A property on each item of the given array. + * match - {String | Object} A string to match. Can also be a regular + * expression literal or object. In addition, it can be any object + * with a method named test. For reqular expressions or other, if + * match.test(map[array][i][property]) evaluates to true, the item will + * be included in the array returned. If no items are found, an empty + * array is returned. + * + * Returns: + * {Array} An array of items where the given property matches the given + * criteria. + */ + getBy: function(array, property, match) { + var test = (typeof match.test == "function"); + var found = OpenLayers.Array.filter(this[array], function(item) { + return item[property] == match || (test && match.test(item[property])); + }); + return found; + }, + + /** + * APIMethod: getLayersBy + * Get a list of layers with properties matching the given criteria. + * + * Parameter: + * property - {String} A layer property to be matched. + * match - {String | Object} A string to match. Can also be a regular + * expression literal or object. In addition, it can be any object + * with a method named test. For reqular expressions or other, if + * match.test(layer[property]) evaluates to true, the layer will be + * included in the array returned. If no layers are found, an empty + * array is returned. + * + * Returns: + * {Array()} A list of layers matching the given criteria. + * An empty array is returned if no matches are found. + */ + getLayersBy: function(property, match) { + return this.getBy("layers", property, match); + }, + + /** + * APIMethod: getLayersByName + * Get a list of layers with names matching the given name. + * + * Parameter: + * match - {String | Object} A layer name. The name can also be a regular + * expression literal or object. In addition, it can be any object + * with a method named test. For reqular expressions or other, if + * name.test(layer.name) evaluates to true, the layer will be included + * in the list of layers returned. If no layers are found, an empty + * array is returned. + * + * Returns: + * {Array()} A list of layers matching the given name. + * An empty array is returned if no matches are found. + */ + getLayersByName: function(match) { + return this.getLayersBy("name", match); + }, + + /** + * APIMethod: getLayersByClass + * Get a list of layers of a given class (CLASS_NAME). + * + * Parameter: + * match - {String | Object} A layer class name. The match can also be a + * regular expression literal or object. In addition, it can be any + * object with a method named test. For reqular expressions or other, + * if type.test(layer.CLASS_NAME) evaluates to true, the layer will + * be included in the list of layers returned. If no layers are + * found, an empty array is returned. + * + * Returns: + * {Array()} A list of layers matching the given class. + * An empty array is returned if no matches are found. + */ + getLayersByClass: function(match) { + return this.getLayersBy("CLASS_NAME", match); + }, + + /** + * APIMethod: getControlsBy + * Get a list of controls with properties matching the given criteria. + * + * Parameter: + * property - {String} A control property to be matched. + * match - {String | Object} A string to match. Can also be a regular + * expression literal or object. In addition, it can be any object + * with a method named test. For reqular expressions or other, if + * match.test(layer[property]) evaluates to true, the layer will be + * included in the array returned. If no layers are found, an empty + * array is returned. + * + * Returns: + * {Array()} A list of controls matching the given + * criteria. An empty array is returned if no matches are found. + */ + getControlsBy: function(property, match) { + return this.getBy("controls", property, match); + }, + + /** + * APIMethod: getControlsByClass + * Get a list of controls of a given class (CLASS_NAME). + * + * Parameter: + * match - {String | Object} A control class name. The match can also be a + * regular expression literal or object. In addition, it can be any + * object with a method named test. For reqular expressions or other, + * if type.test(control.CLASS_NAME) evaluates to true, the control will + * be included in the list of controls returned. If no controls are + * found, an empty array is returned. + * + * Returns: + * {Array()} A list of controls matching the given class. + * An empty array is returned if no matches are found. + */ + getControlsByClass: function(match) { + return this.getControlsBy("CLASS_NAME", match); + }, + + /********************************************************/ + /* */ + /* Layer Functions */ + /* */ + /* The following functions deal with adding and */ + /* removing Layers to and from the Map */ + /* */ + /********************************************************/ + + /** + * APIMethod: getLayer + * Get a layer based on its id + * + * Parameter: + * id - {String} A layer id + * + * Returns: + * {} The Layer with the corresponding id from the map's + * layer collection, or null if not found. + */ + getLayer: function(id) { + var foundLayer = null; + for (var i=0, len=this.layers.length; i} + * zIdx - {int} + */ + setLayerZIndex: function (layer, zIdx) { + layer.setZIndex( + this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] + + zIdx * 5 ); + }, + + /** + * Method: resetLayersZIndex + * Reset each layer's z-index based on layer's array index + */ + resetLayersZIndex: function() { + for (var i=0, len=this.layers.length; i} + */ + addLayer: function (layer) { + for(var i=0, len=this.layers.length; i )} + */ + addLayers: function (layers) { + for (var i=0, len=layers.length; i} + * setNewBaseLayer - {Boolean} Default is true + */ + removeLayer: function(layer, setNewBaseLayer) { + if (setNewBaseLayer == null) { + setNewBaseLayer = true; + } + + if (layer.isFixed) { + this.viewPortDiv.removeChild(layer.div); + } else { + this.layerContainerDiv.removeChild(layer.div); + } + OpenLayers.Util.removeItem(this.layers, layer); + layer.removeMap(this); + layer.map = null; + + // if we removed the base layer, need to set a new one + if(this.baseLayer == layer) { + this.baseLayer = null; + if(setNewBaseLayer) { + for(var i=0, len=this.layers.length; i} + * + * Returns: + * {Integer} The current (zero-based) index of the given layer in the map's + * layer stack. Returns -1 if the layer isn't on the map. + */ + getLayerIndex: function (layer) { + return OpenLayers.Util.indexOf(this.layers, layer); + }, + + /** + * APIMethod: setLayerIndex + * Move the given layer to the specified (zero-based) index in the layer + * list, changing its z-index in the map display. Use + * map.getLayerIndex() to find out the current index of a layer. Note + * that this cannot (or at least should not) be effectively used to + * raise base layers above overlays. + * + * Parameters: + * layer - {} + * idx - {int} + */ + setLayerIndex: function (layer, idx) { + var base = this.getLayerIndex(layer); + if (idx < 0) { + idx = 0; + } else if (idx > this.layers.length) { + idx = this.layers.length; + } + if (base != idx) { + this.layers.splice(base, 1); + this.layers.splice(idx, 0, layer); + for (var i=0, len=this.layers.length; i} + * delta - {int} + */ + raiseLayer: function (layer, delta) { + var idx = this.getLayerIndex(layer) + delta; + this.setLayerIndex(layer, idx); + }, + + /** + * APIMethod: setBaseLayer + * Allows user to specify one of the currently-loaded layers as the Map's + * new base layer. + * + * Parameters: + * newBaseLayer - {} + */ + setBaseLayer: function(newBaseLayer) { + var oldExtent = null; + if (this.baseLayer) { + oldExtent = this.baseLayer.getExtent(); + } + + if (newBaseLayer != this.baseLayer) { + + // is newBaseLayer an already loaded layer?m + if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) { + + // make the old base layer invisible + if (this.baseLayer != null && !this.allOverlays) { + this.baseLayer.setVisibility(false); + } + + // set new baselayer + this.baseLayer = newBaseLayer; + + // Increment viewRequestID since the baseLayer is + // changing. This is used by tiles to check if they should + // draw themselves. + this.viewRequestID++; + if(!this.allOverlays) { + this.baseLayer.visibility = true; + } + + //redraw all layers + var center = this.getCenter(); + if (center != null) { + + //either get the center from the old Extent or just from + // the current center of the map. + var newCenter = (oldExtent) + ? oldExtent.getCenterLonLat() + : center; + + //the new zoom will either come from the old Extent or + // from the current resolution of the map + var newZoom = (oldExtent) + ? this.getZoomForExtent(oldExtent, true) + : this.getZoomForResolution(this.resolution, true); + + // zoom and force zoom change + this.setCenter(newCenter, newZoom, false, true); + } + + this.events.triggerEvent("changebaselayer", { + layer: this.baseLayer + }); + } + } + }, + + + /********************************************************/ + /* */ + /* Control Functions */ + /* */ + /* The following functions deal with adding and */ + /* removing Controls to and from the Map */ + /* */ + /********************************************************/ + + /** + * APIMethod: addControl + * + * Parameters: + * control - {} + * px - {} + */ + addControl: function (control, px) { + this.controls.push(control); + this.addControlToMap(control, px); + }, + + /** + * Method: addControlToMap + * + * Parameters: + * + * control - {} + * px - {} + */ + addControlToMap: function (control, px) { + // If a control doesn't have a div at this point, it belongs in the + // viewport. + control.outsideViewport = (control.div != null); + + // If the map has a displayProjection, and the control doesn't, set + // the display projection. + if (this.displayProjection && !control.displayProjection) { + control.displayProjection = this.displayProjection; + } + + control.setMap(this); + var div = control.draw(px); + if (div) { + if(!control.outsideViewport) { + div.style.zIndex = this.Z_INDEX_BASE['Control'] + + this.controls.length; + this.viewPortDiv.appendChild( div ); + } + } + }, + + /** + * APIMethod: getControl + * + * Parameters: + * id - {String} ID of the control to return. + * + * Returns: + * {} The control from the map's list of controls + * which has a matching 'id'. If none found, + * returns null. + */ + getControl: function (id) { + var returnControl = null; + for(var i=0, len=this.controls.length; i} The control to remove. + */ + removeControl: function (control) { + //make sure control is non-null and actually part of our map + if ( (control) && (control == this.getControl(control.id)) ) { + if (control.div && (control.div.parentNode == this.viewPortDiv)) { + this.viewPortDiv.removeChild(control.div); + } + OpenLayers.Util.removeItem(this.controls, control); + } + }, + + /********************************************************/ + /* */ + /* Popup Functions */ + /* */ + /* The following functions deal with adding and */ + /* removing Popups to and from the Map */ + /* */ + /********************************************************/ + + /** + * APIMethod: addPopup + * + * Parameters: + * popup - {} + * exclusive - {Boolean} If true, closes all other popups first + */ + addPopup: function(popup, exclusive) { + + if (exclusive) { + //remove all other popups from screen + for (var i = this.popups.length - 1; i >= 0; --i) { + this.removePopup(this.popups[i]); + } + } + + popup.map = this; + this.popups.push(popup); + var popupDiv = popup.draw(); + if (popupDiv) { + popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] + + this.popups.length; + this.layerContainerDiv.appendChild(popupDiv); + } + }, + + /** + * APIMethod: removePopup + * + * Parameters: + * popup - {} + */ + removePopup: function(popup) { + OpenLayers.Util.removeItem(this.popups, popup); + if (popup.div) { + try { this.layerContainerDiv.removeChild(popup.div); } + catch (e) { } // Popups sometimes apparently get disconnected + // from the layerContainerDiv, and cause complaints. + } + popup.map = null; + }, + + /********************************************************/ + /* */ + /* Container Div Functions */ + /* */ + /* The following functions deal with the access to */ + /* and maintenance of the size of the container div */ + /* */ + /********************************************************/ + + /** + * APIMethod: getSize + * + * Returns: + * {} An object that represents the + * size, in pixels, of the div into which OpenLayers + * has been loaded. + * Note - A clone() of this locally cached variable is + * returned, so as not to allow users to modify it. + */ + getSize: function () { + var size = null; + if (this.size != null) { + size = this.size.clone(); + } + return size; + }, + + /** + * APIMethod: updateSize + * This function should be called by any external code which dynamically + * changes the size of the map div (because mozilla wont let us catch + * the "onresize" for an element) + */ + updateSize: function() { + // the div might have moved on the page, also + this.events.clearMouseCache(); + var newSize = this.getCurrentSize(); + var oldSize = this.getSize(); + if (oldSize == null) { + this.size = oldSize = newSize; + } + if (!newSize.equals(oldSize)) { + + // store the new size + this.size = newSize; + + //notify layers of mapresize + for(var i=0, len=this.layers.length; i} A new object with the dimensions + * of the map div + */ + getCurrentSize: function() { + + var size = new OpenLayers.Size(this.div.clientWidth, + this.div.clientHeight); + + // Workaround for the fact that hidden elements return 0 for size. + if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { + var dim = OpenLayers.Element.getDimensions(this.div); + size.w = dim.width; + size.h = dim.height; + } + if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { + size.w = parseInt(this.div.style.width); + size.h = parseInt(this.div.style.height); + } + return size; + }, + + /** + * Method: calculateBounds + * + * Parameters: + * center - {} Default is this.getCenter() + * resolution - {float} Default is this.getResolution() + * + * Returns: + * {} A bounds based on resolution, center, and + * current mapsize. + */ + calculateBounds: function(center, resolution) { + + var extent = null; + + if (center == null) { + center = this.getCenter(); + } + if (resolution == null) { + resolution = this.getResolution(); + } + + if ((center != null) && (resolution != null)) { + + var size = this.getSize(); + var w_deg = size.w * resolution; + var h_deg = size.h * resolution; + + extent = new OpenLayers.Bounds(center.lon - w_deg / 2, + center.lat - h_deg / 2, + center.lon + w_deg / 2, + center.lat + h_deg / 2); + + } + + return extent; + }, + + + /********************************************************/ + /* */ + /* Zoom, Center, Pan Functions */ + /* */ + /* The following functions handle the validation, */ + /* getting and setting of the Zoom Level and Center */ + /* as well as the panning of the Map */ + /* */ + /********************************************************/ + /** + * APIMethod: getCenter + * + * Returns: + * {} + */ + getCenter: function () { + var center = null; + if (this.center) { + center = this.center.clone(); + } + return center; + }, + + + /** + * APIMethod: getZoom + * + * Returns: + * {Integer} + */ + getZoom: function () { + return this.zoom; + }, + + /** + * APIMethod: pan + * Allows user to pan by a value of screen pixels + * + * Parameters: + * dx - {Integer} + * dy - {Integer} + * options - {Object} Options to configure panning: + * - *animate* {Boolean} Use panTo instead of setCenter. Default is true. + * - *dragging* {Boolean} Call setCenter with dragging true. Default is + * false. + */ + pan: function(dx, dy, options) { + options = OpenLayers.Util.applyDefaults(options, { + animate: true, + dragging: false + }); + // getCenter + var centerPx = this.getViewPortPxFromLonLat(this.getCenter()); + + // adjust + var newCenterPx = centerPx.add(dx, dy); + + // only call setCenter if not dragging or there has been a change + if (!options.dragging || !newCenterPx.equals(centerPx)) { + var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx); + if (options.animate) { + this.panTo(newCenterLonLat); + } else { + this.setCenter(newCenterLonLat, null, options.dragging); + } + } + + }, + + /** + * APIMethod: panTo + * Allows user to pan to a new lonlat + * If the new lonlat is in the current extent the map will slide smoothly + * + * Parameters: + * lonlat - {} + */ + panTo: function(lonlat) { + if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) { + if (!this.panTween) { + this.panTween = new OpenLayers.Tween(this.panMethod); + } + var center = this.getCenter(); + + // center will not change, don't do nothing + if (lonlat.lon == center.lon && + lonlat.lat == center.lat) { + return; + } + + var from = { + lon: center.lon, + lat: center.lat + }; + var to = { + lon: lonlat.lon, + lat: lonlat.lat + }; + this.panTween.start(from, to, this.panDuration, { + callbacks: { + start: OpenLayers.Function.bind(function(lonlat) { + this.events.triggerEvent("movestart"); + }, this), + eachStep: OpenLayers.Function.bind(function(lonlat) { + lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat); + this.moveTo(lonlat, this.zoom, { + 'dragging': true, + 'noEvent': true + }); + }, this), + done: OpenLayers.Function.bind(function(lonlat) { + lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat); + this.moveTo(lonlat, this.zoom, { + 'noEvent': true + }); + this.events.triggerEvent("moveend"); + }, this) + } + }); + } else { + this.setCenter(lonlat); + } + }, + + /** + * APIMethod: setCenter + * Set the map center (and optionally, the zoom level). + * + * Parameters: + * lonlat - {} The new center location. + * zoom - {Integer} Optional zoom level. + * dragging - {Boolean} Specifies whether or not to trigger + * movestart/end events + * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom + * change events (needed on baseLayer change) + * + * TBD: reconsider forceZoomChange in 3.0 + */ + setCenter: function(lonlat, zoom, dragging, forceZoomChange) { + this.moveTo(lonlat, zoom, { + 'dragging': dragging, + 'forceZoomChange': forceZoomChange, + 'caller': 'setCenter' + }); + }, + + /** + * Method: moveTo + * + * Parameters: + * lonlat - {} + * zoom - {Integer} + * options - {Object} + */ + moveTo: function(lonlat, zoom, options) { + if (!options) { + options = {}; + } + // dragging is false by default + var dragging = options.dragging; + // forceZoomChange is false by default + var forceZoomChange = options.forceZoomChange; + // noEvent is false by default + var noEvent = options.noEvent; + + if (this.panTween && options.caller == "setCenter") { + this.panTween.stop(); + } + + if (!this.center && !this.isValidLonLat(lonlat)) { + lonlat = this.maxExtent.getCenterLonLat(); + } + + if(this.restrictedExtent != null) { + // In 3.0, decide if we want to change interpretation of maxExtent. + if(lonlat == null) { + lonlat = this.getCenter(); + } + if(zoom == null) { + zoom = this.getZoom(); + } + var resolution = this.getResolutionForZoom(zoom); + var extent = this.calculateBounds(lonlat, resolution); + if(!this.restrictedExtent.containsBounds(extent)) { + var maxCenter = this.restrictedExtent.getCenterLonLat(); + if(extent.getWidth() > this.restrictedExtent.getWidth()) { + lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); + } else if(extent.left < this.restrictedExtent.left) { + lonlat = lonlat.add(this.restrictedExtent.left - + extent.left, 0); + } else if(extent.right > this.restrictedExtent.right) { + lonlat = lonlat.add(this.restrictedExtent.right - + extent.right, 0); + } + if(extent.getHeight() > this.restrictedExtent.getHeight()) { + lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); + } else if(extent.bottom < this.restrictedExtent.bottom) { + lonlat = lonlat.add(0, this.restrictedExtent.bottom - + extent.bottom); + } + else if(extent.top > this.restrictedExtent.top) { + lonlat = lonlat.add(0, this.restrictedExtent.top - + extent.top); + } + } + } + + var zoomChanged = forceZoomChange || ( + (this.isValidZoomLevel(zoom)) && + (zoom != this.getZoom()) ); + + var centerChanged = (this.isValidLonLat(lonlat)) && + (!lonlat.equals(this.center)); + + + // if neither center nor zoom will change, no need to do anything + if (zoomChanged || centerChanged || !dragging) { + + if (!this.dragging && !noEvent) { + this.events.triggerEvent("movestart"); + } + + if (centerChanged) { + if ((!zoomChanged) && (this.center)) { + // if zoom hasnt changed, just slide layerContainer + // (must be done before setting this.center to new value) + this.centerLayerContainer(lonlat); + } + this.center = lonlat.clone(); + } + + // (re)set the layerContainerDiv's location + if ((zoomChanged) || (this.layerContainerOrigin == null)) { + this.layerContainerOrigin = this.center.clone(); + this.layerContainerDiv.style.left = "0px"; + this.layerContainerDiv.style.top = "0px"; + } + + if (zoomChanged) { + this.zoom = zoom; + this.resolution = this.getResolutionForZoom(zoom); + // zoom level has changed, increment viewRequestID. + this.viewRequestID++; + } + + var bounds = this.getExtent(); + + //send the move call to the baselayer and all the overlays + + if(this.baseLayer.visibility) { + this.baseLayer.moveTo(bounds, zoomChanged, dragging); + if(dragging) { + this.baseLayer.events.triggerEvent("move"); + } else { + this.baseLayer.events.triggerEvent("moveend", + {"zoomChanged": zoomChanged} + ); + } + } + + bounds = this.baseLayer.getExtent(); + + for (var i=0, len=this.layers.length; i} + */ + centerLayerContainer: function (lonlat) { + + var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin); + var newPx = this.getViewPortPxFromLonLat(lonlat); + + if ((originPx != null) && (newPx != null)) { + this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px"; + this.layerContainerDiv.style.top = Math.round(originPx.y - newPx.y) + "px"; + } + }, + + /** + * Method: isValidZoomLevel + * + * Parameters: + * zoomLevel - {Integer} + * + * Returns: + * {Boolean} Whether or not the zoom level passed in is non-null and + * within the min/max range of zoom levels. + */ + isValidZoomLevel: function(zoomLevel) { + return ( (zoomLevel != null) && + (zoomLevel >= 0) && + (zoomLevel < this.getNumZoomLevels()) ); + }, + + /** + * Method: isValidLonLat + * + * Parameters: + * lonlat - {} + * + * Returns: + * {Boolean} Whether or not the lonlat passed in is non-null and within + * the maxExtent bounds + */ + isValidLonLat: function(lonlat) { + var valid = false; + if (lonlat != null) { + var maxExtent = this.getMaxExtent(); + valid = maxExtent.containsLonLat(lonlat); + } + return valid; + }, + + /********************************************************/ + /* */ + /* Layer Options */ + /* */ + /* Accessor functions to Layer Options parameters */ + /* */ + /********************************************************/ + + /** + * APIMethod: getProjection + * This method returns a string representing the projection. In + * the case of projection support, this will be the srsCode which + * is loaded -- otherwise it will simply be the string value that + * was passed to the projection at startup. + * + * FIXME: In 3.0, we will remove getProjectionObject, and instead + * return a Projection object from this function. + * + * Returns: + * {String} The Projection string from the base layer or null. + */ + getProjection: function() { + var projection = this.getProjectionObject(); + return projection ? projection.getCode() : null; + }, + + /** + * APIMethod: getProjectionObject + * Returns the projection obect from the baselayer. + * + * Returns: + * {} The Projection of the base layer. + */ + getProjectionObject: function() { + var projection = null; + if (this.baseLayer != null) { + projection = this.baseLayer.projection; + } + return projection; + }, + + /** + * APIMethod: getMaxResolution + * + * Returns: + * {String} The Map's Maximum Resolution + */ + getMaxResolution: function() { + var maxResolution = null; + if (this.baseLayer != null) { + maxResolution = this.baseLayer.maxResolution; + } + return maxResolution; + }, + + /** + * APIMethod: getMaxExtent + * + * Parameters: + * options - {Object} + * + * Allowed Options: + * restricted - {Boolean} If true, returns restricted extent (if it is + * available.) + * + * Returns: + * {} The maxExtent property as set on the current + * baselayer, unless the 'restricted' option is set, in which case + * the 'restrictedExtent' option from the map is returned (if it + * is set). + */ + getMaxExtent: function (options) { + var maxExtent = null; + if(options && options.restricted && this.restrictedExtent){ + maxExtent = this.restrictedExtent; + } else if (this.baseLayer != null) { + maxExtent = this.baseLayer.maxExtent; + } + return maxExtent; + }, + + /** + * APIMethod: getNumZoomLevels + * + * Returns: + * {Integer} The total number of zoom levels that can be displayed by the + * current baseLayer. + */ + getNumZoomLevels: function() { + var numZoomLevels = null; + if (this.baseLayer != null) { + numZoomLevels = this.baseLayer.numZoomLevels; + } + return numZoomLevels; + }, + + /********************************************************/ + /* */ + /* Baselayer Functions */ + /* */ + /* The following functions, all publicly exposed */ + /* in the API?, are all merely wrappers to the */ + /* the same calls on whatever layer is set as */ + /* the current base layer */ + /* */ + /********************************************************/ + + /** + * APIMethod: getExtent + * + * Returns: + * {} A Bounds object which represents the lon/lat + * bounds of the current viewPort. + * If no baselayer is set, returns null. + */ + getExtent: function () { + var extent = null; + if (this.baseLayer != null) { + extent = this.baseLayer.getExtent(); + } + return extent; + }, + + /** + * APIMethod: getResolution + * + * Returns: + * {Float} The current resolution of the map. + * If no baselayer is set, returns null. + */ + getResolution: function () { + var resolution = null; + if (this.baseLayer != null) { + resolution = this.baseLayer.getResolution(); + } + return resolution; + }, + + /** + * APIMethod: getUnits + * + * Returns: + * {Float} The current units of the map. + * If no baselayer is set, returns null. + */ + getUnits: function () { + var units = null; + if (this.baseLayer != null) { + units = this.baseLayer.units; + } + return units; + }, + + /** + * APIMethod: getScale + * + * Returns: + * {Float} The current scale denominator of the map. + * If no baselayer is set, returns null. + */ + getScale: function () { + var scale = null; + if (this.baseLayer != null) { + var res = this.getResolution(); + var units = this.baseLayer.units; + scale = OpenLayers.Util.getScaleFromResolution(res, units); + } + return scale; + }, + + + /** + * APIMethod: getZoomForExtent + * + * Parameters: + * bounds - {} + * closest - {Boolean} Find the zoom level that most closely fits the + * specified bounds. Note that this may result in a zoom that does + * not exactly contain the entire extent. + * Default is false. + * + * Returns: + * {Integer} A suitable zoom level for the specified bounds. + * If no baselayer is set, returns null. + */ + getZoomForExtent: function (bounds, closest) { + var zoom = null; + if (this.baseLayer != null) { + zoom = this.baseLayer.getZoomForExtent(bounds, closest); + } + return zoom; + }, + + /** + * APIMethod: getResolutionForZoom + * + * Parameter: + * zoom - {Float} + * + * Returns: + * {Float} A suitable resolution for the specified zoom. If no baselayer + * is set, returns null. + */ + getResolutionForZoom: function(zoom) { + var resolution = null; + if(this.baseLayer) { + resolution = this.baseLayer.getResolutionForZoom(zoom); + } + return resolution; + }, + + /** + * APIMethod: getZoomForResolution + * + * Parameter: + * resolution - {Float} + * closest - {Boolean} Find the zoom level that corresponds to the absolute + * closest resolution, which may result in a zoom whose corresponding + * resolution is actually smaller than we would have desired (if this + * is being called from a getZoomForExtent() call, then this means that + * the returned zoom index might not actually contain the entire + * extent specified... but it'll be close). + * Default is false. + * + * Returns: + * {Integer} A suitable zoom level for the specified resolution. + * If no baselayer is set, returns null. + */ + getZoomForResolution: function(resolution, closest) { + var zoom = null; + if (this.baseLayer != null) { + zoom = this.baseLayer.getZoomForResolution(resolution, closest); + } + return zoom; + }, + + /********************************************************/ + /* */ + /* Zooming Functions */ + /* */ + /* The following functions, all publicly exposed */ + /* in the API, are all merely wrappers to the */ + /* the setCenter() function */ + /* */ + /********************************************************/ + + /** + * APIMethod: zoomTo + * Zoom to a specific zoom level + * + * Parameters: + * zoom - {Integer} + */ + zoomTo: function(zoom) { + if (this.isValidZoomLevel(zoom)) { + this.setCenter(null, zoom); + } + }, + + /** + * APIMethod: zoomIn + * + * Parameters: + * zoom - {int} + */ + zoomIn: function() { + this.zoomTo(this.getZoom() + 1); + }, + + /** + * APIMethod: zoomOut + * + * Parameters: + * zoom - {int} + */ + zoomOut: function() { + this.zoomTo(this.getZoom() - 1); + }, + + /** + * APIMethod: zoomToExtent + * Zoom to the passed in bounds, recenter + * + * Parameters: + * bounds - {} + * closest - {Boolean} Find the zoom level that most closely fits the + * specified bounds. Note that this may result in a zoom that does + * not exactly contain the entire extent. + * Default is false. + * + */ + zoomToExtent: function(bounds, closest) { + var center = bounds.getCenterLonLat(); + if (this.baseLayer.wrapDateLine) { + var maxExtent = this.getMaxExtent(); + + //fix straddling bounds (in the case of a bbox that straddles the + // dateline, it's left and right boundaries will appear backwards. + // we fix this by allowing a right value that is greater than the + // max value at the dateline -- this allows us to pass a valid + // bounds to calculate zoom) + // + bounds = bounds.clone(); + while (bounds.right < bounds.left) { + bounds.right += maxExtent.getWidth(); + } + //if the bounds was straddling (see above), then the center point + // we got from it was wrong. So we take our new bounds and ask it + // for the center. Because our new bounds is at least partially + // outside the bounds of maxExtent, the new calculated center + // might also be. We don't want to pass a bad center value to + // setCenter, so we have it wrap itself across the date line. + // + center = bounds.getCenterLonLat().wrapDateLine(maxExtent); + } + this.setCenter(center, this.getZoomForExtent(bounds, closest)); + }, + + /** + * APIMethod: zoomToMaxExtent + * Zoom to the full extent and recenter. + * + * Parameters: + * options - + * + * Allowed Options: + * restricted - {Boolean} True to zoom to restricted extent if it is + * set. Defaults to true. + */ + zoomToMaxExtent: function(options) { + //restricted is true by default + var restricted = (options) ? options.restricted : true; + + var maxExtent = this.getMaxExtent({ + 'restricted': restricted + }); + this.zoomToExtent(maxExtent); + }, + + /** + * APIMethod: zoomToScale + * Zoom to a specified scale + * + * Parameters: + * scale - {float} + * closest - {Boolean} Find the zoom level that most closely fits the + * specified scale. Note that this may result in a zoom that does + * not exactly contain the entire extent. + * Default is false. + * + */ + zoomToScale: function(scale, closest) { + var res = OpenLayers.Util.getResolutionFromScale(scale, + this.baseLayer.units); + var size = this.getSize(); + var w_deg = size.w * res; + var h_deg = size.h * res; + var center = this.getCenter(); + + var extent = new OpenLayers.Bounds(center.lon - w_deg / 2, + center.lat - h_deg / 2, + center.lon + w_deg / 2, + center.lat + h_deg / 2); + this.zoomToExtent(extent, closest); + }, + + /********************************************************/ + /* */ + /* Translation Functions */ + /* */ + /* The following functions translate between */ + /* LonLat, LayerPx, and ViewPortPx */ + /* */ + /********************************************************/ + + // + // TRANSLATION: LonLat <-> ViewPortPx + // + + /** + * Method: getLonLatFromViewPortPx + * + * Parameters: + * viewPortPx - {} + * + * Returns: + * {} An OpenLayers.LonLat which is the passed-in view + * port , translated into lon/lat + * by the current base layer. + */ + getLonLatFromViewPortPx: function (viewPortPx) { + var lonlat = null; + if (this.baseLayer != null) { + lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx); + } + return lonlat; + }, + + /** + * APIMethod: getViewPortPxFromLonLat + * + * Parameters: + * lonlat - {} + * + * Returns: + * {} An OpenLayers.Pixel which is the passed-in + * , translated into view port + * pixels by the current base layer. + */ + getViewPortPxFromLonLat: function (lonlat) { + var px = null; + if (this.baseLayer != null) { + px = this.baseLayer.getViewPortPxFromLonLat(lonlat); + } + return px; + }, + + + // + // CONVENIENCE TRANSLATION FUNCTIONS FOR API + // + + /** + * APIMethod: getLonLatFromPixel + * + * Parameters: + * px - {} + * + * Returns: + * {} An OpenLayers.LonLat corresponding to the given + * OpenLayers.Pixel, translated into lon/lat by the + * current base layer + */ + getLonLatFromPixel: function (px) { + return this.getLonLatFromViewPortPx(px); + }, + + /** + * APIMethod: getPixelFromLonLat + * Returns a pixel location given a map location. The map location is + * translated to an integer pixel location (in viewport pixel + * coordinates) by the current base layer. + * + * Parameters: + * lonlat - {} A map location. + * + * Returns: + * {} An OpenLayers.Pixel corresponding to the + * translated into view port pixels by the current + * base layer. + */ + getPixelFromLonLat: function (lonlat) { + var px = this.getViewPortPxFromLonLat(lonlat); + px.x = Math.round(px.x); + px.y = Math.round(px.y); + return px; + }, + + + + // + // TRANSLATION: ViewPortPx <-> LayerPx + // + + /** + * APIMethod: getViewPortPxFromLayerPx + * + * Parameters: + * layerPx - {} + * + * Returns: + * {} Layer Pixel translated into ViewPort Pixel + * coordinates + */ + getViewPortPxFromLayerPx:function(layerPx) { + var viewPortPx = null; + if (layerPx != null) { + var dX = parseInt(this.layerContainerDiv.style.left); + var dY = parseInt(this.layerContainerDiv.style.top); + viewPortPx = layerPx.add(dX, dY); + } + return viewPortPx; + }, + + /** + * APIMethod: getLayerPxFromViewPortPx + * + * Parameters: + * viewPortPx - {} + * + * Returns: + * {} ViewPort Pixel translated into Layer Pixel + * coordinates + */ + getLayerPxFromViewPortPx:function(viewPortPx) { + var layerPx = null; + if (viewPortPx != null) { + var dX = -parseInt(this.layerContainerDiv.style.left); + var dY = -parseInt(this.layerContainerDiv.style.top); + layerPx = viewPortPx.add(dX, dY); + if (isNaN(layerPx.x) || isNaN(layerPx.y)) { + layerPx = null; + } + } + return layerPx; + }, + + // + // TRANSLATION: LonLat <-> LayerPx + // + + /** + * Method: getLonLatFromLayerPx + * + * Parameters: + * px - {} + * + * Returns: + * {} + */ + getLonLatFromLayerPx: function (px) { + //adjust for displacement of layerContainerDiv + px = this.getViewPortPxFromLayerPx(px); + return this.getLonLatFromViewPortPx(px); + }, + + /** + * APIMethod: getLayerPxFromLonLat + * + * Parameters: + * lonlat - {} lonlat + * + * Returns: + * {} An OpenLayers.Pixel which is the passed-in + * , translated into layer pixels + * by the current base layer + */ + getLayerPxFromLonLat: function (lonlat) { + //adjust for displacement of layerContainerDiv + var px = this.getPixelFromLonLat(lonlat); + return this.getLayerPxFromViewPortPx(px); + }, + + CLASS_NAME: "OpenLayers.Map" +}); + +/** + * Constant: TILE_WIDTH + * {Integer} 256 Default tile width (unless otherwise specified) + */ +OpenLayers.Map.TILE_WIDTH = 256; +/** + * Constant: TILE_HEIGHT + * {Integer} 256 Default tile height (unless otherwise specified) + */ +OpenLayers.Map.TILE_HEIGHT = 256; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Marker.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Marker.js new file mode 100755 index 0000000000..3e0845eb5e --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Marker.js @@ -0,0 +1,241 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Events.js + * @requires OpenLayers/Icon.js + */ + +/** + * Class: OpenLayers.Marker + * Instances of OpenLayers.Marker are a combination of a + * and an . + * + * Markers are generally added to a special layer called + * . + * + * Example: + * (code) + * var markers = new OpenLayers.Layer.Markers( "Markers" ); + * map.addLayer(markers); + * + * var size = new OpenLayers.Size(10,17); + * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); + * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset); + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); + * + * (end) + * + * Note that if you pass an icon into the Marker constructor, it will take + * that icon and use it. This means that you should not share icons between + * markers -- you use them once, but you should clone() for any additional + * markers using that same icon. + */ +OpenLayers.Marker = OpenLayers.Class({ + + /** + * Property: icon + * {} The icon used by this marker. + */ + icon: null, + + /** + * Property: lonlat + * {} location of object + */ + lonlat: null, + + /** + * Property: events + * {} the event handler. + */ + events: null, + + /** + * Property: map + * {} the map this marker is attached to + */ + map: null, + + /** + * Constructor: OpenLayers.Marker + * Parameters: + * lonlat - {} the position of this marker + * icon - {} the icon for this marker + */ + initialize: function(lonlat, icon) { + this.lonlat = lonlat; + + var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); + if (this.icon == null) { + this.icon = newIcon; + } else { + this.icon.url = newIcon.url; + this.icon.size = newIcon.size; + this.icon.offset = newIcon.offset; + this.icon.calculateOffset = newIcon.calculateOffset; + } + this.events = new OpenLayers.Events(this, this.icon.imageDiv, null); + }, + + /** + * APIMethod: destroy + * Destroy the marker. You must first remove the marker from any + * layer which it has been added to, or you will get buggy behavior. + * (This can not be done within the marker since the marker does not + * know which layer it is attached to.) + */ + destroy: function() { + // erase any drawn features + this.erase(); + + this.map = null; + + this.events.destroy(); + this.events = null; + + if (this.icon != null) { + this.icon.destroy(); + this.icon = null; + } + }, + + /** + * Method: draw + * Calls draw on the icon, and returns that output. + * + * Parameters: + * px - {} + * + * Returns: + * {DOMElement} A new DOM Image with this marker's icon set at the + * location passed-in + */ + draw: function(px) { + return this.icon.draw(px); + }, + + /** + * Method: erase + * Erases any drawn elements for this marker. + */ + erase: function() { + if (this.icon != null) { + this.icon.erase(); + } + }, + + /** + * Method: moveTo + * Move the marker to the new location. + * + * Parameters: + * px - {} the pixel position to move to + */ + moveTo: function (px) { + if ((px != null) && (this.icon != null)) { + this.icon.moveTo(px); + } + this.lonlat = this.map.getLonLatFromLayerPx(px); + }, + + /** + * APIMethod: isDrawn + * + * Returns: + * {Boolean} Whether or not the marker is drawn. + */ + isDrawn: function() { + var isDrawn = (this.icon && this.icon.isDrawn()); + return isDrawn; + }, + + /** + * Method: onScreen + * + * Returns: + * {Boolean} Whether or not the marker is currently visible on screen. + */ + onScreen:function() { + + var onScreen = false; + if (this.map) { + var screenBounds = this.map.getExtent(); + onScreen = screenBounds.containsLonLat(this.lonlat); + } + return onScreen; + }, + + /** + * Method: inflate + * Englarges the markers icon by the specified ratio. + * + * Parameters: + * inflate - {float} the ratio to enlarge the marker by (passing 2 + * will double the size). + */ + inflate: function(inflate) { + if (this.icon) { + var newSize = new OpenLayers.Size(this.icon.size.w * inflate, + this.icon.size.h * inflate); + this.icon.setSize(newSize); + } + }, + + /** + * Method: setOpacity + * Change the opacity of the marker by changin the opacity of + * its icon + * + * Parameters: + * opacity - {float} Specified as fraction (0.4, etc) + */ + setOpacity: function(opacity) { + this.icon.setOpacity(opacity); + }, + + /** + * Method: setUrl + * Change URL of the Icon Image. + * + * url - {String} + */ + setUrl: function(url) { + this.icon.setUrl(url); + }, + + /** + * Method: display + * Hide or show the icon + * + * display - {Boolean} + */ + display: function(display) { + this.icon.display(display); + }, + + CLASS_NAME: "OpenLayers.Marker" +}); + + +/** + * Function: defaultIcon + * Creates a default . + * + * Returns: + * {} A default OpenLayers.Icon to use for a marker + */ +OpenLayers.Marker.defaultIcon = function() { + var url = OpenLayers.Util.getImagesLocation() + "marker.png"; + var size = new OpenLayers.Size(21, 25); + var calculateOffset = function(size) { + return new OpenLayers.Pixel(-(size.w/2), -size.h); + }; + + return new OpenLayers.Icon(url, size, null, calculateOffset); +}; + + diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Popup.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Popup.js new file mode 100755 index 0000000000..76df7a4fc6 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Popup.js @@ -0,0 +1,1051 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * Class: OpenLayers.Popup + * A popup is a small div that can opened and closed on the map. + * Typically opened in response to clicking on a marker. + * See . Popup's don't require their own + * layer and are added the the map using the + * method. + * + * Example: + * (code) + * popup = new OpenLayers.Popup("chicken", + * new OpenLayers.LonLat(5,40), + * new OpenLayers.Size(200,200), + * "example popup", + * true); + * + * map.addPopup(popup); + * (end) + */ +OpenLayers.Popup = OpenLayers.Class({ + + /** + * Property: events + * {} custom event manager + */ + events: null, + + /** Property: id + * {String} the unique identifier assigned to this popup. + */ + id: "", + + /** + * Property: lonlat + * {} the position of this popup on the map + */ + lonlat: null, + + /** + * Property: div + * {DOMElement} the div that contains this popup. + */ + div: null, + + /** + * Property: contentSize + * {} the width and height of the content. + */ + contentSize: null, + + /** + * Property: size + * {} the width and height of the popup. + */ + size: null, + + /** + * Property: contentHTML + * {String} An HTML string for this popup to display. + */ + contentHTML: null, + + /** + * Property: backgroundColor + * {String} the background color used by the popup. + */ + backgroundColor: "", + + /** + * Property: opacity + * {float} the opacity of this popup (between 0.0 and 1.0) + */ + opacity: "", + + /** + * Property: border + * {String} the border size of the popup. (eg 2px) + */ + border: "", + + /** + * Property: contentDiv + * {DOMElement} a reference to the element that holds the content of + * the div. + */ + contentDiv: null, + + /** + * Property: groupDiv + * {DOMElement} First and only child of 'div'. The group Div contains the + * 'contentDiv' and the 'closeDiv'. + */ + groupDiv: null, + + /** + * Property: closeDiv + * {DOMElement} the optional closer image + */ + closeDiv: null, + + /** + * APIProperty: autoSize + * {Boolean} Resize the popup to auto-fit the contents. + * Default is false. + */ + autoSize: false, + + /** + * APIProperty: minSize + * {} Minimum size allowed for the popup's contents. + */ + minSize: null, + + /** + * APIProperty: maxSize + * {} Maximum size allowed for the popup's contents. + */ + maxSize: null, + + /** + * Property: displayClass + * {String} The CSS class of the popup. + */ + displayClass: "olPopup", + + /** + * Property: contentDisplayClass + * {String} The CSS class of the popup content div. + */ + contentDisplayClass: "olPopupContent", + + /** + * Property: padding + * {int or } An extra opportunity to specify internal + * padding of the content div inside the popup. This was originally + * confused with the css padding as specified in style.css's + * 'olPopupContent' class. We would like to get rid of this altogether, + * except that it does come in handy for the framed and anchoredbubble + * popups, who need to maintain yet another barrier between their + * content and the outer border of the popup itself. + * + * Note that in order to not break API, we must continue to support + * this property being set as an integer. Really, though, we'd like to + * have this specified as a Bounds object so that user can specify + * distinct left, top, right, bottom paddings. With the 3.0 release + * we can make this only a bounds. + */ + padding: 0, + + /** + * Property: disableFirefoxOverflowHack + * {Boolean} The hack for overflow in Firefox causes all elements + * to be re-drawn, which causes Flash elements to be + * re-initialized, which is troublesome. + * With this property the hack can be disabled. + */ + disableFirefoxOverflowHack: false, + + /** + * Method: fixPadding + * To be removed in 3.0, this function merely helps us to deal with the + * case where the user may have set an integer value for padding, + * instead of an object. + */ + fixPadding: function() { + if (typeof this.padding == "number") { + this.padding = new OpenLayers.Bounds( + this.padding, this.padding, this.padding, this.padding + ); + } + }, + + /** + * APIProperty: panMapIfOutOfView + * {Boolean} When drawn, pan map such that the entire popup is visible in + * the current viewport (if necessary). + * Default is false. + */ + panMapIfOutOfView: false, + + /** + * APIProperty: keepInMap + * {Boolean} If panMapIfOutOfView is false, and this property is true, + * contrain the popup such that it always fits in the available map + * space. By default, this is not set on the base class. If you are + * creating popups that are near map edges and not allowing pannning, + * and especially if you have a popup which has a + * fixedRelativePosition, setting this to false may be a smart thing to + * do. Subclasses may want to override this setting. + * + * Default is false. + */ + keepInMap: false, + + /** + * APIProperty: closeOnMove + * {Boolean} When map pans, close the popup. + * Default is false. + */ + closeOnMove: false, + + /** + * Property: map + * {} this gets set in Map.js when the popup is added to the map + */ + map: null, + + /** + * Constructor: OpenLayers.Popup + * Create a popup. + * + * Parameters: + * id - {String} a unqiue identifier for this popup. If null is passed + * an identifier will be automatically generated. + * lonlat - {} The position on the map the popup will + * be shown. + * contentSize - {} The size of the content. + * contentHTML - {String} An HTML string to display inside the + * popup. + * closeBox - {Boolean} Whether to display a close box inside + * the popup. + * closeBoxCallback - {Function} Function to be called on closeBox click. + */ + initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) { + if (id == null) { + id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + } + + this.id = id; + this.lonlat = lonlat; + + this.contentSize = (contentSize != null) ? contentSize + : new OpenLayers.Size( + OpenLayers.Popup.WIDTH, + OpenLayers.Popup.HEIGHT); + if (contentHTML != null) { + this.contentHTML = contentHTML; + } + this.backgroundColor = OpenLayers.Popup.COLOR; + this.opacity = OpenLayers.Popup.OPACITY; + this.border = OpenLayers.Popup.BORDER; + + this.div = OpenLayers.Util.createDiv(this.id, null, null, + null, null, null, "hidden"); + this.div.className = this.displayClass; + + var groupDivId = this.id + "_GroupDiv"; + this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, + null, "relative", null, + "hidden"); + + var id = this.div.id + "_contentDiv"; + this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), + null, "relative"); + this.contentDiv.className = this.contentDisplayClass; + this.groupDiv.appendChild(this.contentDiv); + this.div.appendChild(this.groupDiv); + + if (closeBox) { + this.addCloseBox(closeBoxCallback); + } + + this.registerEvents(); + }, + + /** + * Method: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + + this.id = null; + this.lonlat = null; + this.size = null; + this.contentHTML = null; + + this.backgroundColor = null; + this.opacity = null; + this.border = null; + + if (this.closeOnMove && this.map) { + this.map.events.unregister("movestart", this, this.hide); + } + + this.events.destroy(); + this.events = null; + + if (this.closeDiv) { + OpenLayers.Event.stopObservingElement(this.closeDiv); + this.groupDiv.removeChild(this.closeDiv); + } + this.closeDiv = null; + + this.div.removeChild(this.groupDiv); + this.groupDiv = null; + + if (this.map != null) { + this.map.removePopup(this); + } + this.map = null; + this.div = null; + + this.autoSize = null; + this.minSize = null; + this.maxSize = null; + this.padding = null; + this.panMapIfOutOfView = null; + }, + + /** + * Method: draw + * Constructs the elements that make up the popup. + * + * Parameters: + * px - {} the position the popup in pixels. + * + * Returns: + * {DOMElement} Reference to a div that contains the drawn popup + */ + draw: function(px) { + if (px == null) { + if ((this.lonlat != null) && (this.map != null)) { + px = this.map.getLayerPxFromLonLat(this.lonlat); + } + } + + // this assumes that this.map already exists, which is okay because + // this.draw is only called once the popup has been added to the map. + if (this.closeOnMove) { + this.map.events.register("movestart", this, this.hide); + } + + //listen to movestart, moveend to disable overflow (FF bug) + if (!this.disableFirefoxOverflowHack && OpenLayers.Util.getBrowserName() == 'firefox') { + this.map.events.register("movestart", this, function() { + var style = document.defaultView.getComputedStyle( + this.contentDiv, null + ); + var currentOverflow = style.getPropertyValue("overflow"); + if (currentOverflow != "hidden") { + this.contentDiv._oldOverflow = currentOverflow; + this.contentDiv.style.overflow = "hidden"; + } + }); + this.map.events.register("moveend", this, function() { + var oldOverflow = this.contentDiv._oldOverflow; + if (oldOverflow) { + this.contentDiv.style.overflow = oldOverflow; + this.contentDiv._oldOverflow = null; + } + }); + } + + this.moveTo(px); + if (!this.autoSize && !this.size) { + this.setSize(this.contentSize); + } + this.setBackgroundColor(); + this.setOpacity(); + this.setBorder(); + this.setContentHTML(); + + if (this.panMapIfOutOfView) { + this.panIntoView(); + } + + return this.div; + }, + + /** + * Method: updatePosition + * if the popup has a lonlat and its map members set, + * then have it move itself to its proper position + */ + updatePosition: function() { + if ((this.lonlat) && (this.map)) { + var px = this.map.getLayerPxFromLonLat(this.lonlat); + if (px) { + this.moveTo(px); + } + } + }, + + /** + * Method: moveTo + * + * Parameters: + * px - {} the top and left position of the popup div. + */ + moveTo: function(px) { + if ((px != null) && (this.div != null)) { + this.div.style.left = px.x + "px"; + this.div.style.top = px.y + "px"; + } + }, + + /** + * Method: visible + * + * Returns: + * {Boolean} Boolean indicating whether or not the popup is visible + */ + visible: function() { + return OpenLayers.Element.visible(this.div); + }, + + /** + * Method: toggle + * Toggles visibility of the popup. + */ + toggle: function() { + if (this.visible()) { + this.hide(); + } else { + this.show(); + } + }, + + /** + * Method: show + * Makes the popup visible. + */ + show: function() { + OpenLayers.Element.show(this.div); + + if (this.panMapIfOutOfView) { + this.panIntoView(); + } + }, + + /** + * Method: hide + * Makes the popup invisible. + */ + hide: function() { + OpenLayers.Element.hide(this.div); + }, + + /** + * Method: setSize + * Used to adjust the size of the popup. + * + * Parameters: + * contentSize - {} the new size for the popup's + * contents div (in pixels). + */ + setSize:function(contentSize) { + this.size = contentSize.clone(); + + // if our contentDiv has a css 'padding' set on it by a stylesheet, we + // must add that to the desired "size". + var contentDivPadding = this.getContentDivPadding(); + var wPadding = contentDivPadding.left + contentDivPadding.right; + var hPadding = contentDivPadding.top + contentDivPadding.bottom; + + // take into account the popup's 'padding' property + this.fixPadding(); + wPadding += this.padding.left + this.padding.right; + hPadding += this.padding.top + this.padding.bottom; + + // make extra space for the close div + if (this.closeDiv) { + var closeDivWidth = parseInt(this.closeDiv.style.width); + wPadding += closeDivWidth + contentDivPadding.right; + } + + //increase size of the main popup div to take into account the + // users's desired padding and close div. + this.size.w += wPadding; + this.size.h += hPadding; + + //now if our browser is IE, we need to actually make the contents + // div itself bigger to take its own padding into effect. this makes + // me want to shoot someone, but so it goes. + if (OpenLayers.Util.getBrowserName() == "msie") { + this.contentSize.w += + contentDivPadding.left + contentDivPadding.right; + this.contentSize.h += + contentDivPadding.bottom + contentDivPadding.top; + } + + if (this.div != null) { + this.div.style.width = this.size.w + "px"; + this.div.style.height = this.size.h + "px"; + } + if (this.contentDiv != null){ + this.contentDiv.style.width = contentSize.w + "px"; + this.contentDiv.style.height = contentSize.h + "px"; + } + }, + + /** + * APIMethod: updateSize + * Auto size the popup so that it precisely fits its contents (as + * determined by this.contentDiv.innerHTML). Popup size will, of + * course, be limited by the available space on the current map + */ + updateSize: function() { + + // determine actual render dimensions of the contents by putting its + // contents into a fake contentDiv (for the CSS) and then measuring it + var preparedHTML = "
" + + this.contentDiv.innerHTML + + "
"; + + var containerElement = (this.map) ? this.map.layerContainerDiv + : document.body; + var realSize = OpenLayers.Util.getRenderedDimensions( + preparedHTML, null, { + displayClass: this.displayClass, + containerElement: containerElement + } + ); + + // is the "real" size of the div is safe to display in our map? + var safeSize = this.getSafeContentSize(realSize); + + var newSize = null; + if (safeSize.equals(realSize)) { + //real size of content is small enough to fit on the map, + // so we use real size. + newSize = realSize; + + } else { + + //make a new OL.Size object with the clipped dimensions + // set or null if not clipped. + var fixedSize = new OpenLayers.Size(); + fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null; + fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null; + + if (fixedSize.w && fixedSize.h) { + //content is too big in both directions, so we will use + // max popup size (safeSize), knowing well that it will + // overflow both ways. + newSize = safeSize; + } else { + //content is clipped in only one direction, so we need to + // run getRenderedDimensions() again with a fixed dimension + var clippedSize = OpenLayers.Util.getRenderedDimensions( + preparedHTML, fixedSize, { + displayClass: this.contentDisplayClass, + containerElement: containerElement + } + ); + + //if the clipped size is still the same as the safeSize, + // that means that our content must be fixed in the + // offending direction. If overflow is 'auto', this means + // we are going to have a scrollbar for sure, so we must + // adjust for that. + // + var currentOverflow = OpenLayers.Element.getStyle( + this.contentDiv, "overflow" + ); + if ( (currentOverflow != "hidden") && + (clippedSize.equals(safeSize)) ) { + var scrollBar = OpenLayers.Util.getScrollbarWidth(); + if (fixedSize.w) { + clippedSize.h += scrollBar; + } else { + clippedSize.w += scrollBar; + } + } + + newSize = this.getSafeContentSize(clippedSize); + } + } + this.setSize(newSize); + }, + + /** + * Method: setBackgroundColor + * Sets the background color of the popup. + * + * Parameters: + * color - {String} the background color. eg "#FFBBBB" + */ + setBackgroundColor:function(color) { + if (color != undefined) { + this.backgroundColor = color; + } + + if (this.div != null) { + this.div.style.backgroundColor = this.backgroundColor; + } + }, + + /** + * Method: setOpacity + * Sets the opacity of the popup. + * + * Parameters: + * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). + */ + setOpacity:function(opacity) { + if (opacity != undefined) { + this.opacity = opacity; + } + + if (this.div != null) { + // for Mozilla and Safari + this.div.style.opacity = this.opacity; + + // for IE + this.div.style.filter = 'alpha(opacity=' + this.opacity*100 + ')'; + } + }, + + /** + * Method: setBorder + * Sets the border style of the popup. + * + * Parameters: + * border - {String} The border style value. eg 2px + */ + setBorder:function(border) { + if (border != undefined) { + this.border = border; + } + + if (this.div != null) { + this.div.style.border = this.border; + } + }, + + /** + * Method: setContentHTML + * Allows the user to set the HTML content of the popup. + * + * Parameters: + * contentHTML - {String} HTML for the div. + */ + setContentHTML:function(contentHTML) { + + if (contentHTML != null) { + this.contentHTML = contentHTML; + } + + if ((this.contentDiv != null) && + (this.contentHTML != null) && + (this.contentHTML != this.contentDiv.innerHTML)) { + + this.contentDiv.innerHTML = this.contentHTML; + + if (this.autoSize) { + + //if popup has images, listen for when they finish + // loading and resize accordingly + this.registerImageListeners(); + + //auto size the popup to its current contents + this.updateSize(); + } + } + + }, + + /** + * Method: registerImageListeners + * Called when an image contained by the popup loaded. this function + * updates the popup size, then unregisters the image load listener. + */ + registerImageListeners: function() { + + // As the images load, this function will call updateSize() to + // resize the popup to fit the content div (which presumably is now + // bigger than when the image was not loaded). + // + // If the 'panMapIfOutOfView' property is set, we will pan the newly + // resized popup back into view. + // + // Note that this function, when called, will have 'popup' and + // 'img' properties in the context. + // + var onImgLoad = function() { + + this.popup.updateSize(); + + if ( this.popup.visible() && this.popup.panMapIfOutOfView ) { + this.popup.panIntoView(); + } + + OpenLayers.Event.stopObserving( + this.img, "load", this.img._onImageLoad + ); + + }; + + //cycle through the images and if their size is 0x0, that means that + // they haven't been loaded yet, so we attach the listener, which + // will fire when the images finish loading and will resize the + // popup accordingly to its new size. + var images = this.contentDiv.getElementsByTagName("img"); + for (var i = 0, len = images.length; i < len; i++) { + var img = images[i]; + if (img.width == 0 || img.height == 0) { + + var context = { + 'popup': this, + 'img': img + }; + + //expando this function to the image itself before registering + // it. This way we can easily and properly unregister it. + img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context); + + OpenLayers.Event.observe(img, 'load', img._onImgLoad); + } + } + }, + + /** + * APIMethod: getSafeContentSize + * + * Parameters: + * size - {} Desired size to make the popup. + * + * Returns: + * {} A size to make the popup which is neither smaller + * than the specified minimum size, nor bigger than the maximum + * size (which is calculated relative to the size of the viewport). + */ + getSafeContentSize: function(size) { + + var safeContentSize = size.clone(); + + // if our contentDiv has a css 'padding' set on it by a stylesheet, we + // must add that to the desired "size". + var contentDivPadding = this.getContentDivPadding(); + var wPadding = contentDivPadding.left + contentDivPadding.right; + var hPadding = contentDivPadding.top + contentDivPadding.bottom; + + // take into account the popup's 'padding' property + this.fixPadding(); + wPadding += this.padding.left + this.padding.right; + hPadding += this.padding.top + this.padding.bottom; + + if (this.closeDiv) { + var closeDivWidth = parseInt(this.closeDiv.style.width); + wPadding += closeDivWidth + contentDivPadding.right; + } + + // prevent the popup from being smaller than a specified minimal size + if (this.minSize) { + safeContentSize.w = Math.max(safeContentSize.w, + (this.minSize.w - wPadding)); + safeContentSize.h = Math.max(safeContentSize.h, + (this.minSize.h - hPadding)); + } + + // prevent the popup from being bigger than a specified maximum size + if (this.maxSize) { + safeContentSize.w = Math.min(safeContentSize.w, + (this.maxSize.w - wPadding)); + safeContentSize.h = Math.min(safeContentSize.h, + (this.maxSize.h - hPadding)); + } + + //make sure the desired size to set doesn't result in a popup that + // is bigger than the map's viewport. + // + if (this.map && this.map.size) { + + var extraX = 0, extraY = 0; + if (this.keepInMap && !this.panMapIfOutOfView) { + var px = this.map.getPixelFromLonLat(this.lonlat); + switch (this.relativePosition) { + case "tr": + extraX = px.x; + extraY = this.map.size.h - px.y; + break; + case "tl": + extraX = this.map.size.w - px.x; + extraY = this.map.size.h - px.y; + break; + case "bl": + extraX = this.map.size.w - px.x; + extraY = px.y; + break; + case "br": + extraX = px.x; + extraY = px.y; + break; + default: + extraX = px.x; + extraY = this.map.size.h - px.y; + break; + } + } + + var maxY = this.map.size.h - + this.map.paddingForPopups.top - + this.map.paddingForPopups.bottom - + hPadding - extraY; + + var maxX = this.map.size.w - + this.map.paddingForPopups.left - + this.map.paddingForPopups.right - + wPadding - extraX; + + safeContentSize.w = Math.min(safeContentSize.w, maxX); + safeContentSize.h = Math.min(safeContentSize.h, maxY); + } + + return safeContentSize; + }, + + /** + * Method: getContentDivPadding + * Glorious, oh glorious hack in order to determine the css 'padding' of + * the contentDiv. IE/Opera return null here unless we actually add the + * popup's main 'div' element (which contains contentDiv) to the DOM. + * So we make it invisible and then add it to the document temporarily. + * + * Once we've taken the padding readings we need, we then remove it + * from the DOM (it will actually get added to the DOM in + * Map.js's addPopup) + * + * Returns: + * {} + */ + getContentDivPadding: function() { + + //use cached value if we have it + var contentDivPadding = this._contentDivPadding; + if (!contentDivPadding) { + + if (this.div.parentNode == null) { + //make the div invisible and add it to the page + this.div.style.display = "none"; + document.body.appendChild(this.div); + } + + //read the padding settings from css, put them in an OL.Bounds + contentDivPadding = new OpenLayers.Bounds( + OpenLayers.Element.getStyle(this.contentDiv, "padding-left"), + OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"), + OpenLayers.Element.getStyle(this.contentDiv, "padding-right"), + OpenLayers.Element.getStyle(this.contentDiv, "padding-top") + ); + + //cache the value + this._contentDivPadding = contentDivPadding; + + if (this.div.parentNode == document.body) { + //remove the div from the page and make it visible again + document.body.removeChild(this.div); + this.div.style.display = ""; + } + } + return contentDivPadding; + }, + + /** + * Method: addCloseBox + * + * Parameters: + * callback - {Function} The callback to be called when the close button + * is clicked. + */ + addCloseBox: function(callback) { + + this.closeDiv = OpenLayers.Util.createDiv( + this.id + "_close", null, new OpenLayers.Size(17, 17) + ); + this.closeDiv.className = "olPopupCloseBox"; + + // use the content div's css padding to determine if we should + // padd the close div + var contentDivPadding = this.getContentDivPadding(); + + this.closeDiv.style.right = contentDivPadding.right + "px"; + this.closeDiv.style.top = contentDivPadding.top + "px"; + this.groupDiv.appendChild(this.closeDiv); + + var closePopup = callback || function(e) { + this.hide(); + OpenLayers.Event.stop(e); + }; + OpenLayers.Event.observe(this.closeDiv, "click", + OpenLayers.Function.bindAsEventListener(closePopup, this)); + }, + + /** + * Method: panIntoView + * Pans the map such that the popup is totaly viewable (if necessary) + */ + panIntoView: function() { + + var mapSize = this.map.getSize(); + + //start with the top left corner of the popup, in px, + // relative to the viewport + var origTL = this.map.getViewPortPxFromLayerPx( new OpenLayers.Pixel( + parseInt(this.div.style.left), + parseInt(this.div.style.top) + )); + var newTL = origTL.clone(); + + //new left (compare to margins, using this.size to calculate right) + if (origTL.x < this.map.paddingForPopups.left) { + newTL.x = this.map.paddingForPopups.left; + } else + if ( (origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) { + newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w; + } + + //new top (compare to margins, using this.size to calculate bottom) + if (origTL.y < this.map.paddingForPopups.top) { + newTL.y = this.map.paddingForPopups.top; + } else + if ( (origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) { + newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h; + } + + var dx = origTL.x - newTL.x; + var dy = origTL.y - newTL.y; + + this.map.pan(dx, dy); + }, + + /** + * Method: registerEvents + * Registers events on the popup. + * + * Do this in a separate function so that subclasses can + * choose to override it if they wish to deal differently + * with mouse events + * + * Note in the following handler functions that some special + * care is needed to deal correctly with mousing and popups. + * + * Because the user might select the zoom-rectangle option and + * then drag it over a popup, we need a safe way to allow the + * mousemove and mouseup events to pass through the popup when + * they are initiated from outside. + * + * Otherwise, we want to essentially kill the event propagation + * for all other events, though we have to do so carefully, + * without disabling basic html functionality, like clicking on + * hyperlinks or drag-selecting text. + */ + registerEvents:function() { + this.events = new OpenLayers.Events(this, this.div, null, true); + + this.events.on({ + "mousedown": this.onmousedown, + "mousemove": this.onmousemove, + "mouseup": this.onmouseup, + "click": this.onclick, + "mouseout": this.onmouseout, + "dblclick": this.ondblclick, + scope: this + }); + + }, + + /** + * Method: onmousedown + * When mouse goes down within the popup, make a note of + * it locally, and then do not propagate the mousedown + * (but do so safely so that user can select text inside) + * + * Parameters: + * evt - {Event} + */ + onmousedown: function (evt) { + this.mousedown = true; + OpenLayers.Event.stop(evt, true); + }, + + /** + * Method: onmousemove + * If the drag was started within the popup, then + * do not propagate the mousemove (but do so safely + * so that user can select text inside) + * + * Parameters: + * evt - {Event} + */ + onmousemove: function (evt) { + if (this.mousedown) { + OpenLayers.Event.stop(evt, true); + } + }, + + /** + * Method: onmouseup + * When mouse comes up within the popup, after going down + * in it, reset the flag, and then (once again) do not + * propagate the event, but do so safely so that user can + * select text inside + * + * Parameters: + * evt - {Event} + */ + onmouseup: function (evt) { + if (this.mousedown) { + this.mousedown = false; + OpenLayers.Event.stop(evt, true); + } + }, + + /** + * Method: onclick + * Ignore clicks, but allowing default browser handling + * + * Parameters: + * evt - {Event} + */ + onclick: function (evt) { + OpenLayers.Event.stop(evt, true); + }, + + /** + * Method: onmouseout + * When mouse goes out of the popup set the flag to false so that + * if they let go and then drag back in, we won't be confused. + * + * Parameters: + * evt - {Event} + */ + onmouseout: function (evt) { + this.mousedown = false; + }, + + /** + * Method: ondblclick + * Ignore double-clicks, but allowing default browser handling + * + * Parameters: + * evt - {Event} + */ + ondblclick: function (evt) { + OpenLayers.Event.stop(evt, true); + }, + + CLASS_NAME: "OpenLayers.Popup" +}); + +OpenLayers.Popup.WIDTH = 200; +OpenLayers.Popup.HEIGHT = 200; +OpenLayers.Popup.COLOR = "white"; +OpenLayers.Popup.OPACITY = 1; +OpenLayers.Popup.BORDER = "0px"; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Projection.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Projection.js new file mode 100755 index 0000000000..b02f4cb598 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Projection.js @@ -0,0 +1,177 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license. + * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt + * for the full text of the license. */ + +/** + * @requires OpenLayers/Util.js + */ + +/** + * Class: OpenLayers.Projection + * Class for coordinate transforms between coordinate systems. + * Depends on the proj4js library. If proj4js is not available, + * then this is just an empty stub. + */ +OpenLayers.Projection = OpenLayers.Class({ + + /** + * Property: proj + * {Object} Proj4js.Proj instance. + */ + proj: null, + + /** + * Property: projCode + * {String} + */ + projCode: null, + + /** + * Constructor: OpenLayers.Projection + * This class offers several methods for interacting with a wrapped + * pro4js projection object. + * + * Parameters: + * projCode - {String} A string identifying the Well Known Identifier for + * the projection. + * options - {Object} An optional object to set additional properties + * on the layer. + * + * Returns: + * {} A projection object. + */ + initialize: function(projCode, options) { + OpenLayers.Util.extend(this, options); + this.projCode = projCode; + if (window.Proj4js) { + this.proj = new Proj4js.Proj(projCode); + } + }, + + /** + * APIMethod: getCode + * Get the string SRS code. + * + * Returns: + * {String} The SRS code. + */ + getCode: function() { + return this.proj ? this.proj.srsCode : this.projCode; + }, + + /** + * APIMethod: getUnits + * Get the units string for the projection -- returns null if + * proj4js is not available. + * + * Returns: + * {String} The units abbreviation. + */ + getUnits: function() { + return this.proj ? this.proj.units : null; + }, + + /** + * Method: toString + * Convert projection to string (getCode wrapper). + * + * Returns: + * {String} The projection code. + */ + toString: function() { + return this.getCode(); + }, + + /** + * Method: equals + * Test equality of two projection instances. Determines equality based + * soley on the projection code. + * + * Returns: + * {Boolean} The two projections are equivalent. + */ + equals: function(projection) { + if (projection && projection.getCode) { + return this.getCode() == projection.getCode(); + } else { + return false; + } + }, + + /* Method: destroy + * Destroy projection object. + */ + destroy: function() { + delete this.proj; + delete this.projCode; + }, + + CLASS_NAME: "OpenLayers.Projection" +}); + +/** + * Property: transforms + * Transforms is an object, with from properties, each of which may + * have a to property. This allows you to define projections without + * requiring support for proj4js to be included. + * + * This object has keys which correspond to a 'source' projection object. The + * keys should be strings, corresponding to the projection.getCode() value. + * Each source projection object should have a set of destination projection + * keys included in the object. + * + * Each value in the destination object should be a transformation function, + * where the function is expected to be passed an object with a .x and a .y + * property. The function should return the object, with the .x and .y + * transformed according to the transformation function. + * + * Note - Properties on this object should not be set directly. To add a + * transform method to this object, use the method. For an + * example of usage, see the OpenLayers.Layer.SphericalMercator file. + */ +OpenLayers.Projection.transforms = {}; + +/** + * APIMethod: addTransform + * Set a custom transform method between two projections. Use this method in + * cases where the proj4js lib is not available or where custom projections + * need to be handled. + * + * Parameters: + * from - {String} The code for the source projection + * to - {String} the code for the destination projection + * method - {Function} A function that takes a point as an argument and + * transforms that point from the source to the destination projection + * in place. The original point should be modified. + */ +OpenLayers.Projection.addTransform = function(from, to, method) { + if(!OpenLayers.Projection.transforms[from]) { + OpenLayers.Projection.transforms[from] = {}; + } + OpenLayers.Projection.transforms[from][to] = method; +}; + +/** + * APIMethod: transform + * Transform a point coordinate from one projection to another. Note that + * the input point is transformed in place. + * + * Parameters: + * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y + * properties representing coordinates in those dimensions. + * sourceProj - {OpenLayers.Projection} Source map coordinate system + * destProj - {OpenLayers.Projection} Destination map coordinate system + * + * Returns: + * point - {object} A transformed coordinate. The original point is modified. + */ +OpenLayers.Projection.transform = function(point, source, dest) { + if (source.proj && dest.proj) { + point = Proj4js.transform(source.proj, dest.proj, point); + } else if (source && dest && + OpenLayers.Projection.transforms[source.getCode()] && + OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) { + OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point); + } + return point; +}; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Protocol.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Protocol.js new file mode 100755 index 0000000000..f4fd833360 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Protocol.js @@ -0,0 +1,227 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * Class: OpenLayers.Protocol + * Abstract vector layer protocol class. Not to be instantiated directly. Use + * one of the protocol subclasses instead. + */ +OpenLayers.Protocol = OpenLayers.Class({ + + /** + * Property: format + * {} The format used by this protocol. + */ + format: null, + + /** + * Property: options + * {Object} Any options sent to the constructor. + */ + options: null, + + /** + * Property: autoDestroy + * {Boolean} The creator of the protocol can set autoDestroy to false + * to fully control when the protocol is destroyed. Defaults to + * true. + */ + autoDestroy: true, + + /** + * Constructor: OpenLayers.Protocol + * Abstract class for vector protocols. Create instances of a subclass. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + */ + initialize: function(options) { + options = options || {}; + OpenLayers.Util.extend(this, options); + this.options = options; + }, + + /** + * APIMethod: destroy + * Clean up the protocol. + */ + destroy: function() { + this.options = null; + this.format = null; + }, + + /** + * APIMethod: read + * Construct a request for reading new features. + * + * Parameters: + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * object, the same object will be passed to the callback function passed + * if one exists in the options object. + */ + read: function() { + }, + + + /** + * APIMethod: create + * Construct a request for writing newly created features. + * + * Parameters: + * features - {Array({})} or + * {} + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * object, the same object will be passed to the callback function passed + * if one exists in the options object. + */ + create: function() { + }, + + /** + * APIMethod: update + * Construct a request updating modified features. + * + * Parameters: + * features - {Array({})} or + * {} + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * object, the same object will be passed to the callback function passed + * if one exists in the options object. + */ + update: function() { + }, + + /** + * APIMethod: delete + * Construct a request deleting a removed feature. + * + * Parameters: + * feature - {} + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * object, the same object will be passed to the callback function passed + * if one exists in the options object. + */ + "delete": function() { + }, + + /** + * APIMethod: commit + * Go over the features and for each take action + * based on the feature state. Possible actions are create, + * update and delete. + * + * Parameters: + * features - {Array({})} + * options - {Object} Object whose possible keys are "create", "update", + * "delete", "callback" and "scope", the values referenced by the + * first three are objects as passed to the "create", "update", and + * "delete" methods, the value referenced by the "callback" key is + * a function which is called when the commit operation is complete + * using the scope referenced by the "scope" key. + * + * Returns: + * {Array({})} An array of + * objects. + */ + commit: function() { + }, + + /** + * Method: abort + * Abort an ongoing request. + * + * Parameters: + * response - {} + */ + abort: function(response) { + }, + + CLASS_NAME: "OpenLayers.Protocol" +}); + +/** + * Class: OpenLayers.Protocol.Response + * Protocols return Response objects to their users. + */ +OpenLayers.Protocol.Response = OpenLayers.Class({ + /** + * Property: code + * {Number} - OpenLayers.Protocol.Response.SUCCESS or + * OpenLayers.Protocol.Response.FAILURE + */ + code: null, + + /** + * Property: requestType + * {String} The type of request this response corresponds to. Either + * "create", "read", "update" or "delete". + */ + requestType: null, + + /** + * Property: last + * {Boolean} - true if this is the last response expected in a commit, + * false otherwise, defaults to true. + */ + last: true, + + /** + * Property: features + * {Array({})} or {} + * The features returned in the response by the server. + */ + features: null, + + /** + * Property: reqFeatures + * {Array({})} or {} + * The features provided by the user and placed in the request by the + * protocol. + */ + reqFeatures: null, + + /** + * Property: priv + */ + priv: null, + + /** + * Constructor: OpenLayers.Protocol.Response + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + }, + + /** + * Method: success + * + * Returns: + * {Boolean} - true on success, false otherwise + */ + success: function() { + return this.code > 0; + }, + + CLASS_NAME: "OpenLayers.Protocol.Response" +}); + +OpenLayers.Protocol.Response.SUCCESS = 1; +OpenLayers.Protocol.Response.FAILURE = 0; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Renderer.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Renderer.js new file mode 100755 index 0000000000..93e841f0f6 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Renderer.js @@ -0,0 +1,301 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * Class: OpenLayers.Renderer + * This is the base class for all renderers. + * + * This is based on a merger code written by Paul Spencer and Bertil Chapuis. + * It is largely composed of virtual functions that are to be implemented + * in technology-specific subclasses, but there is some generic code too. + * + * The functions that *are* implemented here merely deal with the maintenance + * of the size and extent variables, as well as the cached 'resolution' + * value. + * + * A note to the user that all subclasses should use getResolution() instead + * of directly accessing this.resolution in order to correctly use the + * cacheing system. + * + */ +OpenLayers.Renderer = OpenLayers.Class({ + + /** + * Property: container + * {DOMElement} + */ + container: null, + + /** + * Property: root + * {DOMElement} + */ + root: null, + + /** + * Property: extent + * {} + */ + extent: null, + + /** + * Property: locked + * {Boolean} If the renderer is currently in a state where many things + * are changing, the 'locked' property is set to true. This means + * that renderers can expect at least one more drawFeature event to be + * called with the 'locked' property set to 'true': In some renderers, + * this might make sense to use as a 'only update local information' + * flag. + */ + locked: false, + + /** + * Property: size + * {} + */ + size: null, + + /** + * Property: resolution + * {Float} cache of current map resolution + */ + resolution: null, + + /** + * Property: map + * {} Reference to the map -- this is set in Vector's setMap() + */ + map: null, + + /** + * Constructor: OpenLayers.Renderer + * + * Parameters: + * containerID - {} + * options - {Object} options for this renderer. See sublcasses for + * supported options. + */ + initialize: function(containerID, options) { + this.container = OpenLayers.Util.getElement(containerID); + }, + + /** + * APIMethod: destroy + */ + destroy: function() { + this.container = null; + this.extent = null; + this.size = null; + this.resolution = null; + this.map = null; + }, + + /** + * APIMethod: supported + * This should be overridden by specific subclasses + * + * Returns: + * {Boolean} Whether or not the browser supports the renderer class + */ + supported: function() { + return false; + }, + + /** + * Method: setExtent + * Set the visible part of the layer. + * + * Resolution has probably changed, so we nullify the resolution + * cache (this.resolution) -- this way it will be re-computed when + * next it is needed. + * We nullify the resolution cache (this.resolution) if resolutionChanged + * is set to true - this way it will be re-computed on the next + * getResolution() request. + * + * Parameters: + * extent - {} + * resolutionChanged - {Boolean} + */ + setExtent: function(extent, resolutionChanged) { + this.extent = extent.clone(); + if (resolutionChanged) { + this.resolution = null; + } + }, + + /** + * Method: setSize + * Sets the size of the drawing surface. + * + * Resolution has probably changed, so we nullify the resolution + * cache (this.resolution) -- this way it will be re-computed when + * next it is needed. + * + * Parameters: + * size - {} + */ + setSize: function(size) { + this.size = size.clone(); + this.resolution = null; + }, + + /** + * Method: getResolution + * Uses cached copy of resolution if available to minimize computing + * + * Returns: + * The current map's resolution + */ + getResolution: function() { + this.resolution = this.resolution || this.map.getResolution(); + return this.resolution; + }, + + /** + * Method: drawFeature + * Draw the feature. The optional style argument can be used + * to override the feature's own style. This method should only + * be called from layer.drawFeature(). + * + * Parameters: + * feature - {} + * style - {} + * + * Returns: + * {Boolean} true if the feature has been drawn completely, false if not, + * undefined if the feature had no geometry + */ + drawFeature: function(feature, style) { + if(style == null) { + style = feature.style; + } + if (feature.geometry) { + var bounds = feature.geometry.getBounds(); + if(bounds) { + if (!bounds.intersectsBounds(this.extent)) { + style = {display: "none"}; + } + var rendered = this.drawGeometry(feature.geometry, style, feature.id); + if(style.display != "none" && style.label && rendered !== false) { + this.drawText(feature.id, style, feature.geometry.getCentroid()); + } else { + this.removeText(feature.id); + } + return rendered; + } + } + }, + + + /** + * Method: drawGeometry + * + * Draw a geometry. This should only be called from the renderer itself. + * Use layer.drawFeature() from outside the renderer. + * virtual function + * + * Parameters: + * geometry - {} + * style - {Object} + * featureId - {} + */ + drawGeometry: function(geometry, style, featureId) {}, + + /** + * Method: drawText + * Function for drawing text labels. + * This method is only called by the renderer itself. + * + * Parameters: + * featureId - {String} + * style - + * location - {} + */ + drawText: function(featureId, style, location) {}, + + /** + * Method: removeText + * Function for removing text labels. + * This method is only called by the renderer itself. + * + * Parameters: + * featureId - {String} + */ + removeText: function(featureId) {}, + + /** + * Method: clear + * Clear all vectors from the renderer. + * virtual function. + */ + clear: function() {}, + + /** + * Method: getFeatureIdFromEvent + * Returns a feature id from an event on the renderer. + * How this happens is specific to the renderer. This should be + * called from layer.getFeatureFromEvent(). + * Virtual function. + * + * Parameters: + * evt - {} + * + * Returns: + * {String} A feature id or null. + */ + getFeatureIdFromEvent: function(evt) {}, + + /** + * Method: eraseFeatures + * This is called by the layer to erase features + * + * Parameters: + * features - {Array()} + */ + eraseFeatures: function(features) { + if(!(features instanceof Array)) { + features = [features]; + } + for(var i=0, len=features.length; i} + */ + eraseGeometry: function(geometry) {}, + + /** + * Method: moveRoot + * moves this renderer's root to a (different) renderer. + * To be implemented by subclasses that require a common renderer root for + * feature selection. + * + * Parameters: + * renderer - {} target renderer for the moved root + */ + moveRoot: function(renderer) {}, + + /** + * Method: getRenderLayerId + * Gets the layer that this renderer's output appears on. If moveRoot was + * used, this will be different from the id of the layer containing the + * features rendered by this renderer. + * + * Returns: + * {String} the id of the output layer. + */ + getRenderLayerId: function() { + return this.container.id; + }, + + CLASS_NAME: "OpenLayers.Renderer" +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Request.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Request.js new file mode 100755 index 0000000000..0434e1d874 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Request.js @@ -0,0 +1,332 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Events.js + */ + +/** + * Namespace: OpenLayers.Request + * The OpenLayers.Request namespace contains convenience methods for working + * with XMLHttpRequests. These methods work with a cross-browser + * W3C compliant class. + */ +OpenLayers.Request = { + + /** + * Constant: DEFAULT_CONFIG + * {Object} Default configuration for all requests. + */ + DEFAULT_CONFIG: { + method: "GET", + url: window.location.href, + async: true, + user: undefined, + password: undefined, + params: null, + proxy: OpenLayers.ProxyHost, + headers: {}, + data: null, + callback: function() {}, + success: null, + failure: null, + scope: null + }, + + /** + * APIProperty: events + * {} An events object that handles all + * events on the {} object. + * + * All event listeners will receive an event object with three properties: + * request - {} The request object. + * config - {Object} The config object sent to the specific request method. + * requestUrl - {String} The request url. + * + * Supported event types: + * complete - Triggered when we have a response from the request, if a + * listener returns false, no further response processing will take + * place. + * success - Triggered when the HTTP response has a success code (200-299). + * failure - Triggered when the HTTP response does not have a success code. + */ + events: new OpenLayers.Events(this, null, ["complete", "success", "failure"]), + + /** + * APIMethod: issue + * Create a new XMLHttpRequest object, open it, set any headers, bind + * a callback to done state, and send any data. It is recommended that + * you use one , , , , , or . + * This method is only documented to provide detail on the configuration + * options available to all request methods. + * + * Parameters: + * config - {Object} Object containing properties for configuring the + * request. Allowed configuration properties are described below. + * This object is modified and should not be reused. + * + * Allowed config properties: + * method - {String} One of GET, POST, PUT, DELETE, HEAD, or + * OPTIONS. Default is GET. + * url - {String} URL for the request. + * async - {Boolean} Open an asynchronous request. Default is true. + * user - {String} User for relevant authentication scheme. Set + * to null to clear current user. + * password - {String} Password for relevant authentication scheme. + * Set to null to clear current password. + * proxy - {String} Optional proxy. Defaults to + * . + * params - {Object} Any key:value pairs to be appended to the + * url as a query string. Assumes url doesn't already include a query + * string or hash. Typically, this is only appropriate for + * requests where the query string will be appended to the url. + * Parameter values that are arrays will be + * concatenated with a comma (note that this goes against form-encoding) + * as is done with . + * headers - {Object} Object with header:value pairs to be set on + * the request. + * data - {String | Document} Optional data to send with the request. + * Typically, this is only used with and requests. + * Make sure to provide the appropriate "Content-Type" header for your + * data. For and requests, the content type defaults to + * "application-xml". If your data is a different content type, or + * if you are using a different HTTP method, set the "Content-Type" + * header to match your data type. + * callback - {Function} Function to call when request is done. + * To determine if the request failed, check request.status (200 + * indicates success). + * success - {Function} Optional function to call if request status is in + * the 200s. This will be called in addition to callback above and + * would typically only be used as an alternative. + * failure - {Function} Optional function to call if request status is not + * in the 200s. This will be called in addition to callback above and + * would typically only be used as an alternative. + * scope - {Object} If callback is a public method on some object, + * set the scope to that object. + * + * Returns: + * {XMLHttpRequest} Request object. To abort the request before a response + * is received, call abort() on the request object. + */ + issue: function(config) { + // apply default config - proxy host may have changed + var defaultConfig = OpenLayers.Util.extend( + this.DEFAULT_CONFIG, + {proxy: OpenLayers.ProxyHost} + ); + config = OpenLayers.Util.applyDefaults(config, defaultConfig); + + // create request, open, and set headers + var request = new OpenLayers.Request.XMLHttpRequest(); + var url = config.url; + if(config.params) { + var paramString = OpenLayers.Util.getParameterString(config.params); + if(paramString.length > 0) { + var separator = (url.indexOf('?') > -1) ? '&' : '?'; + url += separator + paramString; + } + } + if(config.proxy && (url.indexOf("http") == 0)) { + url = config.proxy + encodeURIComponent(url); + } + request.open( + config.method, url, config.async, config.user, config.password + ); + for(var header in config.headers) { + request.setRequestHeader(header, config.headers[header]); + } + + // bind callbacks to readyState 4 (done) + var complete = (config.scope) ? + OpenLayers.Function.bind(config.callback, config.scope) : + config.callback; + + // optional success callback + var success; + if(config.success) { + success = (config.scope) ? + OpenLayers.Function.bind(config.success, config.scope) : + config.success; + } + + // optional failure callback + var failure; + if(config.failure) { + failure = (config.scope) ? + OpenLayers.Function.bind(config.failure, config.scope) : + config.failure; + } + + var events = this.events; + + request.onreadystatechange = function() { + if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) { + var proceed = events.triggerEvent( + "complete", + {request: request, config: config, requestUrl: url} + ); + if(proceed !== false) { + complete(request); + if (!request.status || (request.status >= 200 && request.status < 300)) { + events.triggerEvent( + "success", + {request: request, config: config, requestUrl: url} + ); + if(success) { + success(request); + } + } + if(request.status && (request.status < 200 || request.status >= 300)) { + events.triggerEvent( + "failure", + {request: request, config: config, requestUrl: url} + ); + if(failure) { + failure(request); + } + } + } + } + }; + + // send request (optionally with data) and return + // call in a timeout for asynchronous requests so the return is + // available before readyState == 4 for cached docs + if(config.async === false) { + request.send(config.data); + } else { + window.setTimeout(function(){ + request.send(config.data); + }, 0); + } + return request; + }, + + /** + * APIMethod: GET + * Send an HTTP GET request. Additional configuration properties are + * documented in the method, with the method property set + * to GET. + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. + * This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + GET: function(config) { + config = OpenLayers.Util.extend(config, {method: "GET"}); + return OpenLayers.Request.issue(config); + }, + + /** + * APIMethod: POST + * Send a POST request. Additional configuration properties are + * documented in the method, with the method property set + * to POST and "Content-Type" header set to "application/xml". + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. The + * default "Content-Type" header will be set to "application-xml" if + * none is provided. This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + POST: function(config) { + config = OpenLayers.Util.extend(config, {method: "POST"}); + // set content type to application/xml if it isn't already set + config.headers = config.headers ? config.headers : {}; + if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { + config.headers["Content-Type"] = "application/xml"; + } + return OpenLayers.Request.issue(config); + }, + + /** + * APIMethod: PUT + * Send an HTTP PUT request. Additional configuration properties are + * documented in the method, with the method property set + * to PUT and "Content-Type" header set to "application/xml". + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. The + * default "Content-Type" header will be set to "application-xml" if + * none is provided. This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + PUT: function(config) { + config = OpenLayers.Util.extend(config, {method: "PUT"}); + // set content type to application/xml if it isn't already set + config.headers = config.headers ? config.headers : {}; + if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { + config.headers["Content-Type"] = "application/xml"; + } + return OpenLayers.Request.issue(config); + }, + + /** + * APIMethod: DELETE + * Send an HTTP DELETE request. Additional configuration properties are + * documented in the method, with the method property set + * to DELETE. + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. + * This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + DELETE: function(config) { + config = OpenLayers.Util.extend(config, {method: "DELETE"}); + return OpenLayers.Request.issue(config); + }, + + /** + * APIMethod: HEAD + * Send an HTTP HEAD request. Additional configuration properties are + * documented in the method, with the method property set + * to HEAD. + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. + * This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + HEAD: function(config) { + config = OpenLayers.Util.extend(config, {method: "HEAD"}); + return OpenLayers.Request.issue(config); + }, + + /** + * APIMethod: OPTIONS + * Send an HTTP OPTIONS request. Additional configuration properties are + * documented in the method, with the method property set + * to OPTIONS. + * + * Parameters: + * config - {Object} Object with properties for configuring the request. + * See the method for documentation of allowed properties. + * This object is modified and should not be reused. + * + * Returns: + * {XMLHttpRequest} Request object. + */ + OPTIONS: function(config) { + config = OpenLayers.Util.extend(config, {method: "OPTIONS"}); + return OpenLayers.Request.issue(config); + } + +}; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Rule.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Rule.js new file mode 100755 index 0000000000..43732f0a8c --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Rule.js @@ -0,0 +1,209 @@ +/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. + * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt + * for the full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Style.js + */ + +/** + * Class: OpenLayers.Rule + * This class represents an SLD Rule, as being used for rule-based SLD styling. + */ +OpenLayers.Rule = OpenLayers.Class({ + + /** + * Property: id + * {String} A unique id for this session. + */ + id: null, + + /** + * APIProperty: name + * {String} name of this rule + */ + name: 'default', + + /** + * Property: title + * {String} Title of this rule (set if included in SLD) + */ + title: null, + + /** + * Property: description + * {String} Description of this rule (set if abstract is included in SLD) + */ + description: null, + + /** + * Property: context + * {Object} An optional object with properties that the rule should be + * evaluated against. If no context is specified, feature.attributes will + * be used. + */ + context: null, + + /** + * Property: filter + * {} Optional filter for the rule. + */ + filter: null, + + /** + * Property: elseFilter + * {Boolean} Determines whether this rule is only to be applied only if + * no other rules match (ElseFilter according to the SLD specification). + * Default is false. For instances of OpenLayers.Rule, if elseFilter is + * false, the rule will always apply. For subclasses, the else property is + * ignored. + */ + elseFilter: false, + + /** + * Property: symbolizer + * {Object} Symbolizer or hash of symbolizers for this rule. If hash of + * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The + * latter if useful if it is required to style e.g. vertices of a line + * with a point symbolizer. Note, however, that this is not implemented + * yet in OpenLayers, but it is the way how symbolizers are defined in + * SLD. + */ + symbolizer: null, + + /** + * APIProperty: minScaleDenominator + * {Number} or {String} minimum scale at which to draw the feature. + * In the case of a String, this can be a combination of text and + * propertyNames in the form "literal ${propertyName}" + */ + minScaleDenominator: null, + + /** + * APIProperty: maxScaleDenominator + * {Number} or {String} maximum scale at which to draw the feature. + * In the case of a String, this can be a combination of text and + * propertyNames in the form "literal ${propertyName}" + */ + maxScaleDenominator: null, + + /** + * Constructor: OpenLayers.Rule + * Creates a Rule. + * + * Parameters: + * options - {Object} An optional object with properties to set on the + * rule + * + * Returns: + * {} + */ + initialize: function(options) { + this.symbolizer = {}; + OpenLayers.Util.extend(this, options); + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + for (var i in this.symbolizer) { + this.symbolizer[i] = null; + } + this.symbolizer = null; + }, + + /** + * APIMethod: evaluate + * evaluates this rule for a specific feature + * + * Parameters: + * feature - {} feature to apply the rule to. + * + * Returns: + * {Boolean} true if the rule applies, false if it does not. + * This rule is the default rule and always returns true. + */ + evaluate: function(feature) { + var context = this.getContext(feature); + var applies = true; + + if (this.minScaleDenominator || this.maxScaleDenominator) { + var scale = feature.layer.map.getScale(); + } + + // check if within minScale/maxScale bounds + if (this.minScaleDenominator) { + applies = scale >= OpenLayers.Style.createLiteral( + this.minScaleDenominator, context); + } + if (applies && this.maxScaleDenominator) { + applies = scale < OpenLayers.Style.createLiteral( + this.maxScaleDenominator, context); + } + + // check if optional filter applies + if(applies && this.filter) { + // feature id filters get the feature, others get the context + if(this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { + applies = this.filter.evaluate(feature); + } else { + applies = this.filter.evaluate(context); + } + } + + return applies; + }, + + /** + * Method: getContext + * Gets the context for evaluating this rule + * + * Paramters: + * feature - {} feature to take the context from if + * none is specified. + */ + getContext: function(feature) { + var context = this.context; + if (!context) { + context = feature.attributes || feature.data; + } + if (typeof this.context == "function") { + context = this.context(feature); + } + return context; + }, + + /** + * APIMethod: clone + * Clones this rule. + * + * Returns: + * {} Clone of this rule. + */ + clone: function() { + var options = OpenLayers.Util.extend({}, this); + // clone symbolizer + options.symbolizer = {}; + for(var key in this.symbolizer) { + value = this.symbolizer[key]; + type = typeof value; + if(type === "object") { + options.symbolizer[key] = OpenLayers.Util.extend({}, value); + } else if(type === "string") { + options.symbolizer[key] = value; + } + } + // clone filter + options.filter = this.filter && this.filter.clone(); + // clone context + options.context = this.context && OpenLayers.Util.extend({}, this.context); + return new OpenLayers.Rule(options); + }, + + CLASS_NAME: "OpenLayers.Rule" +}); \ No newline at end of file diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/SingleFile.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/SingleFile.js new file mode 100755 index 0000000000..4d06ecb5a9 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/SingleFile.js @@ -0,0 +1,9 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +var OpenLayers = { + singleFile: true +}; + + diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Strategy.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Strategy.js new file mode 100755 index 0000000000..ba209cd5b6 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Strategy.js @@ -0,0 +1,116 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * Class: OpenLayers.Strategy + * Abstract vector layer strategy class. Not to be instantiated directly. Use + * one of the strategy subclasses instead. + */ +OpenLayers.Strategy = OpenLayers.Class({ + + /** + * Property: layer + * {} The layer this strategy belongs to. + */ + layer: null, + + /** + * Property: options + * {Object} Any options sent to the constructor. + */ + options: null, + + /** + * Property: active + * {Boolean} The control is active. + */ + active: null, + + /** + * Property: autoActivate + * {Boolean} The creator of the strategy can set autoActivate to false + * to fully control when the protocol is activated and deactivated. + * Defaults to true. + */ + autoActivate: true, + + /** + * Property: autoDestroy + * {Boolean} The creator of the strategy can set autoDestroy to false + * to fully control when the strategy is destroyed. Defaults to + * true. + */ + autoDestroy: true, + + /** + * Constructor: OpenLayers.Strategy + * Abstract class for vector strategies. Create instances of a subclass. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + this.options = options; + // set the active property here, so that user cannot override it + this.active = false; + }, + + /** + * APIMethod: destroy + * Clean up the strategy. + */ + destroy: function() { + this.deactivate(); + this.layer = null; + this.options = null; + }, + + /** + * Method: setLayer + * Called to set the property. + * + * Parameters: + * {} + */ + setLayer: function(layer) { + this.layer = layer; + }, + + /** + * Method: activate + * Activate the strategy. Register any listeners, do appropriate setup. + * + * Returns: + * {Boolean} True if the strategy was successfully activated or false if + * the strategy was already active. + */ + activate: function() { + if (!this.active) { + this.active = true; + return true; + } + return false; + }, + + /** + * Method: deactivate + * Deactivate the strategy. Unregister any listeners, do appropriate + * tear-down. + * + * Returns: + * {Boolean} True if the strategy was successfully deactivated or false if + * the strategy was already inactive. + */ + deactivate: function() { + if (this.active) { + this.active = false; + return true; + } + return false; + }, + + CLASS_NAME: "OpenLayers.Strategy" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Style.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Style.js new file mode 100755 index 0000000000..f64a58eb1c --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Style.js @@ -0,0 +1,407 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Style + * This class represents a UserStyle obtained + * from a SLD, containing styling rules. + */ +OpenLayers.Style = OpenLayers.Class({ + + /** + * APIProperty: name + * {String} + */ + name: null, + + /** + * Property: title + * {String} Title of this style (set if included in SLD) + */ + title: null, + + /** + * Property: description + * {String} Description of this style (set if abstract is included in SLD) + */ + description: null, + + /** + * APIProperty: layerName + * {} name of the layer that this style belongs to, usually + * according to the NamedLayer attribute of an SLD document. + */ + layerName: null, + + /** + * APIProperty: isDefault + * {Boolean} + */ + isDefault: false, + + /** + * Property: rules + * {Array()} + */ + rules: null, + + /** + * Property: context + * {Object} An optional object with properties that symbolizers' property + * values should be evaluated against. If no context is specified, + * feature.attributes will be used + */ + context: null, + + /** + * Property: defaultStyle + * {Object} hash of style properties to use as default for merging + * rule-based style symbolizers onto. If no rules are defined, + * createSymbolizer will return this style. If is set to + * true, the defaultStyle will only be taken into account if there are + * rules defined. + */ + defaultStyle: null, + + /** + * Property: defaultsPerSymbolizer + * {Boolean} If set to true, the will extend the symbolizer + * of every rule. Properties of the will also be used to set + * missing symbolizer properties if the symbolizer has stroke, fill or + * graphic set to true. Default is false. + */ + defaultsPerSymbolizer: false, + + /** + * Property: propertyStyles + * {Hash of Boolean} cache of style properties that need to be parsed for + * propertyNames. Property names are keys, values won't be used. + */ + propertyStyles: null, + + + /** + * Constructor: OpenLayers.Style + * Creates a UserStyle. + * + * Parameters: + * style - {Object} Optional hash of style properties that will be + * used as default style for this style object. This style + * applies if no rules are specified. Symbolizers defined in + * rules will extend this default style. + * options - {Object} An optional object with properties to set on the + * style. + * + * Valid options: + * rules - {Array()} List of rules to be added to the + * style. + * + * Return: + * {} + */ + initialize: function(style, options) { + + OpenLayers.Util.extend(this, options); + this.rules = []; + if(options && options.rules) { + this.addRules(options.rules); + } + + // use the default style from OpenLayers.Feature.Vector if no style + // was given in the constructor + this.setDefaultStyle(style || + OpenLayers.Feature.Vector.style["default"]); + + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + for (var i=0, len=this.rules.length; i} feature to evaluate rules for + * + * Returns: + * {Object} symbolizer hash + */ + createSymbolizer: function(feature) { + var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( + OpenLayers.Util.extend({}, this.defaultStyle), feature); + + var rules = this.rules; + + var rule, context; + var elseRules = []; + var appliedRules = false; + for(var i=0, len=rules.length; i 0) { + appliedRules = true; + for(var i=0, len=elseRules.length; i 0 && appliedRules == false) { + style.display = "none"; + } + + return style; + }, + + /** + * Method: applySymbolizer + * + * Parameters: + * rule - {OpenLayers.Rule} + * style - {Object} + * feature - {} + * + * Returns: + * {Object} A style with new symbolizer applied. + */ + applySymbolizer: function(rule, style, feature) { + var symbolizerPrefix = feature.geometry ? + this.getSymbolizerPrefix(feature.geometry) : + OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; + + var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; + + if(this.defaultsPerSymbolizer === true) { + var defaults = this.defaultStyle; + OpenLayers.Util.applyDefaults(symbolizer, { + pointRadius: defaults.pointRadius + }); + if(symbolizer.stroke === true || symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + strokeWidth: defaults.strokeWidth, + strokeColor: defaults.strokeColor, + strokeOpacity: defaults.strokeOpacity, + strokeDashstyle: defaults.strokeDashstyle, + strokeLinecap: defaults.strokeLinecap + }); + } + if(symbolizer.fill === true || symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + fillColor: defaults.fillColor, + fillOpacity: defaults.fillOpacity + }); + } + if(symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + pointRadius: this.defaultStyle.pointRadius, + externalGraphic: this.defaultStyle.externalGraphic, + graphicName: this.defaultStyle.graphicName, + graphicOpacity: this.defaultStyle.graphicOpacity, + graphicWidth: this.defaultStyle.graphicWidth, + graphicHeight: this.defaultStyle.graphicHeight, + graphicXOffset: this.defaultStyle.graphicXOffset, + graphicYOffset: this.defaultStyle.graphicYOffset + }); + } + } + + // merge the style with the current style + return this.createLiterals( + OpenLayers.Util.extend(style, symbolizer), feature); + }, + + /** + * Method: createLiterals + * creates literals for all style properties that have an entry in + * . + * + * Parameters: + * style - {Object} style to create literals for. Will be modified + * inline. + * feature - {Object} + * + * Returns: + * {Object} the modified style + */ + createLiterals: function(style, feature) { + var context = this.context || feature.attributes || feature.data; + + for (var i in this.propertyStyles) { + style[i] = OpenLayers.Style.createLiteral(style[i], context, feature); + } + return style; + }, + + /** + * Method: findPropertyStyles + * Looks into all rules for this style and the defaultStyle to collect + * all the style hash property names containing ${...} strings that have + * to be replaced using the createLiteral method before returning them. + * + * Returns: + * {Object} hash of property names that need createLiteral parsing. The + * name of the property is the key, and the value is true; + */ + findPropertyStyles: function() { + var propertyStyles = {}; + + // check the default style + var style = this.defaultStyle; + this.addPropertyStyles(propertyStyles, style); + + // walk through all rules to check for properties in their symbolizer + var rules = this.rules; + var symbolizer, value; + for (var i=0, len=rules.length; i)} + */ + addRules: function(rules) { + this.rules = this.rules.concat(rules); + this.propertyStyles = this.findPropertyStyles(); + }, + + /** + * APIMethod: setDefaultStyle + * Sets the default style for this style object. + * + * Parameters: + * style - {Object} Hash of style properties + */ + setDefaultStyle: function(style) { + this.defaultStyle = style; + this.propertyStyles = this.findPropertyStyles(); + }, + + /** + * Method: getSymbolizerPrefix + * Returns the correct symbolizer prefix according to the + * geometry type of the passed geometry + * + * Parameters: + * geometry {} + * + * Returns: + * {String} key of the according symbolizer + */ + getSymbolizerPrefix: function(geometry) { + var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; + for (var i=0, len=prefixes.length; i for evaluating functions in the context. + * + * Returns: + * {String} the parsed value. In the example of the value parameter above, the + * result would be "foo valueOfBar", assuming that the passed feature has an + * attribute named "bar" with the value "valueOfBar". + */ +OpenLayers.Style.createLiteral = function(value, context, feature) { + if (typeof value == "string" && value.indexOf("${") != -1) { + value = OpenLayers.String.format(value, context, [feature]); + value = (isNaN(value) || !value) ? value : parseFloat(value); + } + return value; +}; + +/** + * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES + * {Array} prefixes of the sld symbolizers. These are the + * same as the main geometry types + */ +OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text']; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/StyleMap.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/StyleMap.js new file mode 100755 index 0000000000..757dc4c657 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/StyleMap.js @@ -0,0 +1,159 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Style.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.StyleMap + */ +OpenLayers.StyleMap = OpenLayers.Class({ + + /** + * Property: styles + * Hash of {}, keyed by names of well known + * rendering intents (e.g. "default", "temporary", "select", "delete"). + */ + styles: null, + + /** + * Property: extendDefault + * {Boolean} if true, every render intent will extend the symbolizers + * specified for the "default" intent at rendering time. Otherwise, every + * rendering intent will be treated as a completely independent style. + */ + extendDefault: true, + + /** + * Constructor: OpenLayers.StyleMap + * + * Parameters: + * style - {Object} Optional. Either a style hash, or a style object, or + * a hash of style objects (style hashes) keyed by rendering + * intent. If just one style hash or style object is passed, + * this will be used for all known render intents (default, + * select, temporary) + * options - {Object} optional hash of additional options for this + * instance + */ + initialize: function (style, options) { + this.styles = { + "default": new OpenLayers.Style( + OpenLayers.Feature.Vector.style["default"]), + "select": new OpenLayers.Style( + OpenLayers.Feature.Vector.style["select"]), + "temporary": new OpenLayers.Style( + OpenLayers.Feature.Vector.style["temporary"]), + "delete": new OpenLayers.Style( + OpenLayers.Feature.Vector.style["delete"]) + }; + + // take whatever the user passed as style parameter and convert it + // into parts of stylemap. + if(style instanceof OpenLayers.Style) { + // user passed a style object + this.styles["default"] = style; + this.styles["select"] = style; + this.styles["temporary"] = style; + this.styles["delete"] = style; + } else if(typeof style == "object") { + for(var key in style) { + if(style[key] instanceof OpenLayers.Style) { + // user passed a hash of style objects + this.styles[key] = style[key]; + } else if(typeof style[key] == "object") { + // user passsed a hash of style hashes + this.styles[key] = new OpenLayers.Style(style[key]); + } else { + // user passed a style hash (i.e. symbolizer) + this.styles["default"] = new OpenLayers.Style(style); + this.styles["select"] = new OpenLayers.Style(style); + this.styles["temporary"] = new OpenLayers.Style(style); + this.styles["delete"] = new OpenLayers.Style(style); + break; + } + } + } + OpenLayers.Util.extend(this, options); + }, + + /** + * Method: destroy + */ + destroy: function() { + for(var key in this.styles) { + this.styles[key].destroy(); + } + this.styles = null; + }, + + /** + * Method: createSymbolizer + * Creates the symbolizer for a feature for a render intent. + * + * Parameters: + * feature - {} The feature to evaluate the rules + * of the intended style against. + * intent - {String} The intent determines the symbolizer that will be + * used to draw the feature. Well known intents are "default" + * (for just drawing the features), "select" (for selected + * features) and "temporary" (for drawing features). + * + * Returns: + * {Object} symbolizer hash + */ + createSymbolizer: function(feature, intent) { + if(!feature) { + feature = new OpenLayers.Feature.Vector(); + } + if(!this.styles[intent]) { + intent = "default"; + } + feature.renderIntent = intent; + var defaultSymbolizer = {}; + if(this.extendDefault && intent != "default") { + defaultSymbolizer = this.styles["default"].createSymbolizer(feature); + } + return OpenLayers.Util.extend(defaultSymbolizer, + this.styles[intent].createSymbolizer(feature)); + }, + + /** + * Method: addUniqueValueRules + * Convenience method to create comparison rules for unique values of a + * property. The rules will be added to the style object for a specified + * rendering intent. This method is a shortcut for creating something like + * the "unique value legends" familiar from well known desktop GIS systems + * + * Parameters: + * renderIntent - {String} rendering intent to add the rules to + * property - {String} values of feature attributes to create the + * rules for + * symbolizers - {Object} Hash of symbolizers, keyed by the desired + * property values + * context - {Object} An optional object with properties that + * symbolizers' property values should be evaluated + * against. If no context is specified, feature.attributes + * will be used + */ + addUniqueValueRules: function(renderIntent, property, symbolizers, context) { + var rules = []; + for (var value in symbolizers) { + rules.push(new OpenLayers.Rule({ + symbolizer: symbolizers[value], + context: context, + filter: new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.EQUAL_TO, + property: property, + value: value + }) + })); + } + this.styles[renderIntent].addRules(rules); + }, + + CLASS_NAME: "OpenLayers.StyleMap" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tile.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tile.js new file mode 100755 index 0000000000..429814dd1c --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tile.js @@ -0,0 +1,280 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/* + * @requires OpenLayers/Util.js + * @requires OpenLayers/Console.js + */ + +/* + * Class: OpenLayers.Tile + * This is a class designed to designate a single tile, however + * it is explicitly designed to do relatively little. Tiles store + * information about themselves -- such as the URL that they are related + * to, and their size - but do not add themselves to the layer div + * automatically, for example. Create a new tile with the + * constructor, or a subclass. + * + * TBD 3.0 - remove reference to url in above paragraph + * + */ +OpenLayers.Tile = OpenLayers.Class({ + + /** + * Constant: EVENT_TYPES + * {Array(String)} Supported application event types + */ + EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"], + + /** + * APIProperty: events + * {} An events object that handles all + * events on the tile. + */ + events: null, + + /** + * Property: id + * {String} null + */ + id: null, + + /** + * Property: layer + * {} layer the tile is attached to + */ + layer: null, + + /** + * Property: url + * {String} url of the request. + * + * TBD 3.0 + * Deprecated. The base tile class does not need an url. This should be + * handled in subclasses. Does not belong here. + */ + url: null, + + /** + * APIProperty: bounds + * {} null + */ + bounds: null, + + /** + * Property: size + * {} null + */ + size: null, + + /** + * Property: position + * {} Top Left pixel of the tile + */ + position: null, + + /** + * Property: isLoading + * {Boolean} Is the tile loading? + */ + isLoading: false, + + /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. + * there is no need for the base tile class to have a url. + * + * Constructor: OpenLayers.Tile + * Constructor for a new instance. + * + * Parameters: + * layer - {} layer that the tile will go in. + * position - {} + * bounds - {} + * url - {} + * size - {} + */ + initialize: function(layer, position, bounds, url, size) { + this.layer = layer; + this.position = position.clone(); + this.bounds = bounds.clone(); + this.url = url; + this.size = size.clone(); + + //give the tile a unique id based on its BBOX. + this.id = OpenLayers.Util.createUniqueID("Tile_"); + + this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES); + }, + + /** + * Method: unload + * Call immediately before destroying if you are listening to tile + * events, so that counters are properly handled if tile is still + * loading at destroy-time. Will only fire an event if the tile is + * still loading. + */ + unload: function() { + if (this.isLoading) { + this.isLoading = false; + this.events.triggerEvent("unload"); + } + }, + + /** + * APIMethod: destroy + * Nullify references to prevent circular references and memory leaks. + */ + destroy:function() { + this.layer = null; + this.bounds = null; + this.size = null; + this.position = null; + + this.events.destroy(); + this.events = null; + }, + + /** + * Method: clone + * + * Parameters: + * obj - {} The tile to be cloned + * + * Returns: + * {} An exact clone of this + */ + clone: function (obj) { + if (obj == null) { + obj = new OpenLayers.Tile(this.layer, + this.position, + this.bounds, + this.url, + this.size); + } + + // catch any randomly tagged-on properties + OpenLayers.Util.applyDefaults(obj, this); + + return obj; + }, + + /** + * Method: draw + * Clear whatever is currently in the tile, then return whether or not + * it should actually be re-drawn. + * + * Returns: + * {Boolean} Whether or not the tile should actually be drawn. Note that + * this is not really the best way of doing things, but such is + * the way the code has been developed. Subclasses call this and + * depend on the return to know if they should draw or not. + */ + draw: function() { + var maxExtent = this.layer.maxExtent; + var withinMaxExtent = (maxExtent && + this.bounds.intersectsBounds(maxExtent, false)); + + // The only case where we *wouldn't* want to draw the tile is if the + // tile is outside its layer's maxExtent. + this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent); + + //clear tile's contents and mark as not drawn + this.clear(); + + return this.shouldDraw; + }, + + /** + * Method: moveTo + * Reposition the tile. + * + * Parameters: + * bounds - {} + * position - {} + * redraw - {Boolean} Call draw method on tile after moving. + * Default is true + */ + moveTo: function (bounds, position, redraw) { + if (redraw == null) { + redraw = true; + } + + this.bounds = bounds.clone(); + this.position = position.clone(); + if (redraw) { + this.draw(); + } + }, + + /** + * Method: clear + * Clear the tile of any bounds/position-related data so that it can + * be reused in a new location. To be implemented by subclasses. + */ + clear: function() { + // to be implemented by subclasses + }, + + /** + * Method: getBoundsFromBaseLayer + * Take the pixel locations of the corner of the tile, and pass them to + * the base layer and ask for the location of those pixels, so that + * displaying tiles over Google works fine. + * + * Parameters: + * position - {} + * + * Returns: + * bounds - {} + */ + getBoundsFromBaseLayer: function(position) { + var msg = OpenLayers.i18n('reprojectDeprecated', + {'layerName':this.layer.name}); + OpenLayers.Console.warn(msg); + var topLeft = this.layer.map.getLonLatFromLayerPx(position); + var bottomRightPx = position.clone(); + bottomRightPx.x += this.size.w; + bottomRightPx.y += this.size.h; + var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx); + // Handle the case where the base layer wraps around the date line. + // Google does this, and it breaks WMS servers to request bounds in + // that fashion. + if (topLeft.lon > bottomRight.lon) { + if (topLeft.lon < 0) { + topLeft.lon = -180 - (topLeft.lon+180); + } else { + bottomRight.lon = 180+bottomRight.lon+180; + } + } + var bounds = new OpenLayers.Bounds(topLeft.lon, + bottomRight.lat, + bottomRight.lon, + topLeft.lat); + return bounds; + }, + + /** + * Method: showTile + * Show the tile only if it should be drawn. + */ + showTile: function() { + if (this.shouldDraw) { + this.show(); + } + }, + + /** + * Method: show + * Show the tile. To be implemented by subclasses. + */ + show: function() { }, + + /** + * Method: hide + * Hide the tile. To be implemented by subclasses. + */ + hide: function() { }, + + CLASS_NAME: "OpenLayers.Tile" +}); diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tween.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tween.js new file mode 100755 index 0000000000..f799df3c72 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Tween.js @@ -0,0 +1,322 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Console.js + */ + +/** + * Namespace: OpenLayers.Tween + */ +OpenLayers.Tween = OpenLayers.Class({ + + /** + * Constant: INTERVAL + * {int} Interval in milliseconds between 2 steps + */ + INTERVAL: 10, + + /** + * APIProperty: easing + * {(Function)} Easing equation used for the animation + * Defaultly set to OpenLayers.Easing.Expo.easeOut + */ + easing: null, + + /** + * APIProperty: begin + * {Object} Values to start the animation with + */ + begin: null, + + /** + * APIProperty: finish + * {Object} Values to finish the animation with + */ + finish: null, + + /** + * APIProperty: duration + * {int} duration of the tween (number of steps) + */ + duration: null, + + /** + * APIProperty: callbacks + * {Object} An object with start, eachStep and done properties whose values + * are functions to be call during the animation. They are passed the + * current computed value as argument. + */ + callbacks: null, + + /** + * Property: time + * {int} Step counter + */ + time: null, + + /** + * Property: interval + * {int} Interval id returned by window.setInterval + */ + interval: null, + + /** + * Property: playing + * {Boolean} Tells if the easing is currently playing + */ + playing: false, + + /** + * Constructor: OpenLayers.Tween + * Creates a Tween. + * + * Parameters: + * easing - {(Function)} easing function method to use + */ + initialize: function(easing) { + this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut; + }, + + /** + * APIMethod: start + * Plays the Tween, and calls the callback method on each step + * + * Parameters: + * begin - {Object} values to start the animation with + * finish - {Object} values to finish the animation with + * duration - {int} duration of the tween (number of steps) + * options - {Object} hash of options (for example callbacks (start, eachStep, done)) + */ + start: function(begin, finish, duration, options) { + this.playing = true; + this.begin = begin; + this.finish = finish; + this.duration = duration; + this.callbacks = options.callbacks; + this.time = 0; + if (this.interval) { + window.clearInterval(this.interval); + this.interval = null; + } + if (this.callbacks && this.callbacks.start) { + this.callbacks.start.call(this, this.begin); + } + this.interval = window.setInterval( + OpenLayers.Function.bind(this.play, this), this.INTERVAL); + }, + + /** + * APIMethod: stop + * Stops the Tween, and calls the done callback + * Doesn't do anything if animation is already finished + */ + stop: function() { + if (!this.playing) { + return; + } + + if (this.callbacks && this.callbacks.done) { + this.callbacks.done.call(this, this.finish); + } + window.clearInterval(this.interval); + this.interval = null; + this.playing = false; + }, + + /** + * Method: play + * Calls the appropriate easing method + */ + play: function() { + var value = {}; + for (var i in this.begin) { + var b = this.begin[i]; + var f = this.finish[i]; + if (b == null || f == null || isNaN(b) || isNaN(f)) { + OpenLayers.Console.error('invalid value for Tween'); + } + + var c = f - b; + value[i] = this.easing.apply(this, [this.time, b, c, this.duration]); + } + this.time++; + + if (this.callbacks && this.callbacks.eachStep) { + this.callbacks.eachStep.call(this, value); + } + + if (this.time > this.duration) { + if (this.callbacks && this.callbacks.done) { + this.callbacks.done.call(this, this.finish); + this.playing = false; + } + window.clearInterval(this.interval); + this.interval = null; + } + }, + + /** + * Create empty functions for all easing methods. + */ + CLASS_NAME: "OpenLayers.Tween" +}); + +/** + * Namespace: OpenLayers.Easing + * + * Credits: + * Easing Equations by Robert Penner, + */ +OpenLayers.Easing = { + /** + * Create empty functions for all easing methods. + */ + CLASS_NAME: "OpenLayers.Easing" +}; + +/** + * Namespace: OpenLayers.Easing.Linear + */ +OpenLayers.Easing.Linear = { + + /** + * Function: easeIn + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeIn: function(t, b, c, d) { + return c*t/d + b; + }, + + /** + * Function: easeOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeOut: function(t, b, c, d) { + return c*t/d + b; + }, + + /** + * Function: easeInOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeInOut: function(t, b, c, d) { + return c*t/d + b; + }, + + CLASS_NAME: "OpenLayers.Easing.Linear" +}; + +/** + * Namespace: OpenLayers.Easing.Expo + */ +OpenLayers.Easing.Expo = { + + /** + * Function: easeIn + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeIn: function(t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + + /** + * Function: easeOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeOut: function(t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + + /** + * Function: easeInOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeInOut: function(t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + + CLASS_NAME: "OpenLayers.Easing.Expo" +}; + +/** + * Namespace: OpenLayers.Easing.Quad + */ +OpenLayers.Easing.Quad = { + + /** + * Function: easeIn + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeIn: function(t, b, c, d) { + return c*(t/=d)*t + b; + }, + + /** + * Function: easeOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeOut: function(t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + + /** + * Function: easeInOut + * + * Parameters: + * t - {Float} time + * b - {Float} beginning position + * c - {Float} total change + * d - {Float} duration of the transition + */ + easeInOut: function(t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + + CLASS_NAME: "OpenLayers.Easing.Quad" +}; diff --git a/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Util.js b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Util.js new file mode 100755 index 0000000000..caa0a59e75 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/OpenLayers/Util.js @@ -0,0 +1,1616 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Console.js + */ + +/** + * Namespace: Util + */ +OpenLayers.Util = {}; + +/** + * Function: getElement + * This is the old $() from prototype + */ +OpenLayers.Util.getElement = function() { + var elements = []; + + for (var i=0, len=arguments.length; i= 0; i--) { + if(array[i] == item) { + array.splice(i,1); + //break;more than once?? + } + } + return array; +}; + +/** + * Function: clearArray + * *Deprecated*. This function will disappear in 3.0. + * Please use "array.length = 0" instead. + * + * Parameters: + * array - {Array} + */ +OpenLayers.Util.clearArray = function(array) { + OpenLayers.Console.warn( + OpenLayers.i18n( + "methodDeprecated", {'newMethod': 'array = []'} + ) + ); + array.length = 0; +}; + +/** + * Function: indexOf + * Seems to exist already in FF, but not in MOZ. + * + * Parameters: + * array - {Array} + * obj - {Object} + * + * Returns: + * {Integer} The index at, which the object was found in the array. + * If not found, returns -1. + */ +OpenLayers.Util.indexOf = function(array, obj) { + + for(var i=0, len=array.length; i} The left and top style position. + * sz - {} The width and height style attributes. + * position - {String} The position attribute. eg: absolute, + * relative, etc. + * border - {String} The style.border attribute. eg: + * solid black 2px + * overflow - {String} The style.overview attribute. + * opacity - {Float} Fractional value (0.0 - 1.0) + */ +OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, + border, overflow, opacity) { + + if (id) { + element.id = id; + } + if (px) { + element.style.left = px.x + "px"; + element.style.top = px.y + "px"; + } + if (sz) { + element.style.width = sz.w + "px"; + element.style.height = sz.h + "px"; + } + if (position) { + element.style.position = position; + } + if (border) { + element.style.border = border; + } + if (overflow) { + element.style.overflow = overflow; + } + if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) { + element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; + element.style.opacity = opacity; + } else if (parseFloat(opacity) == 1.0) { + element.style.filter = ''; + element.style.opacity = ''; + } +}; + +/** + * Function: createDiv + * Creates a new div and optionally set some standard attributes. + * Null may be passed to each parameter if you do not wish to + * set a particular attribute. + * Note - zIndex is NOT set on the resulting div. + * + * Parameters: + * id - {String} An identifier for this element. If no id is + * passed an identifier will be created + * automatically. + * px - {} The element left and top position. + * sz - {} The element width and height. + * imgURL - {String} A url pointing to an image to use as a + * background image. + * position - {String} The style.position value. eg: absolute, + * relative etc. + * border - {String} The the style.border value. + * eg: 2px solid black + * overflow - {String} The style.overflow value. Eg. hidden + * opacity - {Float} Fractional value (0.0 - 1.0) + * + * Returns: + * {DOMElement} A DOM Div created with the specified attributes. + */ +OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, + border, overflow, opacity) { + + var dom = document.createElement('div'); + + if (imgURL) { + dom.style.backgroundImage = 'url(' + imgURL + ')'; + } + + //set generic properties + if (!id) { + id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); + } + if (!position) { + position = "absolute"; + } + OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, + border, overflow, opacity); + + return dom; +}; + +/** + * Function: createImage + * Creates an img element with specific attribute values. + * + * Parameters: + * id - {String} The id field for the img. If none assigned one will be + * automatically generated. + * px - {} The left and top positions. + * sz - {} The style.width and style.height values. + * imgURL - {String} The url to use as the image source. + * position - {String} The style.position value. + * border - {String} The border to place around the image. + * opacity - {Float} Fractional value (0.0 - 1.0) + * delayDisplay - {Boolean} If true waits until the image has been + * loaded. + * + * Returns: + * {DOMElement} A DOM Image created with the specified attributes. + */ +OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border, + opacity, delayDisplay) { + + var image = document.createElement("img"); + + //set generic properties + if (!id) { + id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); + } + if (!position) { + position = "relative"; + } + OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, + border, null, opacity); + + if(delayDisplay) { + image.style.display = "none"; + OpenLayers.Event.observe(image, "load", + OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image)); + OpenLayers.Event.observe(image, "error", + OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image)); + + } + + //set special properties + image.style.alt = id; + image.galleryImg = "no"; + if (imgURL) { + image.src = imgURL; + } + + + + return image; +}; + +/** + * Function: setOpacity + * *Deprecated*. This function has been deprecated. Instead, please use + * + * or + * + * + * Set the opacity of a DOM Element + * Note that for this function to work in IE, elements must "have layout" + * according to: + * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp + * + * Parameters: + * element - {DOMElement} Set the opacity on this DOM element + * opacity - {Float} Opacity value (0.0 - 1.0) + */ +OpenLayers.Util.setOpacity = function(element, opacity) { + OpenLayers.Util.modifyDOMElement(element, null, null, null, + null, null, null, opacity); +}; + +/** + * Function: onImageLoad + * Bound to image load events. For all images created with or + * , this function will be bound to the load event. + */ +OpenLayers.Util.onImageLoad = function() { + // The complex check here is to solve issues described in #480. + // Every time a map view changes, it increments the 'viewRequestID' + // property. As the requests for the images for the new map view are sent + // out, they are tagged with this unique viewRequestID. + // + // If an image has no viewRequestID property set, we display it regardless, + // but if it does have a viewRequestID property, we check that it matches + // the viewRequestID set on the map. + // + // If the viewRequestID on the map has changed, that means that the user + // has changed the map view since this specific request was sent out, and + // therefore this tile does not need to be displayed (so we do not execute + // this code that turns its display on). + // + if (!this.viewRequestID || + (this.map && this.viewRequestID == this.map.viewRequestID)) { + this.style.backgroundColor ="transparent"; + this.style.display = ""; + } +}; + +/** + * Property: onImageLoadErrorColor + * {String} The color tiles with load errors will turn. + * Default is "pink" + */ +OpenLayers.Util.onImageLoadErrorColor = "pink"; + +/** + * Property: IMAGE_RELOAD_ATTEMPTS + * {Integer} How many times should we try to reload an image before giving up? + * Default is 0 + */ +OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0; + +/** + * Function: onImageLoadError + */ +OpenLayers.Util.onImageLoadError = function() { + this._attempts = (this._attempts) ? (this._attempts + 1) : 1; + if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) { + var urls = this.urls; + if (urls && urls instanceof Array && urls.length > 1){ + var src = this.src.toString(); + var current_url, k; + for (k = 0; current_url = urls[k]; k++){ + if(src.indexOf(current_url) != -1){ + break; + } + } + var guess = Math.floor(urls.length * Math.random()); + var new_url = urls[guess]; + k = 0; + while(new_url == current_url && k++ < 4){ + guess = Math.floor(urls.length * Math.random()); + new_url = urls[guess]; + } + this.src = src.replace(current_url, new_url); + } else { + this.src = this.src; + } + } else { + this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor; + } + this.style.display = ""; +}; + +/** + * Property: alphaHackNeeded + * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. + */ +OpenLayers.Util.alphaHackNeeded = null; + +/** + * Function: alphaHack + * Checks whether it's necessary (and possible) to use the png alpha + * hack which allows alpha transparency for png images under Internet + * Explorer. + * + * Returns: + * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. + */ +OpenLayers.Util.alphaHack = function() { + if (OpenLayers.Util.alphaHackNeeded == null) { + var arVersion = navigator.appVersion.split("MSIE"); + var version = parseFloat(arVersion[1]); + var filter = false; + + // IEs4Lin dies when trying to access document.body.filters, because + // the property is there, but requires a DLL that can't be provided. This + // means that we need to wrap this in a try/catch so that this can + // continue. + + try { + filter = !!(document.body.filters); + } catch (e) {} + + OpenLayers.Util.alphaHackNeeded = (filter && + (version >= 5.5) && (version < 7)); + } + return OpenLayers.Util.alphaHackNeeded; +}; + +/** + * Function: modifyAlphaImageDiv + * + * div - {DOMElement} Div containing Alpha-adjusted Image + * id - {String} + * px - {} + * sz - {} + * imgURL - {String} + * position - {String} + * border - {String} + * sizing {String} 'crop', 'scale', or 'image'. Default is "scale" + * opacity - {Float} Fractional value (0.0 - 1.0) + */ +OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, + position, border, sizing, + opacity) { + + OpenLayers.Util.modifyDOMElement(div, id, px, sz, position, + null, null, opacity); + + var img = div.childNodes[0]; + + if (imgURL) { + img.src = imgURL; + } + OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, + "relative", border); + + if (OpenLayers.Util.alphaHack()) { + if(div.style.display != "none") { + div.style.display = "inline-block"; + } + if (sizing == null) { + sizing = "scale"; + } + + div.style.filter = "progid:DXImageTransform.Microsoft" + + ".AlphaImageLoader(src='" + img.src + "', " + + "sizingMethod='" + sizing + "')"; + if (parseFloat(div.style.opacity) >= 0.0 && + parseFloat(div.style.opacity) < 1.0) { + div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")"; + } + + img.style.filter = "alpha(opacity=0)"; + } +}; + +/** + * Function: createAlphaImageDiv + * + * id - {String} + * px - {} + * sz - {} + * imgURL - {String} + * position - {String} + * border - {String} + * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" + * opacity - {Float} Fractional value (0.0 - 1.0) + * delayDisplay - {Boolean} If true waits until the image has been + * loaded. + * + * Returns: + * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is + * needed for transparency in IE, it is added. + */ +OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, + position, border, sizing, + opacity, delayDisplay) { + + var div = OpenLayers.Util.createDiv(); + var img = OpenLayers.Util.createImage(null, null, null, null, null, null, + null, false); + div.appendChild(img); + + if (delayDisplay) { + img.style.display = "none"; + OpenLayers.Event.observe(img, "load", + OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div)); + OpenLayers.Event.observe(img, "error", + OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div)); + } + + OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, + border, sizing, opacity); + + return div; +}; + + +/** + * Function: upperCaseObject + * Creates a new hashtable and copies over all the keys from the + * passed-in object, but storing them under an uppercased + * version of the key at which they were stored. + * + * Parameters: + * object - {Object} + * + * Returns: + * {Object} A new Object with all the same keys but uppercased + */ +OpenLayers.Util.upperCaseObject = function (object) { + var uObject = {}; + for (var key in object) { + uObject[key.toUpperCase()] = object[key]; + } + return uObject; +}; + +/** + * Function: applyDefaults + * Takes an object and copies any properties that don't exist from + * another properties, by analogy with OpenLayers.Util.extend() from + * Prototype.js. + * + * Parameters: + * to - {Object} The destination object. + * from - {Object} The source object. Any properties of this object that + * are undefined in the to object will be set on the to object. + * + * Returns: + * {Object} A reference to the to object. Note that the to argument is modified + * in place and returned by this function. + */ +OpenLayers.Util.applyDefaults = function (to, from) { + to = to || {}; + /* + * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative + * prototype object" when calling hawOwnProperty if the source object is an + * instance of window.Event. + */ + var fromIsEvt = typeof window.Event == "function" + && from instanceof window.Event; + + for (var key in from) { + if (to[key] === undefined || + (!fromIsEvt && from.hasOwnProperty + && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) { + to[key] = from[key]; + } + } + /** + * IE doesn't include the toString property when iterating over an object's + * properties with the for(property in object) syntax. Explicitly check if + * the source has its own toString property. + */ + if(!fromIsEvt && from && from.hasOwnProperty + && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) { + to.toString = from.toString; + } + + return to; +}; + +/** + * Function: getParameterString + * + * Parameters: + * params - {Object} + * + * Returns: + * {String} A concatenation of the properties of an object in + * http parameter notation. + * (ex. "key1=value1&key2=value2&key3=value3") + * If a parameter is actually a list, that parameter will then + * be set to a comma-seperated list of values (foo,bar) instead + * of being URL escaped (foo%3Abar). + */ +OpenLayers.Util.getParameterString = function(params) { + var paramsArray = []; + + for (var key in params) { + var value = params[key]; + if ((value != null) && (typeof value != 'function')) { + var encodedValue; + if (typeof value == 'object' && value.constructor == Array) { + /* value is an array; encode items and separate with "," */ + var encodedItemArray = []; + for (var itemIndex=0, len=value.length; itemIndex 0)) + { + if (!index) { + index=0; + } + if (result[index].childNodes.length > 1) { + return result.childNodes[1].nodeValue; + } + else if (result[index].childNodes.length == 1) { + return result[index].firstChild.nodeValue; + } + } else { + return ""; + } +}; + +/** + * Function: getXmlNodeValue + * + * Parameters: + * node - {XMLNode} + * + * Returns: + * {String} The text value of the given node, without breaking in firefox or IE + */ +OpenLayers.Util.getXmlNodeValue = function(node) { + var val = null; + OpenLayers.Util.Try( + function() { + val = node.text; + if (!val) { + val = node.textContent; + } + if (!val) { + val = node.firstChild.nodeValue; + } + }, + function() { + val = node.textContent; + }); + return val; +}; + +/** + * Function: mouseLeft + * + * Parameters: + * evt - {Event} + * div - {HTMLDivElement} + * + * Returns: + * {Boolean} + */ +OpenLayers.Util.mouseLeft = function (evt, div) { + // start with the element to which the mouse has moved + var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement; + // walk up the DOM tree. + while (target != div && target != null) { + target = target.parentNode; + } + // if the target we stop at isn't the div, then we've left the div. + return (target != div); +}; + +/** + * Property: precision + * {Number} The number of significant digits to retain to avoid + * floating point precision errors. + * + * We use 14 as a "safe" default because, although IEEE 754 double floats + * (standard on most modern operating systems) support up to about 16 + * significant digits, 14 significant digits are sufficient to represent + * sub-millimeter accuracy in any coordinate system that anyone is likely to + * use with OpenLayers. + * + * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior + * of OpenLayers <2.8 is preserved. Be aware that this will cause problems + * with certain projections, e.g. spherical Mercator. + * + */ +OpenLayers.Util.DEFAULT_PRECISION = 14; + +/** + * Function: toFloat + * Convenience method to cast an object to a Number, rounded to the + * desired floating point precision. + * + * Parameters: + * number - {Number} The number to cast and round. + * precision - {Number} An integer suitable for use with + * Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION. + * If set to 0, no rounding is performed. + * + * Returns: + * {Number} The cast, rounded number. + */ +OpenLayers.Util.toFloat = function (number, precision) { + if (precision == null) { + precision = OpenLayers.Util.DEFAULT_PRECISION; + } + var number; + if (precision == 0) { + number = parseFloat(number); + } else { + number = parseFloat(parseFloat(number).toPrecision(precision)); + } + return number; +}; + +/** + * Function: rad + * + * Parameters: + * x - {Float} + * + * Returns: + * {Float} + */ +OpenLayers.Util.rad = function(x) {return x*Math.PI/180;}; + +/** + * Function: distVincenty + * Given two objects representing points with geographic coordinates, this + * calculates the distance between those points on the surface of an + * ellipsoid. + * + * Parameters: + * p1 - {} (or any object with both .lat, .lon properties) + * p2 - {} (or any object with both .lat, .lon properties) + * + * Returns: + * {Float} The distance (in km) between the two input points as measured on an + * ellipsoid. Note that the input point objects must be in geographic + * coordinates (decimal degrees) and the return distance is in kilometers. + */ +OpenLayers.Util.distVincenty=function(p1, p2) { + var a = 6378137, b = 6356752.3142, f = 1/298.257223563; + var L = OpenLayers.Util.rad(p2.lon - p1.lon); + var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat))); + var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat))); + var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); + var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); + var lambda = L, lambdaP = 2*Math.PI; + var iterLimit = 20; + while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) { + var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); + var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); + if (sinSigma==0) { + return 0; // co-incident points + } + var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; + var sigma = Math.atan2(sinSigma, cosSigma); + var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma); + var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha); + var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; + var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); + lambdaP = lambda; + lambda = L + (1-C) * f * Math.sin(alpha) * + (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); + } + if (iterLimit==0) { + return NaN; // formula failed to converge + } + var uSq = cosSqAlpha * (a*a - b*b) / (b*b); + var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); + var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); + var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- + B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); + var s = b*A*(sigma-deltaSigma); + var d = s.toFixed(3)/1000; // round to 1mm precision + return d; +}; + +/** + * Function: getParameters + * Parse the parameters from a URL or from the current page itself into a + * JavaScript Object. Note that parameter values with commas are separated + * out into an Array. + * + * Parameters: + * url - {String} Optional url used to extract the query string. + * If null, query string is taken from page location. + * + * Returns: + * {Object} An object of key/value pairs from the query string. + */ +OpenLayers.Util.getParameters = function(url) { + // if no url specified, take it from the location bar + url = url || window.location.href; + + //parse out parameters portion of url string + var paramsString = ""; + if (OpenLayers.String.contains(url, '?')) { + var start = url.indexOf('?') + 1; + var end = OpenLayers.String.contains(url, "#") ? + url.indexOf('#') : url.length; + paramsString = url.substring(start, end); + } + + var parameters = {}; + var pairs = paramsString.split(/[&;]/); + for(var i=0, len=pairs.length; i + * + * Parameters: + * url - {String} Optional url used to extract the query string. + * If null, query string is taken from page location. + * + * Returns: + * {Object} An object of key/value pairs from the query string. + */ +OpenLayers.Util.getArgs = function(url) { + OpenLayers.Console.warn( + OpenLayers.i18n( + "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'} + ) + ); + return OpenLayers.Util.getParameters(url); +}; + +/** + * Property: lastSeqID + * {Integer} The ever-incrementing count variable. + * Used for generating unique ids. + */ +OpenLayers.Util.lastSeqID = 0; + +/** + * Function: createUniqueID + * Create a unique identifier for this session. Each time this function + * is called, a counter is incremented. The return will be the optional + * prefix (defaults to "id_") appended with the counter value. + * + * Parameters: + * prefix {String} Optionsal string to prefix unique id. Default is "id_". + * + * Returns: + * {String} A unique id string, built on the passed in prefix. + */ +OpenLayers.Util.createUniqueID = function(prefix) { + if (prefix == null) { + prefix = "id_"; + } + OpenLayers.Util.lastSeqID += 1; + return prefix + OpenLayers.Util.lastSeqID; +}; + +/** + * Constant: INCHES_PER_UNIT + * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c + * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile + * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/) + * and PROJ.4 (http://trac.osgeo.org/proj/) + * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c + * The hardcoded table of PROJ.4 units are in pj_units.c. + */ +OpenLayers.INCHES_PER_UNIT = { + 'inches': 1.0, + 'ft': 12.0, + 'mi': 63360.0, + 'm': 39.3701, + 'km': 39370.1, + 'dd': 4374754, + 'yd': 36 +}; +OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches; +OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd; +OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m; + +// Units from CS-Map +OpenLayers.METERS_PER_INCH = 0.02540005080010160020; +OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, { + "Inch": OpenLayers.INCHES_PER_UNIT.inches, + "Meter": 1.0 / OpenLayers.METERS_PER_INCH, //EPSG:9001 + "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH, //EPSG:9003 + "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9002 + "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH, //EPSG:9005 + "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH, //EPSG:9041 + "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH, //EPSG:9094 + "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH, + "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH, + "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH, + "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH, + "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9036 + "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH, + "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH, //EPSG:9040 + "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH, //EPSG:9084 + "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH, //EPSG:9085 + "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH, //EPSG:9086 + "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH, //EPSG:9087 + "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH, //EPSG:9080 + "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH, //EPSG:9081 + "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH, //EPSG:9082 + "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH, //EPSG:9083 + "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH, + "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9096 + "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9093 + "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9030 + "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH, + "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH, + "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH, + "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH, + "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH, + "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH, + "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH, + "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH, //EPSG:9031 + "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH, + "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9038 + "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9033 + "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9062 + "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9042 + "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9039 + "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9034 + "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9063 + "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9043 + "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH, + "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH, //EPSG:9097 + "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH, //EPSG:9098 + "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH, + "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH, + "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH, + "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH, + "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH, + "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH, + "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH, + "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH, + "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH, + "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH, + "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH +}); + +//unit abbreviations supported by PROJ.4 +OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, { + "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0, + "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0, + "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0, + "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0, + "kmi": OpenLayers.INCHES_PER_UNIT["nmi"], //International Nautical Mile + "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom + "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"], //International Chain + "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link + "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch + "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot + "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard + "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain + "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"], //U.S. Surveyor's Statute Mile + "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"], //Indian Yard + "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"], //Indian Foot + "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH //Indian Chain +}); + +/** + * Constant: DOTS_PER_INCH + * {Integer} 72 (A sensible default) + */ +OpenLayers.DOTS_PER_INCH = 72; + +/** + * Function: normalizeScale + * + * Parameters: + * scale - {float} + * + * Returns: + * {Float} A normalized scale value, in 1 / X format. + * This means that if a value less than one ( already 1/x) is passed + * in, it just returns scale directly. Otherwise, it returns + * 1 / scale + */ +OpenLayers.Util.normalizeScale = function (scale) { + var normScale = (scale > 1.0) ? (1.0 / scale) + : scale; + return normScale; +}; + +/** + * Function: getResolutionFromScale + * + * Parameters: + * scale - {Float} + * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. + * Default is degrees + * + * Returns: + * {Float} The corresponding resolution given passed-in scale and unit + * parameters. + */ +OpenLayers.Util.getResolutionFromScale = function (scale, units) { + + if (units == null) { + units = "degrees"; + } + + var normScale = OpenLayers.Util.normalizeScale(scale); + + var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units] + * OpenLayers.DOTS_PER_INCH); + return resolution; +}; + +/** + * Function: getScaleFromResolution + * + * Parameters: + * resolution - {Float} + * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. + * Default is degrees + * + * Returns: + * {Float} The corresponding scale given passed-in resolution and unit + * parameters. + */ +OpenLayers.Util.getScaleFromResolution = function (resolution, units) { + + if (units == null) { + units = "degrees"; + } + + var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] * + OpenLayers.DOTS_PER_INCH; + return scale; +}; + +/** + * Function: safeStopPropagation + * *Deprecated*. This function has been deprecated. Please use directly + * passing 'true' as the 2nd + * argument (preventDefault) + * + * Safely stop the propagation of an event *without* preventing + * the default browser action from occurring. + * + * Parameter: + * evt - {Event} + */ +OpenLayers.Util.safeStopPropagation = function(evt) { + OpenLayers.Event.stop(evt, true); +}; + +/** + * Function: pagePositon + * Calculates the position of an element on the page. + * + * Parameters: + * forElement - {DOMElement} + * + * Returns: + * {Array} two item array, L value then T value. + */ +OpenLayers.Util.pagePosition = function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + var child = forElement; + while(element) { + + if(element == document.body) { + if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') { + break; + } + } + + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + child = element; + try { + // wrapping this in a try/catch because IE chokes on the offsetParent + element = element.offsetParent; + } catch(e) { + OpenLayers.Console.error(OpenLayers.i18n( + "pagePositionFailed",{'elemId':element.id})); + break; + } + } + + element = forElement; + while(element) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + element = element.parentNode; + } + + return [valueL, valueT]; +}; + + +/** + * Function: isEquivalentUrl + * Test two URLs for equivalence. + * + * Setting 'ignoreCase' allows for case-independent comparison. + * + * Comparison is based on: + * - Protocol + * - Host (evaluated without the port) + * - Port (set 'ignorePort80' to ignore "80" values) + * - Hash ( set 'ignoreHash' to disable) + * - Pathname (for relative <-> absolute comparison) + * - Arguments (so they can be out of order) + * + * Parameters: + * url1 - {String} + * url2 - {String} + * options - {Object} Allows for customization of comparison: + * 'ignoreCase' - Default is True + * 'ignorePort80' - Default is True + * 'ignoreHash' - Default is True + * + * Returns: + * {Boolean} Whether or not the two URLs are equivalent + */ +OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) { + options = options || {}; + + OpenLayers.Util.applyDefaults(options, { + ignoreCase: true, + ignorePort80: true, + ignoreHash: true + }); + + var urlObj1 = OpenLayers.Util.createUrlObject(url1, options); + var urlObj2 = OpenLayers.Util.createUrlObject(url2, options); + + //compare all keys except for "args" (treated below) + for(var key in urlObj1) { + if(key !== "args") { + if(urlObj1[key] != urlObj2[key]) { + return false; + } + } + } + + // compare search args - irrespective of order + for(var key in urlObj1.args) { + if(urlObj1.args[key] != urlObj2.args[key]) { + return false; + } + delete urlObj2.args[key]; + } + // urlObj2 shouldn't have any args left + for(var key in urlObj2.args) { + return false; + } + + return true; +}; + +/** + * Function: createUrlObject + * + * Parameters: + * url - {String} + * options - {Object} A hash of options. Can be one of: + * ignoreCase: lowercase url, + * ignorePort80: don't include explicit port if port is 80, + * ignoreHash: Don't include part of url after the hash (#). + * + * Returns: + * {Object} An object with separate url, a, port, host, and args parsed out + * and ready for comparison + */ +OpenLayers.Util.createUrlObject = function(url, options) { + options = options || {}; + + // deal with relative urls first + if(!(/^\w+:\/\//).test(url)) { + var loc = window.location; + var port = loc.port ? ":" + loc.port : ""; + var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port; + if(url.indexOf("/") === 0) { + // full pathname + url = fullUrl + url; + } else { + // relative to current path + var parts = loc.pathname.split("/"); + parts.pop(); + url = fullUrl + parts.join("/") + "/" + url; + } + } + + if (options.ignoreCase) { + url = url.toLowerCase(); + } + + var a = document.createElement('a'); + a.href = url; + + var urlObject = {}; + + //host (without port) + urlObject.host = a.host.split(":").shift(); + + //protocol + urlObject.protocol = a.protocol; + + //port (get uniform browser behavior with port 80 here) + if(options.ignorePort80) { + urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port; + } else { + urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port; + } + + //hash + urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash; + + //args + var queryString = a.search; + if (!queryString) { + var qMark = url.indexOf("?"); + queryString = (qMark != -1) ? url.substr(qMark) : ""; + } + urlObject.args = OpenLayers.Util.getParameters(queryString); + + //pathname (uniform browser behavior with leading "/") + urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname; + + return urlObject; +}; + +/** + * Function: removeTail + * Takes a url and removes everything after the ? and # + * + * Parameters: + * url - {String} The url to process + * + * Returns: + * {String} The string with all queryString and Hash removed + */ +OpenLayers.Util.removeTail = function(url) { + var head = null; + + var qMark = url.indexOf("?"); + var hashMark = url.indexOf("#"); + + if (qMark == -1) { + head = (hashMark != -1) ? url.substr(0,hashMark) : url; + } else { + head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) + : url.substr(0, qMark); + } + return head; +}; + + +/** + * Function: getBrowserName + * + * Returns: + * {String} A string which specifies which is the current + * browser in which we are running. + * + * Currently-supported browser detection and codes: + * * 'opera' -- Opera + * * 'msie' -- Internet Explorer + * * 'safari' -- Safari + * * 'firefox' -- FireFox + * * 'mozilla' -- Mozilla + * + * If we are unable to property identify the browser, we + * return an empty string. + */ +OpenLayers.Util.getBrowserName = function() { + var browserName = ""; + + var ua = navigator.userAgent.toLowerCase(); + if ( ua.indexOf( "opera" ) != -1 ) { + browserName = "opera"; + } else if ( ua.indexOf( "msie" ) != -1 ) { + browserName = "msie"; + } else if ( ua.indexOf( "safari" ) != -1 ) { + browserName = "safari"; + } else if ( ua.indexOf( "mozilla" ) != -1 ) { + if ( ua.indexOf( "firefox" ) != -1 ) { + browserName = "firefox"; + } else { + browserName = "mozilla"; + } + } + + return browserName; +}; + + + + +/** + * Method: getRenderedDimensions + * Renders the contentHTML offscreen to determine actual dimensions for + * popup sizing. As we need layout to determine dimensions the content + * is rendered -9999px to the left and absolute to ensure the + * scrollbars do not flicker + * + * Parameters: + * contentHTML + * size - {} If either the 'w' or 'h' properties is + * specified, we fix that dimension of the div to be measured. This is + * useful in the case where we have a limit in one dimension and must + * therefore meaure the flow in the other dimension. + * options - {Object} + * displayClass - {String} Optional parameter. A CSS class name(s) string + * to provide the CSS context of the rendered content. + * containerElement - {DOMElement} Optional parameter. Insert the HTML to + * this node instead of the body root when calculating dimensions. + * + * Returns: + * {OpenLayers.Size} + */ +OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) { + + var w, h; + + // create temp container div with restricted size + var container = document.createElement("div"); + container.style.visibility = "hidden"; + + var containerElement = (options && options.containerElement) + ? options.containerElement : document.body; + + //fix a dimension, if specified. + if (size) { + if (size.w) { + w = size.w; + container.style.width = w + "px"; + } else if (size.h) { + h = size.h; + container.style.height = h + "px"; + } + } + + //add css classes, if specified + if (options && options.displayClass) { + container.className = options.displayClass; + } + + // create temp content div and assign content + var content = document.createElement("div"); + content.innerHTML = contentHTML; + + // we need overflow visible when calculating the size + content.style.overflow = "visible"; + if (content.childNodes) { + for (var i=0, l=content.childNodes.length; i 0.5; + }, + + isDark: function() { + return ! this.isBright(); + }, + + asRGB: function() { + return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; + }, + + asHex: function() { + return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); + }, + + asHSB: function() { + return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); + }, + + toString: function() { + return this.asHex(); + } + +}); + +OpenLayers.Rico.Color.createFromHex = function(hexCode) { + if(hexCode.length==4) { + var shortHexCode = hexCode; + var hexCode = '#'; + for(var i=1;i<4;i++) { + hexCode += (shortHexCode.charAt(i) + +shortHexCode.charAt(i)); + } + } + if ( hexCode.indexOf('#') == 0 ) { + hexCode = hexCode.substring(1); + } + var red = hexCode.substring(0,2); + var green = hexCode.substring(2,4); + var blue = hexCode.substring(4,6); + return new OpenLayers.Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) ); +}; + +/** + * Factory method for creating a color from the background of + * an HTML element. + */ +OpenLayers.Rico.Color.createColorFromBackground = function(elem) { + + var actualColor = + RicoUtil.getElementsComputedStyle(OpenLayers.Util.getElement(elem), + "backgroundColor", + "background-color"); + + if ( actualColor == "transparent" && elem.parentNode ) { + return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); + } + if ( actualColor == null ) { + return new OpenLayers.Rico.Color(255,255,255); + } + if ( actualColor.indexOf("rgb(") == 0 ) { + var colors = actualColor.substring(4, actualColor.length - 1 ); + var colorArray = colors.split(","); + return new OpenLayers.Rico.Color( parseInt( colorArray[0] ), + parseInt( colorArray[1] ), + parseInt( colorArray[2] ) ); + + } + else if ( actualColor.indexOf("#") == 0 ) { + return OpenLayers.Rico.Color.createFromHex(actualColor); + } + else { + return new OpenLayers.Rico.Color(255,255,255); + } +}; + +OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { + + var red = 0; + var green = 0; + var blue = 0; + + if (saturation == 0) { + red = parseInt(brightness * 255.0 + 0.5); + green = red; + blue = red; + } + else { + var h = (hue - Math.floor(hue)) * 6.0; + var f = h - Math.floor(h); + var p = brightness * (1.0 - saturation); + var q = brightness * (1.0 - saturation * f); + var t = brightness * (1.0 - (saturation * (1.0 - f))); + + switch (parseInt(h)) { + case 0: + red = (brightness * 255.0 + 0.5); + green = (t * 255.0 + 0.5); + blue = (p * 255.0 + 0.5); + break; + case 1: + red = (q * 255.0 + 0.5); + green = (brightness * 255.0 + 0.5); + blue = (p * 255.0 + 0.5); + break; + case 2: + red = (p * 255.0 + 0.5); + green = (brightness * 255.0 + 0.5); + blue = (t * 255.0 + 0.5); + break; + case 3: + red = (p * 255.0 + 0.5); + green = (q * 255.0 + 0.5); + blue = (brightness * 255.0 + 0.5); + break; + case 4: + red = (t * 255.0 + 0.5); + green = (p * 255.0 + 0.5); + blue = (brightness * 255.0 + 0.5); + break; + case 5: + red = (brightness * 255.0 + 0.5); + green = (p * 255.0 + 0.5); + blue = (q * 255.0 + 0.5); + break; + } + } + + return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) }; +}; + +OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { + + var hue; + var saturation; + var brightness; + + var cmax = (r > g) ? r : g; + if (b > cmax) { + cmax = b; + } + var cmin = (r < g) ? r : g; + if (b < cmin) { + cmin = b; + } + brightness = cmax / 255.0; + if (cmax != 0) { + saturation = (cmax - cmin)/cmax; + } else { + saturation = 0; + } + if (saturation == 0) { + hue = 0; + } else { + var redc = (cmax - r)/(cmax - cmin); + var greenc = (cmax - g)/(cmax - cmin); + var bluec = (cmax - b)/(cmax - cmin); + + if (r == cmax) { + hue = bluec - greenc; + } else if (g == cmax) { + hue = 2.0 + redc - bluec; + } else { + hue = 4.0 + greenc - redc; + } + hue = hue / 6.0; + if (hue < 0) { + hue = hue + 1.0; + } + } + + return { h : hue, s : saturation, b : brightness }; +}; + diff --git a/pandora_console/include/javascript/OpenLayers/lib/Rico/Corner.js b/pandora_console/include/javascript/OpenLayers/lib/Rico/Corner.js new file mode 100755 index 0000000000..80f73c0ad0 --- /dev/null +++ b/pandora_console/include/javascript/OpenLayers/lib/Rico/Corner.js @@ -0,0 +1,330 @@ +/* + * This file has been edited substantially from the Rico-released + * version by the OpenLayers development team. + * + * Copyright 2005 Sabre Airline Solutions + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the * License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or + * implied. See the License for the specific language governing + * permissions * and limitations under the License. + * + */ +OpenLayers.Rico = new Object(); +OpenLayers.Rico.Corner = { + + round: function(e, options) { + e = OpenLayers.Util.getElement(e); + this._setOptions(options); + + var color = this.options.color; + if ( this.options.color == "fromElement" ) { + color = this._background(e); + } + var bgColor = this.options.bgColor; + if ( this.options.bgColor == "fromParent" ) { + bgColor = this._background(e.offsetParent); + } + this._roundCornersImpl(e, color, bgColor); + }, + + /** This is a helper function to change the background + * color of
that has had Rico rounded corners added. + * + * It seems we cannot just set the background color for the + * outer
so each element used to create the + * corners must have its background color set individually. + * + * @param {DOM} theDiv - A child of the outer
that was + * supplied to the `round` method. + * + * @param {String} newColor - The new background color to use. + */ + changeColor: function(theDiv, newColor) { + + theDiv.style.backgroundColor = newColor; + + var spanElements = theDiv.parentNode.getElementsByTagName("span"); + + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { + spanElements[currIdx].style.backgroundColor = newColor; + } + }, + + + /** This is a helper function to change the background + * opacity of
that has had Rico rounded corners added. + * + * See changeColor (above) for algorithm explanation + * + * @param {DOM} theDiv A child of the outer
that was + * supplied to the `round` method. + * + * @param {int} newOpacity The new opacity to use (0-1). + */ + changeOpacity: function(theDiv, newOpacity) { + + var mozillaOpacity = newOpacity; + var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')'; + + theDiv.style.opacity = mozillaOpacity; + theDiv.style.filter = ieOpacity; + + var spanElements = theDiv.parentNode.getElementsByTagName("span"); + + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { + spanElements[currIdx].style.opacity = mozillaOpacity; + spanElements[currIdx].style.filter = ieOpacity; + } + + }, + + /** this function takes care of redoing the rico cornering + * + * you can't just call updateRicoCorners() again and pass it a + * new options string. you have to first remove the divs that + * rico puts on top and below the content div. + * + * @param {DOM} theDiv - A child of the outer
that was + * supplied to the `round` method. + * + * @param {Object} options - list of options + */ + reRound: function(theDiv, options) { + + var topRico = theDiv.parentNode.childNodes[0]; + //theDiv would be theDiv.parentNode.childNodes[1] + var bottomRico = theDiv.parentNode.childNodes[2]; + + theDiv.parentNode.removeChild(topRico); + theDiv.parentNode.removeChild(bottomRico); + + this.round(theDiv.parentNode, options); + }, + + _roundCornersImpl: function(e, color, bgColor) { + if(this.options.border) { + this._renderBorder(e,bgColor); + } + if(this._isTopRounded()) { + this._roundTopCorners(e,color,bgColor); + } + if(this._isBottomRounded()) { + this._roundBottomCorners(e,color,bgColor); + } + }, + + _renderBorder: function(el,bgColor) { + var borderValue = "1px solid " + this._borderColor(bgColor); + var borderL = "border-left: " + borderValue; + var borderR = "border-right: " + borderValue; + var style = "style='" + borderL + ";" + borderR + "'"; + el.innerHTML = "
" + el.innerHTML + "
"; + }, + + _roundTopCorners: function(el, color, bgColor) { + var corner = this._createCorner(bgColor); + for(var i=0 ; i < this.options.numSlices ; i++ ) { + corner.appendChild(this._createCornerSlice(color,bgColor,i,"top")); + } + el.style.paddingTop = 0; + el.insertBefore(corner,el.firstChild); + }, + + _roundBottomCorners: function(el, color, bgColor) { + var corner = this._createCorner(bgColor); + for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) { + corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom")); + } + el.style.paddingBottom = 0; + el.appendChild(corner); + }, + + _createCorner: function(bgColor) { + var corner = document.createElement("div"); + corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); + return corner; + }, + + _createCornerSlice: function(color,bgColor, n, position) { + var slice = document.createElement("span"); + + var inStyle = slice.style; + inStyle.backgroundColor = color; + inStyle.display = "block"; + inStyle.height = "1px"; + inStyle.overflow = "hidden"; + inStyle.fontSize = "1px"; + + var borderColor = this._borderColor(color,bgColor); + if ( this.options.border && n == 0 ) { + inStyle.borderTopStyle = "solid"; + inStyle.borderTopWidth = "1px"; + inStyle.borderLeftWidth = "0px"; + inStyle.borderRightWidth = "0px"; + inStyle.borderBottomWidth = "0px"; + inStyle.height = "0px"; // assumes css compliant box model + inStyle.borderColor = borderColor; + } + else if(borderColor) { + inStyle.borderColor = borderColor; + inStyle.borderStyle = "solid"; + inStyle.borderWidth = "0px 1px"; + } + + if ( !this.options.compact && (n == (this.options.numSlices-1)) ) { + inStyle.height = "2px"; + } + this._setMargin(slice, n, position); + this._setBorder(slice, n, position); + return slice; + }, + + _setOptions: function(options) { + this.options = { + corners : "all", + color : "fromElement", + bgColor : "fromParent", + blend : true, + border : false, + compact : false + }; + OpenLayers.Util.extend(this.options, options || {}); + + this.options.numSlices = this.options.compact ? 2 : 4; + if ( this._isTransparent() ) { + this.options.blend = false; + } + }, + + _whichSideTop: function() { + if ( this._hasString(this.options.corners, "all", "top") ) { + return ""; + } + if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) { + return ""; + } + if (this.options.corners.indexOf("tl") >= 0) { + return "left"; + } else if (this.options.corners.indexOf("tr") >= 0) { + return "right"; + } + return ""; + }, + + _whichSideBottom: function() { + if ( this._hasString(this.options.corners, "all", "bottom") ) { + return ""; + } + if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) { + return ""; + } + + if(this.options.corners.indexOf("bl") >=0) { + return "left"; + } else if(this.options.corners.indexOf("br")>=0) { + return "right"; + } + return ""; + }, + + _borderColor : function(color,bgColor) { + if ( color == "transparent" ) { + return bgColor; + } else if ( this.options.border ) { + return this.options.border; + } else if ( this.options.blend ) { + return this._blend( bgColor, color ); + } else { + return ""; + } + }, + + + _setMargin: function(el, n, corners) { + var marginSize = this._marginSize(n); + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); + + if ( whichSide == "left" ) { + el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px"; + } + else if ( whichSide == "right" ) { + el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px"; + } + else { + el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px"; + } + }, + + _setBorder: function(el,n,corners) { + var borderSize = this._borderSize(n); + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); + if ( whichSide == "left" ) { + el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px"; + } + else if ( whichSide == "right" ) { + el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px"; + } + else { + el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px"; + } + if (this.options.border != false) { + el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px"; + } + }, + + _marginSize: function(n) { + if ( this._isTransparent() ) { + return 0; + } + var marginSizes = [ 5, 3, 2, 1 ]; + var blendedMarginSizes = [ 3, 2, 1, 0 ]; + var compactMarginSizes = [ 2, 1 ]; + var smBlendedMarginSizes = [ 1, 0 ]; + + if ( this.options.compact && this.options.blend ) { + return smBlendedMarginSizes[n]; + } else if ( this.options.compact ) { + return compactMarginSizes[n]; + } else if ( this.options.blend ) { + return blendedMarginSizes[n]; + } else { + return marginSizes[n]; + } + }, + + _borderSize: function(n) { + var transparentBorderSizes = [ 5, 3, 2, 1 ]; + var blendedBorderSizes = [ 2, 1, 1, 1 ]; + var compactBorderSizes = [ 1, 0 ]; + var actualBorderSizes = [ 0, 2, 0, 0 ]; + + if ( this.options.compact && (this.options.blend || this._isTransparent()) ) { + return 1; + } else if ( this.options.compact ) { + return compactBorderSizes[n]; + } else if ( this.options.blend ) { + return blendedBorderSizes[n]; + } else if ( this.options.border ) { + return actualBorderSizes[n]; + } else if ( this._isTransparent() ) { + return transparentBorderSizes[n]; + } + return 0; + }, + + _hasString: function(str) { for(var i=1 ; i= 0) { return true; } return false; }, + _blend: function(c1, c2) { var cc1 = OpenLayers.Rico.Color.createFromHex(c1); cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); return cc1; }, + _background: function(el) { try { return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } }, + _isTransparent: function() { return this.options.color == "transparent"; }, + _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); }, + _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); }, + _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; } +}; \ No newline at end of file