FEATURE: Allow dismissing tooltips by clicking their button (#26668)

Also: fixes typos, updates tests, and moves the tooltip element into document.body
This commit is contained in:
Jarek Radosz 2024-04-18 13:16:55 +02:00 committed by GitHub
parent 285acf0b86
commit 27d9b53bac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 44 deletions

View File

@ -29,47 +29,49 @@ function applyInlineFootnotes(elem) {
}
function buildTooltip() {
let html = `
const template = document.createElement("template");
template.innerHTML = `
<div id="footnote-tooltip" role="tooltip">
<div class="footnote-tooltip-content"></div>
<div id="arrow" data-popper-arrow></div>
</div>
`;
`.trim();
let template = document.createElement("template");
html = html.trim();
template.innerHTML = html;
return template.content.firstChild;
}
function footNoteEventHandler(event) {
inlineFootnotePopper?.destroy();
function footnoteEventHandler(event) {
const tooltip = document.getElementById("footnote-tooltip");
const displayedFootnoteId = tooltip?.dataset.footnoteId;
const expandableFootnote = event.target;
const footnoteId = expandableFootnote.dataset.footnoteId;
// reset state by hidding tooltip, it handles "click outside"
// allowing to hide the tooltip when you click anywhere else
inlineFootnotePopper?.destroy();
tooltip?.removeAttribute("data-show");
tooltip?.removeAttribute("data-footnote-id");
// if we didn't actually click a footnote button, exit early
if (!event.target.classList.contains("expand-footnote")) {
// dismissing the tooltip by clicking outside
return;
}
event.preventDefault();
event.stopPropagation();
// append footnote to tooltip body
const expandableFootnote = event.target;
const cooked = expandableFootnote.closest(".cooked");
const footnoteId = expandableFootnote.dataset.footnoteId;
const footnoteContent = tooltip.querySelector(".footnote-tooltip-content");
let newContent = cooked.querySelector(footnoteId);
if (displayedFootnoteId === footnoteId) {
// dismissing the tooltip by clicking the footnote button
return;
}
// append footnote to tooltip body
const footnoteContent = tooltip.querySelector(".footnote-tooltip-content");
const cooked = expandableFootnote.closest(".cooked");
const newContent = cooked.querySelector(footnoteId);
footnoteContent.innerHTML = newContent.innerHTML;
// display tooltip
tooltip.dataset.show = "";
tooltip.dataset.footnoteId = footnoteId;
// setup popper
inlineFootnotePopper?.destroy();
@ -104,9 +106,8 @@ export default {
return;
}
document.documentElement.append(buildTooltip());
window.addEventListener("click", footNoteEventHandler);
document.body.append(buildTooltip());
window.addEventListener("click", footnoteEventHandler);
withPluginApi("0.8.9", (api) => {
api.decorateCookedElement((elem) => applyInlineFootnotes(elem), {
@ -115,16 +116,18 @@ export default {
});
api.onPageChange(() => {
document
.getElementById("footnote-tooltip")
?.removeAttribute("data-show");
inlineFootnotePopper?.destroy();
const tooltip = document.getElementById("footnote-tooltip");
tooltip?.removeAttribute("data-show");
tooltip?.removeAttribute("data-footnote-id");
});
});
},
teardown() {
inlineFootnotePopper?.destroy();
window.removeEventListener("click", footNoteEventHandler);
window.removeEventListener("click", footnoteEventHandler);
document.getElementById("footnote-tooltip")?.remove();
},
};

View File

@ -1,12 +1,10 @@
import { click, visit } from "@ember/test-helpers";
import { test } from "qunit";
import topicFixtures from "discourse/tests/fixtures/topic";
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
import { cloneJSON } from "discourse-common/lib/object";
acceptance("Discourse Foonote Plugin", function (needs) {
needs.user();
acceptance("Discourse Footnote Plugin", function (needs) {
needs.settings({
display_footnotes_inline: true,
});
@ -28,30 +26,47 @@ acceptance("Discourse Foonote Plugin", function (needs) {
});
});
test("displays the foonote on click", async function (assert) {
await visit("/t/45");
test("displays the footnote on click", async function (assert) {
await visit("/t/-/45");
const tooltip = document.getElementById("footnote-tooltip");
assert.ok(exists(tooltip));
assert.dom("#footnote-tooltip", document.body).exists();
// open
await click(".expand-footnote");
assert.equal(
tooltip.querySelector(".footnote-tooltip-content").textContent.trim(),
"consectetur adipiscing elit ↩︎"
);
assert
.dom(".footnote-tooltip-content", document.body)
.hasText("consectetur adipiscing elit ↩︎");
assert.dom("#footnote-tooltip", document.body).hasAttribute("data-show");
// close by clicking outside
await click(document.body);
assert
.dom("#footnote-tooltip", document.body)
.doesNotHaveAttribute("data-show");
// open again
await click(".expand-footnote");
assert
.dom(".footnote-tooltip-content", document.body)
.hasText("consectetur adipiscing elit ↩︎");
assert.dom("#footnote-tooltip", document.body).hasAttribute("data-show");
// close by clicking the button
await click(".expand-footnote");
assert
.dom("#footnote-tooltip", document.body)
.doesNotHaveAttribute("data-show");
});
test("clicking a second footnote with same name works", async function (assert) {
await visit("/t/45");
await visit("/t/-/45");
const tooltip = document.getElementById("footnote-tooltip");
assert.ok(exists(tooltip));
assert.dom("#footnote-tooltip", document.body).exists();
await click(".second .expand-footnote");
assert.equal(
tooltip.querySelector(".footnote-tooltip-content").textContent.trim(),
"consectetur adipiscing elit ↩︎"
);
assert
.dom(".footnote-tooltip-content", document.body)
.hasText("consectetur adipiscing elit ↩︎");
assert.dom("#footnote-tooltip", document.body).hasAttribute("data-show");
});
});