import * as i0 from '@angular/core';
import { Component, Attribute, Inject, Optional, ViewChild, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i3 from '@wm/components/base';
import { PROP_BOOLEAN, PROP_STRING, PROP_ANY, PROP_NUMBER, register, registerFormWidget, styler, getConditionalClasses, getUniqObjsByDataField, ALLFIELDS, configureDnD, provideAs, provideAsWidgetRef, WmComponentsModule } from '@wm/components/base';
import * as i2 from '@wm/components/basic/search';
import { SearchComponent, SearchModule } from '@wm/components/basic/search';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { FormWidgetType, isDefined, debounce, $unwatch, $watch, $appDigest, toBoolean, isAppleProduct } from '@wm/core';
import { DatasetAwareFormComponent } from '@wm/components/input';
import { forEach, clone, slice, isObject, isEqual, toString, find, trim, findIndex, filter, isArray, max, reduce, pullAt } from 'lodash-es';

const chipsProps = new Map([
    ['allowonlyselect', PROP_BOOLEAN],
    ['autofocus', PROP_BOOLEAN],
    ['chipclass', PROP_STRING],
    ['class', PROP_STRING],
    ['compareby', PROP_STRING],
    ['datafield', PROP_STRING],
    ['dataoptions', PROP_ANY],
    ['dataset', { value: 'Option 1, Option 2, Option 3', ...PROP_ANY }],
    ['datasource', PROP_ANY],
    ['datavalue', PROP_ANY],
    ['datavaluesource', PROP_ANY],
    ['dateformat', PROP_STRING],
    ['disabled', PROP_BOOLEAN],
    ['displayexpression', PROP_STRING],
    ['displayfield', PROP_STRING],
    ['displayimagesrc', PROP_STRING],
    ['enablereorder', PROP_BOOLEAN],
    ['groupby', PROP_STRING],
    ['inputposition', { value: 'last', ...PROP_STRING }],
    ['inputwidth', { value: 'default', ...PROP_STRING }],
    ['limit', PROP_NUMBER],
    ['loadingdatamsg', { value: 'Loading items...', ...PROP_STRING }],
    ['match', PROP_STRING],
    ['matchmode', PROP_STRING],
    ['maxsize', PROP_NUMBER],
    ['minchars', { value: 1, ...PROP_NUMBER }],
    ['name', PROP_STRING],
    ['navsearchbar', { value: false, ...PROP_BOOLEAN }],
    ['orderby', PROP_STRING],
    ['placeholder', { value: 'Type here..', ...PROP_STRING }],
    ['query', PROP_STRING],
    ['readonly', PROP_BOOLEAN],
    ['searchkey', PROP_STRING],
    ['shortcutkey', PROP_STRING],
    ['show', { value: true, ...PROP_BOOLEAN }],
    ['showsearchicon', PROP_BOOLEAN],
    ['tabindex', { value: 0, ...PROP_NUMBER }],
    ['type', { value: 'search', ...PROP_STRING }],
    ['debouncetime', { value: 250, ...PROP_NUMBER }],
    ['datacompletemsg', { value: 'No more data to load', ...PROP_STRING }],
]);
const registerProps = () => {
    register('wm-chips', chipsProps);
    registerFormWidget(FormWidgetType.CHIPS, new Map(chipsProps));
};

const _c0 = ["wmChips", ""];
const _c1 = a0 => ({ "full-width": a0 });
const _c2 = (a0, a1) => ({ "active": a0, "disabled": a1 });
const _c3 = (a0, a1, a2) => ({ "no-drag": a0, "chip-duplicate bg-danger": a1, "chip-picture": a2 });
function ChipsComponent_li_0_img_2_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "img", 9);
} if (rf & 2) {
    const item_r3 = i0.ɵɵnextContext().$implicit;
    i0.ɵɵproperty("src", item_r3.imgSrc, i0.ɵɵsanitizeUrl);
} }
function ChipsComponent_li_0_button_4_Template(rf, ctx) { if (rf & 1) {
    const _r10 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "button", 10);
    i0.ɵɵlistener("click", function ChipsComponent_li_0_button_4_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r10 = i0.ɵɵnextContext(); const item_r3 = ctx_r10.$implicit; const $index_r6 = ctx_r10.index; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.removeItem($event, item_r3, $index_r6)); });
    i0.ɵɵelement(1, "i", 11);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const item_r3 = i0.ɵɵnextContext().$implicit;
    i0.ɵɵattribute("aria-label", "Clear " + item_r3.label);
} }
function ChipsComponent_li_0_Template(rf, ctx) { if (rf & 1) {
    const _r2 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "li", 4)(1, "a", 5);
    i0.ɵɵlistener("click", function ChipsComponent_li_0_Template_a_click_1_listener($event) { const item_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.handleChipClick($event, item_r3)); })("keydown.delete", function ChipsComponent_li_0_Template_a_keydown_delete_1_listener($event) { const ctx_r4 = i0.ɵɵrestoreView(_r2); const item_r3 = ctx_r4.$implicit; const $index_r6 = ctx_r4.index; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onDelete($event, item_r3, $index_r6)); })("keydown.backspace", function ChipsComponent_li_0_Template_a_keydown_backspace_1_listener($event) { const ctx_r6 = i0.ɵɵrestoreView(_r2); const item_r3 = ctx_r6.$implicit; const $index_r6 = ctx_r6.index; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onBackspace($event, item_r3, $index_r6)); })("keydown.arrowleft", function ChipsComponent_li_0_Template_a_keydown_arrowleft_1_listener() { const ctx_r7 = i0.ɵɵrestoreView(_r2); const item_r3 = ctx_r7.$implicit; const $index_r6 = ctx_r7.index; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onArrowLeft(item_r3, $index_r6)); })("keydown.arrowright", function ChipsComponent_li_0_Template_a_keydown_arrowright_1_listener() { const ctx_r8 = i0.ɵɵrestoreView(_r2); const item_r3 = ctx_r8.$implicit; const $index_r6 = ctx_r8.index; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onArrowRight(item_r3, $index_r6)); })("focus", function ChipsComponent_li_0_Template_a_focus_1_listener($event) { const item_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.handleChipFocus($event, item_r3)); })("blur", function ChipsComponent_li_0_Template_a_blur_1_listener() { const item_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.readonly ? 0 : item_r3.active = false); });
    i0.ɵɵtemplate(2, ChipsComponent_li_0_img_2_Template, 1, 1, "img", 6);
    i0.ɵɵelement(3, "span", 7);
    i0.ɵɵtemplate(4, ChipsComponent_li_0_button_4_Template, 2, 1, "button", 8);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const item_r3 = ctx.$implicit;
    const ctx_r3 = i0.ɵɵnextContext();
    i0.ɵɵclassMapInterpolate1("chip-item ", ctx_r3.chipclass && !ctx_r3.bindChipclass ? ctx_r3.chipclass : "", "");
    i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction2(9, _c2, item_r3.active, ctx_r3.disabled));
    i0.ɵɵadvance();
    i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction3(12, _c3, !ctx_r3.enablereorder, item_r3.isDuplicate, item_r3.imgSrc));
    i0.ɵɵadvance();
    i0.ɵɵproperty("ngIf", item_r3.imgSrc);
    i0.ɵɵadvance();
    i0.ɵɵproperty("textContent", item_r3.label)("title", item_r3.label);
    i0.ɵɵadvance();
    i0.ɵɵproperty("ngIf", !ctx_r3.readonly);
} }
const WIDGET_CONFIG = {
    widgetType: 'wm-chips',
    hostClass: 'app-chips nav nav-pills list-inline'
};
class ChipsComponent extends DatasetAwareFormComponent {
    static { this.initializeProps = registerProps(); }
    // getter setter is added to pass the datasource to searchcomponent.
    get datasource() {
        return this._datasource;
    }
    set datasource(nv) {
        this._datasource = nv;
        this.searchComponent.datasource = nv;
        this._debounceUpdateQueryModel(this.datavalue || this.toBeProcessedDatavalue);
    }
    constructor(inj, bindDisplayField, bindDisplayExpr, bindDisplayImgSrc, bindDataField, bindDataSet, bindChipclass, explicitContext) {
        super(inj, WIDGET_CONFIG, explicitContext);
        this.bindDisplayField = bindDisplayField;
        this.bindDisplayExpr = bindDisplayExpr;
        this.bindDisplayImgSrc = bindDisplayImgSrc;
        this.bindDataField = bindDataField;
        this.bindDataSet = bindDataSet;
        this.bindChipclass = bindChipclass;
        this.chipsList = [];
        this.maxSizeReached = 'Max size reached';
        this._unsubscribeDv = false;
        styler(this.nativeElement, this);
        // set the showsearchicon as false by default.
        if (!isDefined(this.showsearchicon)) {
            this.showsearchicon = false;
        }
        this.multiple = true;
        this.nextItemIndex = 0; // default chip index
        this._debounceUpdateQueryModel = debounce((val) => {
            this.updateQueryModel(val).then(() => {
                if (this.bindChipclass) {
                    forEach(this.chipsList, (item, index) => {
                        this.registerChipItemClass(item, index);
                    });
                }
            });
        }, 150);
        const datasetSubscription = this.dataset$.subscribe(() => {
            this.searchComponent.dataset = this.dataset;
            // clearing the last results when dataset is reassigned
            this.searchComponent._lastResult = undefined;
            this.nextItemIndex = this.datasetItems.length;
            this._debounceUpdateQueryModel(this.datavalue || this.toBeProcessedDatavalue);
        });
        this.registerDestroyListener(() => datasetSubscription.unsubscribe());
        const datavalueSubscription = this.datavalue$.subscribe((val) => {
            // update queryModel only when parentRef is available.
            if (!this._unsubscribeDv) {
                this.chipsList = [];
                // if the datafield is ALLFILEDS do not fetch the records
                // update the query model with the values we have
                this._debounceUpdateQueryModel(val);
            }
        });
        this.registerDestroyListener(() => datavalueSubscription.unsubscribe());
    }
    ngOnInit() {
        super.ngOnInit();
        this.searchComponent.multiple = true;
        this.searchComponent.binddisplayimagesrc = this.bindDisplayImgSrc;
        this.searchComponent.displayimagesrc = this.displayimagesrc;
        this.searchComponent.binddisplaylabel = this.bindDisplayExpr;
        this.searchComponent.displaylabel = this.displayfield;
        this.searchComponent.datafield = this.bindDataField || this.datafield;
        this.searchComponent.binddataset = this.bindDataSet;
        this.searchComponent.dataset = this.dataset;
        this.searchComponent.searchkey = this.searchkey;
        this.searchComponent.limit = this.limit;
        this.searchComponent.debouncetime = this.debouncetime;
        this.searchComponent.matchmode = this.matchmode;
        this.getTransformedData = (val, isCustom) => {
            return this.searchComponent.getTransformedData([val], this.nextItemIndex++, isCustom);
        };
    }
    ngAfterViewInit() {
        super.ngAfterViewInit();
        if (this.enablereorder) {
            this.configureDnD();
        }
    }
    /**
     * This method returns the evaluated class expression.
     * @param $index index of the chip
     * @param item chip object containing the key, value, label
     * @returns {any} evaluated class expression value
     */
    registerChipItemClass(item, $index) {
        if (this.bindChipclass) {
            const watchName = `${this.widgetId}_chipItemClass_${$index}`;
            $unwatch(watchName);
            //[Todo-CSP]: same as list item class
            this.registerDestroyListener($watch(this.bindChipclass, this.viewParent, { item, $index }, (nv, ov) => {
                this.applyItemClass(getConditionalClasses(nv, ov), $index);
            }, watchName));
        }
    }
    applyItemClass(val, index) {
        const chipItem = this.nativeElement.querySelectorAll('.chip-item').item(index);
        $(chipItem).removeClass(val.toRemove).addClass(val.toAdd);
    }
    removeDuplicates() {
        this.chipsList = getUniqObjsByDataField(this.chipsList, this.datafield, this.displayfield || this.displaylabel);
    }
    // This method updates the queryModel.
    // default call to get the default data can be done only when defaultQuery is true.
    updateQueryModel(data) {
        const promises = [];
        if (!data) {
            this.chipsList = [];
            return Promise.resolve();
        }
        // clone the data as the updations on data will change the datavalue.
        let dataValue = clone(data);
        const prevChipsList = this.chipsList;
        this.chipsList = [];
        // update the model when model has items more than maxsize
        if (this.maxsize && dataValue.length > this.maxsize) {
            this._modelByValue = dataValue = slice(dataValue, 0, this.maxsize);
            data = dataValue;
        }
        const searchQuery = [];
        /**
         * For each value in datavalue,
         * 1. check whether value is in datasetItems, if item is found, addd to the chipsList.
         * 2. else make a default query to the filter and get the record.
         * 3. In step 2, if datavalue is not ALLFIELDS, then make a query. Extract the chipsList from the query response.
         * 4. If there is no response for the value and allowonlyselect is true, remove the value from the datavalue. So that datavalue just contains the valid values.
         * 5. In step 2, if datavalue is ALLFIELDS and value is object, then just prepare the datasetItem from the value.
         * 6. If value is not object and allowonlyselect is false, then create a customModel and replace this value with customModel and prepare datasetItem from this value
         */
        dataValue.forEach((val, i) => {
            const itemFound = find(this.datasetItems, item => {
                return isObject(item.value) ? isEqual(item.value, val) : toString(item.value) === toString(val);
            });
            if (itemFound) {
                this.chipsList.push(itemFound);
            }
            else if (this.datafield !== ALLFIELDS) {
                searchQuery.push(val);
            }
            else if (this.datafield === ALLFIELDS) {
                let dataObj, isCustom = false;
                if (!isObject(val)) {
                    dataObj = this.createCustomDataModel(val);
                    isCustom = true;
                    if (dataObj) {
                        data.splice(i, 1, dataObj);
                    }
                }
                else {
                    // if custom chips is already generated, val will be object as {'dataField_val': 'entered_val'}
                    // Hence check this val in previous chipList and assign the iscustom flag
                    const prevChipObj = prevChipsList.find(obj => {
                        return isEqual(obj.value, val);
                    });
                    if (prevChipObj) {
                        isCustom = prevChipObj.iscustom;
                    }
                }
                dataObj = dataObj || val;
                const transformedData = this.getTransformedData(dataObj, isCustom);
                const chipObj = transformedData[0];
                if (isCustom) {
                    chipObj.iscustom = isCustom;
                }
                this.chipsList.push(chipObj);
            }
        });
        // make default query with all the values and if response for the value is not in datavalue then add a custom chip object.
        if (searchQuery.length) {
            promises.push(this.getDefaultModel(searchQuery, this.nextItemIndex)
                .then(response => {
                this.chipsList = this.chipsList.concat(response || []);
                dataValue.forEach((val, i) => {
                    const isExists = find(this.chipsList, (obj) => {
                        return obj.value.toString() === val.toString();
                    });
                    if (!isExists) {
                        if (this.allowonlyselect) {
                            const index = data.indexOf(val);
                            if (index > -1) {
                                data.splice(index, 1);
                            }
                            return;
                        }
                        const transformedData = this.getTransformedData(val, true);
                        const chipObj = transformedData[0];
                        chipObj.iscustom = true;
                        this.chipsList.push(chipObj);
                    }
                });
            }));
        }
        // default chip data is adding focus on to the search input. Hence this flag helps not to focus.
        this.resetSearchModel(true);
        return Promise.all(promises).then(() => {
            this._modelByValue = data;
            this.removeDuplicates();
            this.updateMaxSize();
            $appDigest();
        });
    }
    resetSearchModel(defaultQuery) {
        this._unsubscribeDv = true;
        // clear search will empty the query model and gets the data when minchars is 0 (i.e. autocomplete) on focus
        // defaultQuery flag is set when widget is not active. This will only load the autocomplete dropup with minchars as 0 when widget is focused/active
        this.searchComponent.clearSearch(undefined, !this.minchars && !defaultQuery);
        this._unsubscribeDv = false;
    }
    // Add the newItem to the list
    addItem($event, widget) {
        const searchComponent = widget;
        let allowAdd;
        let chipObj;
        if (searchComponent && isDefined(searchComponent.datavalue) && searchComponent.queryModel !== '') {
            if (!searchComponent.query || !trim(searchComponent.query)) {
                return;
            }
            chipObj = searchComponent.queryModel;
        }
        else {
            if (this.allowonlyselect) {
                return;
            }
            let dataObj;
            if (this.datafield === ALLFIELDS) {
                if (!isObject(this.searchComponent.query) && trim(this.searchComponent.query)) {
                    dataObj = this.createCustomDataModel(this.searchComponent.query);
                    // return if the custom chip is empty
                    if (!dataObj) {
                        this.resetSearchModel();
                        return;
                    }
                }
            }
            const data = dataObj || trim(this.searchComponent.query);
            if (data) {
                const transformedData = this.getTransformedData(data, true);
                chipObj = transformedData[0];
                chipObj.iscustom = true;
            }
        }
        if (!isDefined(chipObj) || chipObj === '') {
            return;
        }
        allowAdd = this.invokeEventCallback('beforeadd', { $event, newItem: chipObj });
        if (isDefined(allowAdd) && !toBoolean(allowAdd)) {
            return;
        }
        if (this.isDuplicate(chipObj)) {
            this.resetSearchModel();
            return;
        }
        this.registerChipItemClass(chipObj, this.chipsList.length);
        this.chipsList.push(chipObj);
        if (!this.datavalue) {
            this._modelByValue = [chipObj.value];
        }
        else {
            this._modelByValue = [...this._modelByValue, chipObj.value];
        }
        this._unsubscribeDv = true;
        this.invokeOnTouched();
        this.invokeOnChange(this._modelByValue, $event || {}, true);
        this.invokeEventCallback('add', { $event, $item: chipObj });
        this.updateMaxSize();
        // reset input box when item is added.
        this.resetSearchModel();
        // stop the event to not to call the submit event on enter press.
        if ($event && ($event.key === 'Enter' || $event.keyCode === 13)) {
            this.stopEvent($event);
        }
    }
    // Prepare datavalue object from a string(junk) value when datafield is allFields.
    createCustomDataModel(val) {
        const key = this.displayfield || (this.datafield !== ALLFIELDS ? this.datafield : undefined);
        if (key) {
            const customObj = {};
            customObj[key] = val;
            return customObj;
        }
    }
    // Check if newItem already exists
    isDuplicate(item) {
        if (this.datafield === ALLFIELDS) {
            return findIndex(this.chipsList, { value: item.value }) > -1;
        }
        return findIndex(this.chipsList, { key: item.key }) > -1;
    }
    // Check if max size is reached
    updateMaxSize() {
        this.saturate = this.maxsize > 0 && this.chipsList.length === this.maxsize;
    }
    // Makes call to searchComponent to filter the dataSource based on the query.
    getDefaultModel(query, index) {
        this.nextItemIndex++;
        return this.searchComponent.getDataSource(query, true, index)
            .then((response) => {
            // @ts-ignore
            return filter(query, queryVal => {
                find(response, { value: queryVal });
            });
        });
    }
    handleChipClick($event, chip) {
        if (this.readonly) {
            return;
        }
        $event.currentTarget.focus();
        this.invokeEventCallback('chipclick', { $event, $item: chip });
    }
    handleChipFocus($event, chip) {
        if (this.readonly) {
            return;
        }
        chip.active = true;
        this.invokeEventCallback('chipselect', { $event, $item: chip });
    }
    // To avoid form submit on pressing enter key
    stopEvent($event) {
        $event.stopPropagation();
        $event.preventDefault();
    }
    onTextDelete($event) {
        if (isAppleProduct) {
            this.onInputClear($event);
        }
    }
    onInputClear($event) {
        if (!this.chipsList || !this.chipsList.length || this.searchComponent.query) {
            return;
        }
        this.$element.find('li.chip-item > a.app-chip').last().focus();
        this.stopEvent($event);
    }
    onBackspace($event, $item, $index) {
        if (this.readonly) {
            return;
        }
        this.removeItem($event, $item, $index, true);
    }
    onDelete($event, $item, $index) {
        if (this.readonly) {
            return;
        }
        this.removeItem($event, $item, $index);
    }
    onArrowLeft($item, $index) {
        if (this.readonly) {
            return;
        }
        // On left arrow click when search input query is empty.
        if (!this.searchComponent.query && !isDefined($index) && !isDefined($item)) {
            this.$element.find('li.chip-item > a.app-chip').last().focus();
            return;
        }
        if ($index > 0) {
            this.$element.find('li.chip-item > a.app-chip').get($index - 1).focus();
        }
        else {
            this.focusSearchBox();
        }
    }
    onArrowRight($item, $index) {
        if (this.readonly) {
            return;
        }
        // On right arrow click when search input query is empty.
        if (!this.searchComponent.query && !isDefined($index) && !isDefined($item)) {
            this.$element.find('li.chip-item > a.app-chip').first().focus();
            return;
        }
        if ($index < (this.chipsList.length - 1)) {
            this.$element.find('li.chip-item > a.app-chip').get($index + 1).focus();
        }
        else {
            this.focusSearchBox();
        }
    }
    // focus search box.
    focusSearchBox() {
        this.$element.find('.app-chip-input > input.app-textbox').focus();
    }
    // Remove the item from list
    removeItem($event, item, index, canFocus) {
        $event.stopPropagation();
        const indexes = isArray(index) ? index : [index];
        const focusIndex = max(indexes);
        const items = reduce(indexes, (result, i) => {
            result.push(this.chipsList[i]);
            return result;
        }, []);
        // prevent deletion if the before-remove event callback returns false
        const allowRemove = this.invokeEventCallback('beforeremove', { $event, $item: items.length === 1 ? items[0] : items });
        if (isDefined(allowRemove) && !toBoolean(allowRemove)) {
            return;
        }
        const prevDatavalue = clone(this.datavalue);
        // focus next chip after deletion.
        // if there are no chips in the list focus search box
        setTimeout(() => {
            const chipsLength = this.chipsList.length;
            const $chipsList = this.$element.find('li.chip-item > a.app-chip');
            if (!chipsLength || !canFocus) {
                this.focusSearchBox();
            }
            else if ((chipsLength - 1) < focusIndex) {
                // if focus index is greater than chips length select last chip
                $chipsList.get(chipsLength - 1).focus();
            }
            else {
                // manually set the succeeding chip as active if there is a chip next to the current chip.
                this.chipsList[focusIndex].active = true;
                $chipsList.get(focusIndex).focus();
            }
        });
        const pulledItems = pullAt(this.chipsList, indexes);
        pulledItems.forEach(datasetItem => {
            this._modelByValue = filter(this._modelByValue, val => {
                return !(isObject(val) ? isEqual(val, datasetItem.value) : toString(val) === toString(datasetItem.value));
            });
        });
        this._unsubscribeDv = false;
        this.invokeOnChange(this._modelByValue, $event, true);
        this.invokeEventCallback('change', { $event, newVal: this.datavalue, oldVal: prevDatavalue });
        this.updateMaxSize();
        this.invokeEventCallback('remove', { $event, $item: items.length === 1 ? items[0] : items });
    }
    /**
     * Swaps items in an array if provided with indexes.
     * @param data :- array to be swapped
     * @param newIndex :- new index for the element to be placed
     * @param currentIndex :- the current index of the element.
     */
    swapElementsInArray(data, newIndex, currentIndex) {
        const draggedItem = pullAt(data, currentIndex)[0];
        data.splice(newIndex, 0, draggedItem);
    }
    /**
     * Cancels the reorder by reseting the elements to the original position.
     */
    resetReorder() {
        this.$element.removeData('oldIndex');
    }
    invokeOnBeforeServiceCall(inputData) {
        this.invokeEventCallback('beforeservicecall', { inputData });
    }
    handleEvent(node, eventName, eventCallback, locals) {
        if (eventName === 'remove' || eventName === 'beforeremove' || eventName === 'chipselect'
            || eventName === 'chipclick' || eventName === 'add' || eventName === 'reorder' || eventName === 'change') {
            return;
        }
        super.handleEvent(node, eventName, eventCallback, locals);
    }
    // Configures the reordable feature in chips widgets.
    configureDnD() {
        const options = {
            items: '> li:not(.app-chip-search)',
            placeholder: 'chip-placeholder'
        };
        configureDnD(this.$element, options, this.onReorderStart.bind(this), this.update.bind(this));
    }
    // Triggered on drag start while reordering.
    onReorderStart(evt, ui) {
        const helper = ui.helper;
        // increasing the width of the dragged item by 1
        helper.width(helper.width() + 1);
        this.$element.data('oldIndex', ui.item.index() - (this.inputposition === 'first' ? 1 : 0));
    }
    // updates the chipsList and datavalue on reorder.
    update($event, ui) {
        let changedItem, newIndex, oldIndex;
        // Get the index of the item at position before drag and after the reorder.
        newIndex = ui.item.index() - (this.inputposition === 'first' ? 1 : 0);
        oldIndex = this.$element.data('oldIndex');
        newIndex = this.chipsList.length === newIndex ? newIndex - 1 : newIndex;
        changedItem = {
            oldIndex: oldIndex,
            newIndex: newIndex,
            item: this.chipsList[oldIndex]
        };
        if (newIndex === oldIndex) {
            this.resetReorder();
            return;
        }
        changedItem.item = this.chipsList[oldIndex];
        const allowReorder = this.invokeEventCallback('beforereorder', { $event, $data: this.chipsList, $changedItem: changedItem });
        if (isDefined(allowReorder) && toBoolean(allowReorder) === false) {
            this.resetReorder();
            return;
        }
        // modify the chipsList and datavalue after the reorder.
        this.swapElementsInArray(this.chipsList, newIndex, oldIndex);
        this.swapElementsInArray(this._modelByValue, newIndex, oldIndex);
        changedItem.item = this.chipsList[newIndex];
        this.chipsList = [...this.chipsList];
        this.resetReorder();
        this.invokeEventCallback('reorder', { $event, $data: this.chipsList, $changedItem: changedItem });
    }
    onPropertyChange(key, nv, ov) {
        if (key === 'tabindex') {
            return;
        }
        if (key === 'dataoptions') {
            this.searchComponent.dataoptions = nv;
        }
        if (key === 'datafield') {
            this.searchComponent.datafield = this.datafield;
        }
        if (key === 'displayfield') {
            this.searchComponent.displaylabel = this.displayfield;
        }
        if (key === 'displayexpression') {
            this.searchComponent.binddisplaylabel = this.binddisplayexpression ? this.binddisplayexpression : this.displayexpression;
        }
        if (key === 'displayimagesrc') {
            this.searchComponent.binddisplayimagesrc = this.binddisplayimagesrc ? this.binddisplayimagesrc : this.displayimagesrc;
        }
        if (key === 'limit') {
            this.searchComponent.limit = this.limit;
        }
        if (key === 'matchmode') {
            this.searchComponent.matchmode = this.matchmode;
        }
        if (key === 'groupby') {
            this.searchComponent.groupby = this.groupby;
        }
        if (key === 'enablereorder') {
            if (this.$element.hasClass('ui-sortable')) {
                this.$element.sortable('option', 'disabled', !nv);
            }
            else if (nv) {
                this.configureDnD();
            }
            // Add this block to handle drag prevention
            const chipElements = this.$element.find('.chip-item a.app-chip');
            if (!nv) {
                chipElements.addClass('no-drag');
                // Prevent default drag behavior
                chipElements.on('dragstart', (e) => {
                    e.preventDefault();
                    return false;
                });
            }
            else {
                chipElements.removeClass('no-drag');
                chipElements.off('dragstart');
            }
        }
        if (key === 'readonly') {
            if (nv) {
                this.$element.addClass('readonly');
            }
            else {
                this.$element.removeClass('readonly');
            }
        }
        if (key === 'inputposition') {
            const $inputEl = this.$element.find('li.app-chip-search');
            if (nv === 'first') {
                this.$element.prepend($inputEl);
            }
            else {
                this.$element.append($inputEl);
            }
        }
        if (key === 'autofocus' && nv) {
            // setting the autofocus on the input once after dom is updated
            setTimeout(() => {
                const $chipsList = this.$element.find('.app-chip-input > input.app-textbox');
                if ($chipsList && $chipsList.length) {
                    this.focusSearchBox();
                }
            });
        }
        super.onPropertyChange(key, nv, ov);
    }
    static { this.ɵfac = function ChipsComponent_Factory(t) { return new (t || ChipsComponent)(i0.ɵɵdirectiveInject(i0.Injector), i0.ɵɵinjectAttribute('displayfield.bind'), i0.ɵɵinjectAttribute('displayexpression.bind'), i0.ɵɵinjectAttribute('displayimagesrc.bind'), i0.ɵɵinjectAttribute('datafield.bind'), i0.ɵɵinjectAttribute('dataset.bind'), i0.ɵɵinjectAttribute('chipclass.bind'), i0.ɵɵdirectiveInject('EXPLICIT_CONTEXT', 8)); }; }
    static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ChipsComponent, selectors: [["", "wmChips", ""]], viewQuery: function ChipsComponent_Query(rf, ctx) { if (rf & 1) {
            i0.ɵɵviewQuery(SearchComponent, 7);
        } if (rf & 2) {
            let _t;
            i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.searchComponent = _t.first);
        } }, features: [i0.ɵɵProvidersFeature([
                provideAs(ChipsComponent, NG_VALUE_ACCESSOR, true),
                provideAsWidgetRef(ChipsComponent)
            ]), i0.ɵɵInheritDefinitionFeature], attrs: _c0, decls: 4, vars: 4, consts: [["search", ""], [3, "class", "ngClass", 4, "ngFor", "ngForOf"], [1, "app-chip-search", 3, "ngClass"], ["wmSearch", "", "name", "app-chip-search", "submit.event", "addItem($event, widget)", "beforeservicecall.event", "invokeOnBeforeServiceCall(inputData)", "disabled.bind", "disabled || readonly || saturate", "datafield.bind", "datafield", "allowonlyselect.bind", "allowonlyselect", "searchkey.bind", "searchkey", "orderby.bind", "orderby", "placeholder.bind", "saturate ? maxSizeReached : placeholder", "showsearchicon.bind", "showsearchicon", "tabindex.bind", "tabindex", "minchars.bind", "minchars", "debouncetime.bind", "debouncetime", "matchmode.bind", "matchmode", "datacompletemsg.bind", "datacompletemsg", "groupby.bind", "groupby", "match.bind", "match", "dateformat.bind", "dateformat", 1, "app-chip-input", 3, "keydown.enter", "keydown.delete", "keydown.backspace", "keydown.arrowleft", "keydown.arrowright"], [3, "ngClass"], ["href", "javascript:void(0)", 1, "app-chip", 3, "click", "keydown.delete", "keydown.backspace", "keydown.arrowleft", "keydown.arrowright", "focus", "blur", "ngClass"], ["data-identifier", "img", "alt", "Chip Image", "class", "button-image-icon", 3, "src", 4, "ngIf"], [1, "app-chip-title", 3, "textContent", "title"], ["type", "button", "class", "btn btn-transparent", 3, "click", 4, "ngIf"], ["data-identifier", "img", "alt", "Chip Image", 1, "button-image-icon", 3, "src"], ["type", "button", 1, "btn", "btn-transparent", 3, "click"], [1, "app-icon", "wi", "wi-close"]], template: function ChipsComponent_Template(rf, ctx) { if (rf & 1) {
            const _r1 = i0.ɵɵgetCurrentView();
            i0.ɵɵtemplate(0, ChipsComponent_li_0_Template, 5, 16, "li", 1);
            i0.ɵɵelementStart(1, "li", 2)(2, "div", 3, 0);
            i0.ɵɵlistener("keydown.enter", function ChipsComponent_Template_div_keydown_enter_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.stopEvent($event)); })("keydown.delete", function ChipsComponent_Template_div_keydown_delete_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onTextDelete($event)); })("keydown.backspace", function ChipsComponent_Template_div_keydown_backspace_2_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onInputClear($event)); })("keydown.arrowleft", function ChipsComponent_Template_div_keydown_arrowleft_2_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onArrowLeft()); })("keydown.arrowright", function ChipsComponent_Template_div_keydown_arrowright_2_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onArrowRight()); });
            i0.ɵɵelementEnd()();
        } if (rf & 2) {
            i0.ɵɵproperty("ngForOf", ctx.chipsList);
            i0.ɵɵadvance();
            i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(2, _c1, ctx.inputwidth === "full"));
        } }, dependencies: [i1.NgClass, i1.NgForOf, i1.NgIf, i2.SearchComponent, i3.TextContentDirective], encapsulation: 2 }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ChipsComponent, [{
        type: Component,
        args: [{ selector: '[wmChips]', providers: [
                    provideAs(ChipsComponent, NG_VALUE_ACCESSOR, true),
                    provideAsWidgetRef(ChipsComponent)
                ], template: "<li class=\"chip-item {{chipclass && !bindChipclass ? chipclass : ''}}\"\n    *ngFor=\"let item of chipsList; let $index = index;\"\n    [ngClass]=\"{'active': item.active, 'disabled': disabled}\">\n    <a href=\"javascript:void(0)\" class=\"app-chip\"\n       (click)=\"handleChipClick($event, item)\"\n       (keydown.delete)=\"onDelete($event, item, $index)\"\n       (keydown.backspace)=\"onBackspace($event, item, $index)\"\n       (keydown.arrowleft)=\"onArrowLeft(item, $index)\"\n       (keydown.arrowright)=\"onArrowRight(item, $index)\"\n       (focus)=\"handleChipFocus($event, item)\"\n       (blur)=\"readonly ? 0 : item.active = false\"\n       [ngClass]=\"{'no-drag': !enablereorder,'chip-duplicate bg-danger': item.isDuplicate, 'chip-picture': item.imgSrc}\">\n        <img data-identifier=\"img\" alt=\"Chip Image\" class=\"button-image-icon\" [src]=\"item.imgSrc\" *ngIf=\"item.imgSrc\"/>\n        <span class=\"app-chip-title\" [textContent]=\"item.label\" [title]=\"item.label\"></span>\n        <button type=\"button\" [attr.aria-label]=\"'Clear ' + item.label\" class=\"btn btn-transparent\"\n                (click)=\"removeItem($event, item, $index);\" *ngIf=\"!readonly\">\n            <i class=\"app-icon wi wi-close\"></i>\n        </button>\n    </a>\n</li>\n<li class=\"app-chip-search\" [ngClass]=\"{'full-width': inputwidth === 'full'}\">\n    <div #search wmSearch class=\"app-chip-input\"\n         name=\"app-chip-search\"\n         submit.event=\"addItem($event, widget)\"\n         beforeservicecall.event=\"invokeOnBeforeServiceCall(inputData)\"\n         disabled.bind=\"disabled || readonly || saturate\"\n         datafield.bind=\"datafield\"\n         allowonlyselect.bind=\"allowonlyselect\"\n         searchkey.bind=\"searchkey\"\n         orderby.bind=\"orderby\"\n         placeholder.bind=\"saturate ? maxSizeReached : placeholder\"\n         showsearchicon.bind=\"showsearchicon\"\n         tabindex.bind=\"tabindex\"\n         minchars.bind=\"minchars\"\n         debouncetime.bind=\"debouncetime\"\n         matchmode.bind=\"matchmode\"\n         datacompletemsg.bind = \"datacompletemsg\"\n         groupby.bind=\"groupby\"\n         match.bind=\"match\"\n         dateformat.bind=\"dateformat\"\n         (keydown.enter)=\"stopEvent($event)\"\n         (keydown.delete)=\"onTextDelete($event)\"\n         (keydown.backspace)=\"onInputClear($event)\"\n         (keydown.arrowleft)=\"onArrowLeft()\"\n         (keydown.arrowright)=\"onArrowRight()\">\n    </div>\n</li>\n" }]
    }], () => [{ type: i0.Injector }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['displayfield.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['displayexpression.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['displayimagesrc.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['datafield.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['dataset.bind']
            }] }, { type: undefined, decorators: [{
                type: Attribute,
                args: ['chipclass.bind']
            }] }, { type: undefined, decorators: [{
                type: Inject,
                args: ['EXPLICIT_CONTEXT']
            }, {
                type: Optional
            }] }], { searchComponent: [{
            type: ViewChild,
            args: [SearchComponent, /* TODO: add static flag */ { static: true }]
        }] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ChipsComponent, { className: "ChipsComponent", filePath: "chips.component.ts", lineNumber: 53 }); })();

const components = [
    ChipsComponent
];
class ChipsModule {
    static { this.ɵfac = function ChipsModule_Factory(t) { return new (t || ChipsModule)(); }; }
    static { this.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: ChipsModule }); }
    static { this.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
            SearchModule,
            WmComponentsModule] }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ChipsModule, [{
        type: NgModule,
        args: [{
                imports: [
                    CommonModule,
                    SearchModule,
                    WmComponentsModule
                ],
                declarations: [...components],
                exports: [...components]
            }]
    }], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(ChipsModule, { declarations: [ChipsComponent], imports: [CommonModule,
        SearchModule,
        WmComponentsModule], exports: [ChipsComponent] }); })();

/**
 * Generated bundle index. Do not edit.
 */

export { ChipsComponent, ChipsModule };
//# sourceMappingURL=index.mjs.map
