mirror of
https://github.com/discourse/discourse.git
synced 2025-02-17 06:52:53 +08:00
FEATURE: allows html tooltips (#6665)
This commit is contained in:
parent
e47b478b83
commit
3453707784
|
@ -3,10 +3,13 @@ import { escapeExpression } from "discourse/lib/utilities";
|
|||
const fadeSpeed = 300;
|
||||
const tooltipID = "#discourse-tooltip";
|
||||
|
||||
export function showTooltip() {
|
||||
const $this = $(this);
|
||||
export function showTooltip($this) {
|
||||
const $parent = $this.offsetParent();
|
||||
const content = escapeExpression($this.attr("data-tooltip"));
|
||||
// html tooltip are risky try your best to sanitize anything
|
||||
// displayed as html to avoid XSS attacks
|
||||
const content = $this.attr("data-tooltip")
|
||||
? escapeExpression($this.attr("data-tooltip"))
|
||||
: $this.attr("data-html-tooltip") || "";
|
||||
const retina =
|
||||
window.devicePixelRatio && window.devicePixelRatio > 1
|
||||
? "class='retina'"
|
||||
|
@ -19,7 +22,7 @@ export function showTooltip() {
|
|||
|
||||
hideTooltip(tooltipID);
|
||||
|
||||
$(this).after(`
|
||||
$this.after(`
|
||||
<div id="discourse-tooltip" ${retina}>
|
||||
<div class="tooltip-pointer"></div>
|
||||
<div class="tooltip-content">${content}</div>
|
||||
|
@ -74,7 +77,9 @@ export function hideTooltip() {
|
|||
|
||||
export function registerTooltip(jqueryContext) {
|
||||
if (jqueryContext.length) {
|
||||
jqueryContext.off("click").on("click", showTooltip);
|
||||
jqueryContext
|
||||
.off("click")
|
||||
.on("click", event => showTooltip($(event.currentTarget)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,22 +4,56 @@ import { registerTooltip } from "discourse/lib/tooltip";
|
|||
QUnit.module("lib:tooltip", {
|
||||
beforeEach() {
|
||||
fixture().html(
|
||||
"<a class='test-link' data-tooltip='XSS<s onmouseover\=alert(document.domain)>XSS'>test</a>"
|
||||
`
|
||||
<a class='test-text-link' data-tooltip='XSS<s onmouseover\=alert(document.domain)>XSS'>test</a>
|
||||
<a class='test-html-link' data-html-tooltip='<p>test</p>'>test</a>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("it prevents XSS injection", assert => {
|
||||
const $testLink = fixture(".test-link");
|
||||
registerTooltip($testLink);
|
||||
$testLink.click();
|
||||
QUnit.test("text support", async assert => {
|
||||
const $testTextLink = fixture(".test-text-link");
|
||||
registerTooltip($testTextLink);
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(
|
||||
fixture(".tooltip-content")
|
||||
.html()
|
||||
.trim(),
|
||||
"XSS<s onmouseover=alert(document.domain)>XSS"
|
||||
);
|
||||
});
|
||||
await $testTextLink.click();
|
||||
|
||||
assert.equal(
|
||||
fixture(".tooltip-content")
|
||||
.html()
|
||||
.trim(),
|
||||
"XSS<s onmouseover=alert(document.domain)>XSS",
|
||||
"it prevents XSS injection"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
fixture(".tooltip-content")
|
||||
.text()
|
||||
.trim(),
|
||||
"XSS<s onmouseover=alert(document.domain)>XSS",
|
||||
"it returns content as plain text"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("html support", async assert => {
|
||||
const $testHtmlLink = fixture(".test-html-link");
|
||||
registerTooltip($testHtmlLink);
|
||||
|
||||
await $testHtmlLink.click();
|
||||
|
||||
assert.equal(
|
||||
fixture(".tooltip-content")
|
||||
.html()
|
||||
.trim(),
|
||||
"<p>test</p>",
|
||||
"it doesn’t escape HTML"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
fixture(".tooltip-content")
|
||||
.text()
|
||||
.trim(),
|
||||
"test",
|
||||
"it returns content as plain text"
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user