"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get MultipleSelectUI () {
        return MultipleSelectUI;
    },
    get default () {
        return _default;
    }
});
const _element = require("../../../helpers/dom/element");
const _object = require("../../../helpers/object");
const _unicode = require("../../../helpers/unicode");
const _function = require("../../../helpers/function");
const _data = require("../../../helpers/data");
const _constants = /*#__PURE__*/ _interop_require_wildcard(require("../../../i18n/constants"));
const _event = require("../../../helpers/dom/event");
const _base = require("./_base");
const _input = require("./input");
const _link = require("./link");
const _utils = require("../utils");
function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
const SHORTCUTS_GROUP = 'multipleSelect.itemBox';
var /**
   * List of available select options.
   *
   * @type {Array}
   */ _items = /*#__PURE__*/ new WeakMap(), /**
   * Handsontable instance used as items list element.
   *
   * @type {Handsontable}
   */ _itemsBox = /*#__PURE__*/ new WeakMap(), /**
   * A locale for the component used to compare filtered values.
   *
   * @type {string}
   */ _locale = /*#__PURE__*/ new WeakMap(), /**
   * Input element.
   *
   * @type {InputUI}
   */ _searchInput = /*#__PURE__*/ new WeakMap(), /**
   * "Select all" UI element.
   *
   * @type {LinkUI}
   */ _selectAllUI = /*#__PURE__*/ new WeakMap(), /**
   * "Clear" UI element.
   *
   * @type {LinkUI}
   */ _clearAllUI = /*#__PURE__*/ new WeakMap(), /**
   * 'input' event listener for input element.
   *
   * @param {Event} event DOM event.
   */ _onInput = /*#__PURE__*/ new WeakSet(), /**
   * 'keydown' event listener for input element.
   *
   * @param {Event} event DOM event.
   */ _onInputKeyDown = /*#__PURE__*/ new WeakSet(), /**
   * On click listener for "Select all" link.
   *
   * @param {DOMEvent} event The mouse event object.
   */ _onSelectAllClick = /*#__PURE__*/ new WeakSet(), /**
   * On click listener for "Clear" link.
   *
   * @param {DOMEvent} event The mouse event object.
   */ _onClearAllClick = /*#__PURE__*/ new WeakSet();
class MultipleSelectUI extends _base.BaseUI {
    static get DEFAULTS() {
        return (0, _object.clone)({
            className: 'htUIMultipleSelect',
            value: []
        });
    }
    /**
   * Gets the instance of the internal Handsontable that acts here as a listbox component.
   *
   * @returns {Handsontable}
   */ getItemsBox() {
        return _class_private_field_get(this, _itemsBox);
    }
    /**
   * Register all necessary hooks.
   */ registerHooks() {
        _class_private_field_get(this, _searchInput).addLocalHook('keydown', (event)=>_class_private_method_get(this, _onInputKeyDown, onInputKeyDown).call(this, event));
        _class_private_field_get(this, _searchInput).addLocalHook('input', (event)=>_class_private_method_get(this, _onInput, onInput).call(this, event));
        _class_private_field_get(this, _selectAllUI).addLocalHook('click', (event)=>_class_private_method_get(this, _onSelectAllClick, onSelectAllClick).call(this, event));
        _class_private_field_get(this, _clearAllUI).addLocalHook('click', (event)=>_class_private_method_get(this, _onClearAllClick, onClearAllClick).call(this, event));
    }
    /**
   * Set available options.
   *
   * @param {Array} items Array of objects with `checked` and `label` property.
   */ setItems(items) {
        _class_private_field_set(this, _items, items);
        _class_private_field_get(this, _itemsBox)?.loadData(_class_private_field_get(this, _items));
    }
    /**
   * Set a locale for the component.
   *
   * @param {string} locale Locale used for filter actions performed on data, ie. `en-US`.
   */ setLocale(locale) {
        _class_private_field_set(this, _locale, locale);
    }
    /**
   * Get a locale for the component.
   *
   * @returns {string}
   */ getLocale() {
        return _class_private_field_get(this, _locale);
    }
    /**
   * Get all available options.
   *
   * @returns {Array}
   */ getItems() {
        return [
            ..._class_private_field_get(this, _items)
        ];
    }
    /**
   * Get element value.
   *
   * @returns {Array} Array of selected values.
   */ getValue() {
        return itemsToValue(_class_private_field_get(this, _items));
    }
    /**
   * Gets the instance of the search input element.
   *
   * @returns {InputUI}
   */ getSearchInputElement() {
        return _class_private_field_get(this, _searchInput);
    }
    /**
   * Gets the instance of the "select all" link element.
   *
   * @returns {LinkUI}
   */ getSelectAllElement() {
        return _class_private_field_get(this, _selectAllUI);
    }
    /**
   * Gets the instance of the "clear" link element.
   *
   * @returns {LinkUI}
   */ getClearAllElement() {
        return _class_private_field_get(this, _clearAllUI);
    }
    /**
   * Check if all values listed in element are selected.
   *
   * @returns {boolean}
   */ isSelectedAllValues() {
        return _class_private_field_get(this, _items).length === this.getValue().length;
    }
    /**
   * Build DOM structure.
   */ build() {
        super.build();
        const { rootDocument } = this.hot;
        const itemsBoxWrapper = rootDocument.createElement('div');
        const selectionControl = new _base.BaseUI(this.hot, {
            className: 'htUISelectionControls',
            children: [
                _class_private_field_get(this, _selectAllUI),
                _class_private_field_get(this, _clearAllUI)
            ]
        });
        this._element.appendChild(_class_private_field_get(this, _searchInput).element);
        this._element.appendChild(selectionControl.element);
        this._element.appendChild(itemsBoxWrapper);
        _class_private_field_get(this, _itemsBox)?.destroy();
        (0, _element.addClass)(itemsBoxWrapper, 'htUIMultipleSelectHot');
        // Constructs and initializes a new Handsontable instance
        _class_private_field_set(this, _itemsBox, new this.hot.constructor(itemsBoxWrapper, {
            data: [
                []
            ],
            columns: [
                {
                    data: 'checked',
                    type: 'checkbox',
                    label: {
                        property: 'visualValue',
                        position: 'after'
                    }
                }
            ],
            beforeRenderer: (TD, row, col, prop, value, cellProperties)=>{
                TD.title = cellProperties.instance.getDataAtRowProp(row, cellProperties.label.property);
            },
            afterListen: ()=>{
                this.runLocalHooks('focus', this);
            },
            beforeOnCellMouseUp: ()=>{
                _class_private_field_get(this, _itemsBox).listen();
            },
            modifyColWidth: (width)=>{
                const minWidth = _class_private_field_get(this, _itemsBox).container.scrollWidth - (0, _element.getScrollbarWidth)(rootDocument);
                if (width !== undefined && width < minWidth) {
                    return minWidth;
                }
                return width;
            },
            autoColumnSize: true,
            autoRowSize: false,
            hiddenRows: true,
            maxCols: 1,
            autoWrapCol: true,
            height: 110,
            copyPaste: false,
            disableVisualSelection: 'area',
            fillHandle: false,
            fragmentSelection: 'cell',
            tabMoves: {
                row: 1,
                col: 0
            },
            themeName: this.hot.getCurrentThemeName(),
            layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr'
        }));
        _class_private_field_get(this, _itemsBox).init();
        const shortcutManager = _class_private_field_get(this, _itemsBox).getShortcutManager();
        const gridContext = shortcutManager.getContext('grid');
        gridContext.removeShortcutsByKeys([
            'Tab'
        ]);
        gridContext.removeShortcutsByKeys([
            'Shift',
            'Tab'
        ]);
        gridContext.addShortcut({
            keys: [
                [
                    'Escape'
                ]
            ],
            callback: (event)=>{
                this.runLocalHooks('keydown', event, this);
            },
            group: SHORTCUTS_GROUP
        });
        gridContext.addShortcut({
            keys: [
                [
                    'Tab'
                ],
                [
                    'Shift',
                    'Tab'
                ]
            ],
            callback: (event)=>{
                _class_private_field_get(this, _itemsBox).deselectCell();
                this.runLocalHooks('keydown', event, this);
                this.runLocalHooks('listTabKeydown', event, this);
            },
            group: SHORTCUTS_GROUP
        });
    }
    /**
   * Focus element.
   */ focus() {
        if (this.isBuilt()) {
            _class_private_field_get(this, _itemsBox).listen();
        }
    }
    /**
   * Reset DOM structure.
   */ reset() {
        _class_private_field_get(this, _searchInput).reset();
        _class_private_field_get(this, _selectAllUI).reset();
        _class_private_field_get(this, _clearAllUI).reset();
    }
    /**
   * Update DOM structure.
   */ update() {
        if (!this.isBuilt() || _class_private_field_get(this, _itemsBox).rootElement.offsetHeight === 0) {
            return;
        }
        _class_private_field_get(this, _itemsBox).updateSettings({
            data: valueToItems(_class_private_field_get(this, _items), this.options.value)
        });
        super.update();
    }
    /**
   * Destroy instance.
   */ destroy() {
        _class_private_field_get(this, _itemsBox)?.destroy();
        _class_private_field_get(this, _searchInput).destroy();
        _class_private_field_get(this, _clearAllUI).destroy();
        _class_private_field_get(this, _selectAllUI).destroy();
        _class_private_field_set(this, _searchInput, null);
        _class_private_field_set(this, _clearAllUI, null);
        _class_private_field_set(this, _selectAllUI, null);
        _class_private_field_set(this, _itemsBox, null);
        _class_private_field_set(this, _items, null);
        super.destroy();
    }
    constructor(hotInstance, options){
        super(hotInstance, (0, _object.extend)(MultipleSelectUI.DEFAULTS, options)), _class_private_method_init(this, _onInput), _class_private_method_init(this, _onInputKeyDown), _class_private_method_init(this, _onSelectAllClick), _class_private_method_init(this, _onClearAllClick), _class_private_field_init(this, _items, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _itemsBox, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _locale, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _searchInput, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _selectAllUI, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _clearAllUI, {
            writable: true,
            value: void 0
        }), _class_private_field_set(this, _items, []);
        _class_private_field_set(this, _searchInput, new _input.InputUI(this.hot, {
            placeholder: _constants.FILTERS_BUTTONS_PLACEHOLDER_SEARCH,
            className: 'htUIMultipleSelectSearch'
        }));
        _class_private_field_set(this, _selectAllUI, new _link.LinkUI(this.hot, {
            textContent: _constants.FILTERS_BUTTONS_SELECT_ALL,
            className: 'htUISelectAll'
        }));
        _class_private_field_set(this, _clearAllUI, new _link.LinkUI(this.hot, {
            textContent: _constants.FILTERS_BUTTONS_CLEAR,
            className: 'htUIClearAll'
        }));
        this.registerHooks();
    }
}
function onInput(event) {
    const trimmed = event.target.value.trim();
    const value = trimmed.toLocaleLowerCase(this.getLocale());
    if (this.options.searchMode === 'apply') {
        const hiddenRows = _class_private_field_get(this, _itemsBox).getPlugin('hiddenRows');
        const rowsToHide = [];
        hiddenRows.showRows(hiddenRows.getHiddenRows());
        _class_private_field_get(this, _items).forEach((item, index)=>{
            item.checked = `${item.value}`.toLocaleLowerCase(this.getLocale()).indexOf(value) >= 0;
            if (!item.checked) {
                rowsToHide.push(index);
            }
        });
        hiddenRows.hideRows(rowsToHide);
        _class_private_field_get(this, _itemsBox).view.adjustElementsSize();
        _class_private_field_get(this, _itemsBox).render();
    } else {
        let filteredItems;
        if (value === '') {
            filteredItems = [
                ..._class_private_field_get(this, _items)
            ];
        } else {
            filteredItems = _class_private_field_get(this, _items).filter((item)=>`${item.value}`.toLocaleLowerCase(this.getLocale()).indexOf(value) >= 0);
        }
        _class_private_field_get(this, _itemsBox).loadData(filteredItems);
    }
}
function onInputKeyDown(event) {
    this.runLocalHooks('keydown', event, this);
    const isKeyCode = (0, _function.partial)(_unicode.isKey, event.keyCode);
    if (isKeyCode('ARROW_DOWN')) {
        event.preventDefault();
        (0, _event.stopImmediatePropagation)(event);
        _class_private_field_get(this, _itemsBox).listen();
        _class_private_field_get(this, _itemsBox).selectCell(0, 0);
    }
}
function onSelectAllClick(event) {
    const changes = [];
    event.preventDefault();
    _class_private_field_get(this, _itemsBox).getSourceData().forEach((row, rowIndex)=>{
        row.checked = true;
        changes.push((0, _data.dataRowToChangesArray)(row, rowIndex)[0]);
    });
    _class_private_field_get(this, _itemsBox).setSourceDataAtCell(changes);
}
function onClearAllClick(event) {
    const changes = [];
    event.preventDefault();
    _class_private_field_get(this, _itemsBox).getSourceData().forEach((row, rowIndex)=>{
        row.checked = false;
        changes.push((0, _data.dataRowToChangesArray)(row, rowIndex)[0]);
    });
    _class_private_field_get(this, _itemsBox).setSourceDataAtCell(changes);
}
const _default = MultipleSelectUI;
/**
 * Pick up object items based on selected values.
 *
 * @param {Array} availableItems Base collection to compare values.
 * @param {Array} selectedValue Flat array with selected values.
 * @returns {Array}
 */ function valueToItems(availableItems, selectedValue) {
    const arrayAssertion = (0, _utils.createArrayAssertion)(selectedValue);
    return availableItems.map((item)=>{
        item.checked = arrayAssertion(item.value);
        return item;
    });
}
/**
 * Convert all checked items into flat array.
 *
 * @param {Array} availableItems Base collection.
 * @returns {Array}
 */ function itemsToValue(availableItems) {
    const items = [];
    availableItems.forEach((item)=>{
        if (item.checked) {
            items.push(item.value);
        }
    });
    return items;
}
