2020-04-04 22:14:34 +02:00
|
|
|
function collapse_spoiler(spoiler) {
|
2020-06-17 21:57:12 +02:00
|
|
|
const spoiler_height = spoiler.height();
|
2020-04-04 22:14:34 +02:00
|
|
|
|
|
|
|
// Set height to rendered height on next frame, then to zero on following
|
|
|
|
// frame to allow CSS transition animation to work
|
|
|
|
requestAnimationFrame(function () {
|
|
|
|
spoiler.height(spoiler_height + 'px');
|
|
|
|
spoiler.removeClass("spoiler-content-open");
|
|
|
|
|
|
|
|
requestAnimationFrame(function () {
|
|
|
|
spoiler.height("0px");
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function expand_spoiler(spoiler) {
|
|
|
|
// Normally, the height of the spoiler block is not defined absolutely on
|
|
|
|
// the `spoiler-content-open` class, but just set to `auto` (i.e. the height
|
|
|
|
// of the content). CSS animations do not work with properties set to
|
|
|
|
// `auto`, so we get the actual height of the content here and temporarily
|
|
|
|
// put it explicitly on the element styling to allow the transition to work.
|
|
|
|
const spoiler_height = spoiler.prop('scrollHeight');
|
|
|
|
spoiler.height(spoiler_height + "px");
|
|
|
|
// The `spoiler-content-open` class has CSS animations defined on it which
|
|
|
|
// will trigger on the frame after this class change.
|
|
|
|
spoiler.addClass("spoiler-content-open");
|
|
|
|
|
|
|
|
spoiler.on('transitionend', function () {
|
|
|
|
spoiler.off('transitionend');
|
|
|
|
// When the CSS transition is over, reset the height to auto
|
|
|
|
// This keeps things working if, e.g., the viewport is resized
|
|
|
|
spoiler.height("");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.initialize = function () {
|
2020-06-17 21:57:12 +02:00
|
|
|
$("body").on("click", ".spoiler-header", function (e) {
|
|
|
|
const button = $(this).children('.spoiler-button');
|
|
|
|
const arrow = button.children('.spoiler-arrow');
|
|
|
|
const spoiler_content = $(this).siblings(".spoiler-content");
|
|
|
|
const target = $(e.target);
|
|
|
|
|
|
|
|
// Spoiler headers can contain markdown, including links. We follow the link
|
|
|
|
// and don't expand the spoiler if a link has been clicked (unless it's the dropdown arrow)
|
|
|
|
// This can be accomplished by just breaking from this function before preventing default
|
|
|
|
// or toggling the state of the spoiler block.
|
|
|
|
if (target.is('a') && !target.hasClass('.spoiler-button')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-04 22:14:34 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
if (spoiler_content.hasClass("spoiler-content-open")) {
|
|
|
|
// Content was open, we are collapsing
|
|
|
|
arrow.removeClass("spoiler-button-open");
|
|
|
|
|
|
|
|
// Modify ARIA roles for screen readers
|
2020-06-17 21:57:12 +02:00
|
|
|
button.attr("aria-expanded", "false");
|
2020-04-04 22:14:34 +02:00
|
|
|
spoiler_content.attr("aria-hidden", "true");
|
|
|
|
|
|
|
|
collapse_spoiler(spoiler_content);
|
|
|
|
} else {
|
|
|
|
// Content was closed, we are expanding
|
|
|
|
arrow.addClass("spoiler-button-open");
|
|
|
|
|
|
|
|
// Modify ARIA roles for screen readers
|
2020-06-17 21:57:12 +02:00
|
|
|
button.attr("aria-expanded", "true");
|
2020-04-04 22:14:34 +02:00
|
|
|
spoiler_content.attr("aria-hidden", "false");
|
|
|
|
|
|
|
|
expand_spoiler(spoiler_content);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
window.spoilers = exports;
|