Source: map/filters/ui/DropdownFilter.js

import { FilterUi } from "./FilterUi.js";
import { Dropdown } from "../../../ui/Dropdown.js";
import { CheckboxFilterSettings } from "./CheckboxFilter.js";

export { DropdownFilter };

/**
 * A class that defines the Ui for a Dropdown based AttributeFilter
 * 
 * @author rhess <robin.hess@awi.de>
 * @author sjaswal <shahzeib.jaswal@awi.de>
 * 
 * @memberof vef.map.filters.ui
 */
class DropdownFilter extends FilterUi {

    /**
     * @param {HTMLElement | string} target
     * @param {object} options filter specific options
     * @param {LayerManager} layers Used for included/excluded layers
     */
    constructor(target, options, layers) {

        // apply default options
        options = Object.assign({
            title: "Dropdown Filter",
            allowShowNullValues: true,
            showNullValues: true,
            allowDeselect: true,
            sortFields: true,
            search: true,
            searchPaceholder: "",
            placeholder: "select a filter ...",
            allValues: null,
            fields: [],
            uniqueValueSource: null
        }, options || {});

        super(target, options, layers);

        this.settingsClass_ = CheckboxFilterSettings;

        this.dropdown_ = new Dropdown(null, {
            placeholder: this.options_.placeholder,
            deselectLabel: this.options_.allValues || null,
            showDeselectItem: this.options_.allowDeselect,
            search: this.options_.search,
            searchPlaceholder: this.options_.searchPaceholder
        });

        this.initFilterElement_();

        // add tool to deselect the dropdown
        if (this.options_.allowDeselect) this.addTool("vef vef-deselect-all", () => {
            this.dropdown_.deselect();
            this.fire("change", this);
        }, "Remove All Filters");

        this.initShowNullButton_();
        this.reloadOptions_();
    }

    /**
     * internal method for initializing the main
     * HTML structure of the element
     * 
     * @private
     */
    initFilterElement_() {
        this.setTitle(this.options_.title);
        const container = this.getContentContainer();
        container.classList.add("dropdown-filter");
        container.style.paddingBottom = "5px";
        this.dropdown_.appendTo(container);
    }

    /**
     * Get the filter's options-object
     */
    getOptions() {
        const selectedItem = this.dropdown_.getSelectedItem();

        const options = Object.assign({}, this.options_);

        // assign active field
        for (let i = 0; i < options.fields.length; ++i) {
            options.fields[i].selected = (selectedItem && (options.fields[i] == selectedItem.item));
        }

        return options;
    }

    async getfields_() {
        const fields = this.options_.fields.slice(0);

        if (!this.options_.uniqueValueSource) return fields;
        const layer = this.layers_.getLayerById(this.options_.uniqueValueSource.layer);
        if (!layer) return fields;
        const values = await layer.getUniqueValues(this.options_.uniqueValueSource.column);
        if (values.length == 0) return fields;

        // merge cache and fields and remove duplicates
        for (let i = 0; i < values.length; ++i) {
            const value = values[i];
            if (!fields.find(field => (field.column == this.options_.uniqueValueSource.column) && (field.operator == "eq") && (field.values == value))) {
                fields.push({
                    column: this.options_.uniqueValueSource.column,
                    operator: "eq",
                    values: value,
                    title: value
                });
            }
        }

        return fields;
    }

    /**
     * internal method for initializing dropdown element
     * 
     * @private
     */
    initDropdown_(fields) {
        const items = {};

        let activeItem = null;
        for (let i = 0; i < fields.length; ++i) {
            const item = fields[i];
            items[item.title] = item;
            if (item.selected) activeItem = item.title;
        }

        this.dropdown_.setItems(items);
        if (activeItem) this.dropdown_.select(activeItem);

        this.dropdown_.on("select", e => {
            this.fire("change", this);
        })
    }

    /**
     * Get the filter object to pass it on to the Layers.
     * 
     * @override
     * @returns {object} filter object
     */
    getActiveFilter() {
        if (this.dropdown_) {
            const item = this.dropdown_.getSelectedItem();

            if (item && item.item) {
                let values = (Array.isArray(item.item.values)) ? item.item.values : [item.item.values];
                values = values.map(value => [item.item.operator, value]);
                if (this.options_.showNullValues) values.push(["null"]);
                return {
                    "type": "attribute",
                    "column": item.item.column,
                    "values": values,
                    "excludedLayers": this.getExcludedLayers()
                }
            }
        }

        return {};
    }

    /**
     * method to reload options after applying settings
     */
    reloadOptions_() {
        this.setTitle(this.options_.title);
        this.toggleToolVisibility("btn-power", this.options_.deactivatable);
        this.toggleToolVisibility("btn-show-null", this.options_.allowShowNullValues);
        this.getfields_().then(fields => {
            if (this.options_.sortFields) fields.sort((a, b) => a.title.localeCompare(b.title));
            this.initDropdown_(fields);
            this.fire("change", this);
        });
    }
}