"use strict"; function collapse_spoiler(spoiler) { const spoiler_height = spoiler.height(); // Set height to rendered height on next frame, then to zero on following // frame to allow CSS transition animation to work requestAnimationFrame(() => { spoiler.height(spoiler_height + "px"); spoiler.removeClass("spoiler-content-open"); requestAnimationFrame(() => { 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", () => { 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.hide_spoilers_in_notification = (content) => { content.find(".spoiler-block").each((i, elem) => { $(elem).find(".spoiler-content").remove(); let text = $(elem).find(".spoiler-header").text().trim(); if (text.length > 0) { text = `${text} `; } text = `${text}(…)`; $(elem).find(".spoiler-header").text(text); }); return content; }; exports.initialize = function () { $("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 // return so that clicking such links will be be processed by // the browser rather than opening the header. if (target.closest("a").length > 0) { return; } // Allow selecting text inside a spoiler header. if (document.getSelection().type === "Range") { return; } 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 button.attr("aria-expanded", "false"); 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 button.attr("aria-expanded", "true"); spoiler_content.attr("aria-hidden", "false"); expand_spoiler(spoiler_content); } }); }; window.spoilers = exports;