Files
zulip/static/js/spoilers.js
Anders Kaseorg 6ec808b8df js: Add "use strict" directive to CommonJS files.
ES and TypeScript modules are strict by default and don’t need this
directive.  ESLint will remind us to add it to new CommonJS files and
remove it from ES and TypeScript modules.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2020-07-31 22:09:46 -07:00

96 lines
3.3 KiB
JavaScript

"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;