import { queryAll } from '@ecl/dom-utils';/** * @param {HTMLElement} element DOM element for component instantiation and scope * @param {Object} options * @param {String} options.itemSelector Selector for the items * @param {String} options.parentItemSelector Selector for the parent items * @param {String} options.listSelector Selector for the lists * @param {Boolean} options.attachClickListener Whether or not to bind click events */export class CategoryFilter { /** * @static * Shorthand for instance creation and initialisation. * * @param {HTMLElement} root DOM element for component instantiation and scope * * @return {CategoryFilter} An instance of CategoryFilter. */ static autoInit(root, { CATEGORY_FILTER: defaultOptions = {} } = {}) { const categoryFilter = new CategoryFilter(root, defaultOptions); categoryFilter.init(); root.ECLCategoryFilter = categoryFilter; return categoryFilter; } constructor( element, { itemSelector = '.ecl-category-filter__item', parentItemSelector = 'ecl-category-filter__item--has-children', listSelector = '.ecl-category-filter__list', attachClickListener = true, } = {}, ) { // Check element if (!element || element.nodeType !== Node.ELEMENT_NODE) { throw new TypeError( 'DOM element should be given to initialize this widget.', ); } this.element = element; // Options this.itemSelector = itemSelector; this.parentItemSelector = parentItemSelector; this.listSelector = listSelector; this.attachClickListener = attachClickListener; // Private variables this.items = null; // Bind `this` for use in callbacks this.handleClickExpand = this.handleClickExpand.bind(this); this.expandParents = this.expandParents.bind(this); } /** * Initialise component. */ init() { if (!ECL) { throw new TypeError('Called init but ECL is not present'); } ECL.components = ECL.components || new Map(); // Query elementslur this.items = queryAll(this.itemSelector, this.element); const e = { preventDefault: () => null }; // Bind click event on open if (this.attachClickListener && this.items) { this.items.forEach((item) => { item.addEventListener('click', this.handleClickExpand); // Epand the needed items if there is a current item set if (item.getAttribute('aria-current')) { e.target = item; this.handleClickExpand(e); this.expandParents.call(this, item); } }); } // Set ecl initialized attribute this.element.setAttribute('data-ecl-auto-initialized', 'true'); ECL.components.set(this.element, this); } /** * Destroy component. */ destroy() { if (this.attachClickListener && this.items) { this.items.forEach((item) => { item.removeEventListener('click', this.handleClickExpand, false); }); } if (this.element) { this.element.removeAttribute('data-ecl-auto-initialized'); ECL.components.delete(this.element); } } /** * Expand parents of the given item. * @param {Node} item */ expandParents(item) { if (!item) return; const e = { preventDefault: () => null }; const parent = item.closest(this.listSelector)?.previousElementSibling; if (parent && parent.classList.contains(this.parentItemSelector)) { e.target = parent; this.handleClickExpand(e); this.expandParents.call(this, parent); } } /** * Expand tree list item. * @param {Event} e */ handleClickExpand(e) { // Get item even if we clicked on the icon const treeItem = e.target.closest(this.itemSelector); const isNotInit = typeof e.stopPropagation === 'function'; // Toggle current item if (isNotInit) { this.items.forEach((item) => { if (item === treeItem) { item.setAttribute('aria-current', true); } else { item.removeAttribute('aria-current'); } }); } // Toggle expanded const isExpanded = treeItem.getAttribute('aria-expanded'); if (isExpanded && isExpanded === 'true') { e.preventDefault(); treeItem.setAttribute('aria-expanded', 'false'); treeItem.parentElement.classList.remove( 'ecl-category-filter__list-item--open', ); } else if (isExpanded && isExpanded === 'false') { e.preventDefault(); treeItem.setAttribute('aria-expanded', 'true'); treeItem.parentElement.classList.add( 'ecl-category-filter__list-item--open', ); } if (isExpanded && isNotInit) { // For first level, keep only one item open if (treeItem.classList.contains('ecl-category-filter__item--level-1')) { this.items.forEach((item) => { if (item !== treeItem) { item.parentElement.classList.remove( 'ecl-category-filter__list-item--open', ); if (item.classList.contains(this.parentItemSelector)) { item.setAttribute('aria-expanded', 'false'); } } }); } } }}export default CategoryFilter;