@syncfusion/ej2-dropdowns
Version:
Essential JS 2 DropDown Components
989 lines (984 loc) • 1.12 MB
JavaScript
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)) {