Files
pretix_original/src/pretix/static/pretixbase/js/details.js
T
Raphael MichelandKara Engelhardt d85e52c83e ESlint: Ignore vendored and pre-vue code (#6541)
* ESlint: Ignore vendored and pre-vue code

* Format pre-vue code with eslint where possible

---------

Co-authored-by: Kara Engelhardt <engelhardt@pretix.eu>
2026-09-10 12:35:10 +02:00

150 lines
5.0 KiB
JavaScript

setup_collapsible_details = function (el) {
el.find('.sneak-peek-trigger').each(function () {
let trigger = this
let button = this.querySelector('button')
let content = document.getElementById(button.getAttribute('aria-controls'))
if (content.scrollHeight < 200) {
trigger.remove()
content.classList.remove('sneak-peek-content')
return
}
content.setAttribute('aria-hidden', 'true')
content.setAttribute('inert', true)
button.setAttribute('aria-expanded', 'false')
button.addEventListener('click', function (e) {
button.setAttribute('aria-expanded', 'true')
content.setAttribute('aria-hidden', 'false')
content.removeAttribute('inert')
content.addEventListener('transitionend', function () {
content.classList.remove('sneak-peek-content')
content.style.removeProperty('height')
// we need to keep the trigger/button in the DOM to not irritate screenreaders toggling visibility
trigger.classList.add('sr-only')
}, { once: true })
content.style.height = content.scrollHeight + 'px'
button.addEventListener('click', function (e) {
// this will be called by screenreader users if they kept focus on the button after expanding
// we need to keep the trigger/button in the DOM to not irritate screenreaders toggling visibility
let expanded = button.getAttribute('aria-expanded') == 'true'
button.setAttribute('aria-expanded', !expanded)
content.setAttribute('aria-hidden', expanded)
})
button.addEventListener('blur', function (e) {
// if content is visible and the user leaves the button, we can safely remove the trigger/button
if (button.getAttribute('aria-expanded') == 'true') {
trigger.remove()
}
})
}, { once: true })
let container = this.closest('details.sneak-peek-container')
if (container) {
function removeSneekPeakWhenClosed (e) {
if (e.newState == 'closed') {
container.removeEventListener('toggle', removeSneekPeakWhenClosed)
trigger.remove()
content.removeAttribute('aria-hidden')
content.removeAttribute('inert')
content.classList.remove('sneak-peek-content')
}
}
container.addEventListener('toggle', removeSneekPeakWhenClosed)
}
})
let isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'
el.find('details summary').click(function (e) {
if (this.tagName !== 'A' && $(e.target).closest('a').length > 0) {
return true
}
let $details = $(this).closest('details')
let isOpen = $details.prop('open')
let $detailsNotSummary = $details.children(':not(summary)')
if ($detailsNotSummary.is(':animated')) {
e.preventDefault()
return false
}
if (isOpen) {
$details.removeClass('details-open')
$detailsNotSummary.stop().show().slideUp(500, function () {
$details.prop('open', false)
})
} else {
$detailsNotSummary.stop().hide()
$details.prop('open', true)
$details.addClass('details-open')
$detailsNotSummary.slideDown()
}
e.preventDefault()
return false
}).keyup(function (event) {
if (32 == event.keyCode || (13 == event.keyCode && !isOpera)) {
// Space or Enter is pressed — trigger the `click` event on the `summary` element
// Opera already seems to trigger the `click` event when Enter is pressed
event.preventDefault()
$(this).click()
}
})
$('details').each(function () {
let $details = $(this),
$detailsSummary = $('summary', $details).first(),
$detailsNotSummary = $details.children(':not(summary)')
$details.prop('open', typeof $details.attr('open') == 'string')
if (!$details.prop('open')) {
if ($details.find('.has-error, .alert-danger').length) {
$details.addClass('details-open')
$details.prop('open', true)
} else {
$detailsNotSummary.hide()
}
} else {
$details.addClass('details-open')
}
$detailsSummary.attr({
role: 'button',
'aria-controls': $details.attr('id')
}).prop('tabIndex', 0).bind('selectstart dragstart mousedown', function () {
return false
})
})
el.find('article button[data-toggle=variations]').click(function (e) {
let $button = $(this)
let $details = $button.closest('article')
let $detailsNotSummary = $button.attr('aria-controls') ? $('#' + $button.attr('aria-controls')) : $('.variations', $details)
let isOpen = !$detailsNotSummary.prop('hidden')
if ($detailsNotSummary.is(':animated')) {
e.preventDefault()
return false
}
let altLabel = $button.attr('data-label-alt')
$button.attr('data-label-alt', $button.text().trim())
$button.find('span').text(altLabel)
$button.attr('aria-expanded', !isOpen)
if (isOpen) {
$details.removeClass('details-open')
$detailsNotSummary.stop().show().slideUp(500, function () {
$detailsNotSummary.prop('hidden', true)
})
} else {
$detailsNotSummary.prop('hidden', false).stop().hide()
$details.addClass('details-open')
$detailsNotSummary.slideDown()
}
e.preventDefault()
return false
})
el.find('.variations-collapsed').prop('hidden', true)
}
$(function () {
'use strict'
setup_collapsible_details($('body'))
})