Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/web/OpenLayers/lib/OpenLayers/Util.js @ 76

Revision 76, 56.3 KB checked in by djay, 12 years ago (diff)

Ajout du répertoire web

  • Property svn:executable set to *
Line 
1/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
2 * full list of contributors). Published under the Clear BSD license. 
3 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
4 * full text of the license. */
5
6/**
7 * @requires OpenLayers/Console.js
8 */
9
10/**
11 * Namespace: Util
12 */
13OpenLayers.Util = {};
14
15/**
16 * Function: getElement
17 * This is the old $() from prototype
18 */
19OpenLayers.Util.getElement = function() {
20    var elements = [];
21
22    for (var i=0, len=arguments.length; i<len; i++) {
23        var element = arguments[i];
24        if (typeof element == 'string') {
25            element = document.getElementById(element);
26        }
27        if (arguments.length == 1) {
28            return element;
29        }
30        elements.push(element);
31    }
32    return elements;
33};
34
35/**
36 * Function: isElement
37 * A cross-browser implementation of "e instanceof Element".
38 *
39 * Parameters:
40 * o - {Object} The object to test.
41 *
42 * Returns:
43 * {Boolean}
44 */
45OpenLayers.Util.isElement = function(o) {
46    return !!(o && o.nodeType === 1);
47};
48
49/**
50 * Maintain existing definition of $.
51 */
52if(typeof window.$  === "undefined") {
53    window.$ = OpenLayers.Util.getElement;
54}
55
56/**
57 * APIFunction: extend
58 * Copy all properties of a source object to a destination object.  Modifies
59 *     the passed in destination object.  Any properties on the source object
60 *     that are set to undefined will not be (re)set on the destination object.
61 *
62 * Parameters:
63 * destination - {Object} The object that will be modified
64 * source - {Object} The object with properties to be set on the destination
65 *
66 * Returns:
67 * {Object} The destination object.
68 */
69OpenLayers.Util.extend = function(destination, source) {
70    destination = destination || {};
71    if(source) {
72        for(var property in source) {
73            var value = source[property];
74            if(value !== undefined) {
75                destination[property] = value;
76            }
77        }
78
79        /**
80         * IE doesn't include the toString property when iterating over an object's
81         * properties with the for(property in object) syntax.  Explicitly check if
82         * the source has its own toString property.
83         */
84
85        /*
86         * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
87         * prototype object" when calling hawOwnProperty if the source object
88         * is an instance of window.Event.
89         */
90
91        var sourceIsEvt = typeof window.Event == "function"
92                          && source instanceof window.Event;
93
94        if(!sourceIsEvt
95           && source.hasOwnProperty && source.hasOwnProperty('toString')) {
96            destination.toString = source.toString;
97        }
98    }
99    return destination;
100};
101
102
103/**
104 * Function: removeItem
105 * Remove an object from an array. Iterates through the array
106 *     to find the item, then removes it.
107 *
108 * Parameters:
109 * array - {Array}
110 * item - {Object}
111 *
112 * Return
113 * {Array} A reference to the array
114 */
115OpenLayers.Util.removeItem = function(array, item) {
116    for(var i = array.length - 1; i >= 0; i--) {
117        if(array[i] == item) {
118            array.splice(i,1);
119            //break;more than once??
120        }
121    }
122    return array;
123};
124
125/**
126 * Function: clearArray
127 * *Deprecated*. This function will disappear in 3.0.
128 * Please use "array.length = 0" instead.
129 *
130 * Parameters:
131 * array - {Array}
132 */
133OpenLayers.Util.clearArray = function(array) {
134    OpenLayers.Console.warn(
135        OpenLayers.i18n(
136            "methodDeprecated", {'newMethod': 'array = []'}
137        )
138    );
139    array.length = 0;
140};
141
142/**
143 * Function: indexOf
144 * Seems to exist already in FF, but not in MOZ.
145 *
146 * Parameters:
147 * array - {Array}
148 * obj - {Object}
149 *
150 * Returns:
151 * {Integer} The index at, which the first object was found in the array.
152 *           If not found, returns -1.
153 */
154OpenLayers.Util.indexOf = function(array, obj) {
155    // use the build-in function if available.
156    if (typeof array.indexOf == "function") {
157        return array.indexOf(obj);
158    } else {
159        for (var i = 0, len = array.length; i < len; i++) {
160            if (array[i] == obj) {
161                return i;
162            }
163        }
164        return -1;   
165    }
166};
167
168
169
170/**
171 * Function: modifyDOMElement
172 *
173 * Modifies many properties of a DOM element all at once.  Passing in
174 * null to an individual parameter will avoid setting the attribute.
175 *
176 * Parameters:
177 * id - {String} The element id attribute to set.
178 * px - {<OpenLayers.Pixel>} The left and top style position.
179 * sz - {<OpenLayers.Size>}  The width and height style attributes.
180 * position - {String}       The position attribute.  eg: absolute,
181 *                           relative, etc.
182 * border - {String}         The style.border attribute.  eg:
183 *                           solid black 2px
184 * overflow - {String}       The style.overview attribute. 
185 * opacity - {Float}         Fractional value (0.0 - 1.0)
186 */
187OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
188                                            border, overflow, opacity) {
189
190    if (id) {
191        element.id = id;
192    }
193    if (px) {
194        element.style.left = px.x + "px";
195        element.style.top = px.y + "px";
196    }
197    if (sz) {
198        element.style.width = sz.w + "px";
199        element.style.height = sz.h + "px";
200    }
201    if (position) {
202        element.style.position = position;
203    }
204    if (border) {
205        element.style.border = border;
206    }
207    if (overflow) {
208        element.style.overflow = overflow;
209    }
210    if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
211        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
212        element.style.opacity = opacity;
213    } else if (parseFloat(opacity) == 1.0) {
214        element.style.filter = '';
215        element.style.opacity = '';
216    }
217};
218
219/**
220 * Function: createDiv
221 * Creates a new div and optionally set some standard attributes.
222 * Null may be passed to each parameter if you do not wish to
223 * set a particular attribute.
224 * Note - zIndex is NOT set on the resulting div.
225 *
226 * Parameters:
227 * id - {String} An identifier for this element.  If no id is
228 *               passed an identifier will be created
229 *               automatically.
230 * px - {<OpenLayers.Pixel>} The element left and top position.
231 * sz - {<OpenLayers.Size>} The element width and height.
232 * imgURL - {String} A url pointing to an image to use as a
233 *                   background image.
234 * position - {String} The style.position value. eg: absolute,
235 *                     relative etc.
236 * border - {String} The the style.border value.
237 *                   eg: 2px solid black
238 * overflow - {String} The style.overflow value. Eg. hidden
239 * opacity - {Float} Fractional value (0.0 - 1.0)
240 *
241 * Returns:
242 * {DOMElement} A DOM Div created with the specified attributes.
243 */
244OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
245                                     border, overflow, opacity) {
246
247    var dom = document.createElement('div');
248
249    if (imgURL) {
250        dom.style.backgroundImage = 'url(' + imgURL + ')';
251    }
252
253    //set generic properties
254    if (!id) {
255        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
256    }
257    if (!position) {
258        position = "absolute";
259    }
260    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
261                                     border, overflow, opacity);
262
263    return dom;
264};
265
266/**
267 * Function: createImage
268 * Creates an img element with specific attribute values.
269 * 
270 * Parameters:
271 * id - {String} The id field for the img.  If none assigned one will be
272 *               automatically generated.
273 * px - {<OpenLayers.Pixel>} The left and top positions.
274 * sz - {<OpenLayers.Size>} The style.width and style.height values.
275 * imgURL - {String} The url to use as the image source.
276 * position - {String} The style.position value.
277 * border - {String} The border to place around the image.
278 * opacity - {Float} Fractional value (0.0 - 1.0)
279 * delayDisplay - {Boolean} If true waits until the image has been
280 *                          loaded.
281 *
282 * Returns:
283 * {DOMElement} A DOM Image created with the specified attributes.
284 */
285OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
286                                       opacity, delayDisplay) {
287
288    var image = document.createElement("img");
289
290    //set generic properties
291    if (!id) {
292        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
293    }
294    if (!position) {
295        position = "relative";
296    }
297    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
298                                     border, null, opacity);
299
300    if(delayDisplay) {
301        image.style.display = "none";
302        OpenLayers.Event.observe(image, "load", 
303            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
304        OpenLayers.Event.observe(image, "error", 
305            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
306       
307    }
308   
309    //set special properties
310    image.style.alt = id;
311    image.galleryImg = "no";
312    if (imgURL) {
313        image.src = imgURL;
314    }
315
316
317       
318    return image;
319};
320
321/**
322 * Function: setOpacity
323 * *Deprecated*.  This function has been deprecated. Instead, please use
324 *     <OpenLayers.Util.modifyDOMElement>
325 *     or
326 *     <OpenLayers.Util.modifyAlphaImageDiv>
327 *
328 * Set the opacity of a DOM Element
329 *     Note that for this function to work in IE, elements must "have layout"
330 *     according to:
331 *     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
332 *
333 * Parameters:
334 * element - {DOMElement} Set the opacity on this DOM element
335 * opacity - {Float} Opacity value (0.0 - 1.0)
336 */
337OpenLayers.Util.setOpacity = function(element, opacity) {
338    OpenLayers.Util.modifyDOMElement(element, null, null, null,
339                                     null, null, null, opacity);
340};
341
342/**
343 * Function: onImageLoad
344 * Bound to image load events.  For all images created with <createImage> or
345 *     <createAlphaImageDiv>, this function will be bound to the load event.
346 */
347OpenLayers.Util.onImageLoad = function() {
348    // The complex check here is to solve issues described in #480.
349    // Every time a map view changes, it increments the 'viewRequestID'
350    // property. As the requests for the images for the new map view are sent
351    // out, they are tagged with this unique viewRequestID.
352    //
353    // If an image has no viewRequestID property set, we display it regardless,
354    // but if it does have a viewRequestID property, we check that it matches
355    // the viewRequestID set on the map.
356    //
357    // If the viewRequestID on the map has changed, that means that the user
358    // has changed the map view since this specific request was sent out, and
359    // therefore this tile does not need to be displayed (so we do not execute
360    // this code that turns its display on).
361    //
362    if (!this.viewRequestID ||
363        (this.map && this.viewRequestID == this.map.viewRequestID)) { 
364        this.style.display = ""; 
365    }
366    OpenLayers.Element.removeClass(this, "olImageLoadError");
367};
368
369/**
370 * Property: IMAGE_RELOAD_ATTEMPTS
371 * {Integer} How many times should we try to reload an image before giving up?
372 *           Default is 0
373 */
374OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
375
376/**
377 * Function: onImageLoadError
378 */
379OpenLayers.Util.onImageLoadError = function() {
380    this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
381    if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
382        var urls = this.urls;
383        if (urls && urls instanceof Array && urls.length > 1){
384            var src = this.src.toString();
385            var current_url, k;
386            for (k = 0; current_url = urls[k]; k++){
387                if(src.indexOf(current_url) != -1){
388                    break;
389                }
390            }
391            var guess = Math.floor(urls.length * Math.random());
392            var new_url = urls[guess];
393            k = 0;
394            while(new_url == current_url && k++ < 4){
395                guess = Math.floor(urls.length * Math.random());
396                new_url = urls[guess];
397            }
398            this.src = src.replace(current_url, new_url);
399        } else {
400            this.src = this.src;
401        }
402    } else {
403        OpenLayers.Element.addClass(this, "olImageLoadError");
404    }
405    this.style.display = "";
406};
407
408/**
409 * Property: alphaHackNeeded
410 * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
411 */
412OpenLayers.Util.alphaHackNeeded = null;
413
414/**
415 * Function: alphaHack
416 * Checks whether it's necessary (and possible) to use the png alpha
417 * hack which allows alpha transparency for png images under Internet
418 * Explorer.
419 *
420 * Returns:
421 * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
422 */
423OpenLayers.Util.alphaHack = function() {
424    if (OpenLayers.Util.alphaHackNeeded == null) {
425        var arVersion = navigator.appVersion.split("MSIE");
426        var version = parseFloat(arVersion[1]);
427        var filter = false;
428   
429        // IEs4Lin dies when trying to access document.body.filters, because
430        // the property is there, but requires a DLL that can't be provided. This
431        // means that we need to wrap this in a try/catch so that this can
432        // continue.
433   
434        try { 
435            filter = !!(document.body.filters);
436        } catch (e) {}   
437   
438        OpenLayers.Util.alphaHackNeeded = (filter && 
439                                           (version >= 5.5) && (version < 7));
440    }
441    return OpenLayers.Util.alphaHackNeeded;
442};
443
444/**
445 * Function: modifyAlphaImageDiv
446 *
447 * div - {DOMElement} Div containing Alpha-adjusted Image
448 * id - {String}
449 * px - {<OpenLayers.Pixel>}
450 * sz - {<OpenLayers.Size>}
451 * imgURL - {String}
452 * position - {String}
453 * border - {String}
454 * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
455 * opacity - {Float} Fractional value (0.0 - 1.0)
456 */ 
457OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, 
458                                               position, border, sizing, 
459                                               opacity) {
460
461    OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
462                                     null, null, opacity);
463
464    var img = div.childNodes[0];
465
466    if (imgURL) {
467        img.src = imgURL;
468    }
469    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
470                                     "relative", border);
471   
472    if (OpenLayers.Util.alphaHack()) {
473        if(div.style.display != "none") {
474            div.style.display = "inline-block";
475        }
476        if (sizing == null) {
477            sizing = "scale";
478        }
479       
480        div.style.filter = "progid:DXImageTransform.Microsoft" +
481                           ".AlphaImageLoader(src='" + img.src + "', " +
482                           "sizingMethod='" + sizing + "')";
483        if (parseFloat(div.style.opacity) >= 0.0 && 
484            parseFloat(div.style.opacity) < 1.0) {
485            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
486        }
487
488        img.style.filter = "alpha(opacity=0)";
489    }
490};
491
492/**
493 * Function: createAlphaImageDiv
494 *
495 * id - {String}
496 * px - {<OpenLayers.Pixel>}
497 * sz - {<OpenLayers.Size>}
498 * imgURL - {String}
499 * position - {String}
500 * border - {String}
501 * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
502 * opacity - {Float} Fractional value (0.0 - 1.0)
503 * delayDisplay - {Boolean} If true waits until the image has been
504 *                          loaded.
505 *
506 * Returns:
507 * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
508 *              needed for transparency in IE, it is added.
509 */ 
510OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, 
511                                               position, border, sizing, 
512                                               opacity, delayDisplay) {
513   
514    var div = OpenLayers.Util.createDiv();
515    var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
516                                          null, false);
517    div.appendChild(img);
518
519    if (delayDisplay) {
520        img.style.display = "none";
521        OpenLayers.Event.observe(img, "load",
522            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
523        OpenLayers.Event.observe(img, "error",
524            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
525    }
526
527    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
528                                        border, sizing, opacity);
529   
530    return div;
531};
532
533
534/**
535 * Function: upperCaseObject
536 * Creates a new hashtable and copies over all the keys from the
537 *     passed-in object, but storing them under an uppercased
538 *     version of the key at which they were stored.
539 *
540 * Parameters:
541 * object - {Object}
542 *
543 * Returns:
544 * {Object} A new Object with all the same keys but uppercased
545 */
546OpenLayers.Util.upperCaseObject = function (object) {
547    var uObject = {};
548    for (var key in object) {
549        uObject[key.toUpperCase()] = object[key];
550    }
551    return uObject;
552};
553
554/**
555 * Function: applyDefaults
556 * Takes an object and copies any properties that don't exist from
557 *     another properties, by analogy with OpenLayers.Util.extend() from
558 *     Prototype.js.
559 *
560 * Parameters:
561 * to - {Object} The destination object.
562 * from - {Object} The source object.  Any properties of this object that
563 *     are undefined in the to object will be set on the to object.
564 *
565 * Returns:
566 * {Object} A reference to the to object.  Note that the to argument is modified
567 *     in place and returned by this function.
568 */
569OpenLayers.Util.applyDefaults = function (to, from) {
570    to = to || {};
571    /*
572     * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
573     * prototype object" when calling hawOwnProperty if the source object is an
574     * instance of window.Event.
575     */
576    var fromIsEvt = typeof window.Event == "function"
577                    && from instanceof window.Event;
578
579    for (var key in from) {
580        if (to[key] === undefined ||
581            (!fromIsEvt && from.hasOwnProperty
582             && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
583            to[key] = from[key];
584        }
585    }
586    /**
587     * IE doesn't include the toString property when iterating over an object's
588     * properties with the for(property in object) syntax.  Explicitly check if
589     * the source has its own toString property.
590     */
591    if(!fromIsEvt && from && from.hasOwnProperty
592       && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
593        to.toString = from.toString;
594    }
595   
596    return to;
597};
598
599/**
600 * Function: getParameterString
601 *
602 * Parameters:
603 * params - {Object}
604 *
605 * Returns:
606 * {String} A concatenation of the properties of an object in
607 *          http parameter notation.
608 *          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
609 *          If a parameter is actually a list, that parameter will then
610 *          be set to a comma-seperated list of values (foo,bar) instead
611 *          of being URL escaped (foo%3Abar).
612 */
613OpenLayers.Util.getParameterString = function(params) {
614    var paramsArray = [];
615   
616    for (var key in params) {
617      var value = params[key];
618      if ((value != null) && (typeof value != 'function')) {
619        var encodedValue;
620        if (typeof value == 'object' && value.constructor == Array) {
621          /* value is an array; encode items and separate with "," */
622          var encodedItemArray = [];
623          var item;
624          for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) {
625            item = value[itemIndex];
626            encodedItemArray.push(encodeURIComponent(
627                (item === null || item === undefined) ? "" : item)
628            );
629          }
630          encodedValue = encodedItemArray.join(",");
631        }
632        else {
633          /* value is a string; simply encode */
634          encodedValue = encodeURIComponent(value);
635        }
636        paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
637      }
638    }
639   
640    return paramsArray.join("&");
641};
642
643/**
644 * Function: urlAppend
645 * Appends a parameter string to a url. This function includes the logic for
646 * using the appropriate character (none, & or ?) to append to the url before
647 * appending the param string.
648 *
649 * Parameters:
650 * url - {String} The url to append to
651 * paramStr - {String} The param string to append
652 *
653 * Returns:
654 * {String} The new url
655 */
656OpenLayers.Util.urlAppend = function(url, paramStr) {
657    var newUrl = url;
658    if(paramStr) {
659        var parts = (url + " ").split(/[?&]/);
660        newUrl += (parts.pop() === " " ?
661            paramStr :
662            parts.length ? "&" + paramStr : "?" + paramStr);
663    }
664    return newUrl;
665};
666
667/**
668 * Property: ImgPath
669 * {String} Default is ''.
670 */
671OpenLayers.ImgPath = '';
672
673/**
674 * Function: getImagesLocation
675 *
676 * Returns:
677 * {String} The fully formatted image location string
678 */
679OpenLayers.Util.getImagesLocation = function() {
680    return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
681};
682
683
684/**
685 * Function: Try
686 * Execute functions until one of them doesn't throw an error.
687 *     Capitalized because "try" is a reserved word in JavaScript.
688 *     Taken directly from OpenLayers.Util.Try()
689 *
690 * Parameters:
691 * [*] - {Function} Any number of parameters may be passed to Try()
692 *    It will attempt to execute each of them until one of them
693 *    successfully executes.
694 *    If none executes successfully, returns null.
695 *
696 * Returns:
697 * {*} The value returned by the first successfully executed function.
698 */
699OpenLayers.Util.Try = function() {
700    var returnValue = null;
701
702    for (var i=0, len=arguments.length; i<len; i++) {
703      var lambda = arguments[i];
704      try {
705        returnValue = lambda();
706        break;
707      } catch (e) {}
708    }
709
710    return returnValue;
711};
712
713
714/**
715 * Function: getNodes
716 *
717 * These could/should be made namespace aware?
718 *
719 * Parameters:
720 * p - {}
721 * tagName - {String}
722 *
723 * Returns:
724 * {Array}
725 */
726OpenLayers.Util.getNodes=function(p, tagName) {
727    var nodes = OpenLayers.Util.Try(
728        function () {
729            return OpenLayers.Util._getNodes(p.documentElement.childNodes,
730                                            tagName);
731        },
732        function () {
733            return OpenLayers.Util._getNodes(p.childNodes, tagName);
734        }
735    );
736    return nodes;
737};
738
739/**
740 * Function: _getNodes
741 *
742 * Parameters:
743 * nodes - {Array}
744 * tagName - {String}
745 *
746 * Returns:
747 * {Array}
748 */
749OpenLayers.Util._getNodes=function(nodes, tagName) {
750    var retArray = [];
751    for (var i=0, len=nodes.length; i<len; i++) {
752        if (nodes[i].nodeName==tagName) {
753            retArray.push(nodes[i]);
754        }
755    }
756
757    return retArray;
758};
759
760
761
762/**
763 * Function: getTagText
764 *
765 * Parameters:
766 * parent - {}
767 * item - {String}
768 * index - {Integer}
769 *
770 * Returns:
771 * {String}
772 */
773OpenLayers.Util.getTagText = function (parent, item, index) {
774    var result = OpenLayers.Util.getNodes(parent, item);
775    if (result && (result.length > 0))
776    {
777        if (!index) {
778            index=0;
779        }
780        if (result[index].childNodes.length > 1) {
781            return result.childNodes[1].nodeValue; 
782        }
783        else if (result[index].childNodes.length == 1) {
784            return result[index].firstChild.nodeValue; 
785        }
786    } else { 
787        return ""; 
788    }
789};
790
791/**
792 * Function: getXmlNodeValue
793 *
794 * Parameters:
795 * node - {XMLNode}
796 *
797 * Returns:
798 * {String} The text value of the given node, without breaking in firefox or IE
799 */
800OpenLayers.Util.getXmlNodeValue = function(node) {
801    var val = null;
802    OpenLayers.Util.Try( 
803        function() {
804            val = node.text;
805            if (!val) {
806                val = node.textContent;
807            }
808            if (!val) {
809                val = node.firstChild.nodeValue;
810            }
811        }, 
812        function() {
813            val = node.textContent;
814        }); 
815    return val;
816};
817
818/**
819 * Function: mouseLeft
820 *
821 * Parameters:
822 * evt - {Event}
823 * div - {HTMLDivElement}
824 *
825 * Returns:
826 * {Boolean}
827 */
828OpenLayers.Util.mouseLeft = function (evt, div) {
829    // start with the element to which the mouse has moved
830    var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
831    // walk up the DOM tree.
832    while (target != div && target != null) {
833        target = target.parentNode;
834    }
835    // if the target we stop at isn't the div, then we've left the div.
836    return (target != div);
837};
838
839/**
840 * Property: precision
841 * {Number} The number of significant digits to retain to avoid
842 * floating point precision errors.
843 *
844 * We use 14 as a "safe" default because, although IEEE 754 double floats
845 * (standard on most modern operating systems) support up to about 16
846 * significant digits, 14 significant digits are sufficient to represent
847 * sub-millimeter accuracy in any coordinate system that anyone is likely to
848 * use with OpenLayers.
849 *
850 * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
851 * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
852 * with certain projections, e.g. spherical Mercator.
853 *
854 */
855OpenLayers.Util.DEFAULT_PRECISION = 14;
856
857/**
858 * Function: toFloat
859 * Convenience method to cast an object to a Number, rounded to the
860 * desired floating point precision.
861 *
862 * Parameters:
863 * number    - {Number} The number to cast and round.
864 * precision - {Number} An integer suitable for use with
865 *      Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
866 *      If set to 0, no rounding is performed.
867 *
868 * Returns:
869 * {Number} The cast, rounded number.
870 */
871OpenLayers.Util.toFloat = function (number, precision) {
872    if (precision == null) {
873        precision = OpenLayers.Util.DEFAULT_PRECISION;
874    }
875    var number;
876    if (precision == 0) {
877        number = parseFloat(number);
878    } else {
879        number = parseFloat(parseFloat(number).toPrecision(precision));
880    }
881    return number;
882};
883
884/**
885 * Function: rad
886 *
887 * Parameters:
888 * x - {Float}
889 *
890 * Returns:
891 * {Float}
892 */
893OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
894
895/**
896 * Function: deg
897 *
898 * Parameters:
899 * x - {Float}
900 *
901 * Returns:
902 * {Float}
903 */
904OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
905
906/**
907 * Property: VincentyConstants
908 * {Object} Constants for Vincenty functions.
909 */
910OpenLayers.Util.VincentyConstants = {
911    a: 6378137,
912    b: 6356752.3142,
913    f: 1/298.257223563
914};
915
916/**
917 * APIFunction: distVincenty
918 * Given two objects representing points with geographic coordinates, this
919 *     calculates the distance between those points on the surface of an
920 *     ellipsoid.
921 *
922 * Parameters:
923 * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
924 * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
925 *
926 * Returns:
927 * {Float} The distance (in km) between the two input points as measured on an
928 *     ellipsoid.  Note that the input point objects must be in geographic
929 *     coordinates (decimal degrees) and the return distance is in kilometers.
930 */
931OpenLayers.Util.distVincenty = function(p1, p2) {
932    var ct = OpenLayers.Util.VincentyConstants;
933    var a = ct.a, b = ct.b, f = ct.f;
934
935    var L = OpenLayers.Util.rad(p2.lon - p1.lon);
936    var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
937    var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
938    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
939    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
940    var lambda = L, lambdaP = 2*Math.PI;
941    var iterLimit = 20;
942    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
943        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
944        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
945        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
946        if (sinSigma==0) {
947            return 0;  // co-incident points
948        }
949        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
950        var sigma = Math.atan2(sinSigma, cosSigma);
951        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
952        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
953        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
954        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
955        lambdaP = lambda;
956        lambda = L + (1-C) * f * Math.sin(alpha) *
957        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
958    }
959    if (iterLimit==0) {
960        return NaN;  // formula failed to converge
961    }
962    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
963    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
964    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
965    var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
966        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
967    var s = b*A*(sigma-deltaSigma);
968    var d = s.toFixed(3)/1000; // round to 1mm precision
969    return d;
970};
971
972/**
973 * APIFunction: destinationVincenty
974 * Calculate destination point given start point lat/long (numeric degrees),
975 * bearing (numeric degrees) & distance (in m).
976 * Adapted from Chris Veness work, see
977 * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
978 *
979 * Parameters:
980 * lonlat  - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
981 *     properties) The start point.
982 * brng     - {Float} The bearing (degrees).
983 * distance - {Float} The ground distance (meters).
984 *
985 * Returns:
986 * {<OpenLayers.LonLat>} The destination point.
987 */
988OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) {
989    var u = OpenLayers.Util;
990    var ct = u.VincentyConstants;
991    var a = ct.a, b = ct.b, f = ct.f;
992
993    var lon1 = lonlat.lon;
994    var lat1 = lonlat.lat;
995
996    var s = dist;
997    var alpha1 = u.rad(brng);
998    var sinAlpha1 = Math.sin(alpha1);
999    var cosAlpha1 = Math.cos(alpha1);
1000
1001    var tanU1 = (1-f) * Math.tan(u.rad(lat1));
1002    var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1;
1003    var sigma1 = Math.atan2(tanU1, cosAlpha1);
1004    var sinAlpha = cosU1 * sinAlpha1;
1005    var cosSqAlpha = 1 - sinAlpha*sinAlpha;
1006    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
1007    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
1008    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
1009
1010    var sigma = s / (b*A), sigmaP = 2*Math.PI;
1011    while (Math.abs(sigma-sigmaP) > 1e-12) {
1012        var cos2SigmaM = Math.cos(2*sigma1 + sigma);
1013        var sinSigma = Math.sin(sigma);
1014        var cosSigma = Math.cos(sigma);
1015        var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
1016            B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
1017        sigmaP = sigma;
1018        sigma = s / (b*A) + deltaSigma;
1019    }
1020
1021    var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1;
1022    var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1,
1023        (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp));
1024    var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1);
1025    var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
1026    var L = lambda - (1-C) * f * sinAlpha *
1027        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
1028
1029    var revAz = Math.atan2(sinAlpha, -tmp);  // final bearing
1030
1031    return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
1032};
1033
1034/**
1035 * Function: getParameters
1036 * Parse the parameters from a URL or from the current page itself into a
1037 *     JavaScript Object. Note that parameter values with commas are separated
1038 *     out into an Array.
1039 *
1040 * Parameters:
1041 * url - {String} Optional url used to extract the query string.
1042 *                If null, query string is taken from page location.
1043 *
1044 * Returns:
1045 * {Object} An object of key/value pairs from the query string.
1046 */
1047OpenLayers.Util.getParameters = function(url) {
1048    // if no url specified, take it from the location bar
1049    url = url || window.location.href;
1050
1051    //parse out parameters portion of url string
1052    var paramsString = "";
1053    if (OpenLayers.String.contains(url, '?')) {
1054        var start = url.indexOf('?') + 1;
1055        var end = OpenLayers.String.contains(url, "#") ?
1056                    url.indexOf('#') : url.length;
1057        paramsString = url.substring(start, end);
1058    }
1059
1060    var parameters = {};
1061    var pairs = paramsString.split(/[&;]/);
1062    for(var i=0, len=pairs.length; i<len; ++i) {
1063        var keyValue = pairs[i].split('=');
1064        if (keyValue[0]) {
1065            var key = decodeURIComponent(keyValue[0]);
1066            var value = keyValue[1] || ''; //empty string if no value
1067
1068            //decode individual values (being liberal by replacing "+" with " ")
1069            value = decodeURIComponent(value.replace(/\+/g, " ")).split(",");
1070
1071            //if there's only one value, do not return as array                   
1072            if (value.length == 1) {
1073                value = value[0];
1074            }               
1075           
1076            parameters[key] = value;
1077         }
1078     }
1079    return parameters;
1080};
1081
1082/**
1083 * Function: getArgs
1084 * *Deprecated*.  Will be removed in 3.0.  Please use instead
1085 *     <OpenLayers.Util.getParameters>
1086 *
1087 * Parameters:
1088 * url - {String} Optional url used to extract the query string.
1089 *                If null, query string is taken from page location.
1090 *
1091 * Returns:
1092 * {Object} An object of key/value pairs from the query string.
1093 */
1094OpenLayers.Util.getArgs = function(url) {
1095    OpenLayers.Console.warn(
1096        OpenLayers.i18n(
1097            "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
1098        )
1099    );
1100    return OpenLayers.Util.getParameters(url);
1101};
1102
1103/**
1104 * Property: lastSeqID
1105 * {Integer} The ever-incrementing count variable.
1106 *           Used for generating unique ids.
1107 */
1108OpenLayers.Util.lastSeqID = 0;
1109
1110/**
1111 * Function: createUniqueID
1112 * Create a unique identifier for this session.  Each time this function
1113 *     is called, a counter is incremented.  The return will be the optional
1114 *     prefix (defaults to "id_") appended with the counter value.
1115 *
1116 * Parameters:
1117 * prefix {String} Optionsal string to prefix unique id. Default is "id_".
1118 *
1119 * Returns:
1120 * {String} A unique id string, built on the passed in prefix.
1121 */
1122OpenLayers.Util.createUniqueID = function(prefix) {
1123    if (prefix == null) {
1124        prefix = "id_";
1125    }
1126    OpenLayers.Util.lastSeqID += 1; 
1127    return prefix + OpenLayers.Util.lastSeqID;       
1128};
1129
1130/**
1131 * Constant: INCHES_PER_UNIT
1132 * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
1133 * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
1134 * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
1135 * and PROJ.4 (http://trac.osgeo.org/proj/)
1136 * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
1137 * The hardcoded table of PROJ.4 units are in pj_units.c.
1138 */
1139OpenLayers.INCHES_PER_UNIT = { 
1140    'inches': 1.0,
1141    'ft': 12.0,
1142    'mi': 63360.0,
1143    'm': 39.3701,
1144    'km': 39370.1,
1145    'dd': 4374754,
1146    'yd': 36
1147};
1148OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
1149OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
1150OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
1151
1152// Units from CS-Map
1153OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
1154OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
1155    "Inch": OpenLayers.INCHES_PER_UNIT.inches,
1156    "Meter": 1.0 / OpenLayers.METERS_PER_INCH,   //EPSG:9001
1157    "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH,   //EPSG:9003
1158    "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9002
1159    "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH,   //EPSG:9005
1160    "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH,   //EPSG:9041
1161    "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH,   //EPSG:9094
1162    "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
1163    "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
1164    "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
1165    "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
1166    "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9036
1167    "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
1168    "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH,   //EPSG:9040
1169    "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH,   //EPSG:9084
1170    "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH,   //EPSG:9085
1171    "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH,   //EPSG:9086
1172    "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH,   //EPSG:9087
1173    "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH,   //EPSG:9080
1174    "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH,   //EPSG:9081
1175    "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH,   //EPSG:9082
1176    "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH,   //EPSG:9083
1177    "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
1178    "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9096
1179    "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9093
1180    "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH,   //EPSG:9030
1181    "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
1182    "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
1183    "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
1184    "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
1185    "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
1186    "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
1187    "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
1188    "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH,   //EPSG:9031
1189    "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
1190    "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9038
1191    "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9033
1192    "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9062
1193    "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9042
1194    "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH,   //EPSG:9039
1195    "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH,   //EPSG:9034
1196    "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH,   //EPSG:9063
1197    "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH,   //EPSG:9043
1198    "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
1199    "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH,   //EPSG:9097
1200    "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH,   //EPSG:9098
1201    "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
1202    "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
1203    "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
1204    "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
1205    "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
1206    "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
1207    "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
1208    "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
1209    "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
1210    "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
1211    "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
1212});
1213
1214//unit abbreviations supported by PROJ.4
1215OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
1216    "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
1217    "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
1218    "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
1219    "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
1220    "kmi": OpenLayers.INCHES_PER_UNIT["nmi"],    //International Nautical Mile
1221    "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
1222    "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"],  //International Chain
1223    "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
1224    "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
1225    "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"],        //U.S. Surveyor's Foot
1226    "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"],        //U.S. Surveyor's Yard
1227    "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
1228    "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"],   //U.S. Surveyor's Statute Mile
1229    "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"],  //Indian Yard
1230    "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"],  //Indian Foot
1231    "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH  //Indian Chain
1232});
1233
1234/**
1235 * Constant: DOTS_PER_INCH
1236 * {Integer} 72 (A sensible default)
1237 */
1238OpenLayers.DOTS_PER_INCH = 72;
1239
1240/**
1241 * Function: normalizeScale
1242 *
1243 * Parameters:
1244 * scale - {float}
1245 *
1246 * Returns:
1247 * {Float} A normalized scale value, in 1 / X format.
1248 *         This means that if a value less than one ( already 1/x) is passed
1249 *         in, it just returns scale directly. Otherwise, it returns
1250 *         1 / scale
1251 */
1252OpenLayers.Util.normalizeScale = function (scale) {
1253    var normScale = (scale > 1.0) ? (1.0 / scale) 
1254                                  : scale;
1255    return normScale;
1256};
1257
1258/**
1259 * Function: getResolutionFromScale
1260 *
1261 * Parameters:
1262 * scale - {Float}
1263 * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
1264 *                  Default is degrees
1265 *
1266 * Returns:
1267 * {Float} The corresponding resolution given passed-in scale and unit
1268 *     parameters.  If the given scale is falsey, the returned resolution will
1269 *     be undefined.
1270 */
1271OpenLayers.Util.getResolutionFromScale = function (scale, units) {
1272    var resolution;
1273    if (scale) {
1274        if (units == null) {
1275            units = "degrees";
1276        }
1277        var normScale = OpenLayers.Util.normalizeScale(scale);
1278        resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
1279                                        * OpenLayers.DOTS_PER_INCH);       
1280    }
1281    return resolution;
1282};
1283
1284/**
1285 * Function: getScaleFromResolution
1286 *
1287 * Parameters:
1288 * resolution - {Float}
1289 * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
1290 *                  Default is degrees
1291 *
1292 * Returns:
1293 * {Float} The corresponding scale given passed-in resolution and unit
1294 *         parameters.
1295 */
1296OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
1297
1298    if (units == null) {
1299        units = "degrees";
1300    }
1301
1302    var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
1303                    OpenLayers.DOTS_PER_INCH;
1304    return scale;
1305};
1306
1307/**
1308 * Function: safeStopPropagation
1309 * *Deprecated*. This function has been deprecated. Please use directly
1310 *     <OpenLayers.Event.stop> passing 'true' as the 2nd
1311 *     argument (preventDefault)
1312 *
1313 * Safely stop the propagation of an event *without* preventing
1314 *   the default browser action from occurring.
1315 *
1316 * Parameter:
1317 * evt - {Event}
1318 */
1319OpenLayers.Util.safeStopPropagation = function(evt) {
1320    OpenLayers.Event.stop(evt, true);
1321};
1322
1323/**
1324 * Function: pagePositon
1325 * Calculates the position of an element on the page.
1326 *
1327 * Parameters:
1328 * forElement - {DOMElement}
1329 *
1330 * Returns:
1331 * {Array} two item array, L value then T value.
1332 */
1333OpenLayers.Util.pagePosition = function(forElement) {
1334    var valueT = 0, valueL = 0;
1335
1336    var element = forElement;
1337    var child = forElement;
1338    while(element) {
1339
1340        if(element == document.body) {
1341            if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
1342                break;
1343            }
1344        }
1345       
1346        valueT += element.offsetTop  || 0;
1347        valueL += element.offsetLeft || 0;
1348
1349        child = element;
1350        try {
1351            // wrapping this in a try/catch because IE chokes on the offsetParent
1352            element = element.offsetParent;
1353        } catch(e) {
1354            OpenLayers.Console.error(OpenLayers.i18n(
1355                                  "pagePositionFailed",{'elemId':element.id}));
1356            break;
1357        }
1358    }
1359
1360    element = forElement;
1361    while(element) {
1362        valueT -= element.scrollTop  || 0;
1363        valueL -= element.scrollLeft || 0;
1364        element = element.parentNode;
1365    }
1366   
1367    return [valueL, valueT];
1368};
1369
1370
1371/**
1372 * Function: isEquivalentUrl
1373 * Test two URLs for equivalence.
1374 *
1375 * Setting 'ignoreCase' allows for case-independent comparison.
1376 *
1377 * Comparison is based on:
1378 *  - Protocol
1379 *  - Host (evaluated without the port)
1380 *  - Port (set 'ignorePort80' to ignore "80" values)
1381 *  - Hash ( set 'ignoreHash' to disable)
1382 *  - Pathname (for relative <-> absolute comparison)
1383 *  - Arguments (so they can be out of order)
1384 * 
1385 * Parameters:
1386 * url1 - {String}
1387 * url2 - {String}
1388 * options - {Object} Allows for customization of comparison:
1389 *                    'ignoreCase' - Default is True
1390 *                    'ignorePort80' - Default is True
1391 *                    'ignoreHash' - Default is True
1392 *
1393 * Returns:
1394 * {Boolean} Whether or not the two URLs are equivalent
1395 */
1396OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
1397    options = options || {};
1398
1399    OpenLayers.Util.applyDefaults(options, {
1400        ignoreCase: true,
1401        ignorePort80: true,
1402        ignoreHash: true
1403    });
1404
1405    var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
1406    var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
1407
1408    //compare all keys except for "args" (treated below)
1409    for(var key in urlObj1) {
1410        if(key !== "args") {
1411            if(urlObj1[key] != urlObj2[key]) {
1412                return false;
1413            }
1414        }
1415    }
1416
1417    // compare search args - irrespective of order
1418    for(var key in urlObj1.args) {
1419        if(urlObj1.args[key] != urlObj2.args[key]) {
1420            return false;
1421        }
1422        delete urlObj2.args[key];
1423    }
1424    // urlObj2 shouldn't have any args left
1425    for(var key in urlObj2.args) {
1426        return false;
1427    }
1428   
1429    return true;
1430};
1431
1432/**
1433 * Function: createUrlObject
1434 *
1435 * Parameters:
1436 * url - {String}
1437 * options - {Object} A hash of options.  Can be one of:
1438 *            ignoreCase: lowercase url,
1439 *            ignorePort80: don't include explicit port if port is 80,
1440 *            ignoreHash: Don't include part of url after the hash (#).
1441 *
1442 * Returns:
1443 * {Object} An object with separate url, a, port, host, and args parsed out
1444 *          and ready for comparison
1445 */
1446OpenLayers.Util.createUrlObject = function(url, options) {
1447    options = options || {};
1448
1449    // deal with relative urls first
1450    if(!(/^\w+:\/\//).test(url)) {
1451        var loc = window.location;
1452        var port = loc.port ? ":" + loc.port : "";
1453        var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port;
1454        if(url.indexOf("/") === 0) {
1455            // full pathname
1456            url = fullUrl + url;
1457        } else {
1458            // relative to current path
1459            var parts = loc.pathname.split("/");
1460            parts.pop();
1461            url = fullUrl + parts.join("/") + "/" + url;
1462        }
1463    }
1464 
1465    if (options.ignoreCase) {
1466        url = url.toLowerCase(); 
1467    }
1468
1469    var a = document.createElement('a');
1470    a.href = url;
1471   
1472    var urlObject = {};
1473   
1474    //host (without port)
1475    urlObject.host = a.host.split(":").shift();
1476
1477    //protocol
1478    urlObject.protocol = a.protocol; 
1479
1480    //port (get uniform browser behavior with port 80 here)
1481    if(options.ignorePort80) {
1482        urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port;
1483    } else {
1484        urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port;
1485    }
1486
1487    //hash
1488    urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash; 
1489   
1490    //args
1491    var queryString = a.search;
1492    if (!queryString) {
1493        var qMark = url.indexOf("?");
1494        queryString = (qMark != -1) ? url.substr(qMark) : "";
1495    }
1496    urlObject.args = OpenLayers.Util.getParameters(queryString);
1497
1498    //pathname (uniform browser behavior with leading "/")
1499    urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
1500   
1501    return urlObject; 
1502};
1503 
1504/**
1505 * Function: removeTail
1506 * Takes a url and removes everything after the ? and #
1507 *
1508 * Parameters:
1509 * url - {String} The url to process
1510 *
1511 * Returns:
1512 * {String} The string with all queryString and Hash removed
1513 */
1514OpenLayers.Util.removeTail = function(url) {
1515    var head = null;
1516   
1517    var qMark = url.indexOf("?");
1518    var hashMark = url.indexOf("#");
1519
1520    if (qMark == -1) {
1521        head = (hashMark != -1) ? url.substr(0,hashMark) : url;
1522    } else {
1523        head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) 
1524                                  : url.substr(0, qMark);
1525    }
1526    return head;
1527};
1528
1529
1530/**
1531 * Function: getBrowserName
1532 *
1533 * Returns:
1534 * {String} A string which specifies which is the current
1535 *          browser in which we are running.
1536 *
1537 *          Currently-supported browser detection and codes:
1538 *           * 'opera' -- Opera
1539 *           * 'msie'  -- Internet Explorer
1540 *           * 'safari' -- Safari
1541 *           * 'firefox' -- FireFox
1542 *           * 'mozilla' -- Mozilla
1543 *
1544 *          If we are unable to property identify the browser, we
1545 *           return an empty string.
1546 */
1547OpenLayers.Util.getBrowserName = function() {
1548    var browserName = "";
1549   
1550    var ua = navigator.userAgent.toLowerCase();
1551    if ( ua.indexOf( "opera" ) != -1 ) {
1552        browserName = "opera";
1553    } else if ( ua.indexOf( "msie" ) != -1 ) {
1554        browserName = "msie";
1555    } else if ( ua.indexOf( "safari" ) != -1 ) {
1556        browserName = "safari";
1557    } else if ( ua.indexOf( "mozilla" ) != -1 ) {
1558        if ( ua.indexOf( "firefox" ) != -1 ) {
1559            browserName = "firefox";
1560        } else {
1561            browserName = "mozilla";
1562        }
1563    }
1564   
1565    return browserName;
1566};
1567
1568
1569
1570   
1571/**
1572 * Method: getRenderedDimensions
1573 * Renders the contentHTML offscreen to determine actual dimensions for
1574 *     popup sizing. As we need layout to determine dimensions the content
1575 *     is rendered -9999px to the left and absolute to ensure the
1576 *     scrollbars do not flicker
1577 *     
1578 * Parameters:
1579 * contentHTML
1580 * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
1581 *     specified, we fix that dimension of the div to be measured. This is
1582 *     useful in the case where we have a limit in one dimension and must
1583 *     therefore meaure the flow in the other dimension.
1584 * options - {Object}
1585 *     displayClass - {String} Optional parameter.  A CSS class name(s) string
1586 *         to provide the CSS context of the rendered content.
1587 *     containerElement - {DOMElement} Optional parameter. Insert the HTML to
1588 *         this node instead of the body root when calculating dimensions.
1589 *
1590 * Returns:
1591 * {OpenLayers.Size}
1592 */
1593OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
1594   
1595    var w, h;
1596   
1597    // create temp container div with restricted size
1598    var container = document.createElement("div");
1599    container.style.visibility = "hidden";
1600       
1601    var containerElement = (options && options.containerElement) 
1602        ? options.containerElement : document.body;
1603
1604    //fix a dimension, if specified.
1605    if (size) {
1606        if (size.w) {
1607            w = size.w;
1608            container.style.width = w + "px";
1609        } else if (size.h) {
1610            h = size.h;
1611            container.style.height = h + "px";
1612        }
1613    }
1614
1615    //add css classes, if specified
1616    if (options && options.displayClass) {
1617        container.className = options.displayClass;
1618    }
1619   
1620    // create temp content div and assign content
1621    var content = document.createElement("div");
1622    content.innerHTML = contentHTML;
1623   
1624    // we need overflow visible when calculating the size
1625    content.style.overflow = "visible";
1626    if (content.childNodes) {
1627        for (var i=0, l=content.childNodes.length; i<l; i++) {
1628            if (!content.childNodes[i].style) continue;
1629            content.childNodes[i].style.overflow = "visible";
1630        }
1631    }
1632   
1633    // add content to restricted container
1634    container.appendChild(content);
1635   
1636    // append container to body for rendering
1637    containerElement.appendChild(container);
1638   
1639    // Opera and IE7 can't handle a node with position:aboslute if it inherits
1640    // position:absolute from a parent.
1641    var parentHasPositionAbsolute = false;
1642    var parent = container.parentNode;
1643    while (parent && parent.tagName.toLowerCase()!="body") {
1644        var parentPosition = OpenLayers.Element.getStyle(parent, "position");
1645        if(parentPosition == "absolute") {
1646            parentHasPositionAbsolute = true;
1647            break;
1648        } else if (parentPosition && parentPosition != "static") {
1649            break;
1650        }
1651        parent = parent.parentNode;
1652    }
1653
1654    if(!parentHasPositionAbsolute) {
1655        container.style.position = "absolute";
1656    }
1657   
1658    // calculate scroll width of content and add corners and shadow width
1659    if (!w) {
1660        w = parseInt(content.scrollWidth);
1661   
1662        // update container width to allow height to adjust
1663        container.style.width = w + "px";
1664    }       
1665    // capture height and add shadow and corner image widths
1666    if (!h) {
1667        h = parseInt(content.scrollHeight);
1668    }
1669
1670    // remove elements
1671    container.removeChild(content);
1672    containerElement.removeChild(container);
1673   
1674    return new OpenLayers.Size(w, h);
1675};
1676
1677/**
1678 * APIFunction: getScrollbarWidth
1679 * This function has been modified by the OpenLayers from the original version,
1680 *     written by Matthew Eernisse and released under the Apache 2
1681 *     license here:
1682 *
1683 *     http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
1684 *
1685 *     It has been modified simply to cache its value, since it is physically
1686 *     impossible that this code could ever run in more than one browser at
1687 *     once.
1688 *
1689 * Returns:
1690 * {Integer}
1691 */
1692OpenLayers.Util.getScrollbarWidth = function() {
1693   
1694    var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
1695   
1696    if (scrollbarWidth == null) {
1697        var scr = null;
1698        var inn = null;
1699        var wNoScroll = 0;
1700        var wScroll = 0;
1701   
1702        // Outer scrolling div
1703        scr = document.createElement('div');
1704        scr.style.position = 'absolute';
1705        scr.style.top = '-1000px';
1706        scr.style.left = '-1000px';
1707        scr.style.width = '100px';
1708        scr.style.height = '50px';
1709        // Start with no scrollbar
1710        scr.style.overflow = 'hidden';
1711   
1712        // Inner content div
1713        inn = document.createElement('div');
1714        inn.style.width = '100%';
1715        inn.style.height = '200px';
1716   
1717        // Put the inner div in the scrolling div
1718        scr.appendChild(inn);
1719        // Append the scrolling div to the doc
1720        document.body.appendChild(scr);
1721   
1722        // Width of the inner div sans scrollbar
1723        wNoScroll = inn.offsetWidth;
1724   
1725        // Add the scrollbar
1726        scr.style.overflow = 'scroll';
1727        // Width of the inner div width scrollbar
1728        wScroll = inn.offsetWidth;
1729   
1730        // Remove the scrolling div from the doc
1731        document.body.removeChild(document.body.lastChild);
1732   
1733        // Pixel width of the scroller
1734        OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
1735        scrollbarWidth = OpenLayers.Util._scrollbarWidth;
1736    }
1737
1738    return scrollbarWidth;
1739};
1740
1741/**
1742 * APIFunction: getFormattedLonLat
1743 * This function will return latitude or longitude value formatted as
1744 *
1745 * Parameters:
1746 * coordinate - {Float} the coordinate value to be formatted
1747 * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
1748 *          to be formatted (default = lat)
1749 * dmsOption - {String} specify the precision of the output can be one of:
1750 *           'dms' show degrees minutes and seconds
1751 *           'dm' show only degrees and minutes
1752 *           'd' show only degrees
1753 *
1754 * Returns:
1755 * {String} the coordinate value formatted as a string
1756 */
1757OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
1758    if (!dmsOption) {
1759        dmsOption = 'dms';    //default to show degree, minutes, seconds
1760    }
1761    var abscoordinate = Math.abs(coordinate)
1762    var coordinatedegrees = Math.floor(abscoordinate);
1763
1764    var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
1765    var tempcoordinateminutes = coordinateminutes;
1766    coordinateminutes = Math.floor(coordinateminutes);
1767    var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
1768    coordinateseconds =  Math.round(coordinateseconds*10);
1769    coordinateseconds /= 10;
1770
1771    if( coordinatedegrees < 10 ) {
1772        coordinatedegrees = "0" + coordinatedegrees;
1773    }
1774    var str = coordinatedegrees + "\u00B0";
1775
1776    if (dmsOption.indexOf('dm') >= 0) {
1777        if( coordinateminutes < 10 ) {
1778            coordinateminutes = "0" + coordinateminutes;
1779        }
1780        str += coordinateminutes + "'";
1781 
1782        if (dmsOption.indexOf('dms') >= 0) {
1783            if( coordinateseconds < 10 ) {
1784                coordinateseconds = "0" + coordinateseconds;
1785            }
1786            str += coordinateseconds + '"';
1787        }
1788    }
1789   
1790    if (axis == "lon") {
1791        str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E");
1792    } else {
1793        str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N");
1794    }
1795    return str;
1796};
1797
Note: See TracBrowser for help on using the repository browser.