"use strict"; let accordion_view_list = []; const accordion_resize_observer = new ResizeObserver((changed_item_list) => { for(let one_changed_item of changed_item_list){ accordion_body_resize(one_changed_item.target); } }); window.addEventListener("load", function(event){ // COLLECT ACCORDION VIEWS // let accordion_root_list = document.getElementsByClassName("accordion"); for(let one_accordion_root of accordion_root_list){ // collect this view let accordion_view = accordion_collect_view(one_accordion_root); accordion_view_list.push(accordion_view); // initialized this view accordion_init(accordion_view); } }); /** * HELPER: Collect data for one accordion view. * * @param root Root element. * * @return Accordion view object. */ function accordion_collect_view(root){ // COLLECT ITEMS // let item_list = []; for(let one_child of root.children){ // maybe unwrap if(one_child.classList.contains("wrapper")) one_child = one_child.children[0] ?? null; // validate child as item if(!one_child.classList.contains("item")) continue; // find head element let head; for(let one_item_child of one_child.children){ if(one_item_child.classList.contains("head")){ head = one_item_child; break; } } if(head === undefined) throw "Unable to find accordion item head"; // find icon let icon; for(let one_head_child of head.children){ if(one_head_child.classList.contains("icon")){ icon = one_head_child; break; } } if(icon === undefined) throw "Unable to find accordion item icon"; // find title let title; for(let one_head_child of head.children){ if(one_head_child.classList.contains("title")){ title = one_head_child; break; } } if(title === undefined) throw "Unable to find accordion item title"; // find body container let bodyContainer; for(let one_item_child of one_child.children){ if(one_item_child.classList.contains("body-container")){ bodyContainer = one_item_child; break; } } if(bodyContainer === undefined) throw "Unable to find accordion body container"; // add to item list item_list.push({ element: one_child, head: head, icon: icon, title: title, bodyContainer: bodyContainer, }); } // BUILD OBJECT // return { root: root, item_list: item_list, }; } /** * HELPER: Initialize accordion view. * * @param accordion Accordion view object. */ function accordion_init(accordion){ // REGISTER ONCLICK HANDLERS // for(let one_item of accordion.item_list){ // head one_item.head.onclick = function(event){ event.stopPropagation(); accordion_click(one_item, accordion); }; // title one_item.title.tabIndex = 0; one_item.title.onclick = function(event){ event.stopPropagation(); accordion_click(one_item, accordion); }; one_item.title.onkeypress = function(event){ if(event.key === "Enter"){ event.preventDefault(); event.stopPropagation(); accordion_click(one_item, accordion); } }; } // RESET OPENED STATE // for(let one_item of accordion.item_list){ accordion_state_set(one_item, accordion_state_get(one_item)); } } /** * CALLBACK: Item head was clicked. * * @param item Accordion item. * @param accordion This item's accordion view object. */ function accordion_click(item, accordion){ // get our old state let old_state = accordion_state_get(item); // close all other items // for(let one_item of accordion.item_list){ accordion_state_set(one_item, false); } // set our new state accordion_state_set(item, !old_state); } /** * GETTER: Get state of one accordion item. * * @param item Accordion item. */ function accordion_state_get(item){ return item.element.classList.contains("open"); } /** * SETTER: Set state of one accordion item. * * @param item Accordion item. * @param state New state. */ function accordion_state_set(item, state){ // set observe state if(state) accordion_resize_observer.observe(item.bodyContainer); else accordion_resize_observer.unobserve(item.bodyContainer); // update class item.element.classList.remove("open"); if(state) item.element.classList.add("open"); // update icon direction item.icon.classList.remove("ti-chevron-up", "ti-chevron-right", "ti-chevron-down", "ti-chevron-left"); if(state) item.icon.classList.add("ti-chevron-down"); else item.icon.classList.add("ti-chevron-right"); // set body height if(state) accordion_body_resize(item.bodyContainer); else item.bodyContainer.style.maxHeight = 0; } /** * HELPER: Resize body height. * * @param bodyContainer Accordion body container. */ function accordion_body_resize(bodyContainer){ bodyContainer.style.maxHeight = bodyContainer.scrollHeight + "px"; }