diff --git a/app/assets/javascripts/discourse/widgets/quick-access-item.js.es6 b/app/assets/javascripts/discourse/widgets/quick-access-item.js.es6
index a869484cc70..a37200e5956 100644
--- a/app/assets/javascripts/discourse/widgets/quick-access-item.js.es6
+++ b/app/assets/javascripts/discourse/widgets/quick-access-item.js.es6
@@ -3,7 +3,22 @@ import RawHtml from "discourse/widgets/raw-html";
import { createWidget } from "discourse/widgets/widget";
import { emojiUnescape } from "discourse/lib/text";
import { iconNode } from "discourse-common/lib/icon-library";
+import { escapeExpression } from "discourse/lib/utilities";
+/**
+ * This helper widget tries to enforce a consistent look and behavior for any
+ * item under any quick access panels.
+ *
+ * It accepts the following attributes:
+ * action
+ * actionParam
+ * content
+ * escapedContent
+ * href
+ * icon
+ * read
+ * username
+ */
createWidget("quick-access-item", {
tagName: "li",
@@ -18,13 +33,11 @@ createWidget("quick-access-item", {
return result;
},
- html({ icon, href, content }) {
+ html({ icon, href }) {
return h("a", { attributes: { href } }, [
iconNode(icon),
new RawHtml({
- html: `
${this._usernameHtml()}${emojiUnescape(
- Handlebars.Utils.escapeExpression(content)
- )}
`
+ html: `${this._usernameHtml()}${this._contentHtml()}
`
})
]);
},
@@ -37,6 +50,12 @@ createWidget("quick-access-item", {
}
},
+ _contentHtml() {
+ const content =
+ this.attrs.escapedContent || escapeExpression(this.attrs.content);
+ return emojiUnescape(content);
+ },
+
_usernameHtml() {
return this.attrs.username ? `${this.attrs.username} ` : "";
}
diff --git a/app/assets/javascripts/discourse/widgets/quick-access-messages.js.es6 b/app/assets/javascripts/discourse/widgets/quick-access-messages.js.es6
index 9988e649d7a..e8431bc3d27 100644
--- a/app/assets/javascripts/discourse/widgets/quick-access-messages.js.es6
+++ b/app/assets/javascripts/discourse/widgets/quick-access-messages.js.es6
@@ -12,7 +12,7 @@ function toItem(message) {
);
return {
- content: message.fancy_title,
+ escapedContent: message.fancy_title,
href: postUrl(message.slug, message.id, nextUnreadPostNumber),
icon: ICON,
read: message.last_read_post_number >= message.highest_post_number,
diff --git a/test/javascripts/widgets/quick-access-item-test.js.es6 b/test/javascripts/widgets/quick-access-item-test.js.es6
new file mode 100644
index 00000000000..19da5eff69f
--- /dev/null
+++ b/test/javascripts/widgets/quick-access-item-test.js.es6
@@ -0,0 +1,31 @@
+import { moduleForWidget, widgetTest } from "helpers/widget-test";
+
+moduleForWidget("quick-access-item");
+
+const CONTENT_DIV_SELECTOR = "li > a > div";
+
+widgetTest("content attribute is escaped", {
+ template: '{{mount-widget widget="quick-access-item" args=args}}',
+
+ beforeEach() {
+ this.set("args", { content: "bold" });
+ },
+
+ test(assert) {
+ const contentDiv = find(CONTENT_DIV_SELECTOR)[0];
+ assert.equal(contentDiv.innerText, "bold");
+ }
+});
+
+widgetTest("escapedContent attribute is not escaped", {
+ template: '{{mount-widget widget="quick-access-item" args=args}}',
+
+ beforeEach() {
+ this.set("args", { escapedContent: ""quote"" });
+ },
+
+ test(assert) {
+ const contentDiv = find(CONTENT_DIV_SELECTOR)[0];
+ assert.equal(contentDiv.innerText, '"quote"');
+ }
+});