mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FIX: Which topic do you want to reply to rendering raw HTML (#30962)
Because of
2b63830496
`Which topic do you want to reply to rendering HTML` was rendering raw
HTML.
Added `htmlSafe` for now.
I'll work on testing for this feature.
This commit is contained in:
parent
1b9e2ff4f9
commit
e78c937a5c
@ -0,0 +1,76 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { eq } from "truth-helpers";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { categoryLinkHTML } from "discourse/helpers/category-link";
|
||||||
|
import dIcon from "discourse/helpers/d-icon";
|
||||||
|
import discourseTags from "discourse/helpers/discourse-tags";
|
||||||
|
|
||||||
|
const TopicLabelButton = <template>
|
||||||
|
<DButton class={{@class}} @action={{@action}}>
|
||||||
|
<div class="topic-title">
|
||||||
|
<div class="topic-title__top-line">
|
||||||
|
<span class="topic-statuses">
|
||||||
|
{{#if (eq @topic.archetype "private_message")}}
|
||||||
|
<span class="topic-status">
|
||||||
|
{{dIcon "envelope"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @topic.bookmarked}}
|
||||||
|
<span class="topic-status">
|
||||||
|
{{dIcon "bookmark"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @topic.closed}}
|
||||||
|
<span class="topic-status">
|
||||||
|
{{dIcon "lock"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @topic.pinned}}
|
||||||
|
<span class="topic-status">
|
||||||
|
{{dIcon "thumbtack"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<span class="fancy-title">
|
||||||
|
{{@topic.title}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="topic-title__bottom-line">
|
||||||
|
{{categoryLinkHTML @topic (hash link=false)}}
|
||||||
|
{{discourseTags @topic}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DButton>
|
||||||
|
</template>;
|
||||||
|
|
||||||
|
export default class TopicLabelContent extends Component {
|
||||||
|
@action
|
||||||
|
replyOnOriginal() {
|
||||||
|
this.args.model.replyOnOriginal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
replyOnCurrent() {
|
||||||
|
this.args.model.replyOnCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TopicLabelButton
|
||||||
|
@class="btn-primary btn-reply-where btn-reply-on-original"
|
||||||
|
@action={{this.replyOnOriginal}}
|
||||||
|
@topic={{@model.originalTopic}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TopicLabelButton
|
||||||
|
@class="btn-reply-where btn-reply-here"
|
||||||
|
@action={{this.replyOnCurrent}}
|
||||||
|
@topic={{@model.currentTopic}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -2,7 +2,6 @@ import EmberObject, { action, computed } from "@ember/object";
|
|||||||
import { alias, and, or, reads } from "@ember/object/computed";
|
import { alias, and, or, reads } from "@ember/object/computed";
|
||||||
import { cancel, scheduleOnce } from "@ember/runloop";
|
import { cancel, scheduleOnce } from "@ember/runloop";
|
||||||
import Service, { service } from "@ember/service";
|
import Service, { service } from "@ember/service";
|
||||||
import { htmlSafe } from "@ember/template";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { observes, on } from "@ember-decorators/object";
|
import { observes, on } from "@ember-decorators/object";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
@ -10,7 +9,7 @@ import { Promise } from "rsvp";
|
|||||||
import DiscardDraftModal from "discourse/components/modal/discard-draft";
|
import DiscardDraftModal from "discourse/components/modal/discard-draft";
|
||||||
import PostEnqueuedModal from "discourse/components/modal/post-enqueued";
|
import PostEnqueuedModal from "discourse/components/modal/post-enqueued";
|
||||||
import SpreadsheetEditor from "discourse/components/modal/spreadsheet-editor";
|
import SpreadsheetEditor from "discourse/components/modal/spreadsheet-editor";
|
||||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
import TopicLabelContent from "discourse/components/topic-label-content";
|
||||||
import {
|
import {
|
||||||
cannotPostAgain,
|
cannotPostAgain,
|
||||||
durationTextFromSeconds,
|
durationTextFromSeconds,
|
||||||
@ -26,11 +25,9 @@ import prepareFormTemplateData, {
|
|||||||
import { shortDate } from "discourse/lib/formatter";
|
import { shortDate } from "discourse/lib/formatter";
|
||||||
import { getOwnerWithFallback } from "discourse/lib/get-owner";
|
import { getOwnerWithFallback } from "discourse/lib/get-owner";
|
||||||
import getURL from "discourse/lib/get-url";
|
import getURL from "discourse/lib/get-url";
|
||||||
import { iconHTML } from "discourse/lib/icon-library";
|
|
||||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||||
import { buildQuote } from "discourse/lib/quote";
|
import { buildQuote } from "discourse/lib/quote";
|
||||||
import renderTags from "discourse/lib/render-tags";
|
|
||||||
import { emojiUnescape } from "discourse/lib/text";
|
import { emojiUnescape } from "discourse/lib/text";
|
||||||
import {
|
import {
|
||||||
authorizesOneOrMoreExtensions,
|
authorizesOneOrMoreExtensions,
|
||||||
@ -1092,58 +1089,27 @@ export default class ComposerService extends Service {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const topicLabelContent = function (topicOption) {
|
|
||||||
const topicClosed = topicOption.closed
|
|
||||||
? `<span class="topic-status">${iconHTML("lock")}</span>`
|
|
||||||
: "";
|
|
||||||
const topicPinned = topicOption.pinned
|
|
||||||
? `<span class="topic-status">${iconHTML("thumbtack")}</span>`
|
|
||||||
: "";
|
|
||||||
const topicBookmarked = topicOption.bookmarked
|
|
||||||
? `<span class="topic-status">${iconHTML("bookmark")}</span>`
|
|
||||||
: "";
|
|
||||||
const topicPM =
|
|
||||||
topicOption.archetype === "private_message"
|
|
||||||
? `<span class="topic-status">${iconHTML("envelope")}</span>`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return `<div class="topic-title">
|
|
||||||
<div class="topic-title__top-line">
|
|
||||||
<span class="topic-statuses">
|
|
||||||
${topicPM}${topicBookmarked}${topicClosed}${topicPinned}
|
|
||||||
</span>
|
|
||||||
<span class="fancy-title">
|
|
||||||
${topicOption.fancyTitle}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="topic-title__bottom-line">
|
|
||||||
${categoryBadgeHTML(topicOption.category, {
|
|
||||||
link: false,
|
|
||||||
})}${htmlSafe(renderTags(topicOption))}
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currentTopic.id !== composer.get("topic.id") &&
|
currentTopic.id !== composer.get("topic.id") &&
|
||||||
(this.isStaffUser || !currentTopic.closed)
|
(this.isStaffUser || !currentTopic.closed)
|
||||||
) {
|
) {
|
||||||
this.dialog.alert({
|
this.dialog.alert({
|
||||||
title: i18n("composer.posting_not_on_topic"),
|
title: i18n("composer.posting_not_on_topic"),
|
||||||
|
bodyComponent: TopicLabelContent,
|
||||||
|
bodyComponentModel: {
|
||||||
|
originalTopic,
|
||||||
|
replyOnOriginal: () => {
|
||||||
|
this.save(true);
|
||||||
|
this.dialog.didConfirmWrapped();
|
||||||
|
},
|
||||||
|
currentTopic,
|
||||||
|
replyOnCurrent: () => {
|
||||||
|
composer.setProperties({ topic: currentTopic, post: null });
|
||||||
|
this.save(true);
|
||||||
|
this.dialog.didConfirmWrapped();
|
||||||
|
},
|
||||||
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
|
||||||
label: topicLabelContent(originalTopic),
|
|
||||||
class: "btn-primary btn-reply-where btn-reply-on-original",
|
|
||||||
action: () => this.save(true),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: topicLabelContent(currentTopic),
|
|
||||||
class: "btn-reply-where btn-reply-here",
|
|
||||||
action: () => {
|
|
||||||
composer.setProperties({ topic: currentTopic, post: null });
|
|
||||||
this.save(true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: i18n("composer.cancel"),
|
label: i18n("composer.cancel"),
|
||||||
class: "btn-flat btn-text btn-reply-where__cancel",
|
class: "btn-flat btn-text btn-reply-where__cancel",
|
||||||
|
@ -406,6 +406,8 @@ acceptance("Composer", function (needs) {
|
|||||||
await click("#reply-control button.create");
|
await click("#reply-control button.create");
|
||||||
assert.dom(".reply-where-modal").exists("pops up a modal");
|
assert.dom(".reply-where-modal").exists("pops up a modal");
|
||||||
|
|
||||||
|
assert.dom(".topic-title").exists({ count: 2 }); // modal buttons
|
||||||
|
|
||||||
await click(".btn-reply-here");
|
await click(".btn-reply-here");
|
||||||
assert
|
assert
|
||||||
.dom(".topic-post:last-of-type .cooked p")
|
.dom(".topic-post:last-of-type .cooked p")
|
||||||
|
Loading…
Reference in New Issue
Block a user