File: //var/www/drakkar_site_dev/wp-content/themes/blocksy/static/js/frontend/generic-accordion.js
import { whenTransitionEnds } from './helpers/when-transition-ends'
const computeHasMarginManipulation = (childrenWrap, el) => {
const m = getComputedStyle(el).marginBottom
// return parseFloat(m) > 0 && el.nextElementSibling === childrenWrap
return el.nextElementSibling === childrenWrap
}
// support 3 strategies:
// 1. data-target on el
// 2. when no data-target, find aria-hidden element on the same level
// 3. when no data-target attribute is present, find aria-hidden element on
// upper level.
//
// If you can't find target — do nothing.
const findTargetForEl = (el) => {
// case 1
if (el.hasAttribute('data-target')) {
return document.querySelector(el.getAttribute('data-target'))
}
// case 2
const maybeCurrentLevel = el.parentNode.querySelector('[aria-hidden]')
if (maybeCurrentLevel) {
return maybeCurrentLevel
}
// case 3
const maybeUpperLevel =
el.parentNode.parentNode.querySelector('[aria-hidden]')
if (maybeUpperLevel) {
return maybeUpperLevel
}
// When nothing found -- do nothing
return null
}
const showContent = (childrenWrap, el) => {
const hasMarginManipulation = computeHasMarginManipulation(childrenWrap, el)
if (hasMarginManipulation) {
el.setAttribute('aria-expanded', 'true')
}
requestAnimationFrame(() => {
if (hasMarginManipulation) {
const m = getComputedStyle(el).marginBottom
// Revert back aria-expanded
el.setAttribute('aria-expanded', 'false')
childrenWrap.firstElementChild.prevStyle =
childrenWrap.firstElementChild.getAttribute('style')
childrenWrap.firstElementChild.style.marginTop = m
}
childrenWrap.setAttribute('aria-hidden', 'false')
const actualHeight = childrenWrap.getBoundingClientRect().height
childrenWrap.style.height = '0px'
childrenWrap.style.opacity = '0'
requestAnimationFrame(() => {
childrenWrap.classList.add('is-animating')
requestAnimationFrame(() => {
childrenWrap.style.height = `${actualHeight}px`
childrenWrap.style.opacity = '1'
whenTransitionEnds(childrenWrap, () => {
childrenWrap.classList.remove('is-animating')
childrenWrap.removeAttribute('style')
if (hasMarginManipulation) {
if (childrenWrap.firstElementChild.prevStyle) {
childrenWrap.firstElementChild.style =
childrenWrap.firstElementChild.prevStyle
} else {
childrenWrap.firstElementChild.removeAttribute(
'style'
)
}
}
el.setAttribute('aria-expanded', 'true')
})
})
})
})
}
const hideContent = (childrenWrap, el, cb) => {
const hasMarginManipulation = computeHasMarginManipulation(childrenWrap, el)
if (hasMarginManipulation) {
const m = getComputedStyle(el).marginBottom
childrenWrap.firstElementChild.prevStyle =
childrenWrap.firstElementChild.getAttribute('style')
childrenWrap.firstElementChild.style.marginTop = m
if (el.getAttribute('style')) {
el.prevStyle = el.getAttribute('style')
}
el.style.marginBottom = '0px'
}
requestAnimationFrame(() => {
const actualHeight = childrenWrap.getBoundingClientRect().height
childrenWrap.style.height = `${actualHeight}px`
childrenWrap.style.opacity = '1'
childrenWrap.classList.add('is-animating')
requestAnimationFrame(() => {
childrenWrap.style.height = '0px'
childrenWrap.style.opacity = '0'
whenTransitionEnds(childrenWrap, () => {
childrenWrap.classList.remove('is-animating')
childrenWrap.removeAttribute('style')
if (hasMarginManipulation) {
if (childrenWrap.firstElementChild.prevStyle) {
childrenWrap.firstElementChild.style =
childrenWrap.firstElementChild.prevStyle
} else {
childrenWrap.firstElementChild.removeAttribute('style')
}
if (el.prevStyle) {
el.style = el.prevStyle
} else {
el.removeAttribute('style')
}
}
cb()
})
})
})
}
export const mount = (el, { event }) => {
event.stopPropagation()
event.preventDefault()
const targetEl = findTargetForEl(el)
if (!targetEl) {
return
}
const isExpanded = targetEl.getAttribute('aria-hidden') === 'false'
if (isExpanded) {
hideContent(targetEl, el, () => {
el.setAttribute('aria-expanded', 'false')
targetEl.setAttribute('aria-hidden', 'true')
})
return
}
if (typeof el.dataset.closeOthers !== 'undefined') {
const parent = el.closest('.ct-accordion-tab').parentNode
const toggles = parent.querySelectorAll(
'.ct-expandable-trigger[aria-expanded="true"]'
)
toggles.forEach((toggle) => {
const targetEl = findTargetForEl(toggle)
if (targetEl) {
hideContent(targetEl, el, () => {
toggle.setAttribute('aria-expanded', 'false')
targetEl.setAttribute('aria-hidden', 'true')
})
}
})
}
showContent(targetEl, el)
}