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

View File

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