UNPKG

@syncfusion/ej2-dropdowns

Version:

Essential JS 2 DropDown Components

989 lines (984 loc) 1.12 MB
import { EventHandler, Touch, isNullOrUndefined, getValue, select, Browser, debounce, ChildProperty, Property, Component, selectAll, compile, L10n, addClass, removeClass, extend, append, setStyleAttribute, prepend, rippleEffect, detach, Complex, Event, NotifyPropertyChanges, classList, closest, KeyboardEvents, attributes, isUndefined, formatUnit, Animation, getUniqueID, remove, SanitizeHtmlHelper, setValue, matches as matches$1, createElement, getComponent } from '@syncfusion/ej2-base'; import { DataManager, Query, DataUtil, Predicate, JsonAdaptor } from '@syncfusion/ej2-data'; import { ListBase, Sortable, cssClass, moveTo } from '@syncfusion/ej2-lists'; import { Skeleton } from '@syncfusion/ej2-notifications'; import { hideSpinner, createSpinner, showSpinner, isCollide, Popup, getZindexPartial } from '@syncfusion/ej2-popups'; import { Input, TextBox } from '@syncfusion/ej2-inputs'; import { createCheckBox, Button } from '@syncfusion/ej2-buttons'; import { TreeView } from '@syncfusion/ej2-navigations'; /** * IncrementalSearch module file */ let queryString = ''; let prevString = ''; let tempQueryString = ''; let matches = []; const activeClass = 'e-active'; let prevElementId = ''; /** * Search and focus the list item based on key code matches with list text content. * * @param {number} keyCode - Specifies the key code which pressed on keyboard events. * @param {HTMLElement[]} items - Specifies an array of HTMLElement, from which matches find has done. * @param {number} selectedIndex - Specifies the selected item in list item, so that search will happen after selected item otherwise it will do from initial. * @param {boolean} ignoreCase - Specifies the case consideration when search has done. * @param {string} elementId - Specifies the list element ID. * @param {boolean} [queryStringUpdated] - Optional parameter. * @param {string} [currentValue] - Optional parameter. * @param {boolean} [isVirtual] - Optional parameter. * @param {boolean} [refresh] - Optional parameter. * @returns {Element} Returns list item based on key code matches with list text content. */ function incrementalSearch(keyCode, items, selectedIndex, ignoreCase, elementId, queryStringUpdated, currentValue, isVirtual, refresh) { if (!queryStringUpdated || queryString === '') { if (tempQueryString !== '') { queryString = tempQueryString + String.fromCharCode(keyCode); tempQueryString = ''; } else { queryString += String.fromCharCode(keyCode); } } else if (queryString === prevString) { tempQueryString = String.fromCharCode(keyCode); } if (isVirtual) { setTimeout(function () { tempQueryString = ''; }, 700); setTimeout(function () { queryString = ''; }, 3000); } else { setTimeout(function () { queryString = ''; }, 1000); } let index; queryString = ignoreCase ? queryString.toLowerCase() : queryString; if (prevElementId === elementId && prevString === queryString && !refresh) { for (let i = 0; i < matches.length; i++) { if (matches[i].classList.contains(activeClass)) { index = i; break; } if (currentValue && matches[i].textContent.toLowerCase() === currentValue.toLowerCase()) { index = i; break; } } index = index + 1; if (isVirtual) { return matches[index] && matches.length - 1 !== index ? matches[index] : matches[matches.length]; } return matches[index] ? matches[index] : matches[0]; } else { const listItems = items; const strLength = queryString.length; let text; let item; selectedIndex = selectedIndex ? selectedIndex + 1 : 0; let i = selectedIndex; matches = []; do { if (i === listItems.length) { i = -1; } if (i === -1) { index = 0; } else { index = i; } item = listItems[index]; text = ignoreCase ? item.innerText.toLowerCase() : item.innerText; if (text.substr(0, strLength) === queryString) { matches.push(listItems[index]); } i++; } while (i !== selectedIndex); prevString = queryString; prevElementId = elementId; if (isVirtual) { let indexUpdated = false; for (let i = 0; i < matches.length; i++) { if (currentValue && matches[i].textContent.toLowerCase() === currentValue.toLowerCase()) { index = i; indexUpdated = true; break; } } if (currentValue && indexUpdated) { index = index + 1; } return matches[index] ? matches[index] : matches[0]; } return matches[0]; } } // eslint-disable-next-line valid-jsdoc /** * Search the list item based on given input value matches with search type. * * @param {string} inputVal - Specifies the given input value. * @param {HTMLElement[]} items - Specifies the list items. * @param {SearchType} searchType - Specifies the filter type. * @param {boolean} [ignoreCase=true] - Specifies the case sensitive option for search operation. * @param {(string | number | boolean | { [key: string]: Object })[]} [dataSource] - Specifies the data source. * @param {{ text: string, value: string }} [fields] - Specifies the fields. * @param {string} [type] - Specifies the type. * @returns {{ item: Element | null, index: number | null }} Returns the search matched items. */ function Search(inputVal, items, searchType, ignoreCase, dataSource, fields, type, ignoreAccent) { const listItems = items; ignoreCase = ignoreCase !== undefined && ignoreCase !== null ? ignoreCase : true; const itemData = { item: null, index: null }; if (inputVal && inputVal.length && items) { const strLength = inputVal.length; let queryStr = ignoreCase ? inputVal.toLocaleLowerCase() : inputVal; queryStr = escapeCharRegExp(queryStr); for (let i = 0, itemsData = listItems; i < itemsData.length; i++) { const item = itemsData[i]; let filterValue; if (items && dataSource) { const checkField = item; const fieldValue = fields.text.split('.'); dataSource.filter((data) => { Array.prototype.slice.call(fieldValue).forEach((value) => { /* eslint-disable security/detect-object-injection */ if ((type === 'object' && !data.isHeader && checkField.textContent.toString().indexOf(data[value]) !== -1 && data[fields.value] != null && checkField.getAttribute('data-value') === data[fields.value].toString()) || (type === 'string' && checkField.textContent.toString().indexOf(data) !== -1)) { filterValue = type === 'object' ? data[value] : data; } }); }); } let text = dataSource && filterValue ? (ignoreCase ? filterValue.toString().toLocaleLowerCase() : filterValue).replace(/^\s+|\s+$/g, '') : (ignoreCase ? item.textContent.toLocaleLowerCase() : item.textContent).replace(/^\s+|\s+$/g, ''); /* eslint-disable security/detect-non-literal-regexp */ if (ignoreAccent && text && queryStr) { text = text.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); queryStr = queryStr.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); } if ((searchType === 'Equal' && text === queryStr) || (searchType === 'StartsWith' && text.substr(0, strLength) === queryStr) || (searchType === 'EndsWith' && text.substr(text.length - queryStr.length) === queryStr) || (searchType === 'Contains' && new RegExp(queryStr, 'g').test(text))) { itemData.item = item; itemData.index = i; return { item: item, index: i }; } } return itemData; /* eslint-enable security/detect-non-literal-regexp */ } return itemData; } /** * @param {string} value - The value to escape. * @returns {string} Returns the escaped string. */ function escapeCharRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } /** * @param {string} elementId - The ID of the list element. * @returns {void} */ function resetIncrementalSearchValues(elementId) { if (prevElementId === elementId) { prevElementId = ''; prevString = ''; queryString = ''; matches = []; } } /** * Function helps to find which highlightSearch is to call based on your data. * * @param {HTMLElement} element - Specifies an li element. * @param {string} query - Specifies the string to be highlighted. * @param {boolean} ignoreCase - Specifies the ignoreCase option. * @param {HightLightType} type - Specifies the type of highlight. * @returns {void} */ function highlightSearch(element, query, ignoreCase, type) { const isHtmlElement = /<[^>]*>/g.test(element.innerText); if (isHtmlElement) { element.innerText = element.innerText.replace(/[\u00A0-\u9999<>&]/g, (match) => `&#${match.charCodeAt(0)};`); } if (query === '') { return; } else { const ignoreRegex = ignoreCase ? 'gim' : 'gm'; // eslint-disable-next-line query = /^[a-zA-Z0-9- ]*$/.test(query) ? query : query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); const replaceQuery = type === 'StartsWith' ? '^(' + query + ')' : type === 'EndsWith' ? '(' + query + ')$' : '(' + query + ')'; // eslint-disable-next-line security/detect-non-literal-regexp findTextNode(element, new RegExp(replaceQuery, ignoreRegex)); } } /* eslint-enable jsdoc/require-param, valid-jsdoc */ /** * * @param {HTMLElement} element - Specifies the element. * @param {RegExp} pattern - Specifies the regex to match the searched text. * @returns {void} */ function findTextNode(element, pattern) { for (let index = 0; element.childNodes && (index < element.childNodes.length); index++) { if (element.childNodes[index].nodeType === 3 && element.childNodes[index].textContent.trim() !== '') { const value = element.childNodes[index].nodeValue.trim().replace(pattern, '<span class="e-highlight">$1</span>'); element.childNodes[index].nodeValue = ''; element.innerHTML = element.innerHTML.trim() + value; break; } else { findTextNode(element.childNodes[index], pattern); } } } /** * Function helps to remove highlighted element based on your data. * * @param {HTMLElement} content - Specifies an content element. * @returns {void} */ function revertHighlightSearch(content) { const contentElement = content.querySelectorAll('.e-highlight'); for (let i = contentElement.length - 1; i >= 0; i--) { const parent = contentElement[i].parentNode; const text = document.createTextNode(contentElement[i].textContent); parent.replaceChild(text, contentElement[i]); } } var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; class VirtualScroll { constructor(parent) { this.sentinelInfo = { 'up': { check: (rect, info) => { const top = rect.top - this.containerElementRect.top; info.entered = top >= 0; return top + (this.parent.listItemHeight * this.parent.virtualItemCount / 2) >= 0; }, axis: 'Y' }, 'down': { check: (rect, info) => { const top = rect.bottom; info.entered = rect.bottom <= this.containerElementRect.bottom; return top - (this.parent.listItemHeight * this.parent.virtualItemCount / 2) <= this.parent.listItemHeight * this.parent.virtualItemCount / 2; }, axis: 'Y' } }; this.parent = parent; this.removeEventListener(); this.addEventListener(); } addEventListener() { if (this.parent.isDestroyed) { return; } this.parent.on('observe', this.observe, this); this.parent.on('setGeneratedData', this.setGeneratedData, this); this.parent.on('dataProcessAsync', this.dataProcessAsync, this); this.parent.on('setCurrentViewDataAsync', this.setCurrentViewDataAsync, this); this.parent.on('bindScrollEvent', this.bindScrollEvent, this); } removeEventListener() { if (this.parent.isDestroyed) { return; } this.parent.off('observe', this.observe); this.parent.off('setGeneratedData', this.setGeneratedData); this.parent.off('dataProcessAsync', this.dataProcessAsync); this.parent.off('setCurrentViewDataAsync', this.setCurrentViewDataAsync); this.parent.off('bindScrollEvent', this.bindScrollEvent); } bindScrollEvent(component) { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.component = component.component; this.observe((scrollArgs) => this.scrollListener(scrollArgs)); } observe(callback) { this.containerElementRect = this.parent.popupContentElement.getBoundingClientRect(); EventHandler.add(this.parent.popupContentElement, 'wheel mousedown', this.popupScrollHandler, this); this.touchModule = new Touch(this.parent.popupContentElement, { scroll: this.popupScrollHandler.bind(this) }); EventHandler.add(this.parent.popupContentElement, 'scroll', this.virtualScrollHandler(callback), this); } getModuleName() { return 'VirtualScroll'; } popupScrollHandler() { this.parent.isMouseScrollAction = true; this.parent.isPreventScrollAction = false; } getPageQuery(query, virtualStartIndex, virtualEndIndex) { if (virtualEndIndex !== 0 && !this.parent.allowFiltering && this.component !== 'autocomplete') { query = query.skip(virtualStartIndex); } return query; } setGeneratedData(qStartIndex, recentlyGeneratedData) { let loopIteration = 0; const endIndex = this.parent.listData.length + this.parent.virtualItemStartIndex; for (let i = this.parent.virtualItemStartIndex; i < endIndex; i++) { const alreadyAddedData = this.parent.generatedDataObject[i]; if (!alreadyAddedData) { if (recentlyGeneratedData !== null && this.parent.listData.slice(loopIteration, loopIteration + 1).length > 0) { const slicedData = this.parent.listData.slice(loopIteration, loopIteration + 1); if (slicedData.length > 0) { // Safely assign slicedData to this.parent.generatedDataObject[i] this.parent.generatedDataObject[i] = slicedData; } } } loopIteration++; } } generateAndExecuteQueryAsync(query, virtualItemStartIndex = 0, virtualItemEndIndex = 0, isQueryGenerated = false) { const dataSource = this.parent.dataSource; if (!isQueryGenerated) { // eslint-disable-next-line @typescript-eslint/no-explicit-any if (!isNullOrUndefined(this.parent.query)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const newQuery = this.removeSkipAndTakeEvents(this.parent.query.clone()); query = this.getPageQuery(newQuery, virtualItemStartIndex, virtualItemEndIndex); } else { query = this.getPageQuery(query, virtualItemStartIndex, virtualItemEndIndex); } } const tempCustomFilter = this.parent.isCustomFilter; if (this.component === 'combobox') { let totalData = 0; if (this.parent.dataSource instanceof DataManager) { totalData = this.parent.remoteDataCount; } else if (this.parent.dataSource && this.parent.dataSource.length > 0) { // eslint-disable-next-line @typescript-eslint/no-explicit-any totalData = this.parent.dataSource.length; } if (totalData > 0) { this.parent.isCustomFilter = (totalData === this.parent.totalItemCount && this.parent.queryString !== this.parent.typedString) ? true : this.parent.isCustomFilter; } } this.parent.resetList(dataSource, this.parent.fields, query); this.parent.isCustomFilter = tempCustomFilter; } removeSkipAndTakeEvents(query) { query.queries = query.queries.filter(function (event) { return event.fn !== 'onSkip' && event.fn !== 'onTake'; }); return query; } setCurrentViewDataAsync(component) { // eslint-disable-next-line let currentData = []; let isResetListCalled = false; let isListUpdated = true; if (isNullOrUndefined(this.component)) { this.component = component.component; } let endIndex = this.parent.viewPortInfo.endIndex; if (this.component === 'multiselect' && this.parent.mode === 'CheckBox' && this.parent.value && Array.isArray(this.parent.value) && this.parent.value.length > 0 && this.parent.enableSelectionOrder && this.parent.targetElement().trim() === '') { if (this.parent.viewPortInfo.startIndex < this.parent.value.length) { endIndex = this.parent.viewPortInfo.endIndex - this.parent.value.length; if (this.parent.viewPortInfo.startIndex === 0) { const oldUlElement = this.parent.list.querySelector('.e-list-parent' + ':not(.e-reorder)'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } this.parent.updateVirtualReOrderList(true); if (this.parent.value.length < this.parent.itemCount && this.parent.value.length !== this.parent.totalItemCount) { const oldUlElement = this.parent.list.querySelector('.e-list-parent' + ':not(.e-reorder)'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } let query = this.parent.getForQuery(this.parent.value).clone(); query = query.skip(0) .take(this.parent.itemCount - (this.parent.value.length - this.parent.viewPortInfo.startIndex)); this.parent.appendUncheckList = true; this.parent.setCurrentView = false; this.parent.resetList(this.parent.dataSource, this.parent.fields, query); isListUpdated = false; this.parent.appendUncheckList = this.parent.dataSource instanceof DataManager ? this.parent.appendUncheckList : false; isListUpdated = false; } else { const oldUlElement = this.parent.list.querySelector('.e-list-parent' + ':not(.e-reorder)'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } } isListUpdated = false; } else if (this.parent.viewPortInfo.startIndex !== 0) { this.parent.updateVirtualReOrderList(true); const oldUlElement = this.parent.list.querySelector('.e-list-parent' + ':not(.e-reorder)'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } isListUpdated = false; } if (this.parent.viewPortInfo.startIndex !== 0 && this.parent.viewPortInfo.startIndex - this.parent.value.length !== this.parent.itemCount && (this.parent.viewPortInfo.startIndex + this.parent.itemCount > this.parent.value.length)) { let query = this.parent.getForQuery(this.parent.value).clone(); query = query.skip(0).take(this.parent.itemCount - (this.parent.value.length - this.parent.viewPortInfo.startIndex)); this.parent.appendUncheckList = true; this.parent.setCurrentView = false; const oldUlElement = this.parent.list.querySelector('.e-list-parent' + ':not(.e-reorder)'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } this.parent.resetList(this.parent.dataSource, this.parent.fields, query); isListUpdated = false; this.parent.appendUncheckList = this.parent.dataSource instanceof DataManager ? this.parent.appendUncheckList : false; } } else { const reOrderList = this.parent.list.querySelectorAll('.e-reorder')[0]; if (this.parent.list.querySelector('.e-virtual-ddl-content') && reOrderList) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(reOrderList); } let query = this.parent.getForQuery(this.parent.value).clone(); // Assuming query is of type any const skipvalue = this.parent.viewPortInfo.startIndex - this.parent.value.length >= 0 ? this.parent.viewPortInfo.startIndex - this.parent.value.length : 0; query = query.skip(skipvalue); this.parent.setCurrentView = false; this.parent.resetList(this.parent.dataSource, this.parent.fields, query); isListUpdated = false; } this.parent.totalItemsCount(); } if (isListUpdated) { for (let i = this.parent.viewPortInfo.startIndex; i < endIndex; i++) { const index = i; if (this.component === 'multiselect' && this.parent.mode === 'CheckBox') { const oldUlElement = this.parent.list.querySelector('.e-list-parent' + '.e-reorder'); if (oldUlElement) { this.parent.list.querySelector('.e-virtual-ddl-content').removeChild(oldUlElement); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any const alreadyAddedData = this.parent.generatedDataObject[index]; if (this.component === 'multiselect' && this.parent.hideSelectedItem) { if (alreadyAddedData) { const value = getValue(this.parent.fields.value, alreadyAddedData[0]); if (this.parent.value && value !== null && Array.isArray(this.parent.value) && this.parent.value.length > 0 && this.parent.value.indexOf(value) < 0) { let query = this.parent.getForQuery(this.parent.value).clone(); if (this.parent.viewPortInfo.endIndex === this.parent.totalItemCount + this.parent.value.length && this.parent.hideSelectedItem) { query = query.skip(this.parent.totalItemCount - this.parent.itemCount); } else { query = query.skip(this.parent.viewPortInfo.startIndex); } this.parent.setCurrentView = false; this.parent.isPreventScrollAction = true; this.parent.resetList(this.parent.dataSource, this.parent.fields, query); isResetListCalled = true; break; } else if (this.parent.value === null || (this.parent.value && this.parent.value.length === 0)) { currentData.push(alreadyAddedData[0]); } } if (index === endIndex - 1) { if (currentData.length !== this.parent.itemCount) { if (this.parent.hideSelectedItem) { let query = this.parent.value && this.parent.value.length > 0 ? this.parent.getForQuery(this.parent.value).clone() : new Query; if (this.parent.value && (this.parent.viewPortInfo.endIndex === this.parent.totalItemCount + this.parent.value.length) && this.parent.hideSelectedItem) { query = query.skip(this.parent.totalItemCount - this.parent.itemCount); } else { query = query.skip(this.parent.viewPortInfo.startIndex); } this.parent.setCurrentView = false; this.parent.resetList(this.parent.dataSource, this.parent.fields, query); isResetListCalled = true; } } } } else { if (alreadyAddedData) { currentData.push(alreadyAddedData[0]); } } this.parent.setCurrentView = false; } } if (!isResetListCalled && isListUpdated) { if (this.component === 'multiselect' && this.parent.allowCustomValue && this.parent.viewPortInfo.startIndex === 0 && this.parent.virtualCustomData) { currentData.splice(0, 0, this.parent.virtualCustomData); } let totalData = []; if (this.component === 'multiselect' && this.parent.allowCustomValue && this.parent.viewPortInfo.endIndex === this.parent.totalItemCount) { if (this.parent.virtualCustomSelectData && this.parent.virtualCustomSelectData.length > 0) { totalData = currentData.concat(this.parent.virtualCustomSelectData); currentData = totalData; } } this.parent.renderItems(currentData, this.parent.fields, this.component === 'multiselect' && this.parent.mode === 'CheckBox'); this.parent.updateSelectionList(); } if (this.component === 'multiselect') { this.parent.updatevirtualizationList(); this.parent.checkMaxSelection(); } this.parent.getSkeletonCount(); this.parent.skeletonCount = this.parent.totalItemCount !== 0 && this.parent.totalItemCount < this.parent.itemCount * 2 && ((!(this.parent.dataSource instanceof DataManager)) || ((this.parent.dataSource instanceof DataManager) && (this.parent.totalItemCount <= this.parent.itemCount))) ? 0 : this.parent.skeletonCount; // eslint-disable-next-line @typescript-eslint/no-explicit-any const virtualTrackElement = this.parent.list.getElementsByClassName('e-virtual-ddl')[0]; const preventAction = this.component !== 'multiselect' || (this.component === 'multiselect' && ((!(this.parent.dataSource instanceof DataManager))) || (this.parent.dataSource instanceof DataManager && !isResetListCalled)); if (virtualTrackElement && preventAction) { virtualTrackElement.style = this.parent.GetVirtualTrackHeight(); } else if (!virtualTrackElement && this.parent.skeletonCount > 0 && this.parent.popupWrapper) { const virualElement = this.parent.createElement('div', { id: this.parent.element.id + '_popup', className: 'e-virtual-ddl', styles: this.parent.GetVirtualTrackHeight() }); this.parent.popupWrapper.querySelector('.e-dropdownbase').appendChild(virualElement); } if (this.component !== 'multiselect' || (this.component === 'multiselect' && ((!(this.parent.dataSource instanceof DataManager))) || (this.parent.dataSource instanceof DataManager && (!isResetListCalled || this.parent.viewPortInfo.startIndex === 0)))) { this.parent.UpdateSkeleton(); } this.parent.liCollections = this.parent.list.querySelectorAll('.e-list-item'); // eslint-disable-next-line @typescript-eslint/no-explicit-any const virtualContentElement = this.parent.list.getElementsByClassName('e-virtual-ddl-content')[0]; if (virtualContentElement && preventAction) { (virtualContentElement).style = this.parent.getTransformValues(); } if (this.parent.fields.groupBy) { this.parent.scrollStop(); } if (this.parent.keyCode === 40 && this.parent.isScrollChanged && this.parent.hideSelectedItem && !isNullOrUndefined(this.parent.currentFocuedListElement)) { const currentSelectElem = this.parent.getElementByValue(this.parent.currentFocuedListElement.getAttribute('data-value')); this.parent.addListFocus(currentSelectElem); this.parent.isScrollChanged = false; } } generateQueryAndSetQueryIndexAsync(query, isPopupOpen) { let isStartIndexInitialised = false; let queryStartIndex = 0; let queryEndIndex = 0; const vEndIndex = this.parent.viewPortInfo.endIndex; if (!isPopupOpen && vEndIndex !== 0) { for (let i = this.parent.viewPortInfo.startIndex; i <= vEndIndex; i++) { if (!(i in this.parent.generatedDataObject)) { if (!isStartIndexInitialised) { isStartIndexInitialised = true; queryStartIndex = queryEndIndex = i; } else { queryEndIndex = i === vEndIndex ? i : i + 1; } } } } if (isStartIndexInitialised && !(this.parent.totalItemCount === queryStartIndex && this.parent.totalItemCount === queryEndIndex)) { this.parent.virtualItemStartIndex = queryStartIndex; this.parent.virtualItemEndIndex = queryEndIndex; this.parent.setCurrentView = true; this.generateAndExecuteQueryAsync(query, queryStartIndex, queryEndIndex); if (this.component === 'multiselect' && this.parent.hideSelectedItem && this.parent.value && Array.isArray(this.parent.value) && this.parent.value.length > 0) { this.parent.totalItemsCount(); } if (this.component === 'multiselect' && this.parent.virtualItemStartIndex === this.parent.virtualItemEndIndex) { this.parent.virtualItemStartIndex = this.parent.viewPortInfo.startIndex; this.parent.virtualItemEndIndex = this.parent.viewPortInfo.endIndex; } } if (!(this.parent.dataSource instanceof DataManager) || (this.parent.dataSource instanceof DataManager && !this.parent.isRequesting)) { this.setCurrentViewDataAsync(); } } dataProcessAsync(isOpenPopup) { this.parent.selectedValueInfo = null; this.parent.virtualItemStartIndex = this.parent.viewPortInfo.startIndex; this.parent.virtualItemEndIndex = this.parent.viewPortInfo.endIndex; this.generateQueryAndSetQueryIndexAsync(new Query(), isOpenPopup); } virtualScrollRefreshAsync() { return __awaiter(this, void 0, void 0, function* () { this.parent.isCustomFilter = (!(this.parent.isTyped || (this.component === 'combobox' && this.parent.allowFiltering && this.parent.queryString !== this.parent.typedString) || (!isNullOrUndefined(this.parent.filterInput) && !isNullOrUndefined(this.parent.filterInput.value) && this.parent.filterInput.value !== '') && this.component !== 'combobox') && !(this.component === 'autocomplete' && this.parent.value != null)) || this.parent.isCustomFilter; if (this.parent.allowFiltering || this.component === 'autocomplete') { if (!isNullOrUndefined(this.parent.typedString) && !(this.component === 'combobox' && !isNullOrUndefined(this.parent.typedString) && this.parent.allowFiltering)) { if (this.parent.viewPortInfo.endIndex >= this.parent.dataCount) { this.parent.viewPortInfo.endIndex = this.parent.dataCount; } if (this.parent.viewPortInfo.startIndex >= this.parent.dataCount) { this.parent.viewPortInfo.startIndex = this.parent.dataCount - this.parent.itemCount; } } else { this.parent.getSkeletonCount(true); if (this.component === 'combobox') { this.parent.skeletonCount = this.parent.totalItemCount !== 0 && this.parent.totalItemCount < (this.parent.itemCount * 2) && ((!(this.parent.dataSource instanceof DataManager)) || ((this.parent.dataSource instanceof DataManager) && (this.parent.totalItemCount <= this.parent.itemCount))) ? 0 : this.parent.skeletonCount; } } } yield this.dataProcessAsync(); if (this.parent.keyboardEvent != null && (!(this.parent.dataSource instanceof DataManager) || (this.parent.dataSource instanceof DataManager && !this.parent.isRequesting))) { this.parent.handleVirtualKeyboardActions(this.parent.keyboardEvent, this.parent.pageCount); } if (!this.parent.customFilterQuery) { this.parent.isCustomFilter = false; } }); } scrollListener(scrollArgs) { if (!this.parent.isPreventScrollAction && !this.parent.isVirtualTrackHeight) { this.parent.preventSetCurrentData = false; const info = scrollArgs.sentinel; const pStartIndex = this.parent.previousStartIndex; this.parent.viewPortInfo = this.getInfoFromView(scrollArgs.direction, info, scrollArgs.offset, false); this.parent.isUpwardScrolling = false; if (this.parent.previousStartIndex !== pStartIndex && !this.parent.isKeyBoardAction) { this.parent.isScrollActionTriggered = false; this.parent.currentPageNumber = this.parent.viewPortInfo.currentPageNumber; this.parent.virtualListInfo = Object.assign({}, this.parent.viewPortInfo); this.parent.isPreventKeyAction = true; this.parent.isVirtualScrolling = true; setTimeout(() => { this.parent.pageCount = this.parent.getPageCount(); this.parent.isRequesting = false; this.virtualScrollRefreshAsync().then(() => { if (this.parent.popupObj) { this.parent.list = this.parent.popupObj.element.querySelector('.' + 'e-content') || select('.' + 'e-content'); this.parent.updateSelectionList(); this.parent.liCollections = this.parent.getItems(); } this.parent.isKeyBoardAction = false; this.parent.isVirtualScrolling = false; this.parent.isPreventKeyAction = false; }); }, 5); } else if (this.parent.isScrollActionTriggered) { this.parent.isPreventKeyAction = false; this.parent.isScrollActionTriggered = false; // eslint-disable-next-line @typescript-eslint/no-explicit-any this.parent.list.getElementsByClassName('e-virtual-ddl-content')[0].style = this.parent.getTransformValues(); } this.parent.previousInfo = this.parent.viewPortInfo; } } getInfoFromView(direction, info, e, isscrollAction) { const infoType = { direction: direction, sentinelInfo: info, offsets: e, startIndex: this.parent.previousStartIndex, endIndex: this.parent.previousEndIndex }; const vHeight = this.parent.popupContentElement ? this.parent.popupContentElement.getBoundingClientRect().height : 0; //Row Start and End Index calculation const rowHeight = this.parent.listItemHeight; const exactTopIndex = e.top / rowHeight; const infoViewIndices = vHeight / rowHeight; const exactEndIndex = exactTopIndex + infoViewIndices; const pageSizeBy4 = this.parent.virtualItemCount / 4; const totalItemCount = this.parent.totalItemCount; if (infoType.direction === 'down') { const sIndex = Math.round(exactEndIndex) - Math.round((pageSizeBy4)); if (isNullOrUndefined(infoType.startIndex) || (exactEndIndex > (infoType.startIndex + Math.round((this.parent.virtualItemCount / 2 + pageSizeBy4))) && infoType.endIndex !== totalItemCount)) { infoType.startIndex = sIndex >= 0 ? Math.round(sIndex) : 0; infoType.startIndex = infoType.startIndex > exactTopIndex ? Math.floor(exactTopIndex) : infoType.startIndex; const eIndex = infoType.startIndex + this.parent.virtualItemCount; infoType.startIndex = eIndex < exactEndIndex ? (Math.ceil(exactEndIndex) - this.parent.virtualItemCount) : infoType.startIndex; infoType.endIndex = eIndex < totalItemCount ? eIndex : totalItemCount; infoType.startIndex = eIndex >= totalItemCount ? (infoType.endIndex - this.parent.virtualItemCount > 0 ? infoType.endIndex - this.parent.virtualItemCount : 0) : infoType.startIndex; infoType.currentPageNumber = Math.ceil(infoType.endIndex / this.parent.virtualItemCount); } } else if (infoType.direction === 'up') { if ((infoType.startIndex && infoType.endIndex) || (Math.ceil(exactTopIndex) > this.parent.previousStartIndex)) { const loadAtIndex = Math.round(((infoType.startIndex * rowHeight) + (pageSizeBy4 * rowHeight)) / rowHeight); if (exactTopIndex < loadAtIndex || (Math.ceil(exactTopIndex) > this.parent.previousStartIndex)) { const idxAddedToExactTop = (pageSizeBy4) > infoViewIndices ? pageSizeBy4 : (infoViewIndices + infoViewIndices / 4); const eIndex = Math.round(exactTopIndex + idxAddedToExactTop); infoType.endIndex = (eIndex < totalItemCount) ? eIndex : totalItemCount; const sIndex = infoType.endIndex - this.parent.virtualItemCount; infoType.startIndex = sIndex > 0 ? sIndex : 0; infoType.endIndex = sIndex < 0 ? this.parent.virtualItemCount : infoType.endIndex; infoType.currentPageNumber = Math.ceil(infoType.startIndex / this.parent.virtualItemCount); } } } if (!isscrollAction) { this.parent.previousStartIndex = infoType.startIndex; this.parent.startIndex = infoType.startIndex; this.parent.previousEndIndex = infoType.endIndex; } else { this.parent.scrollPreStartIndex = infoType.startIndex; } return infoType; } virtualScrollHandler(callback) { const delay = Browser.info.name === 'chrome' ? 200 : 100; let prevTop = 0; const debounced100 = debounce(callback, delay); const debounced50 = debounce(callback, 50); return (e) => { const top = e.target.scrollTop; const left = e.target.scrollLeft; const direction = prevTop < top && !this.parent.isUpwardScrolling ? 'down' : 'up'; prevTop = top; const current = this.sentinelInfo[direction]; const pstartIndex = this.parent.scrollPreStartIndex; const scrollOffsetargs = { top: top, left: left }; if (this.parent.list && this.parent.list.querySelectorAll('.e-virtual-list').length > 0) { this.getInfoFromView(direction, current, scrollOffsetargs, true); if (this.parent.scrollPreStartIndex !== pstartIndex && !this.parent.isPreventScrollAction) { this.parent.isScrollActionTriggered = true; const virtualPoup = (this.parent.list.querySelector('.e-virtual-ddl-content')); virtualPoup.style.transform = 'translate(0px,' + top + 'px)'; } } let debounceFunction = debounced100; if (current.axis === 'X') { debounceFunction = debounced50; } debounceFunction({ direction: direction, sentinel: current, offset: { top: top, left: left }, focusElement: document.activeElement }); }; } destroy() { this.removeEventListener(); } } var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; class FieldSettings extends ChildProperty { } __decorate([ Property() ], FieldSettings.prototype, "text", void 0); __decorate([ Property() ], FieldSettings.prototype, "value", void 0); __decorate([ Property() ], FieldSettings.prototype, "iconCss", void 0); __decorate([ Property() ], FieldSettings.prototype, "groupBy", void 0); __decorate([ Property() ], FieldSettings.prototype, "htmlAttributes", void 0); __decorate([ Property() ], FieldSettings.prototype, "disabled", void 0); const dropDownBaseClasses = { root: 'e-dropdownbase', rtl: 'e-rtl', content: 'e-content', selected: 'e-active', hover: 'e-hover', noData: 'e-nodata', fixedHead: 'e-fixed-head', focus: 'e-item-focus', li: 'e-list-item', group: 'e-list-group-item', disabled: 'e-disabled', grouping: 'e-dd-group', virtualList: 'e-list-item e-virtual-list' }; const ITEMTEMPLATE_PROPERTY = 'ItemTemplate'; const DISPLAYTEMPLATE_PROPERTY = 'DisplayTemplate'; const SPINNERTEMPLATE_PROPERTY = 'SpinnerTemplate'; const VALUETEMPLATE_PROPERTY = 'ValueTemplate'; const GROUPTEMPLATE_PROPERTY = 'GroupTemplate'; const HEADERTEMPLATE_PROPERTY = 'HeaderTemplate'; const FOOTERTEMPLATE_PROPERTY = 'FooterTemplate'; const NORECORDSTEMPLATE_PROPERTY = 'NoRecordsTemplate'; const ACTIONFAILURETEMPLATE_PROPERTY = 'ActionFailureTemplate'; const HIDE_GROUPLIST = 'e-hide-group-header'; /** * DropDownBase component will generate the list items based on given data and act as base class to drop-down related components */ let DropDownBase = class DropDownBase extends Component { /** * * Constructor for DropDownBase class * * @param {DropDownBaseModel} options - Specifies the DropDownBase model. * @param {string | HTMLElement} element - Specifies the element to render as component. * @private */ constructor(options, element) { super(options, element); this.preventChange = false; this.isPreventChange = false; this.isDynamicDataChange = false; this.addedNewItem = false; this.isAddNewItemTemplate = false; this.isRequesting = false; this.isVirtualizationEnabled = false; this.isCustomDataUpdated = false; this.isAllowFiltering = false; this.virtualizedItemsCount = 0; this.isCheckBoxSelection = false; this.totalItemCount = 0; this.dataCount = 0; this.remoteDataCount = -1; this.isRemoteDataUpdated = false; this.isIncrementalRequest = false; this.itemCount = 30; this.virtualListHeight = 0; this.isVirtualScrolling = false; this.isPreventScrollAction = false; this.scrollPreStartIndex = 0; this.isScrollActionTriggered = false; this.previousStartIndex = 0; this.isMouseScrollAction = false; this.isKeyBoardAction = false; this.isScrollChanged = false; this.isUpwardScrolling = false; this.startIndex = 0; this.currentPageNumber = 0; this.pageCount = 0; this.isPreventKeyAction = false; this.generatedDataObject = {}; this.skeletonCount = 32; this.isVirtualTrackHeight = false; this.virtualSelectAll = false; this.isVirtualReorder = false; this.incrementalQueryString = ''; this.incrementalEndIndex = 0; this.incrementalStartIndex = 0; this.incrementalPreQueryString = ''; this.isObjectCustomValue = false; this.appendUncheckList = false; this.getInitialData = false; this.preventPopupOpen = true; this.virtualSelectAllState = false; this.CurrentEvent = null; this.isDynamicData = false; this.isPrimitiveData = false; this.isCustomFiltering = false; this.debounceTimer = null; this.virtualListInfo = { currentPageNumber: null, direction: null, sentinelInfo: {}, offsets: {}, startIndex: 0, endIndex: 0 }; this.viewPortInfo = { currentPageNumber: null, direction: null, sentinelInfo: {}, offsets: {}, startIndex: 0, endIndex: 0 }; this.selectedValueInfo = { currentPageNumber: null, direction: null, sentinelInfo: {}, offsets: {}, startIndex: 0, endIndex: 0 }; } getPropObject(prop, newProp, oldProp) { const newProperty = new Object(); const oldProperty = new Object(); const propName = (prop) => { return prop; }; newProperty[propName(prop)] = newProp[propName(prop)]; oldProperty[propName(prop)] = oldProp[propName(prop)]; const data = new Object(); data.newProperty = newProperty; data.oldProperty = oldProperty; return data; } getValueByText(text, ignoreCase, ignoreAccent) { let value = null; if (!isNullOrUndefined(this.listData)) { if (ignoreCase) { value = this.checkValueCase(text, true, ignoreAccent); } else { value = this.checkValueCase(text, false, ignoreAccent); } } return value; } checkValueCase(text, ignoreCase, ignoreAccent, isTextByValue) { let value = null; if (isTextByValue) { value = text; } if (!isNullOrUndefined(this.listData)) { const dataSource = this.listData; const fields = this.fields; const type = this.typeOfData(dataSource).typeof; if (type === 'string' || type === 'number' || type === 'boolean') { for (const item of dataSource) { if (!isNullOrUndefined(item)) { if (ignoreAccent) { value = this.checkingAccent(String(item), text, ignoreCase); } else { if (ignoreCase) { if (this.checkIgnoreCase(String(item), text)) {