UNPKG

@syncfusion/ej2-lists

Version:

The listview control allows you to select an item or multiple items from a list-like interface and represents the data in interactive hierarchical structure across different layouts or views.

886 lines (885 loc) 46.6 kB
import { classNames } from './list-view'; import { EventHandler, append, isNullOrUndefined, detach, compile, formatUnit, select } from '@syncfusion/ej2-base'; import { ListBase } from '../common/list-base'; import { DataManager } from '@syncfusion/ej2-data'; var listElementCount = 1.5; var windowElementCount = 3; var Virtualization = /** @class */ (function () { function Virtualization(instance) { this.elementDifference = 0; this.listViewInstance = instance; } /** * For internal use only. * * @private */ Virtualization.prototype.isNgTemplate = function () { return !isNullOrUndefined(this.listViewInstance.templateRef) && typeof this.listViewInstance.templateRef !== 'string'; }; /** * Checks if the platform is a Vue and its template property is a function type. * * @returns {boolean} indicating the result of the check */ Virtualization.prototype.isVueFunctionTemplate = function () { return this.listViewInstance.isVue && typeof this.listViewInstance.template === 'function'; }; /** * For internal use only. * * @private */ Virtualization.prototype.uiVirtualization = function () { this.wireScrollEvent(false); var curViewDS = this.listViewInstance.curViewDS; var isRendered = this.listViewInstance.isRendered; var firstIndex = isRendered && !isNullOrUndefined(this.uiFirstIndex) && this.uiLastIndex <= Object.keys(curViewDS).length ? this.uiFirstIndex : 0; var firstDs = curViewDS.slice(firstIndex, firstIndex + 1); this.listViewInstance.ulElement = this.listViewInstance.curUL = ListBase.createList(this.listViewInstance.createElement, firstDs, this.listViewInstance.listBaseOption, null, this.listViewInstance); this.listViewInstance.contentContainer = this.listViewInstance.createElement('div', { className: classNames.container }); this.listViewInstance.element.appendChild(this.listViewInstance.contentContainer); this.listViewInstance.contentContainer.appendChild(this.listViewInstance.ulElement); this.listItemHeight = this.listViewInstance.ulElement.firstElementChild.getBoundingClientRect().height; this.expectedDomItemCount = this.ValidateItemCount(10000); this.updateDOMItemCount(); var lastIndex = isRendered && !isNullOrUndefined(this.uiLastIndex) && this.listDiff !== 0 ? this.uiLastIndex : this.domItemCount - 1; this.uiFirstIndex = firstIndex; this.uiLastIndex = lastIndex; var otherDs = curViewDS.slice(firstIndex + 1, lastIndex + 1); var listItems = ListBase.createListItemFromJson(this.listViewInstance.createElement, otherDs, this.listViewInstance.listBaseOption, null, null, this.listViewInstance); append(listItems, this.listViewInstance.ulElement); this.listViewInstance.liCollection = this.listViewInstance.curUL.querySelectorAll('li'); this.topElement = this.listViewInstance.createElement('div'); this.listViewInstance.ulElement.insertBefore(this.topElement, this.listViewInstance.ulElement.firstElementChild); this.bottomElement = this.listViewInstance.createElement('div'); this.listViewInstance.ulElement.insertBefore(this.bottomElement, null); this.totalHeight = (Object.keys(curViewDS).length * this.listItemHeight) - (this.domItemCount * this.listItemHeight); this.topElement.style.height = isRendered ? this.topElementHeight + 'px' : '0px'; this.bottomElement.style.height = isRendered ? (this.totalHeight - this.topElementHeight) + 'px' : this.totalHeight + 'px'; this.topElementHeight = isRendered ? this.topElementHeight : 0; this.bottomElementHeight = isRendered ? (this.totalHeight - this.topElementHeight) : this.totalHeight; this.listDiff = isRendered && Object.keys(curViewDS).length !== this.domItemCount ? this.listDiff : 0; if (isRendered) { this.listViewInstance.element.scrollTop = this.listViewInstance.previousScrollTop; } this.uiIndicesInitialization(); }; Virtualization.prototype.wireScrollEvent = function (destroy) { if (!destroy) { if (this.listViewInstance.isWindow) { this.onVirtualScroll = this.onVirtualUiScroll.bind(this); window.addEventListener('scroll', this.onVirtualScroll); } else { EventHandler.add(this.listViewInstance.element, 'scroll', this.onVirtualUiScroll, this); } } else { if (this.listViewInstance.isWindow === true) { window.removeEventListener('scroll', this.onVirtualScroll); window.removeEventListener('scroll', this.updateUl); } else { EventHandler.remove(this.listViewInstance.element, 'scroll', this.onVirtualUiScroll); } } }; Virtualization.prototype.ValidateItemCount = function (dataSourceLength) { var height = parseFloat(formatUnit(this.listViewInstance.height)); var itemCount; if (this.listViewInstance.isWindow) { itemCount = Math.round((window.innerHeight / this.listItemHeight) * windowElementCount); } else { if (typeof this.listViewInstance.height === 'string' && this.listViewInstance.height.indexOf('%') !== -1) { itemCount = Math.round((this.listViewInstance.element.getBoundingClientRect().height / this.listItemHeight) * listElementCount); } else { itemCount = Math.round((height / this.listItemHeight) * listElementCount); } } if (itemCount > dataSourceLength) { itemCount = dataSourceLength; } return itemCount; }; Virtualization.prototype.updateDOMItemCount = function () { this.domItemCount = this.ValidateItemCount(Object.keys(this.listViewInstance.curViewDS).length); }; Virtualization.prototype.uiIndicesInitialization = function () { this.uiIndices = { 'activeIndices': [], 'disabledItemIndices': [], 'hiddenItemIndices': [] }; var data = this.listViewInstance.curViewDS; for (var i = 0; i < data.length; i++) { if (this.listViewInstance.showCheckBox && data[i][this.listViewInstance.fields.isChecked]) { this.uiIndices.activeIndices.push(i); } if (!isNullOrUndefined(data[parseInt(i.toString(), 10)][this.listViewInstance.fields.enabled]) && !data[i][this.listViewInstance.fields.enabled]) { (this.uiIndices.disabledItemIndices.push(i)); } } if (this.isNgTemplate()) { var items = this.listViewInstance.element.querySelectorAll('.' + classNames.listItem); for (var index = 0; index < items.length; index++) { items[index].context = this.listViewInstance.viewContainerRef.get(index).context; } } }; Virtualization.prototype.refreshItemHeight = function () { if (this.listViewInstance.curViewDS.length) { var curViewDS = this.listViewInstance.curViewDS; this.listItemHeight = this.topElement.nextSibling.getBoundingClientRect().height; this.totalHeight = (Object.keys(curViewDS).length * this.listItemHeight) - (this.domItemCount * this.listItemHeight); this.bottomElementHeight = this.totalHeight; this.bottomElement.style.height = this.totalHeight + 'px'; } }; Virtualization.prototype.getscrollerHeight = function (startingHeight) { return this.listViewInstance.isWindow ? (((pageYOffset - startingHeight) <= 0) ? 0 : (pageYOffset - startingHeight)) : ((this.listViewInstance.element.scrollTop - startingHeight) <= 0) ? 0 : (this.listViewInstance.element.scrollTop - startingHeight); }; Virtualization.prototype.onVirtualUiScroll = function () { var _a; var startingHeight; var curViewDS = this.listViewInstance.curViewDS; this.listItemHeight = select('.e-list-item', this.listViewInstance.element).getBoundingClientRect().height; this.totalHeight = (Object.keys(curViewDS).length * this.listItemHeight) - (this.domItemCount * this.listItemHeight); if (this.listViewInstance.isWindow) { startingHeight = this.listViewInstance.ulElement.getBoundingClientRect().top - document.documentElement.getBoundingClientRect().top; } else { startingHeight = this.listViewInstance.headerEle ? this.listViewInstance.headerEle.getBoundingClientRect().height : 0; } this.scrollPosition = isNullOrUndefined(this.scrollPosition) ? 0 : this.scrollPosition; var scroll = this.getscrollerHeight(startingHeight); this.topElementHeight = this.listItemHeight * Math.floor(scroll / this.listItemHeight); this.bottomElementHeight = this.totalHeight - this.topElementHeight; _a = scroll <= this.totalHeight ? [this.topElementHeight, this.bottomElementHeight] : [this.totalHeight, 0], this.topElementHeight = _a[0], this.bottomElementHeight = _a[1]; if (this.topElementHeight !== parseFloat(this.topElement.style.height)) { this.topElement.style.height = this.topElementHeight + 'px'; this.bottomElement.style.height = this.bottomElementHeight + 'px'; if (scroll > this.scrollPosition) { var listDiff = Math.round(((this.topElementHeight / this.listItemHeight) - this.listDiff)); if (listDiff > (this.expectedDomItemCount + 5)) { this.onLongScroll(listDiff, true); } else { this.onNormalScroll(listDiff, true); } } else { var listDiff = Math.round((this.listDiff - (this.topElementHeight / this.listItemHeight))); if (listDiff > (this.expectedDomItemCount + 5)) { this.onLongScroll(listDiff, false); } else { this.onNormalScroll(listDiff, false); } } } this.listDiff = Math.round(this.topElementHeight / this.listItemHeight); if (typeof this.listViewInstance.onUIScrolled === 'function') { this.listViewInstance.onUIScrolled(); } this.scrollPosition = scroll; }; Virtualization.prototype.onLongScroll = function (listDiff, isScrollingDown) { var index = isScrollingDown ? (this.uiFirstIndex + listDiff) : (this.uiFirstIndex - listDiff); var elements = this.listViewInstance.ulElement.querySelectorAll('li'); for (var i = 0; i < elements.length; i++) { this.updateUI(elements[i], index); index++; } this.uiLastIndex = isScrollingDown ? (this.uiLastIndex + listDiff) : (this.uiLastIndex - listDiff); this.uiFirstIndex = isScrollingDown ? (this.uiFirstIndex + listDiff) : (this.uiFirstIndex - listDiff); }; Virtualization.prototype.onNormalScroll = function (listDiff, isScrollingDown) { if (isScrollingDown) { for (var i = 0; i < listDiff; i++) { var index = ++this.uiLastIndex; this.updateUI(this.topElement.nextElementSibling, index, this.bottomElement); this.uiFirstIndex++; } } else { for (var i = 0; i < listDiff; i++) { var index = --this.uiFirstIndex; var target = this.topElement.nextSibling; this.updateUI(this.bottomElement.previousElementSibling, index, target); this.uiLastIndex--; } } }; Virtualization.prototype.updateUiContent = function (element, index) { var curViewDs = this.listViewInstance.curViewDS; if (typeof this.listViewInstance.dataSource[0] === 'string' || typeof this.listViewInstance.dataSource[0] === 'number') { element.dataset.uid = ListBase.generateId(); element.getElementsByClassName(classNames.listItemText)[0].innerHTML = this.listViewInstance.curViewDS[index].toString(); } else { element.dataset.uid = (curViewDs[parseInt(index.toString(), 10)][this.listViewInstance.fields.id]) ? (curViewDs[parseInt(index.toString(), 10)][this.listViewInstance.fields.id]) : ListBase.generateId(); element.getElementsByClassName(classNames.listItemText)[0].innerHTML = (curViewDs[parseInt(index.toString(), 10)][this.listViewInstance.fields.text]); } if (this.listViewInstance.showIcon) { if (element.querySelector('.' + classNames.listIcon)) { detach(element.querySelector('.' + classNames.listIcon)); } if (this.listViewInstance.curViewDS[index][this.listViewInstance.fields.iconCss]) { var textContent = element.querySelector('.' + classNames.textContent); var curViewDS = this.listViewInstance.curViewDS[index]; var iconCss = curViewDS[this.listViewInstance.fields.iconCss].toString(); var target = this.listViewInstance.createElement('div', { className: classNames.listIcon + ' ' + iconCss }); textContent.insertBefore(target, element.querySelector('.' + classNames.listItemText)); } } if (this.listViewInstance.showCheckBox && this.listViewInstance.fields.groupBy) { if (!this.checkListWrapper) { this.checkListWrapper = this.listViewInstance.curUL.querySelector('.' + classNames.checkboxWrapper).cloneNode(true); } var textContent = element.querySelector('.' + classNames.textContent); if (this.listViewInstance.curViewDS[index].isHeader) { if (element.querySelector('.' + classNames.checkboxWrapper)) { element.classList.remove(classNames.checklist); textContent.classList.remove(classNames.checkbox); detach(element.querySelector('.' + classNames.checkboxWrapper)); } } else { if (!element.querySelector('.' + classNames.checkboxWrapper)) { element.classList.add(classNames.checklist); textContent.classList.add(classNames.checkbox); if (this.listViewInstance.checkBoxPosition === 'Left') { textContent.classList.add('e-checkbox-left'); } else { textContent.classList.add('e-checkbox-right'); } textContent.append(this.checkListWrapper.cloneNode(true)); } } } }; Virtualization.prototype.changeElementAttributes = function (element, index) { element.classList.remove(classNames.disable); if (this.uiIndices.disabledItemIndices.length && this.uiIndices.disabledItemIndices.indexOf(index) !== -1) { element.classList.add(classNames.disable); } element.style.display = ''; if (this.uiIndices.hiddenItemIndices.length && this.uiIndices.hiddenItemIndices.indexOf(index) !== -1) { element.style.display = 'none'; } if (this.listViewInstance.showCheckBox) { var checklistElement = element.querySelector('.' + classNames.checkboxWrapper); element.classList.remove(classNames.selected); element.classList.remove(classNames.focused); if (checklistElement) { checklistElement.removeAttribute('aria-checked'); checklistElement.firstElementChild.classList.remove(classNames.checked); } if (this.uiIndices.activeIndices.length && this.uiIndices.activeIndices.indexOf(index) !== -1 && !this.listViewInstance.curUL.querySelector(classNames.selected)) { element.classList.add(classNames.selected); checklistElement.firstElementChild.classList.add(classNames.checked); checklistElement.setAttribute('aria-checked', 'true'); if (this.activeIndex === index) { element.classList.add(classNames.focused); } } } else { element.classList.remove(classNames.selected); element.removeAttribute('aria-selected'); if (!isNullOrUndefined(this.activeIndex) && this.activeIndex === index && !this.listViewInstance.curUL.querySelector(classNames.selected)) { element.classList.add(classNames.selected); element.setAttribute('aria-selected', 'true'); } } if (this.listViewInstance.fields.groupBy) { if (this.listViewInstance.curViewDS[index].isHeader) { if (element.classList.contains(classNames.listItem)) { element.classList.remove(classNames.listItem); element.setAttribute('role', 'group'); element.classList.add(classNames.groupListItem); } } else { if (element.classList.contains(classNames.groupListItem)) { element.classList.remove(classNames.groupListItem); element.setAttribute('role', 'listitem'); element.classList.add(classNames.listItem); } } } }; Virtualization.prototype.findDSAndIndexFromId = function (ds, fields) { var _this = this; var resultJSON = {}; fields = this.listViewInstance.getElementUID(fields); if (!isNullOrUndefined(fields)) { ds.some(function (data, index) { if ((fields[_this.listViewInstance.fields.id] && fields[_this.listViewInstance.fields.id] === (data[_this.listViewInstance.fields.id] && data[_this.listViewInstance.fields.id]) || fields === data)) { resultJSON.index = index; resultJSON.data = data; return true; } else { return false; } }); } return resultJSON; }; Virtualization.prototype.getSelectedItems = function () { var _this = this; if (!isNullOrUndefined(this.activeIndex) || (this.listViewInstance.showCheckBox && this.uiIndices.activeIndices.length)) { var dataCollection = []; var textCollection = []; if (typeof this.listViewInstance.dataSource[0] === 'string' || typeof this.listViewInstance.dataSource[0] === 'number') { var curViewDS_1 = this.listViewInstance.curViewDS; if (this.listViewInstance.showCheckBox) { var indices = this.uiIndices.activeIndices; for (var i = 0; i < indices.length; i++) { dataCollection.push(curViewDS_1[indices[i]]); } return { text: dataCollection, data: dataCollection, index: this.uiIndices.activeIndices.map(function (index) { return _this.listViewInstance.dataSource.indexOf(curViewDS_1[index]); }) }; } else { return { text: curViewDS_1[this.activeIndex], data: curViewDS_1[this.activeIndex], index: this.listViewInstance.dataSource.indexOf(curViewDS_1[this.activeIndex]) }; } } else { var curViewDS_2 = this.listViewInstance.curViewDS; var text = this.listViewInstance.fields.text; if (this.listViewInstance.showCheckBox) { var indexArray = this.uiIndices.activeIndices; for (var i = 0; i < indexArray.length; i++) { textCollection.push(curViewDS_2[indexArray[i]]["" + text]); dataCollection.push(curViewDS_2[indexArray[parseInt(i.toString(), 10)]]); } var dataSource_1 = this.listViewInstance.dataSource instanceof DataManager ? curViewDS_2 : this.listViewInstance.dataSource; return { text: textCollection, data: dataCollection, index: this.uiIndices.activeIndices.map(function (index) { return dataSource_1.indexOf(curViewDS_2[index]); }) }; } else { var dataSource = this.listViewInstance.dataSource instanceof DataManager ? curViewDS_2 : this.listViewInstance.dataSource; return { text: curViewDS_2[this.activeIndex][this.listViewInstance.fields.text], data: curViewDS_2[this.activeIndex], index: dataSource.indexOf(curViewDS_2[this.activeIndex]) }; } } } else { return undefined; } }; Virtualization.prototype.selectItem = function (obj) { var _this = this; var resutJSON = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj); if (Object.keys(resutJSON).length) { var isSelected = this.activeIndex === resutJSON.index; var isChecked_1; this.activeIndex = resutJSON.index; if (this.listViewInstance.showCheckBox) { if (this.uiIndices.activeIndices.indexOf(resutJSON.index) === -1) { isChecked_1 = true; this.uiIndices.activeIndices.push(resutJSON.index); } else { isChecked_1 = false; this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(resutJSON.index), 1); } if (this.listViewInstance.curUL.querySelector('.' + classNames.focused)) { this.listViewInstance.curUL.querySelector('.' + classNames.focused).classList.remove(classNames.focused); } } if (this.listViewInstance.getLiFromObjOrElement(obj)) { if (this.listViewInstance.showCheckBox) { this.listViewInstance.setCheckboxLI(this.listViewInstance.getLiFromObjOrElement(obj)); } else { this.listViewInstance.setSelectLI(this.listViewInstance.getLiFromObjOrElement(obj)); } } else { var eventArgs_1; if (typeof this.listViewInstance.dataSource[0] === 'string' || typeof this.listViewInstance.dataSource[0] === 'number') { eventArgs_1 = { text: this.listViewInstance.curViewDS[this.activeIndex], data: this.listViewInstance.curViewDS[this.activeIndex], index: this.activeIndex }; } else { var curViewDS = this.listViewInstance.curViewDS; eventArgs_1 = { text: curViewDS[this.activeIndex][this.listViewInstance.fields.text], data: curViewDS[this.activeIndex], index: this.activeIndex }; } if (this.listViewInstance.showCheckBox) { this.listViewInstance.trigger('select', eventArgs_1, function (observedArgs) { if (observedArgs.cancel) { if (!isChecked_1) { eventArgs_1.isChecked = isChecked_1; _this.uiIndices.activeIndices.push(resutJSON.index); } else { eventArgs_1.isChecked = !isChecked_1; _this.uiIndices.activeIndices.splice(_this.uiIndices.activeIndices.indexOf(resutJSON.index), 1); } } }); } else if (!isSelected) { this.listViewInstance.removeSelect(); this.listViewInstance.trigger('select', eventArgs_1, function (observedArgs) { if (observedArgs.cancel) { _this.activeIndex = undefined; } }); } } } else if (isNullOrUndefined(obj) && !this.listViewInstance.showCheckBox) { this.listViewInstance.removeSelect(); this.activeIndex = undefined; } }; Virtualization.prototype.enableItem = function (obj) { var resutJSON = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj); if (Object.keys(resutJSON).length) { this.uiIndices.disabledItemIndices.splice(this.uiIndices.disabledItemIndices.indexOf(resutJSON.index), 1); } }; Virtualization.prototype.disableItem = function (obj) { var resutJSON = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj); if (Object.keys(resutJSON).length && this.uiIndices.disabledItemIndices.indexOf(resutJSON.index) === -1) { this.uiIndices.disabledItemIndices.push(resutJSON.index); } }; Virtualization.prototype.showItem = function (obj) { var resutJSON = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj); if (Object.keys(resutJSON).length) { this.uiIndices.hiddenItemIndices.splice(this.uiIndices.hiddenItemIndices.indexOf(resutJSON.index), 1); } }; Virtualization.prototype.hideItem = function (obj) { var resutJSON = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj); if (Object.keys(resutJSON).length && this.uiIndices.hiddenItemIndices.indexOf(resutJSON.index) === -1) { this.uiIndices.hiddenItemIndices.push(resutJSON.index); } }; Virtualization.prototype.removeItem = function (obj) { var dataSource; var curViewDS = this.listViewInstance.curViewDS; var resutJSON = this.findDSAndIndexFromId(curViewDS, obj); if (Object.keys(resutJSON).length) { dataSource = resutJSON.data; if (curViewDS[resutJSON.index - 1] && curViewDS[resutJSON.index - 1].isHeader && (curViewDS[resutJSON.index - 1]) .items.length === 1) { this.removeUiItem(resutJSON.index - 1); this.removeUiItem(resutJSON.index - 1); } else { this.removeUiItem(resutJSON.index); } } var listDataSource = this.listViewInstance.dataSource instanceof DataManager ? this.listViewInstance.localData : this.listViewInstance.dataSource; var index = listDataSource.indexOf(dataSource); if (index !== -1) { listDataSource.splice(index, 1); this.listViewInstance.setViewDataSource(listDataSource); } // recollect all the list item into collection this.listViewInstance.liCollection = this.listViewInstance.curUL.querySelectorAll('li'); }; // eslint-disable-next-line Virtualization.prototype.setCheckboxLI = function (li, e) { var index = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex; this.activeIndex = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex; if (li.classList.contains(classNames.selected)) { if (this.uiIndices.activeIndices.indexOf(index) === -1) { this.uiIndices.activeIndices.push(index); } } else { this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(index), 1); } }; // eslint-disable-next-line Virtualization.prototype.setSelectLI = function (li, e) { this.activeIndex = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex; }; Virtualization.prototype.checkedItem = function (checked) { if (checked) { this.uiIndices.activeIndices = []; this.activeIndex = undefined; var data = this.listViewInstance.curViewDS; for (var index = 0; index < data.length; index++) { if (!data[index].isHeader) { this.uiIndices.activeIndices.push(index); } } } else { this.activeIndex = undefined; this.uiIndices.activeIndices = []; } }; Virtualization.prototype.addUiItem = function (index) { // virtually new add list item based on the scollbar position // if the scroll bar is at the top, just pretend the new item has been added since no UI // change is required for the item that has been added at last but when scroll bar is at the bottom // just detach top and inject into bottom to mimic new item is added var curViewDs = this.listViewInstance.curViewDS; this.changeUiIndices(index, true); if (this.activeIndex && this.activeIndex >= index) { this.activeIndex++; } if (this.listViewInstance.showCheckBox && curViewDs[index][this.listViewInstance.fields.isChecked]) { this.uiIndices.activeIndices.push(index); } if (!parseFloat(this.bottomElement.style.height) && !parseFloat(this.topElement.style.height)) { this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) + this.listItemHeight + 'px'; } if (parseFloat(this.bottomElement.style.height)) { var liItem = this.listViewInstance.curUL.lastElementChild.previousSibling; var target = this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 1]) || this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 2]); if (target) { this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) + this.listItemHeight + 'px'; this.updateUI(liItem, index, target); } } else { var liItem = this.listViewInstance.curUL.firstElementChild.nextSibling; var target = void 0; if ((Object.keys(this.listViewInstance.curViewDS).length - 1) === index) { target = this.listViewInstance.curUL.lastElementChild; } else { target = this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 1]) || this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 2]); } this.topElement.style.height = parseFloat(this.topElement.style.height) + this.listItemHeight + 'px'; this.uiFirstIndex++; this.uiLastIndex++; if (target) { this.updateUI(liItem, index, target); if (this.listViewInstance.isWindow === true) { window.scrollTo(0, (pageYOffset + this.listItemHeight)); } else { this.listViewInstance.element.scrollTop += this.listItemHeight; } } } this.totalHeight += this.listItemHeight; this.listDiff = Math.round(parseFloat(this.topElement.style.height) / this.listItemHeight); }; Virtualization.prototype.removeUiItem = function (index) { this.totalHeight -= this.listItemHeight; var curViewDS = this.listViewInstance.curViewDS[index]; var liItem = this.listViewInstance.getLiFromObjOrElement(curViewDS); this.listViewInstance.curViewDS.splice(index, 1); if (this.activeIndex && this.activeIndex >= index) { this.activeIndex--; } if (liItem) { if (this.domItemCount > Object.keys(this.listViewInstance.curViewDS).length) { detach(liItem); this.domItemCount--; this.uiLastIndex--; this.totalHeight = 0; } else { if (liItem.classList.contains(classNames.disable)) { liItem.classList.remove(classNames.disable); this.uiIndices.disabledItemIndices.splice(this.uiIndices.disabledItemIndices.indexOf(index), 1); } if (liItem.style.display === 'none') { liItem.style.display = ''; this.uiIndices.hiddenItemIndices.splice(this.uiIndices.hiddenItemIndices.indexOf(index), 1); } if (this.listViewInstance.showCheckBox && liItem.classList.contains(classNames.selected)) { this.listViewInstance.removeSelect(); this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(index), 1); var checklistElement = liItem.querySelector('.' + classNames.checkboxWrapper); checklistElement.removeAttribute('aria-checked'); checklistElement.firstElementChild.classList.remove(classNames.checked); if (liItem.classList.contains(classNames.focused)) { liItem.classList.remove(classNames.focused); this.activeIndex = undefined; } } else if (liItem.classList.contains(classNames.selected)) { this.listViewInstance.removeSelect(); this.activeIndex = undefined; } if (!parseFloat(this.bottomElement.style.height) && !parseFloat(this.topElement.style.height)) { this.updateUI(liItem, this.uiLastIndex, this.bottomElement); } else if (parseFloat(this.bottomElement.style.height)) { this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) - this.listItemHeight + 'px'; this.updateUI(liItem, this.uiLastIndex, this.bottomElement); } else { this.topElement.style.height = parseFloat(this.topElement.style.height) - this.listItemHeight + 'px'; this.updateUI(liItem, (this.uiFirstIndex - 1), this.topElement.nextSibling); this.uiLastIndex--; this.uiFirstIndex--; } } } this.changeUiIndices(index, false); this.listDiff = Math.round(parseFloat(this.topElement.style.height) / this.listItemHeight); }; Virtualization.prototype.changeUiIndices = function (index, increment) { var keys = Object.keys(this.uiIndices); for (var ind = 0; ind < keys.length; ind++) { this.uiIndices[keys[ind]] = this.uiIndices[keys[ind]].map(function (i) { if (i >= index) { return increment ? ++i : --i; } else { return i; } }); } }; Virtualization.prototype.addItem = function (data, fields, dataSource, index) { for (var i = 0; i < data.length; i++) { var currentItem = data[i]; // push the given data to main data array dataSource = this.listViewInstance.addItemAtIndex(index, dataSource, currentItem); // recalculate all the group data or other datasource related things this.listViewInstance.setViewDataSource(dataSource); // render list items for first time due to no datasource present earlier if (!this.domItemCount) { // fresh rendering for first time if ((this.listViewInstance.template || this.listViewInstance.groupTemplate) && !this.isNgTemplate()) { this.listViewInstance.listBaseOption.template = null; this.listViewInstance.listBaseOption.groupTemplate = null; this.listViewInstance.listBaseOption.itemCreated = this.createUIItem.bind(this); } this.uiVirtualization(); // when expected expected DOM count doesn't meet the condition we need to create and inject new item into DOM } else if (this.domItemCount < this.expectedDomItemCount) { var ds = this.listViewInstance.findItemFromDS(dataSource, fields); if (ds instanceof Array) { if (this.listViewInstance.ulElement) { var index_1 = this.listViewInstance.curViewDS.indexOf(currentItem); // inject new list item into DOM this.createAndInjectNewItem(currentItem, index_1); // check for group header item var curViewDS = this.listViewInstance.curViewDS[index_1 - 1]; if (curViewDS && curViewDS.isHeader && curViewDS.items.length === 1) { // target group item index in datasource --index_1; // inject new group header into DOM for previously created list item this.createAndInjectNewItem(curViewDS, index_1); } } // recollect all the list item into collection this.listViewInstance.liCollection = this.listViewInstance.curUL.querySelectorAll('li'); } } else { var index_2 = this.listViewInstance.curViewDS.indexOf(currentItem); // virtually new add list item based on the scollbar position this.addUiItem(index_2); // check for group header item needs to be added var curViewDS = this.listViewInstance.curViewDS[index_2 - 1]; if (curViewDS && curViewDS.isHeader && curViewDS.items.length === 1) { this.addUiItem(index_2 - 1); } } } }; Virtualization.prototype.createAndInjectNewItem = function (itemData, index) { // generate li item for given datasource var target; var li = ListBase.createListItemFromJson(this.listViewInstance.createElement, [itemData], this.listViewInstance.listBaseOption, null, null, this.listViewInstance); // check for target element whether to insert before last item or group item if ((Object.keys(this.listViewInstance.curViewDS).length - 1) === index) { target = this.listViewInstance.curUL.lastElementChild; } else { // target group header's first child item to append its header target = this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index + 1]) || this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index + 2]); } if (this.listViewInstance.fields.groupBy && this.listViewInstance.curViewDS[index + 1] && this.listViewInstance.curViewDS[index + 1].isHeader) { var targetEle = this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index - 1]); if (targetEle) { target = targetEle.nextElementSibling; } } // insert before the target element this.listViewInstance.ulElement.insertBefore(li[0], target); // increment internal DOM count, last index count for new element this.domItemCount++; if (this.bottomElementHeight <= 0) { this.uiLastIndex++; } // recalculate the current item height, to avoid jumpy scroller this.refreshItemHeight(); }; Virtualization.prototype.createUIItem = function (args) { if (!args.item.classList.contains('e-list-group-item')) { this.templateData = args.curData.isHeader ? args.curData.items[0] : args.curData; if (this.listViewInstance.showCheckBox) { this.listViewInstance.renderCheckbox(args); if ((!isNullOrUndefined(this.listViewInstance.virtualCheckBox)) && (!isNullOrUndefined(this.listViewInstance.virtualCheckBox.outerHTML))) { var div_1 = document.createElement('div'); var commonTemplate = '<div class="e-text-content" role="presentation"> ' + '<span class="e-list-text"> ${' + this.listViewInstance.fields.text + '} </span></div>'; var templateFunction = compile(this.listViewInstance.template || commonTemplate, this.listViewInstance); var nodes = templateFunction(this.templateData, this.listViewInstance); if (this.listViewInstance.template && this.listViewInstance.isReact) { this.listViewInstance.renderReactTemplates(); } [].slice.call(nodes).forEach(function (ele) { div_1.appendChild(ele); }); if (div_1.children && div_1.children[0]) { div_1.children[0].classList.add('e-checkbox'); if (this.listViewInstance.checkBoxPosition === 'Left') { div_1.children[0].classList.add('e-checkbox-left'); } else { div_1.children[0].classList.add('e-checkbox-right'); } if (this.listViewInstance.checkBoxPosition === 'Left') { div_1.children[0].insertBefore(this.listViewInstance.virtualCheckBox, div_1.childNodes[0].children[0]); } else { div_1.children[0].appendChild(this.listViewInstance.virtualCheckBox); } while (args.item.lastChild) { args.item.removeChild(args.item.lastChild); } [].slice.call(div_1.children).forEach(function (ele) { args.item.appendChild(ele); }); } } } } }; Virtualization.prototype.reRenderUiVirtualization = function () { this.wireScrollEvent(true); if (this.listViewInstance.contentContainer) { detach(this.listViewInstance.contentContainer); } this.listViewInstance.preRender(); // resetting the dom count to 0, to avoid edge case of dataSource suddenly becoming zero // and then manually adding item using addItem API this.domItemCount = 0; this.listViewInstance.header(); this.listViewInstance.setLocalData(); }; Virtualization.prototype.updateUI = function (element, index, targetElement) { var onChange = this.isNgTemplate() ? this.onNgChange : this.onChange; if (this.listViewInstance.template || this.listViewInstance.groupTemplate) { var curViewDS = this.listViewInstance.curViewDS[index]; element.dataset.uid = (curViewDS[this.listViewInstance.fields.id]) ? (curViewDS[this.listViewInstance.fields.id]) : ListBase.generateId(); onChange(curViewDS, element, this); } else { this.updateUiContent(element, index); } this.changeElementAttributes(element, index); if (targetElement) { this.listViewInstance.ulElement.insertBefore(element, targetElement); } }; /** * Handles the UI change in vue for the list view. * * @param {DataSource} newData - The new data source for the list view. * @param {ElementContext} listElement - The HTML element context for the list view. * @param {Virtualization} virtualThis - The virtualization context for the list view. * @returns {void} */ Virtualization.prototype.onChange = function (newData, listElement, virtualThis) { var liItem = ListBase.createListItemFromJson(virtualThis.listViewInstance.createElement, [newData], virtualThis.listViewInstance.listBaseOption, null, null, virtualThis.listViewInstance); if (virtualThis.listViewInstance.isReact) { virtualThis.listViewInstance.renderReactTemplates(); } while (listElement.lastChild) { listElement.removeChild(listElement.lastChild); } [].slice.call(liItem[0].children).forEach(function (ele) { listElement.appendChild(ele); }); }; Virtualization.prototype.onNgChange = function (newData, listElement, virtualThis) { // compile given target element with template for new data var templateCompiler = compile(virtualThis.listViewInstance.template); var resultElement = templateCompiler(newData); while (listElement.lastChild) { listElement.removeChild(listElement.lastChild); } listElement.appendChild(resultElement[0]); }; Virtualization.prototype.getModuleName = function () { return 'virtualization'; }; Virtualization.prototype.destroy = function () { this.wireScrollEvent(true); this.topElement = null; this.bottomElement = null; }; return Virtualization; }()); export { Virtualization };