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.

1,077 lines (1,076 loc) 52 kB
/* eslint-disable no-inner-declarations */ import { extend, merge, isNullOrUndefined, getValue, SanitizeHtmlHelper } from '@syncfusion/ej2-base'; import { attributes, prepend, isVisible, append, addClass } from '@syncfusion/ej2-base'; import { compile } from '@syncfusion/ej2-base'; import { DataManager, Query } from '@syncfusion/ej2-data'; export var cssClass = { li: 'e-list-item', ul: 'e-list-parent e-ul', group: 'e-list-group-item', icon: 'e-list-icon', text: 'e-list-text', check: 'e-list-check', checked: 'e-checked', selected: 'e-selected', expanded: 'e-expanded', textContent: 'e-text-content', hasChild: 'e-has-child', level: 'e-level', url: 'e-list-url', collapsible: 'e-icon-collapsible', disabled: 'e-disabled', image: 'e-list-img', iconWrapper: 'e-icon-wrapper', anchorWrap: 'e-anchor-wrap', navigable: 'e-navigable' }; /** * Base List Generator */ // eslint-disable-next-line @typescript-eslint/no-namespace export var ListBase; (function (ListBase) { /** * * Default mapped fields. */ ListBase.defaultMappedFields = { id: 'id', text: 'text', url: 'url', value: 'value', isChecked: 'isChecked', enabled: 'enabled', expanded: 'expanded', selected: 'selected', iconCss: 'iconCss', child: 'child', isVisible: 'isVisible', hasChildren: 'hasChildren', tooltip: 'tooltip', htmlAttributes: 'htmlAttributes', urlAttributes: 'urlAttributes', imageAttributes: 'imageAttributes', imageUrl: 'imageUrl', groupBy: null, sortBy: null }; var defaultAriaAttributes = { level: 1, listRole: 'presentation', itemRole: 'presentation', groupItemRole: 'group', itemText: 'list-item', wrapperRole: 'presentation' }; var defaultListBaseOptions = { showCheckBox: false, showIcon: false, enableHtmlSanitizer: false, expandCollapse: false, fields: ListBase.defaultMappedFields, ariaAttributes: defaultAriaAttributes, listClass: '', itemClass: '', processSubChild: false, sortOrder: 'None', template: null, groupTemplate: null, headerTemplate: null, expandIconClass: 'e-icon-collapsible', moduleName: 'list', expandIconPosition: 'Right', itemNavigable: false }; /** * Function helps to created and return the UL Li element based on your data. * * @param {createElementParams} createElement - Specifies an array of JSON data. * * @param {{Object}[]} dataSource - Specifies an array of JSON data. * * @param {ListBaseOptions} [options] - Specifies the list options that need to provide. * * @param {boolean} [isSingleLevel] - Specifies the list options that need to provide. * * @param {any} [componentInstance] - Specifies the list options that need to provide. * * @returns {createElement} createListFromJson - Specifies the list options that need to provide. */ function createList(createElement, dataSource, options, isSingleLevel, componentInstance) { var curOpt = extend({}, defaultListBaseOptions, options); var ariaAttributes = extend({}, defaultAriaAttributes, curOpt.ariaAttributes); var type = typeofData(dataSource).typeof; if (type === 'string' || type === 'number') { return createListFromArray(createElement, dataSource, isSingleLevel, options, componentInstance); } else { return createListFromJson(createElement, dataSource, options, ariaAttributes.level, isSingleLevel, componentInstance); } } ListBase.createList = createList; /** * Function helps to created an element list based on string array input . * * @param {createElementParams} createElement - Specifies an array of JSON data. * * @param {{Object}[]} dataSource - Specifies an array of JSON data. * * @param {boolean} [isSingleLevel] - Specifies the list options that need to provide. * * @param {ListBaseOptions} [options] - Specifies the list options that need to provide. * * @param {any} [componentInstance] - Specifies the list options that need to provide. * * @returns {createElement} generateUL - returns the list options that need to provide. */ function createListFromArray(createElement, dataSource, isSingleLevel, options, componentInstance) { var subChild = createListItemFromArray(createElement, dataSource, isSingleLevel, options, componentInstance); return generateUL(createElement, subChild, null, options); } ListBase.createListFromArray = createListFromArray; /** * Function helps to created an element list based on string array input . * * @param {createElementParams} createElement - Specifies an array of JSON data. * * @param {{Object}[]} dataSource - Specifies an array of JSON data. * * @param {boolean} [isSingleLevel] - Specifies the list options that need to provide. * * @param {ListBaseOptions} [options] - Specifies the list options that need to provide. * * @param {any} [componentInstance] - Specifies the list options that need to provide. * * @returns {HTMLElement[]} subChild - returns the list options that need to provide. */ function createListItemFromArray(createElement, dataSource, isSingleLevel, options, componentInstance) { var subChild = []; var curOpt = extend({}, defaultListBaseOptions, options); cssClass = getModuleClass(curOpt.moduleName); var id = generateId(); // generate id for drop-down-list option. for (var i = 0; i < dataSource.length; i++) { if (isNullOrUndefined(dataSource[i])) { continue; } var li = void 0; if (curOpt.itemCreating && typeof curOpt.itemCreating === 'function') { var curData = { dataSource: dataSource, curData: dataSource[i], text: dataSource[i], options: curOpt }; curOpt.itemCreating(curData); } if (isSingleLevel) { li = generateSingleLevelLI(createElement, dataSource[i], undefined, null, null, [], null, id, i, options); } else { li = generateLI(createElement, dataSource[i], undefined, null, null, options, componentInstance); } if (curOpt.itemCreated && typeof curOpt.itemCreated === 'function') { var curData = { dataSource: dataSource, curData: dataSource[i], text: dataSource[i], item: li, options: curOpt }; curOpt.itemCreated(curData); } subChild.push(li); } return subChild; } ListBase.createListItemFromArray = createListItemFromArray; /** * Function helps to created an element list based on array of JSON input . * * @param {createElementParams} createElement - Specifies an array of JSON data. * * @param {{Object}[]} dataSource - Specifies an array of JSON data. * * @param {ListBaseOptions} [options] - Specifies the list options that need to provide. * * @param {number} [level] - Specifies the list options that need to provide. * * @param {boolean} [isSingleLevel] - Specifies the list options that need to provide. * * @param {any} [componentInstance] - Specifies the list options that need to provide. * * @returns {HTMLElement[]} child - returns the list options that need to provide. */ function createListItemFromJson(createElement, dataSource, options, level, isSingleLevel, componentInstance) { var curOpt = extend({}, defaultListBaseOptions, options); cssClass = getModuleClass(curOpt.moduleName); var fields = (componentInstance && (componentInstance.getModuleName() === 'listview' || componentInstance.getModuleName() === 'multiselect')) ? curOpt.fields : extend({}, ListBase.defaultMappedFields, curOpt.fields); var ariaAttributes = extend({}, defaultAriaAttributes, curOpt.ariaAttributes); var id; var checkboxElement = []; if (level) { ariaAttributes.level = level; } var child = []; var li; var anchorElement; if (dataSource && dataSource.length && !isNullOrUndefined(typeofData(dataSource).item) && !Object.prototype.hasOwnProperty.call(typeofData(dataSource).item, fields.id)) { id = generateId(); // generate id for drop-down-list option. } for (var i = 0; i < dataSource.length; i++) { var fieldData = getFieldValues(dataSource[i], fields); if (isNullOrUndefined(dataSource[i])) { continue; } if (curOpt.itemCreating && typeof curOpt.itemCreating === 'function') { var curData = { dataSource: dataSource, curData: dataSource[i], text: fieldData[fields.text], options: curOpt, fields: fields }; curOpt.itemCreating(curData); } var curItem = dataSource[i]; if (curOpt.itemCreating && typeof curOpt.itemCreating === 'function') { fieldData = getFieldValues(dataSource[i], fields); } if (Object.prototype.hasOwnProperty.call(fieldData, fields.id) && !isNullOrUndefined(fieldData[fields.id])) { id = fieldData[fields.id]; } var innerEle = []; if (curOpt.showCheckBox) { if (curOpt.itemNavigable && (fieldData[fields.url] || fieldData[fields.urlAttributes])) { checkboxElement.push(createElement('input', { className: cssClass.check, attrs: { type: 'checkbox' } })); } else { innerEle.push(createElement('input', { className: cssClass.check, attrs: { type: 'checkbox' } })); } } if (isSingleLevel === true) { if (curOpt.showIcon && Object.prototype.hasOwnProperty.call(fieldData, fields.iconCss) && !isNullOrUndefined(fieldData[fields.iconCss])) { innerEle.push(createElement('span', { className: cssClass.icon + ' ' + fieldData[fields.iconCss] })); } li = generateSingleLevelLI(createElement, curItem, fieldData, fields, curOpt.itemClass, innerEle, (Object.prototype.hasOwnProperty.call(curItem, 'isHeader') && curItem.isHeader) ? true : false, id, i, options); anchorElement = li.querySelector('.' + cssClass.anchorWrap); if (Object.prototype.hasOwnProperty.call(fieldData, fields.tooltip)) { var tooltipText = fieldData[fields.tooltip]; if (options && options.enableHtmlSanitizer) { tooltipText = SanitizeHtmlHelper.sanitize(tooltipText); } else { var tooltipTextElement = createElement('span', { innerHTML: tooltipText }); tooltipText = tooltipTextElement.innerText; tooltipTextElement = null; } li.setAttribute('title', tooltipText); } if (curOpt.itemNavigable && checkboxElement.length) { prepend(checkboxElement, li.firstElementChild); } } else { li = generateLI(createElement, curItem, fieldData, fields, curOpt.itemClass, options, componentInstance); li.classList.add(cssClass.level + '-' + ariaAttributes.level); li.setAttribute('aria-level', ariaAttributes.level.toString()); if (ariaAttributes.groupItemRole === 'presentation' || ariaAttributes.itemRole === 'presentation') { li.removeAttribute('aria-level'); } anchorElement = li.querySelector('.' + cssClass.anchorWrap); if (Object.prototype.hasOwnProperty.call(fieldData, fields.tooltip)) { var tooltipText = fieldData[fields.tooltip]; if (options && options.enableHtmlSanitizer) { tooltipText = SanitizeHtmlHelper.sanitize(tooltipText); } else { var tooltipTextElement = createElement('span', { innerHTML: tooltipText }); tooltipText = tooltipTextElement.innerText; tooltipTextElement = null; } li.setAttribute('title', tooltipText); } if (Object.prototype.hasOwnProperty.call(fieldData, fields.htmlAttributes) && fieldData[fields.htmlAttributes]) { var htmlAttributes = fieldData[fields.htmlAttributes]; // Check if 'class' attribute is present and not an empty string if ('class' in htmlAttributes && typeof htmlAttributes['class'] === 'string' && htmlAttributes['class'].trim() === '') { delete htmlAttributes['class']; } setAttribute(li, htmlAttributes); } if (Object.prototype.hasOwnProperty.call(fieldData, fields.enabled) && fieldData[fields.enabled] === false) { li.classList.add(cssClass.disabled); } if (Object.prototype.hasOwnProperty.call(fieldData, fields.isVisible) && fieldData[fields.isVisible] === false) { li.style.display = 'none'; } if (Object.prototype.hasOwnProperty.call(fieldData, fields.imageUrl) && !isNullOrUndefined(fieldData[fields.imageUrl]) && !curOpt.template) { var attr = { src: fieldData[fields.imageUrl], alt: !isNullOrUndefined(fieldData.name) ? ('Displaying ' + fieldData.name + ' Image') : 'Displaying Image' }; merge(attr, fieldData[fields.imageAttributes]); var imageElemnt = createElement('img', { className: cssClass.image, attrs: attr }); if (anchorElement) { anchorElement.insertAdjacentElement('afterbegin', imageElemnt); } else { prepend([imageElemnt], li.firstElementChild); } } if (curOpt.showIcon && Object.prototype.hasOwnProperty.call(fieldData, fields.iconCss) && !isNullOrUndefined(fieldData[fields.iconCss]) && !curOpt.template) { var iconElement = createElement('div', { className: cssClass.icon + ' ' + fieldData[fields.iconCss] }); if (anchorElement) { anchorElement.insertAdjacentElement('afterbegin', iconElement); } else { prepend([iconElement], li.firstElementChild); } } if (innerEle.length) { prepend(innerEle, li.firstElementChild); } if (curOpt.itemNavigable && checkboxElement.length) { prepend(checkboxElement, li.firstElementChild); } processSubChild(createElement, fieldData, fields, dataSource, curOpt, li, ariaAttributes.level); } if (anchorElement) { addClass([li], [cssClass.navigable]); } if (curOpt.itemCreated && typeof curOpt.itemCreated === 'function') { var curData = { dataSource: dataSource, curData: dataSource[i], text: fieldData[fields.text], item: li, options: curOpt, fields: fields }; curOpt.itemCreated(curData); } checkboxElement = []; child.push(li); } return child; } ListBase.createListItemFromJson = createListItemFromJson; /** * Function helps to created an element list based on array of JSON input . * * @param {createElementParams} createElement - Specifies an array of JSON data. * * @param {{Object}[]} dataSource - Specifies an array of JSON data. * * @param {ListBaseOptions} [options] - Specifies the list options that need to provide. * * @param {number} [level] - Specifies the list options that need to provide. * * @param {boolean} [isSingleLevel] - Specifies the list options that need to provide. * * @param {any} [componentInstance] - Specifies the list options that need to provide. * * @returns {createElement} generateUL - Specifies the list options that need to provide. */ function createListFromJson(createElement, dataSource, options, level, isSingleLevel, componentInstance) { var curOpt = extend({}, defaultListBaseOptions, options); var li = createListItemFromJson(createElement, dataSource, options, level, isSingleLevel, componentInstance); return generateUL(createElement, li, curOpt.listClass, options); } ListBase.createListFromJson = createListFromJson; /** * Return the next or previous visible element. * * @param {Element[]|NodeList} elementArray - An element array to find next or previous element. * @param {Element} element - An element to find next or previous after this element. * @param {boolean} [isPrevious] - Specify when the need get previous element from array. * @returns {Element|undefined} The next or previous visible element, or undefined if the element array is empty. */ function getSiblingLI(elementArray, element, isPrevious) { cssClass = getModuleClass(defaultListBaseOptions.moduleName); if (!elementArray || !elementArray.length) { return void 0; } var siblingLI; var liIndex; var liCollections = Array.prototype.slice.call(elementArray); if (element) { liIndex = indexOf(element, liCollections); } else { liIndex = (isPrevious === true ? liCollections.length : -1); } siblingLI = liCollections[liIndex + (isPrevious === true ? -1 : 1)]; while (siblingLI && (!isVisible(siblingLI) || siblingLI.classList.contains(cssClass.disabled))) { liIndex = liIndex + (isPrevious === true ? -1 : 1); siblingLI = liCollections[liIndex]; } return siblingLI; } ListBase.getSiblingLI = getSiblingLI; /** * Return the index of the li element * * @param {Element} item - An element to find next or previous after this element. * @param {Element[]} elementArray - An element array to find index of given li. * @returns {number} - The index of the item in the element array, or undefined if either parameter is false. */ function indexOf(item, elementArray) { if (!elementArray || !item) { return void 0; } else { var liCollections = elementArray; liCollections = Array.prototype.slice.call(elementArray); return liCollections.indexOf(item); } } ListBase.indexOf = indexOf; /** * Returns the grouped data from given dataSource. * * @param {{Object}[]} dataSource - The JSON data which is necessary to process. * @param {FieldsMapping} fields - Fields that are mapped from the data source. * @param {SortOrder} [sortOrder='None'] - Specifies final result sort order. Defaults to 'None'. * @returns {Object[]} - The grouped data. */ function groupDataSource(dataSource, fields, sortOrder) { if (sortOrder === void 0) { sortOrder = 'None'; } var curFields = extend({}, ListBase.defaultMappedFields, fields); var cusQuery = new Query().group(curFields.groupBy); // need to remove once sorting issues fixed in DataManager cusQuery = addSorting(sortOrder, 'key', cusQuery); var ds = getDataSource(dataSource, cusQuery); dataSource = []; for (var j = 0; j < ds.length; j++) { var itemObj = ds[j].items; var grpItem = {}; var hdr = 'isHeader'; grpItem[curFields.text] = ds[j].key; grpItem["" + hdr] = true; var newtext = curFields.text; if (newtext === 'id') { newtext = 'text'; grpItem["" + newtext] = ds[j].key; } grpItem._id = 'group-list-item-' + (ds[j].key ? ds[j].key.toString().trim() : 'undefined'); grpItem.items = itemObj; dataSource.push(grpItem); for (var k = 0; k < itemObj.length; k++) { dataSource.push(itemObj[k]); } } return dataSource; } ListBase.groupDataSource = groupDataSource; /** * Returns a sorted query object. * * @param {SortOrder} sortOrder - Specifies that sort order. * @param {string} sortBy - Specifies sortBy fields. * @param {Query} query - Pass if any existing query. * @returns {Query} - The updated query object with sorting applied. */ function addSorting(sortOrder, sortBy, query) { if (query === void 0) { query = new Query(); } if (sortOrder === 'Ascending') { query.sortBy(sortBy, 'ascending', true); } else if (sortOrder === 'Descending') { query.sortBy(sortBy, 'descending', true); } else { for (var i = 0; i < query.queries.length; i++) { if (query.queries[i].fn === 'onSortBy') { query.queries.splice(i, 1); } } } return query; } ListBase.addSorting = addSorting; /** * Return an array of JSON Data that processed based on queries. * * @param {{Object}[]} dataSource - Specifies local JSON data source. * * @param {Query} query - Specifies query that need to process. * * @returns {Object[]} - An array of objects representing the retrieved data. */ function getDataSource(dataSource, query) { return new DataManager(dataSource) .executeLocal(query); } ListBase.getDataSource = getDataSource; /** * Created JSON data based the UL and LI element * * @param {HTMLElement|Element} element - UL element that need to convert as a JSON * @param {ListBaseOptions} [options] - Specifies ListBase option for fields. * @returns {Object[]} - An array of objects representing the JSON data. */ function createJsonFromElement(element, options) { var curOpt = extend({}, defaultListBaseOptions, options); var fields = extend({}, ListBase.defaultMappedFields, curOpt.fields); var curEle = element.cloneNode(true); var jsonAr = []; curEle.classList.add('json-parent'); var childs = curEle.querySelectorAll('.json-parent>li'); curEle.classList.remove('json-parent'); for (var i = 0; i < childs.length; i++) { var li = childs[i]; var anchor = li.querySelector('a'); var ul = li.querySelector('ul'); var json = {}; var childNodes = anchor ? anchor.childNodes : li.childNodes; var keys = Object.keys(childNodes); for (var i_1 = 0; i_1 < childNodes.length; i_1++) { if (!(childNodes[Number(keys[i_1])]).hasChildNodes()) { json[fields.text] = childNodes[Number(keys[i_1])].textContent; } } var attributes_1 = getAllAttributes(li); if (attributes_1.id) { json[fields.id] = attributes_1.id; delete attributes_1.id; } else { json[fields.id] = generateId(); } if (Object.keys(attributes_1).length) { json[fields.htmlAttributes] = attributes_1; } if (anchor) { attributes_1 = getAllAttributes(anchor); if (Object.keys(attributes_1).length) { json[fields.urlAttributes] = attributes_1; } } if (ul) { json[fields.child] = createJsonFromElement(ul, options); } jsonAr.push(json); } return jsonAr; } ListBase.createJsonFromElement = createJsonFromElement; /** * Determines the type of data in an array of objects, strings, or numbers. * * @param {Object[] | string[] | number[]} data - The array containing objects, strings, or numbers. * @returns {{typeof: (string | null), item: (Object | string | number)}} - An object containing the type of data and the corresponding item. */ function typeofData(data) { var match = { typeof: null, item: null }; for (var i = 0; i < data.length; i++) { if (!isNullOrUndefined(data[i])) { return match = { typeof: typeof data[i], item: data[i] }; } } return match; } /** * Sets attributes on an HTML element. * * @param {HTMLElement} element - The HTML element to set attributes on. * @param {Object.<string, string>} elementAttributes - An object containing attribute names and their corresponding values. * @returns {void} */ function setAttribute(element, elementAttributes) { var attr = {}; merge(attr, elementAttributes); if (attr.class) { addClass([element], attr.class.split(' ')); delete attr.class; } attributes(element, attr); } /** * Retrieves all attributes of an HTML element. * * @param {HTMLElement} element - The HTML element to retrieve attributes from. * @returns {Object.<string, string>} - An object containing attribute names as keys and their corresponding values as values. */ function getAllAttributes(element) { var attributes = {}; var attr = element.attributes; for (var index = 0; index < attr.length; index++) { attributes[attr[index].nodeName] = attr[index].nodeValue; } return attributes; } /** * Created UL element from content template. * * @param {createElementParams} createElement - Specifies an array of JSON data. * @param {string} template - that need to convert and generate li element. * @param {{Object}[]} dataSource - Specifies local JSON data source. * @param {FieldsMapping} [fields] - Specifies fields for mapping the dataSource. * @param {ListBaseOptions} [options] - Specifies ListBase option for fields. * @param {any} [componentInstance] - Specifies component instance. * @returns {HTMLElement} - The generated LI element. */ function renderContentTemplate(createElement, template, dataSource, fields, options, componentInstance) { cssClass = getModuleClass(defaultListBaseOptions.moduleName); var ulElement = createElement('ul', { className: cssClass.ul, attrs: { role: 'presentation' } }); var curOpt = extend({}, defaultListBaseOptions, options); var curFields = extend({}, ListBase.defaultMappedFields, fields); var compiledString = compileTemplate(template); var liCollection = []; var value; var id = generateId(); // generate id for drop-down-list option. for (var i = 0; i < dataSource.length; i++) { var fieldData = getFieldValues(dataSource[i], curFields); var curItem = dataSource[i]; var isHeader = curItem.isHeader; if (typeof dataSource[i] === 'string' || typeof dataSource[i] === 'number') { value = curItem; } else { value = fieldData[curFields.value]; } if (curOpt.itemCreating && typeof curOpt.itemCreating === 'function') { var curData = { dataSource: dataSource, curData: curItem, text: value, options: curOpt, fields: curFields }; curOpt.itemCreating(curData); } if (curOpt.itemCreating && typeof curOpt.itemCreating === 'function') { fieldData = getFieldValues(dataSource[i], curFields); if (typeof dataSource[i] === 'string' || typeof dataSource[i] === 'number') { value = curItem; } else { value = fieldData[curFields.value]; } } var li = createElement('li', { id: id + '-' + i, className: isHeader ? cssClass.group : cssClass.li, attrs: { role: 'presentation' } }); if (isHeader) { if (typeof dataSource[i] === 'string' || typeof dataSource[i] === 'number') { li.innerText = curItem; } else { li.innerText = fieldData[curFields.text]; } } else { var currentID = isHeader ? curOpt.groupTemplateID : curOpt.templateID; if (isHeader) { if (componentInstance && componentInstance.getModuleName() !== 'listview') { var compiledElement = compiledString(curItem, componentInstance, 'headerTemplate', currentID, !!curOpt.isStringTemplate, null, li); if (compiledElement) { append(compiledElement, li); } } else { append(compiledString(curItem, componentInstance, 'headerTemplate', currentID, !!curOpt.isStringTemplate), li); } } else { if (componentInstance && componentInstance.getModuleName() !== 'listview') { var compiledElement = compiledString(curItem, componentInstance, 'template', currentID, !!curOpt.isStringTemplate, null, li); if (compiledElement) { append(compiledElement, li); } } else { append(compiledString(curItem, componentInstance, 'template', currentID, !!curOpt.isStringTemplate), li); } } li.setAttribute('data-value', isNullOrUndefined(value) ? 'null' : value); li.setAttribute('role', 'option'); } if (curOpt.itemCreated && typeof curOpt.itemCreated === 'function') { var curData = { dataSource: dataSource, curData: curItem, text: value, item: li, options: curOpt, fields: curFields }; curOpt.itemCreated(curData); } liCollection.push(li); } append(liCollection, ulElement); return ulElement; } ListBase.renderContentTemplate = renderContentTemplate; /** * Created header items from group template. * * @param {string | Function} groupTemplate - that need to convert and generate li element. * * @param {{Object}[]} groupDataSource - Specifies local JSON data source. * * @param {FieldsMapping} fields - Specifies fields for mapping the dataSource. * * @param {Element[]} headerItems - Specifies ListBase header items. * * @param {ListBaseOptions} [options] - Optional ListBase options. * * @param {*} [componentInstance] - Optional component instance. * * @returns {Element[]} - An array of header elements with the rendered group template content. */ function renderGroupTemplate(groupTemplate, // tslint:disable-next-line groupDataSource, fields, headerItems, options, componentInstance) { var compiledString = compileTemplate(groupTemplate); var curFields = extend({}, ListBase.defaultMappedFields, fields); var curOpt = extend({}, defaultListBaseOptions, options); var category = curFields.groupBy; for (var _i = 0, headerItems_1 = headerItems; _i < headerItems_1.length; _i++) { var header = headerItems_1[_i]; var headerData = {}; headerData["" + category] = header.textContent; header.innerHTML = ''; if (componentInstance && componentInstance.getModuleName() !== 'listview') { var compiledElement = compiledString(headerData, componentInstance, 'groupTemplate', curOpt.groupTemplateID, !!curOpt.isStringTemplate, null, header); if (compiledElement) { append(compiledElement, header); } } else { append(compiledString(headerData, componentInstance, 'groupTemplate', curOpt.groupTemplateID, !!curOpt.isStringTemplate), header); } } return headerItems; } ListBase.renderGroupTemplate = renderGroupTemplate; /** * Generates a random hexadecimal ID string. * * @returns {string} - The generated ID string. */ function generateId() { var array = new Uint32Array(1); window.crypto.getRandomValues(array); return Math.floor((1 + array[0] / (0xFFFFFFFF + 1)) * 0x10000) .toString(16) .substring(1); } ListBase.generateId = generateId; /** * Processes the sub-child elements and creates corresponding elements based on the provided field data and options. * * @param {Function} createElement - Function for creating elements. * @param {Object} fieldData - Field data containing sub-child information. * @param {FieldsMapping} fields - Field mappings. * @param {Object[]} ds - The data source array containing sub-child elements. * @param {ListBaseOptions} options - ListBase options. * @param {HTMLElement} element - The parent HTML element to append sub-child elements to. * @param {number} level - The level of the sub-child elements. * @returns {void} */ function processSubChild(createElement, fieldData, fields, ds, options, element, level) { // Get SubList var subDS = fieldData[fields.child] || []; var hasChildren = fieldData[fields.hasChildren]; //Create Sub child if (subDS.length) { hasChildren = true; element.classList.add(cssClass.hasChild); if (options.processSubChild) { var subLi = createListFromJson(createElement, subDS, options, ++level); element.appendChild(subLi); } } // Create expand and collapse node if (!!options.expandCollapse && hasChildren && !options.template) { element.firstElementChild.classList.add(cssClass.iconWrapper); var expandElement = options.expandIconPosition === 'Left' ? prepend : append; expandElement([createElement('div', { className: 'e-icons ' + options.expandIconClass })], element.querySelector('.' + cssClass.textContent)); } } /** * Generates a single-level LI (list item) element based on the provided item and field data. * * @param {Function} createElement - Function for creating elements. * @param {string | Object | number} item - The item data. * @param {Object} fieldData - Field data mapped from the item. * @param {FieldsMapping} [fields] - Field mappings. * @param {string} [className] - Optional class name to add to the created LI element. * @param {HTMLElement[]} [innerElements] - Optional array of inner elements to append to the LI element. * @param {boolean} [grpLI] - Indicates if the LI element is a group item. * @param {string} [id] - The ID of the LI element. * @param {number} [index] - The index of the LI element. * @param {ListBaseOptions} [options] - Optional ListBase options. * @returns {HTMLElement} - The generated LI element. */ function generateSingleLevelLI(createElement, item, fieldData, fields, className, innerElements, grpLI, id, index, options) { var curOpt = extend({}, defaultListBaseOptions, options); var ariaAttributes = extend({}, defaultAriaAttributes, curOpt.ariaAttributes); var text = item; var value = item; var dataSource; if (typeof item !== 'string' && typeof item !== 'number' && typeof item !== 'boolean') { dataSource = item; text = (typeof fieldData[fields.text] === 'boolean' || typeof fieldData[fields.text] === 'number') ? fieldData[fields.text] : (fieldData[fields.text] || ''); value = fieldData[fields.value]; } var elementID; if (!isNullOrUndefined(dataSource) && !isNullOrUndefined(fieldData[fields.id]) && fieldData[fields.id] !== '') { elementID = id; } else { elementID = id + '-' + index; } var li = createElement('li', { className: (grpLI === true ? cssClass.group : cssClass.li) + ' ' + (isNullOrUndefined(className) ? '' : className), id: elementID, attrs: (ariaAttributes.groupItemRole !== '' && ariaAttributes.itemRole !== '' ? { role: (grpLI === true ? ariaAttributes.groupItemRole : ariaAttributes.itemRole) } : {}) }); if (dataSource && Object.prototype.hasOwnProperty.call(fieldData, fields.enabled) && fieldData[fields.enabled].toString() === 'false') { li.classList.add(cssClass.disabled); } if (options && options.enableHtmlSanitizer) { text = SanitizeHtmlHelper.sanitize(text); } if (grpLI) { li.innerText = text; } else { li.setAttribute('data-value', isNullOrUndefined(value) ? 'null' : value); li.setAttribute('role', 'option'); if (dataSource && Object.prototype.hasOwnProperty.call(fieldData, fields.htmlAttributes) && fieldData[fields.htmlAttributes]) { setAttribute(li, fieldData[fields.htmlAttributes]); } if (innerElements.length && !curOpt.itemNavigable) { append(innerElements, li); } if (dataSource && (fieldData[fields.url] || (fieldData[fields.urlAttributes] && fieldData[fields.urlAttributes].href))) { li.appendChild(anchorTag(createElement, dataSource, fields, text, innerElements, curOpt.itemNavigable)); } else { if (innerElements.length && curOpt.itemNavigable) { append(innerElements, li); } li.appendChild(document.createTextNode(text)); } } return li; } /** * Returns a set of CSS class names based on the provided module name. * * @param {string} moduleName - The name of the module. * @returns {ClassList} - The CSS class names associated with the module. */ function getModuleClass(moduleName) { var moduleClass; // eslint-disable-next-line return moduleClass = { li: "e-" + moduleName + "-item", ul: "e-" + moduleName + "-parent e-ul", group: "e-" + moduleName + "-group-item", icon: "e-" + moduleName + "-icon", text: "e-" + moduleName + "-text", check: "e-" + moduleName + "-check", checked: 'e-checked', selected: 'e-selected', expanded: 'e-expanded', textContent: 'e-text-content', hasChild: 'e-has-child', level: 'e-level', url: "e-" + moduleName + "-url", collapsible: 'e-icon-collapsible', disabled: 'e-disabled', image: "e-" + moduleName + "-img", iconWrapper: 'e-icon-wrapper', anchorWrap: 'e-anchor-wrap', navigable: 'e-navigable' }; } /** * Creates an anchor tag (<a>) element based on the provided data source, fields, and text. * * @param {Function} createElement - Function for creating elements. * @param {object} dataSource - The data source containing URL-related fields. * @param {FieldsMapping} fields - Field mappings for the data source. * @param {string} text - The text content of the anchor tag. * @param {HTMLElement[]} innerElements - Optional array of inner elements to append to the anchor tag. * @param {boolean} isFullNavigation - Indicates whether the anchor tag should be for full navigation. * @returns {HTMLElement} The created anchor tag element. */ function anchorTag(createElement, dataSource, fields, text, innerElements, isFullNavigation) { var fieldData = getFieldValues(dataSource, fields); var attr = { href: fieldData[fields.url] }; if (Object.prototype.hasOwnProperty.call(fieldData, fields.urlAttributes) && fieldData[fields.urlAttributes]) { merge(attr, fieldData[fields.urlAttributes]); attr.href = fieldData[fields.url] ? fieldData[fields.url] : fieldData[fields.urlAttributes].href; } var anchorTag; if (!isFullNavigation) { anchorTag = createElement('a', { className: cssClass.text + ' ' + cssClass.url, innerHTML: text }); } else { anchorTag = createElement('a', { className: cssClass.text + ' ' + cssClass.url }); var anchorWrapper = createElement('div', { className: cssClass.anchorWrap }); if (innerElements && innerElements.length) { append(innerElements, anchorWrapper); } anchorWrapper.appendChild(document.createTextNode(text)); append([anchorWrapper], anchorTag); } setAttribute(anchorTag, attr); return anchorTag; } /** * Generates an LI element based on the provided item and field data. * * @param {Function} createElement - Function for creating elements. * @param {string | Object | number} item - The item data. * @param {Object} fieldData - Field data mapped from the item. * @param {FieldsMapping} fields - Field mappings. * @param {string} [className] - Optional class name to add to the created LI element. * @param {ListBaseOptions} [options] - Optional ListBase options. * @param {*} [componentInstance] - Optional component instance. * @returns {HTMLElement} - The generated LI element. */ function generateLI(createElement, item, fieldData, fields, className, options, componentInstance) { var curOpt = extend({}, defaultListBaseOptions, options); var ariaAttributes = extend({}, defaultAriaAttributes, curOpt.ariaAttributes); var text = item; var uID; var grpLI; var dataSource; if (typeof item !== 'string' && typeof item !== 'number') { dataSource = item; text = fieldData[fields.text] || ''; uID = (isNullOrUndefined(fieldData['_id'])) ? fieldData[fields.id] : fieldData['_id']; grpLI = (Object.prototype.hasOwnProperty.call(item, 'isHeader') && item.isHeader) ? true : false; } if (options && options.enableHtmlSanitizer) { text = SanitizeHtmlHelper.sanitize(text); } var li = createElement('li', { className: (grpLI === true ? cssClass.group : cssClass.li) + ' ' + (isNullOrUndefined(className) ? '' : className), attrs: (ariaAttributes.groupItemRole !== '' && ariaAttributes.itemRole !== '' ? { role: (grpLI === true ? ariaAttributes.groupItemRole : ariaAttributes.itemRole) } : {}) }); if (!isNullOrUndefined(uID) === true) { li.setAttribute('data-uid', uID); } else { li.setAttribute('data-uid', generateId()); } if (grpLI && options && options.groupTemplate) { var compiledString = compileTemplate(options.groupTemplate); if (componentInstance && componentInstance.getModuleName() !== 'listview') { var compiledElement = compiledString(item, componentInstance, 'groupTemplate', curOpt.groupTemplateID, !!curOpt.isStringTemplate, null, li); if (compiledElement) { append(compiledElement, li); } } else { append(compiledString(item, componentInstance, 'groupTemplate', curOpt.groupTemplateID, !!curOpt.isStringTemplate), li); } } else if (!grpLI && options && options.template) { if (componentInstance && componentInstance.getModuleName() !== 'listview') { var compiledString = compileTemplate(options.template); var compiledElement = compiledString(item, componentInstance, 'template', curOpt.templateID, !!curOpt.isStringTemplate, null, li); if (compiledElement) { append(compiledElement, li); } } else { // For spreadsheet comment templates, call the template function directly instead of relying on compiled string. if (componentInstance && componentInstance.isInternalTemplate) { append(options.template(item), li); } else { var compiledString = compileTemplate(options.template); append(compiledString(item, componentInstance, 'template', curOpt.templateID, !!curOpt.isStringTemplate), li); } } } else { var innerDiv = createElement('div', { className: cssClass.textContent, attrs: (ariaAttributes.wrapperRole !== '' ? { role: ariaAttributes.wrapperRole } : {}) }); if (dataSource && (fieldData[fields.url] || (fieldData[fields.urlAttributes] && fieldData[fields.urlAttributes].href))) { innerDiv.appendChild(anchorTag(createElement, dataSource, fields, text, null, curOpt.itemNavigable)); } else { var element = createElement('span', { className: cssClass.text, attrs: (ariaAttributes.itemText !== '' ? { role: ariaAttributes.itemText } : {}) }); if (options && options.enableHtmlSanitizer) { element.innerText = text; } else { element.innerHTML = text; } innerDiv.appendChild(element); } li.appendChild(innerDiv); } return li; } /** * Returns UL element based on the given LI element. * * @param {Function} createElement - Function for creating elements. * * @param {HTMLElement[]} liElement - Specifies array of LI element. * * @param {string} [className] - Specifies class name that need to be added in UL element. * * @param {ListBaseOptions} [options] - Specifies ListBase options. * * @returns {HTMLElement} - The created UL element. */ function generateUL(createElement, liElement, className, options) { var curOpt = extend({}, defaultListBaseOptions, options); var ariaAttributes = extend({}, defaultAriaAttributes, curOpt.ariaAttributes); cssClass = getModuleClass(curOpt.moduleName); var ulElement = createElement('ul', { className: cssClass.ul + ' ' + (isNullOrUndefined(className) ? '' : className), attrs: (ariaAttributes.listRole !== '' ? { role: ariaAttributes.listRole } : {}) }); append(liElement, ulElement); return ulElement; } ListBase.generateUL = generateUL; /** * Returns LI element with additional DIV tag based on the given LI element. * * @param {Function} createElement - Function for creating elements. * * @param {liElement} liElement - Specifies LI element. * * @param {string} [className] - Specifies class name that need to be added in created DIV element. * * @param {ListBaseOptions} [options] - Specifies ListBase options. * * @returns {HTMLElement} - The modified LI element. */ function generateIcon(createElement, liElement, className, options) { var curOpt = extend({}, defaultListBaseOptions, options); cssClass = getModuleClass(curOpt.moduleName); var expandElement = curOpt.expandIconPosition === 'Left' ? prepend : append; expandElement([createElement('div', {