Source: BKGWebMap/Control/Geocoder/ListView.js

/*
 * Copyright (c) 2013 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/Util.js
 * @requires BKGWebMap/Control/Geocoder/View.js
 * @requires BKGWebMap/Util.js
 * @requires BKGWebMap/Layer/MarkerLayer.js
 */


/**
 * @classdesc Darstellung von Geocodierungsergebnissen als HTML-Liste
 *
 * @constructor BKGWebMap.Control.Geocoder.ListView
 * @param {object} options
 **/
BKGWebMap.Control.Geocoder.ListView = OpenLayers.Class(BKGWebMap.Control.Geocoder.View, {

    /**
     * Referenz zum Ergebniscontainer
     * @type node
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    div: null,

    /**
     * Basisname für CSS-Klassen
     * @type string
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    displayClass: null,

    /**
     * Texte für Labels
     * @type object
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    labels: {
    	/** Keine Suche gestartet. */
    	init : '<p>Bitte nutzen Sie das Suchfeld.</p>',
    	/** Keine Ergebnisse. */
    	noResults : '<p>Keine Ergebnisse gefunden</p>',
    	/** Meinten Sie */
    	didYouMean : '<span class="didyou">Meinten Sie: </span>',
    	/** Führe Suche durch */
    	searching : '<p>Suche ...</p>'
    },


    initialize: function(options) {
        this.displayClass = this.CLASS_NAME.replace("BKGWebMap.", "bkg").replace(/\./g, "");
        OpenLayers.Util.extend(this, options);
        this.draw();
    },

    draw: function() {
        var div = this.div;
        if (!div) {
            // TODO: generiere Div auf HTML-Seite
            // ...
        }
        OpenLayers.Element.addClass(div, this.displayClass);
        div.innerHTML = this.labels.init;
        return div;
    },

    /**
     * Wird ausgelöst, wenn eine neue Suche gestartet wird.
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     * @param {object} evt - Eventobjekt mit element und object
     */
    onStartSearch: function(evt) {
        this.div.innerHTML = this.labels.searching;
    },

    /**
     * Wird ausgelöst, wenn ein Fehler bei der Geocodierung auftrat.
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     * @param {object} evt - Eventobjekt mit element, object und response
     * @param {BKGWebMap.Protocol.Geoindex.Response} evt.response
     */
    onError: function(evt) {
        this.div.innerHTML  = 'Fehler bei der Suche!';
        // TODO: Details!
    },

    /**
     * Wird ausgelöst, wenn die Geocodierung erfolgreich war.
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     * @param {object} evt - Eventobjekt mit element, object und response
     * @param {BKGWebMap.Protocol.Geoindex.Response} evt.response
     */
    onLocationUpdate: function(evt) {
        this.div.innerHTML  = '';

        var response = evt.response;

        // Ergebnisse lokal speichern
        this.features = response.features;

        if(!response.features) {
            return
        }

        // render search input
        var query = document.createElement("h2");
        query.innerHTML = response.data;
        OpenLayers.Element.addClass(query, this.displayClass + "SearchTerm");
        this.div.appendChild(query);

        // Click auf Suchanfrage zoomt auf alle Ergebnisse:
        OpenLayers.Event.observe(query, "click", OpenLayers.Function.bindAsEventListener(this.zoomToDataExtend, this));

        // Anzeige der  Meinten Sie Features. Nur relevant für geoindex
        BKGWebMap.Util.each(
                response.suggestions,
                OpenLayers.Function.bind(
                    function(index, suggestion){ this.div.appendChild( this.renderSuggestion(suggestion)); }, this
                )
        );

        // Anzeige der Ergebnisse
        var ul = document.createElement("ul");
        OpenLayers.Element.addClass(ul, this.displayClass + "ResultList");
        this.div.appendChild(ul);

        // Keine Ergebnisse:
        if (response.features.length == 0) {
            var li = document.createElement('li');
            li.innerHTML += this.labels.noResults;
            ul.appendChild(li);
            return;
        }

        // Ergebnissliste:
        BKGWebMap.Util.each(
            response.features,
            OpenLayers.Function.bind(
                function(index, feature) { ul.appendChild( this.renderFeature(feature) ); }, this
            )
        );

    },

    /**
     * Generiert das HTML für einen alternativen Suchvorschlag.
     *
     * @param {OpenLayers.Feature.Vector} suggestion - alternativer Suchvorschlag.
     * @return {node}
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    renderSuggestion : function(suggestion) {
        var a = document.createElement('a');
        a.href = 'javascript:void(0);';
        a.id = 'test';
        a.innerHTML = suggestion.attributes.fulltext;

        var wrapper = document.createElement('div');
        OpenLayers.Element.addClass(wrapper, this.displayClass + 'DidYouMean');
        wrapper.innerHTML = this.labels.didYouMean;
        wrapper.appendChild(a);

        // Click auf DidYouMean soll Suche auslösen
        var applySuggestion = function(evt) {
            this.applySuggestion(suggestion.attributes.fulltext);
            OpenLayers.Event.stop(evt);
        };
        OpenLayers.Event.observe(a, "click", OpenLayers.Function.bindAsEventListener(applySuggestion, this));

        return wrapper;
    },

    /**
     * Generiert das HTML für ein einzelnes Feature in der Ergebnisliste.
     *
     * @param {OpenLayers.Feature.Vector} feature - Das zu rendernde Feature
     * @return node
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    renderFeature : function(feature) {
        // DOM generieren
        var li =  document.createElement('li');
        OpenLayers.Element.addClass(li, this.displayClass + "ResultListItem");
        var text = feature.attributes.text;
        var typ = feature.attributes.typ;

        li.innerHTML =  text + '<br/><span class="featureType">' + typ + '</span>';

        // DOMElement dem Feature zuweisen
        feature.resultListItem = li;

        // Mouseevents für Listelement registrieren
        var toggleHighligth = function(evt) {
            this.geocoder.hoverFeature(feature, this.hover);
            OpenLayers.Event.stop(evt);
        };
        OpenLayers.Event.observe(li, "mouseover", OpenLayers.Function.bindAsEventListener(toggleHighligth, {geocoder: this.geocoder, hover: true}));
        OpenLayers.Event.observe(li, "mouseout", OpenLayers.Function.bindAsEventListener(toggleHighligth, {geocoder: this.geocoder, hover: false}));

        var togglePopup =  function(evt) {
            BKGWebMap.Layer.MarkerLayer.togglePopup(this);
            if(this.popup && this.popup.visible()) {
                var geometry = this.attributes.bbox ? this.attributes.bbox : this.geometry;
                this.layer.map.zoomToExtent(geometry.getBounds());
            }
            OpenLayers.Event.stop(evt);
        };
        OpenLayers.Event.observe(li, "click", OpenLayers.Function.bindAsEventListener(togglePopup, feature));
        return li;
    },

    /**
     * Wird auferufen, wenn auf den DidYouMean-Link geclickt wird. Löst ein erneutes Geocoding mit dem vorgeschlagenen
     * Suchbegriff aus.
     *
     * @param {string} term - Der Suchvorschlag
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    applySuggestion: function(term) {
        this.geocoder.input.value = term;
        this.geocoder.triggerSearch();
    },

    /**
     * Zoomt auf die Ausdehnung aller Features.
     * @param evt
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     */
    zoomToDataExtend: function(evt) {
        if(!this.features || this.features.length == 0) return;
        this.map.zoomToExtent(BKGWebMap.Util.getDataExtent(this.features), true);
    },

    /**
     * Eventhandler, wenn Feature hervorgehoben wird.
     *
     * @memberOf BKGWebMap.Control.Geocoder.ListView
     * @param {object} evt - Eventobjekt mit element, feature und Hoverstatus
     * @param {OpenLayers.Feature} evt.feature - das hervorzuhebende Feature
     * @param {boolean} evt.hover - der Status zum hervorheben
     */
    onHoverFeature: function(evt) {
        if(evt.hover) {
            OpenLayers.Element.addClass(evt.feature.resultListItem, 'highlighted');
        } else {
            OpenLayers.Element.removeClass(evt.feature.resultListItem, 'highlighted');
        }
    },

    CLASS_NAME: "BKGWebMap.Control.Geocoder.ListView"
});