Source: BKGWebMap/Control/LayerSwitcher/AdvancedLayerEntry.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/BaseTypes/Element.js
 * @requires OpenLayers/Util.js
 * @requires BKGWebMap/Control/LayerSwitcher.js
 * @requires BKGWebMap/Control/LayerSwitcher/LayerEntry.js
 * @requires BKGWebMap/Util.js
 */

/**
 * @classdesc Repräsemtationsklasse für einen simplen Layereintrag im Layerswitcher.
 *
 * @constructor BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
 */
BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry = OpenLayers.Class(BKGWebMap.Control.LayerSwitcher.LayerEntry, {

    /**
     * Schieberegler für Layertransparenz
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @type {BKGWebMap.Util.Slider}
     */
    opacitySlider: null,

    /**
     * Listet die WMS-Ebenen auf, aus denen der Layer ggf. besteht. Wenn mehr als eine Ebene im WMS zur Verfügung
     * stehen, werden zusätzlich Controls angezeigt, die diese Ebenen ein- bzw. ausschalten kann.
     * Die verfügbaren Ebenen werden über die Methode getSubLayers ermittelt.
     *
     * Für jeden WMS-Layer wird in der Liste Name und Titel gespeichert
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @type {Array<object<string,string>>}
     */
    subLayers: null,

    /**
     * CSS-Klasse für HTML-Element des Layereintrags
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @type {string}
     */
    style: 'wmAdvancedLayerEntry',

    /**
     * Texte für Labels
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @type {object<string>}
     */
    labels: {
        opacity: 'Transparenz',
        layers: 'Ebenen',
        order: 'Reihenfolge'
    },

  /**
   * <code>true</code> um Steuerelement für Layerreihenfolge anzuzeigen
   * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
   * @type {boolean}
   */
  drawOrder: true,

  /**
   * <code>true</code> um Steuerelement für Transparenz anzuzeigen
   * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
   * @type {boolean}
   */
  drawOpacity: true,

  /**
   * <code>true</code> um Steuerelement für WMS-Ebenen anzuzeigen
   * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
   * @type {boolean}
   */
  drawSubLayers: true,

    initialize: function (layer, parent) {
        BKGWebMap.Control.LayerSwitcher.LayerEntry.prototype.initialize.apply(this, [layer, parent]);
        this.subLayers = this.getSubLayers(layer);
    },

    destroy: function () {
        if (this.settingsToggler) {
            this.settingsToggler.destroy();
            this.settingsToggler = null;
        }
        if (this.opacitySlider) {
            this.opacitySlider.destroy();
            this.opacitySlider = null;
        }

        if (this.titleDiv) {
            OpenLayers.Event.stopObserving(this.titleDiv, "click");
            this.titleDiv = null;
        }

        if (this.prev) {
            OpenLayers.Event.stopObserving(this.prev, "click");
            this.prev = null;
        }

        if (this.next) {
            OpenLayers.Event.stopObserving(this.next, "click");
            this.prev = null;
        }

        this.toggleSettingsButton = null;
        this.settingsDiv = null;

        if (this.subLayers) {
            BKGWebMap.Util.each(this.subLayers, function (index, subLayer) {
                if (subLayer.div) OpenLayers.Event.stopObserving(subLayer.div, "click");
            });
        }
        this.subLayers = null;
    },

    /**
     * Ermittelt alle dem Layer zur Verfügung stehenden Unterlayer
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {OpenLayers.Layer.WMS} layer
     * @returns {Array<object<string, string>>}
     */
    getSubLayers: function (layer) {
/*
        if (!layer instanceof OpenLayers.Layer.WMS) return [];

        var curentLayers = layer.params.LAYERS.split(',');
        var allLayers = layer.wmSubLayers || curentLayers;
        layer.wmSubLayers = allLayers;

        var layers = [];
        BKGWebMap.Util.each(allLayers, function (index, name) {
            layers.push({
                id: name,
                title: name,
                active: curentLayers.indexOf(name) >= 0
            });
        });
        return layers;
*/
        if (!layer instanceof BKGWebMap.Layer.WMS) return [];

        var layers = [];
        BKGWebMap.Util.each(layer.layers, function (index, layer) {
            layers.push({
                id: layer.name,
                title: layer.title,
                active: layer.active
            });
        });
        return layers;
    },

    /**
     * Ermittelt die Sublayerparameter anhand einer ID.
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {string} id - die gesuchte Layer-ID
     * @returns {Object} Parameter des Sublayers
     */
    getSubLayer: function (id) {
        for (var i = 0; i < this.subLayers.length; i++) {
            if (this.subLayers[i].id == id) return this.subLayers[i];
        }
        return null;
    },

    /**
     * Erzeugt die HTML-Darstellung für einen Layer-Eintrag
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     */
    draw: function () {
        if (!this.layer.displayInLayerSwitcher) return null;

        var baseLayer = this.layer.isBaseLayer;
        var checked = (baseLayer) ? (this.layer == this.parent.map.baseLayer) : this.layer.getVisibility();

        // create Wrapper element
        this.div = document.createElement("div");
        OpenLayers.Element.addClass(this.div, this.style);
        if (checked) {
            OpenLayers.Element.addClass(this.div, this.styleSelected);
        }
        if (!baseLayer && !this.layer.inRange) {
            OpenLayers.Element.addClass(this.div, this.styleInactive);
        }

        // toggle Settings
        this.toggleSettingsButton = document.createElement("div");
        OpenLayers.Element.addClass(this.toggleSettingsButton, 'wmToggleSettingsButton');
        this.div.appendChild(this.toggleSettingsButton);

        // Layer title
        this.titleDiv = document.createElement("div");
        OpenLayers.Element.addClass(this.titleDiv, 'wmLayerTitle');
        this.titleDiv.innerHTML = this.layer.name;
        this.div.appendChild(this.titleDiv);
        OpenLayers.Event.observe(this.titleDiv, "click", OpenLayers.Function.bindAsEventListener(this.toggleLayer, this));

        // Layereinstellungen
        this.settingsDiv = this.drawSettings();
        // Einstellungen ein-/ausblenden
        this.settingsToggler = new BKGWebMap.Util.Toggler(
            this.toggleSettingsButton,
            this.settingsDiv,
            {closed: !this.layer._wmLayerSettingsVisible}
        );
        this.settingsToggler.events.on({
            statechanged: this.onSettingsTogglerChange,
            scope: this
        });


        return this.div;
    },

    /**
     * Erstellt alle Steuerelemente für den Layer
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @returns {HTMLElement} Referenz auf HTML-Container für Steuerelemente
     */
    drawSettings: function () {
        var settingsDiv = document.createElement('div');
        OpenLayers.Element.addClass(settingsDiv, 'wmLayerSettings');
        this.div.appendChild(settingsDiv);

        // Reihenfolge
        if(this.drawOrder)
            this.drawOrderControl(settingsDiv);

        // opacity Slider
        if(this.drawOpacity)
            this.drawOpacityControl(settingsDiv);

        // Layerauswahl für WMS
        if(this.drawSubLayers)
            this.drawSubLayerControl(settingsDiv);

        return settingsDiv;
    },

    /**
     * Erstellt die HTML-Elemente zur Steuerung der Layerreihenfolge.
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {HMTLElement} div - Der Parent für die Steuerelemente.
     */
    drawOrderControl: function (div) {
        var label = document.createElement('label');
        label.innerHTML = this.labels.order;
        div.appendChild(label);

        /*
         var orderDiv = document.createElement('div');
         OpenLayers.Element.addClass(orderDiv, 'wmOrder');
         div.appendChild(orderDiv);
         */
        this.prev = document.createElement('div');
        OpenLayers.Element.addClass(this.prev, 'wmOrderPrev');
        this.next = document.createElement('div');
        OpenLayers.Element.addClass(this.next, 'wmOrderNext');

        label.appendChild(this.prev);
        label.appendChild(this.next);

        // Events registrieren
        OpenLayers.Event.observe(this.prev, "click", OpenLayers.Function.bindAsEventListener(this.onPrevLayer, this));
        OpenLayers.Event.observe(this.next, "click", OpenLayers.Function.bindAsEventListener(this.onNextLayer, this));

    },

    /**
     * Erstellt die HTML-Elemente zur Steuerung der Layertransparenz.
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {HMTLElement} div - Der Parent für die Steuerelemente.
     */
    drawOpacityControl: function (div) {
        var opacityLabel = document.createElement('label');
        opacityLabel.innerHTML = this.labels.opacity;
        div.appendChild(opacityLabel);

        this.opacitySlider = new BKGWebMap.Util.Slider({
            scaleSize: 100, sliderSize: 10, value: this.layer.opacity * 100
        });
        div.appendChild(this.opacitySlider.div);
        this.opacitySlider.events.on({ "valuechanged": OpenLayers.Function.bindAsEventListener(this.onOpacityChanged, this) });
    },

    /**
     * Erstellt die HTML-Elemente zur Steuerung der Ebenen im WMS.
     *
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {HMTLElement} div - Der Parent für die Steuerelemente.
     */
    drawSubLayerControl: function (div) {
        if (this.subLayers.length < 2) return;

        var subLayersLabel = document.createElement('label');
        subLayersLabel.innerHTML = this.labels.layers;
        div.appendChild(subLayersLabel);

        var layerList = document.createElement('ul');
        OpenLayers.Element.addClass(layerList, 'wmSubLayers');
        div.appendChild(layerList);

        var layerEntry = this; // Referenz auf diese Instanz für funktionale Programmierung
        BKGWebMap.Util.each(this.subLayers, function (index, subLayer) {
            var item = document.createElement('li');
            item.innerHTML = subLayer.title;
            item.layerID = subLayer.id;
            layerList.appendChild(item);
            subLayer.div = item;

            // an-/abwählen
            OpenLayers.Event.observe(
                item, "click",
                OpenLayers.Function.bindAsEventListener(layerEntry.onSubLayerClick, layerEntry)
            );
            // Status per CSS
            OpenLayers.Element.addClass(item, subLayer.active ? 'active' : 'inactive');
        });
    },

    /**
     * Aktiviert oder deaktiviert einen Sublayer im WMS.
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     * @param {Object} subLayer - die Sublayerdefinition mit id und aktuellem Status
     * @param {string} subLayer.id - die ID/der Name des Sublayers im WMS
     * @param {boolean} subLayer.active - der aktuelle Zustand des Sublayers
     * @param {HTMLElement} subLayer.div - das HMTL-Element, welches den Sublayer repräsentiert
     */
    toggleSubLayer: function (subLayer, item) {
        var oldState = subLayer.active;
        subLayer.active = !oldState;

        // neuer Request-Parameter
        var layers = [];
        BKGWebMap.Util.each(this.subLayers, function (index, subLayer) {
            if (subLayer.active) layers.push(subLayer.id);
        });
        // Mindestens ein Layer muss für WMS-Requests aktiv sein.
        if (layers.length == 0) {
            subLayer.active = oldState;
            return;
        }

        // Status des Sublayers ändern
        OpenLayers.Element.removeClass(subLayer.div, subLayer.active ? 'inactive' : 'active');
        OpenLayers.Element.addClass(subLayer.div, subLayer.active ? 'active' : 'inactive');

        this.layer.toggleLayer(subLayer.id);
        //this.layer.mergeNewParams({LAYERS: layers.join(',')});
    },

    /**
     * Eventhandler be Änderungen des Opacity-Sliders.
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     */
    onOpacityChanged: function (evt) {
        this.layer.setOpacity(this.opacitySlider.value / 100);
    },

    /**
     * Eventhandler für Clicks auf die Sublayer-Einträge zum Ein-/Ausschalten dieser.
     * @memberOf BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry
     */
    onSubLayerClick: function (evt) {
        var item = BKGWebMap.Util.getEventTarget(evt);
        var subLayer = this.getSubLayer(item.layerID);
        this.toggleSubLayer(subLayer);
    },

    onPrevLayer: function (evt) {
        this.layer.map.raiseLayer(this.layer, -1);
    },

    onNextLayer: function (evt) {
        this.layer.map.raiseLayer(this.layer, 1);
    },

    onSettingsTogglerChange: function (evt) {
        this.layer._wmLayerSettingsVisible = !this.settingsToggler.closed;
    },

    CLASS_NAME: "BKGWebMap.Control.LayerSwitcher.AdvancedLayerEntry"
});