UNPKG

@ulu/frontend

Version:

A versatile SCSS and JavaScript component library offering configurable, accessible components and flexible integration into any project, with SCSS modules suitable for modern JS frameworks.

112 lines (100 loc) 2.94 kB
/** * @module ui/details-group * @description Manages groups of details (ie. onlyOneOpen at a time) */ import { ComponentInitializer } from "../utils/system.js"; /** * Dialog Component Initializer */ export const initializer = new ComponentInitializer({ type: "details-group", baseAttribute: "data-ulu-details-group" }); const childInitAttr = initializer.getAttribute("child-init"); const defaults = { onlyOneOpen: true, childSelector: ":scope > details" }; /** * Initialize everything in document * - This will only initialize elements once, it is safe to call on page changes */ export function init() { initializer.init({ withData: true, events: ["pageModified"], setup({ element, data, initialize }) { setupGroup(element, data); initialize(); } }); } /** * @typedef {Object} DetailsGroupInstance * @property {Function} destroy A function to remove event listeners and attributes. * @property {HTMLElement} element The parent element. * @property {Function} setupChildren A function to initialize the child details elements. */ /** * Sets up a single group of details elements to manage their behavior. * @param {HTMLElement} element - The parent element containing the details elements. * @param {Object} options - The options for this group * @returns {DetailsGroupInstance} */ export function setupGroup(element, userOptions) { const options = Object.assign({}, defaults, userOptions); // Added try because we are using querySelectorAll with :scope by default // which will not work in Internet Explorer or early edge (some alt. browsers too) try { setupChildren(); } catch(error) { console.error(error); } /** * Queries all current children in element * @ignore */ function queryChildren() { return element.querySelectorAll(options.childSelector); } /** * Sets up any children not already setup in group */ function setupChildren() { queryChildren().forEach(child => { if (child.hasAttribute(childInitAttr)) { return; } else { child.setAttribute(childInitAttr, ""); } child.addEventListener("toggle", toggleHandler); }); } /** * Toggle handler for child details element * - For things like one open at a time * @ignore */ function toggleHandler({ target }) { if (options.onlyOneOpen) { if (target.open) { queryChildren().forEach(child => { if (child !== target && child.open) { child.open = false; } }); } } } /** * Function removes all handlers and init attributes */ function destroy() { queryChildren().forEach(child => { child.removeEventListener("toggle", toggleHandler); child.removeAttribute(childInitAttr); }); element.removeAttribute(initializer.getAttribute("init")); } return { destroy, element, setupChildren }; }