mirror of
https://github.com/discourse/discourse.git
synced 2026-08-09 21:45:25 +08:00
`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
116 lines
2.9 KiB
JavaScript
Vendored
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();
|
|
}
|
|
});
|
|
});
|