Source: BKGWebMap/Control/WMSGetFeatureInfo.js

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

/**
 * @requires OpenLayers/BaseTypes/Class.js
 * @requires OpenLayers/Control/WMSGetFeatureInfo.js
 * @requires BKGWebMap/Control.js
 * @requires BKGWebMap/Util.js
 */


/**
 * WMSGetFeatureInfo stellt ein Tool bereit, mit welchem GetFeatureInfo abfragen auf die Layer in der Karte durchgeführt
 * werden können. Standardmäßig werden alle aktiven WMS-Layer abgefragt. Über den Einstellungs-Button können explizit
 * einzelne Layer ausgewählt werden.
 * <br/>
 * Das Ergebnis wird in einem PopUp an der Stelle des Clicks angezeigt.
 *
 * TODO: ein einzelner Layer -> url setzen
 * TODO: alle Layer (mehrere URLs) -> drillDown = true & InfoFormat parseable
 *
 * @classdesc Erweiterte WMSGetFeatureInfo für BKG-Dienste
 *
 * @constructor BKGWebMap.Control.WMSGetFeatureInfo
 * @param {object} options - Optionen für das Controlelement
 **/
BKGWebMap.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control.WMSGetFeatureInfo, {

    title: 'FeatureInfo',

    queryVisible: true,

    textHandler: null,

    popupSize: new OpenLayers.Size(200, 150),
    popupAutoSize: false,

    emptyMessage: 'Die Abfrage lieferte keine Ergebnisse!',

    initialize:function(options) {
        if(!options.eventListeners) {
            options.eventListeners = { getfeatureinfo: this.handleFeatureInfoResponse }
        }
        OpenLayers.Control.WMSGetFeatureInfo.prototype.initialize.apply(this, [options]);

        if (this.infoFormat == 'application/geojson') {
            this.format = new OpenLayers.Format.GeoJSON();
            this.textHandler = this.textHandler || new BKGWebMap.Control.WMSGetFeatureInfo.GeoJSONTextTransformer();
        } else {
            this.textHandler = this.textHandler || new BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer();
        }
    },

    /**
     * Bugfix: Baselayers, die nicht aktiv sind, sollen nicht mit angefragt werden.
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo
     */
    request: function (clickPosition, options) {
      this._text = null;
      this._requestCount = 0;
      OpenLayers.Control.WMSGetFeatureInfo.prototype.request.apply(this, [clickPosition, options]);
    },

    /**
     * Bugfix: Baselayers, die nicht aktiv sind, sollen nicht mit angefragt werden.
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo
     */
    findLayers: function () {
        var layers = OpenLayers.Control.WMSGetFeatureInfo.prototype.findLayers.apply(this);
        var map = this.map;
        layers = BKGWebMap.Util.grep(layers, function(layer) {
            if(!(layer instanceof OpenLayers.Layer.WMS))
                return true;

            return !layer.isBaseLayer || layer==map.baseLayer;
        });
        return layers;
    },

    /**
     * Überschreibt das Standardverhalten des WMSGetFeatureInfo, damit auch bei dirllDown Texte ergänzt werden.
     *
     * @param  xy {OpenLayers.Pixel} - The position on the map where the
     * @param request {XMLHttpRequest} - The request object
     * @param url {String} - The url which was used for this request.
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo
     */
    handleResponse: function (xy, request, url) {
        var doc = request.responseXML;
        if (!doc || !doc.documentElement) {
            doc = request.responseText;
        }
        var features = this.format.read(doc);
        if (this.drillDown === false) {
            this.triggerGetFeatureInfo(request, xy, features);
        } else {
            this._requestCount++;
            if (this.output === "object") {
                this._features = (this._features || []).concat( {url: url, features: features} );
            } else {
                this._features = (this._features || []).concat(features);
            }
            this._text = (this._text || '');
            this._text += '<h2>' + url + '</h2>';
            this._text += request.responseText;
            this._text += '<hr/><p/>';

            if (this._requestCount === this._numRequests) {
                // modify request object
                request.responseText = this._text;
                this.triggerGetFeatureInfo(request, xy, this._features.concat());
                delete this._features;
                delete this.text;
                delete this._requestCount;
                delete this._numRequests;
            }
        }
    },


    /**
     * Standard-Eventhandler für GetFeature-Response
     * @param event - Event-Objekt mit GetFeatureInfo Response
     * @param event.text - Antwort des Servers
     * @param event.object - diese Control-Instanz
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo
     */
    handleFeatureInfoResponse: function(event) {
        var text = event.object.parseText(event.text, event.features, event.xy);
        var popup = new BKGWebMap.Popup (
            null,
            event.object.map.getLonLatFromPixel(event.xy),
            this.popupSize,
            text,
            null,
            true
        );
        popup.autoSize = event.object.popupAutoSize;
        map.addPopup(popup);
    },

    /**
     * Methode zur Anpassung der Serverantwort für Darstellung im Popup
     * @param text {string} - Die GetFeatureInfo-Antwort
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo
     */
    parseText: function(text, features, xy) {
        text = this.textHandler.handle(text, features, xy);
        return (!text) ? this.emptyMessage : text;
    },

    CLASS_NAME: "BKGWebMap.Control.WMSGetFeatureInfo"
});

/**
 * @classdesc Hilfsklasse zur Transformation von WMSGetFeatureInfo-Responses in Text für das Info-PopUp.
 *
 * @constructor BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer
 **/
BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer = OpenLayers.Class({

    initialize: function(options) {
        OpenLayers.Util.extend(this, options);
    },

    /**
     * Wandelt den Text für das PopUp. Für diese Implementierung wird nichts getan.
     * @param text {string}
     * @returns {string}
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer
     */
    handle: function(text, features, xy) {
        return text;
    }
});

/**
 * @classdesc Hilfklasse zur Transformation von WMSGetFeatureInfo-Responses in Text für das Info-PopUp
 *
 * @constructor BKGWebMap.Control.WMSGetFeatureInfo.GeoJSONTextTransformer
 **/
BKGWebMap.Control.WMSGetFeatureInfo.GeoJSONTextTransformer =
        OpenLayers.Class(BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer, {

    initialize: function(options) {
        OpenLayers.Util.extend(this, options);
    },

    /**
     * Wandelt den Text für das PopUp in GeoJSON und gibt alle Attribute aus.
     * @param text {string}
     * @returns {string}
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo.GeoJSONTextTransformer
     */
    handle: function(text, features, xy) {
        var content = '';
        BKGWebMap.Util.each(features, function(index, feature) {
            content += '<div class="feature">';
            for(var key in feature.attributes) {
                if(!feature.attributes.hasOwnProperty(key)) continue;
                content += '<label>' + key + ':</label> ' + feature.attributes[key] + '<br/>'
            }
            content += '</div>';
        });
        return content;
    }
});

/**
 * @classdesc Hilfklasse zur Transformation von WMSGetFeatureInfo-Responses in Text für das Info-PopUp
 *
 * @constructor BKGWebMap.Control.WMSGetFeatureInfo.TextTransformer
 **/
BKGWebMap.Control.WMSGetFeatureInfo.DOPInfoTextTransformer =
        OpenLayers.Class(BKGWebMap.Control.WMSGetFeatureInfo.GeoJSONTextTransformer, {

    /**
     * Wandelt den Text für das PopUp. Für diese Implementierung wird nichts getan.
     * @param text {string}
     * @returns {string}
     * @memberOf BKGWebMap.Control.WMSGetFeatureInfo.DOPInfoTextTransformer
     */
    handle: function(text, features, xy) {
        var content = '';
        BKGWebMap.Util.each(features, function(index, feature) {
            if(feature == null) return;
            content +=
                    '<div class="feature">' +
                        '<h2>Kachel ' + feature.attributes['ID'] + '</h2>' +
                        '<label>Bundesland:</label> ' + feature.attributes['LAND'].toUpperCase() + '<br/>' +
                        '<label>Bildflug:</label> ' + feature.attributes['BILDFLUG'] + '<br/>' +
                    '</div>';
        });
        return content;
    }
});

/**
 * Fügt FeatureInfo der Control-Liste hinzu.
 * @param {Array<OpenLayers.Control>} controls - Liste der Steuerelemente, in die die neue erzeugten Steuerelemente
 *                                               eingefügt werden sollen.
 * @param {object} config - Konfiguration für das FeatureInfo-Steuerelement (s. Konstruktor OpenLayers.Control.WMSGetFeatureInfo).
 */
BKGWebMap.Control.FACTORIES['featureInfo'] = function(controls, config) {
    if (!config) return;
    controls.push(new BKGWebMap.Control.WMSGetFeatureInfo(config));
};