Source: BKGWebMap/Util.js

/*
 * Copyright (c) 2013 Bundesamt by Kartographie und Geodäsie.
 * See license.txt in the BKG WebMap distribution or repository for the
 * full text of the license.
 *
 * Author: Dirk Thalheim
 */

/**
 * @namespace BKGWebMap.Util
 */
BKGWebMap.Util = BKGWebMap.Util || {};

/**
 * Funktion zur Filterung von Elementen aus einer Liste.
 * @param {Array} elements - die zu durchsuchenden Elemente
 * @param {function} filter - die Filterfunktion
 */
BKGWebMap.Util.grep = function(elements, filter) {
    var results = [];

    if(!elements || !elements.length) {
        return results;
    }

    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        if(filter(element, i)) results.push(element);
    }
    return results;
};

/**
 * Hilfsfunktion für die Iteration durch Elemente einer Liste.
 * @param {Array} elements - die zu durchsuchenden Elemente
 * @param {function} method - Funktion für jeden Iterationsschritt
 */
BKGWebMap.Util.each = function(elements, method) {
    if(!elements || !elements.length) {
        return;
    }

    for (var i = 0; i < elements.length; i++) {
        method( i, elements[i] );
    }
};

/**
 * Hilfsfunktion um Elemente einer Liste zu 'mappen'. Es können weitere statische Argumente übergeben werden, die an
 * die Methode übergeben werden.
 *
 * @param {function} method - Funktion für jeden Iterationsschritt
 * @param {Array} elements - die zu durchsuchenden Elemente
 * @return {Array}
 */
BKGWebMap.Util.map = function(method, elements) {
    if(!elements || !elements.length) {
        return [];
    }

    // weitere optionale Argumente ermitteln
    var staticArgs = (arguments.length == 2) ? [] : Array.prototype.slice.call(arguments, 2, arguments.length);

    var result = [];
    for (var i = 0; i < elements.length; i++) {
        var args = [elements[i]];
        args = args.concat(staticArgs);
        result.push( method.apply( this, args ) );
    }
    return result;
};

/**
 * Kapitalisiert den gegebenen String.
 * @param {string} str - Der zu kapitalisierende String
 * @returns {string}
 */
BKGWebMap.Util.capitalize = function(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
};

BKGWebMap.Util.getEventTarget = function (e) {
    var target;
    if (e.target) target = e.target;
   	else if (e.srcElement) target = e.srcElement;

   	if (target.nodeType == 3) // defeat Safari bug
   		target = targ.parentNode;

    return target;
};

/**
 * Gibt den Index des elements innerhalb seiner DOM-Ebene an.
 *
 * @param {node} element
 * @returns {number}
 */
BKGWebMap.Util.getIndex = function(element) {
    var k=0, e=element;
    while (e = e.previousSibling) { k++;}
    return k;
};

/**
 * Berechnet die Datenausdehnung für eine Featurecollection. Über geometry kann eine alternative
 * Geometrie aus den Attributen verwendet werden.
 *
 * @param {Array<OpenLayers.Feature>} features - Die FeatureCollection
 * @param {string} geometry - Attributname der alternativen Geometrie
 * @return OpenLayers.Bounds oder <code>null</code> wenn keine Features gegeben sind
 */
BKGWebMap.Util.getDataExtent = function (features, geometry) {
    var bounds = new OpenLayers.Bounds();
    var g = geometry;

    BKGWebMap.Util.each(
            features,
            function(index, feature) {
                var geometry = g ? feature.attributes[g] : feature.geometry;
                bounds.extend(geometry.getBounds());
            }
    );
    return bounds;
};

BKGWebMap.Util.getSize = function(element) {
    var cStyle = element.ownerDocument && element.ownerDocument.defaultView &&
                    element.ownerDocument.defaultView.getComputedStyle &&
                    element.ownerDocument.defaultView.getComputedStyle(element, null);
    var w = cStyle && cStyle.getPropertyValue('width') || '';
    var h = cStyle && cStyle.getPropertyValue('height') || '';
    if (w && w.indexOf('.') > -1) {
    		w = parseFloat(w) +
                    parseInt(cStyle.getPropertyValue('padding-left')) +
                    parseInt(cStyle.getPropertyValue('padding-right')) +
                    parseInt(cStyle.getPropertyValue('border-left-width')) +
                    parseInt(cStyle.getPropertyValue('border-right-width'));
    } else {
        w = element.offsetWidth;
    }
    if (h && h.indexOf('.') > -1) {
    		h = parseFloat(w) +
                    parseInt(cStyle.getPropertyValue('padding-top')) +
                    parseInt(cStyle.getPropertyValue('padding-bottom')) +
                    parseInt(cStyle.getPropertyValue('border-top-width')) +
                    parseInt(cStyle.getPropertyValue('border-bottom-width'));
    } else {
        h = element.offsetWidth;
    }
    return new OpenLayers.Size(w, h);
};

/**
 * Hilfsfunktion zum Stoppen eines Events
 * @param {Event} evt - Der zu stoppende Event
 */
BKGWebMap.Util.stopEvent = function(evt) {
    OpenLayers.Event.stop(evt, true);
};

/**
 * Hilfsmethode zum ermitteln von berechneten Style-Eigenschaften
 * @param {HTMLElement} element - das zu untersuchende Element
 * @param {string} property - der Name für die CSS-Eigenschaft
 * @return {string}
 */
BKGWebMap.Util.getStyle = function(element, property) {
    if(window.getComputedStyle) {
        // Non IE
        return getComputedStyle(element, null)[property];
    } else {
        // IE < 9
        return element.currentStyle[property];
    }
};

/**
 * Testet ob eine Variable leer ist.
 * @param obj {*} das zu testende Objekt
 * @return {boolean}
 */
BKGWebMap.Util.isEmpty = function(obj) {

    if (obj === undefined) return true;

    // null and undefined are "empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and toValue enumeration bugs in IE < 9
    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) return false;
    }

    return true;
};

/**
 * Ermittelt die Projektion, die per URL-Parameter übergeben wurde
 * @param def {string} Default Projektion
 * @param key {string} Name des Parameters
 * @return {string}
 */
BKGWebMap.Util.getProjection = function(def, key) {
  def = def || BKGWebMap.PROJECTION;
  key = key || 'CRS';
  var parameters = OpenLayers.Util.getParameters();
  return (key in parameters) ? parameters[key] : def;
};

/**
 * Ermittelt den zur Projektion passenden Extent.
 * @param projection {string} Name der Projektion
 * @param extents {object} Map mit Extents
 * @return {Array}
 */
BKGWebMap.Util.getMaxExtent = function(projection, extents) {
  projection = projection || BKGWebMap.PROJECTION;
  return (projection in extents) ? extents[projection] : null;
};

/**
 * Erstellt die BKG Service-URL für den angegebenen Dienst. Hierbei wird das Protokoll der Webanwendung (HTTP/HTTPS).
 *
 * Wenn BKGWebMap.UUID gesetzt ist, wird diese zur Authentifizierung des Dienstes verwendet.
 *
 * Wenn BKGWebMap.APP_ID und BKGWebMap.APP_DOMAIN gesetzt sind, wird ein Session-Token generiert, der zur
 * Authentifizierung des Dienstes verwendet.
 *
 * @param {string} service - Name des Dienstet (z.B. wmts_webatlasde)
 * @param {string} [path=null] - Pfad des Dienstes (z.B. tile/1.0.0), default: null
 * @param {boolean} [ignoreUuid=false] - soll UUID ignoriert werden, default: false
 * @param {boolean} [useSgx=false] - soll sgx Subdomain für Zugriff verwendet werden, default: false
 * @return {string}
 */
BKGWebMap.Util.getServiceUrl = function(service , path, ignoreUuid, useSgx) {
  var path = (path) ? '/' + path : '';
  var ignoreUuid = ignoreUuid || false;
  var useSgx = useSgx || false;

  var base = BKGWebMap.BASE_URL;
  if(useSgx)
    base = base.replace("/sg.", "/sgx.");
  // Damit Cookies bei XHR gesendet werden, muss das Protokoll der Seite übereinstimmen
  var useHttps = window.location.protocol.toLowerCase() == 'https:';

  if (BKGWebMap.UUID && !ignoreUuid) {
    // UUID bevorzugen
    service = service + '__' + BKGWebMap.UUID;
    // bei Verwendung des UUID darf nur HTTPS verwendet werden
    useHttps = true;
  } else if (BKGWebMap.APP_ID && BKGWebMap.APP_DOMAIN) {
    if(!BKGWebMap._SESSION_TOKEN) {
      BKGWebMap._SESSION_TOKEN = BKGWebMap.Util.getSessionToken(BKGWebMap.APP_ID, BKGWebMap.APP_DOMAIN);
    }
    if(BKGWebMap._SESSION_TOKEN.startsWith("sess-")) {
      service = service + '__' + BKGWebMap._SESSION_TOKEN;
      // bei Verwendung des SESSION_TOKEN darf nur HTTPS verwendet werden
      useHttps = true;
    }
  }

  // Protokoll anpassen
  if(useHttps)
    base = base.replace('http://', 'https://');

  return base + service + path;
};

/**
 * Generiert den Session-Token zur Authentifizierung von Zugriffsgeschützten Diensten.
 *
 * @param {string} appId - Applikationsschlüssel
 * @param {string} appDomain - Applikationsdomain
 * @return {string}
 */
BKGWebMap.Util.getSessionToken = function(appId , appDomain) {
  try {
    var baseURL = BKGWebMap.BASE_URL.replace('http://', 'https://');
    var request = OpenLayers.Request.GET({
      url: baseURL + "gdz_getSession",
      params: {bkg_appid: appId, domain: appDomain},
      async: false
    });
    if (request.status !== 200) {
      console.log("Problem bei der Session-Initialisierung: " + request.responseText);
      return "n.a.";
    }
    return request.responseText;
  } catch (err) {
    console.log(err);
    return "n.a.";
  }
};

/**
 * Ermittelt die UUID aus einer URL. Die UUID UUID ist der erste URL-Bestandtteil der mit "__" eingeleitet wird.
 *
 * @param url {string} Die URL aus der die UUID ermittelt werden soll
 * @return {string}
 */
BKGWebMap.Util.getUuidFromUrl = function(url) {
  var pattern = /__([\w\d\-]+)/g;
  var match = pattern.exec(url);
  return (match == null) ? null : match[1];
};

// IE7 Fix
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (obj, start) {
        for (var i = (start || 0), j = this.length; i < j; i++) {
            if (this[i] === obj) {
                return i;
            }
        }
        return -1;
    }
};

(function(fn){
    if (!fn.map) fn.map=function(f){var r=[];for(var i=0;i<this.length;i++)r.push(f(this[i]));return r}
    if (!fn.filter) fn.filter=function(f){var r=[];for(var i=0;i<this.length;i++)if(f(this[i]))r.push(this[i]);return r}
})(Array.prototype);