0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-09 21:45:25 +08:00
discourse/plugins/spoiler-alert/test/javascripts/unit/lib/apply-spoiler-test.js
Bannon Tanner 65d162b350
FIX: Allow re-blur on spoiler when in details view (#41266)
`INTERACTIVE_SELECTOR` includes "details" so that clicking a `<details>`
inside a spoiler expands it without also re-blurring the surrounding
spoiler. But because `closest()` walks up the DOM tree, every click
inside a `[spoiler]` that happens to be nested inside a `[details]` also
matches `closest("details")` against the parent `<details>` — making
such a spoiler impossible to re-blur once revealed.

Fix: scope the `closest()` result with `element.contains(...)` so only
interactive ancestors that live inside the spoiler block re-blurring.
Interactive ancestors above the spoiler are ignored.

Tests cover both directions: a spoiler-inside-details can re-blur, and
clicking an interactive descendant of a revealed spoiler still does not
re-blur it.

Context:
https://meta.discourse.org/t/spoilers-don-t-toggle-when-inside-details/194499
2026-06-29 12:47:49 -05:00

116 lines
2.9 KiB
JavaScript
Vendored

import { setupTest } from "ember-qunit";
import { module, test } from "qunit";
import applySpoiler from "discourse/plugins/spoiler-alert/lib/apply-spoiler";
module("Spoiler Alert | Unit | apply-spoiler", function (hooks) {
setupTest(hooks);
function buildSpoiler() {
const spoiler = document.createElement("div");
spoiler.classList.add("spoiler");
spoiler.textContent = "secret";
return spoiler;
}
test("toggles between blurred and revealed on successive clicks", function (assert) {
const spoiler = buildSpoiler();
document.body.appendChild(spoiler);
try {
applySpoiler(spoiler);
assert
.dom(spoiler)
.hasAttribute("data-spoiler-state", "blurred", "starts blurred");
spoiler.click();
assert
.dom(spoiler)
.hasAttribute("data-spoiler-state", "revealed", "reveals on click");
spoiler.click();
assert
.dom(spoiler)
.hasAttribute(
"data-spoiler-state",
"blurred",
"re-blurs on second click"
);
} finally {
spoiler.remove();
}
});
test("can be re-blurred when nested inside a <details> element", function (assert) {
const details = document.createElement("details");
details.open = true;
const summary = document.createElement("summary");
summary.textContent = "Summary";
details.appendChild(summary);
const spoiler = buildSpoiler();
details.appendChild(spoiler);
document.body.appendChild(details);
try {
applySpoiler(spoiler);
assert
.dom(spoiler)
.hasAttribute("data-spoiler-state", "blurred", "starts blurred");
spoiler.click();
assert
.dom(spoiler)
.hasAttribute(
"data-spoiler-state",
"revealed",
"reveals on first click"
);
spoiler.click();
assert
.dom(spoiler)
.hasAttribute(
"data-spoiler-state",
"blurred",
"re-blurs on second click even though an ancestor <details> exists"
);
} finally {
details.remove();
}
});
test("clicking an interactive descendant does not re-blur the spoiler", function (assert) {
const spoiler = buildSpoiler();
spoiler.textContent = "";
const link = document.createElement("a");
link.href = "#";
link.textContent = "a link";
link.addEventListener("click", (event) => event.preventDefault());
spoiler.appendChild(link);
document.body.appendChild(spoiler);
try {
applySpoiler(spoiler);
spoiler.click();
assert
.dom(spoiler)
.hasAttribute(
"data-spoiler-state",
"revealed",
"reveals on first click"
);
link.click();
assert
.dom(spoiler)
.hasAttribute(
"data-spoiler-state",
"revealed",
"clicking an interactive descendant does not re-blur the spoiler"
);
} finally {
spoiler.remove();
}
});
});