DEV: Add compatibility with the Glimmer Post Stream
This commit is contained in:
parent
ae01ad30c3
commit
200acada1b
|
@ -0,0 +1,96 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import { iconHTML } from "discourse/lib/icon-library";
|
||||||
|
import { formatUsername } from "discourse/lib/utilities";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
export default class SolvedAcceptedAnswer extends Component {
|
||||||
|
@service siteSettings;
|
||||||
|
@service store;
|
||||||
|
|
||||||
|
get topic() {
|
||||||
|
return this.args.post.topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasExcerpt() {
|
||||||
|
return !!this.topic.accepted_answer.excerpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
get htmlAccepter() {
|
||||||
|
const username = this.topic.accepted_answer.accepter_username;
|
||||||
|
const name = this.topic.accepted_answer.accepter_name;
|
||||||
|
|
||||||
|
if (!this.siteSettings.show_who_marked_solved) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formattedUsername =
|
||||||
|
this.siteSettings.display_name_on_posts && name
|
||||||
|
? name
|
||||||
|
: formatUsername(username);
|
||||||
|
|
||||||
|
return htmlSafe(
|
||||||
|
i18n("solved.marked_solved_by", {
|
||||||
|
username: formattedUsername,
|
||||||
|
username_lower: username.toLowerCase(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get htmlExcerpt() {
|
||||||
|
return htmlSafe(this.topic.accepted_answer.excerpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
get htmlSolvedBy() {
|
||||||
|
const username = this.topic.accepted_answer.username;
|
||||||
|
const name = this.topic.accepted_answer.name;
|
||||||
|
const postNumber = this.topic.accepted_answer.post_number;
|
||||||
|
|
||||||
|
if (!username || !postNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayedUser =
|
||||||
|
this.siteSettings.display_name_on_posts && name
|
||||||
|
? name
|
||||||
|
: formatUsername(username);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
icon: iconHTML("square-check", { class: "accepted" }),
|
||||||
|
username_lower: username.toLowerCase(),
|
||||||
|
username: displayedUser,
|
||||||
|
post_path: `${this.topic.url}/${postNumber}`,
|
||||||
|
post_number: postNumber,
|
||||||
|
user_path: this.store.createRecord("user", { username }).path,
|
||||||
|
};
|
||||||
|
|
||||||
|
return htmlSafe(i18n("solved.accepted_html", data));
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<aside
|
||||||
|
class="quote accepted-answer"
|
||||||
|
data-post={{this.topic.accepted_answer.post_number}}
|
||||||
|
data-topic={{this.topic.id}}
|
||||||
|
>
|
||||||
|
<div class={{concatClass "title" (if this.hasExcerpt "title-only")}}>
|
||||||
|
<div class="accepted-answer--solver-accepter">
|
||||||
|
<div class="accepted-answer--solver">
|
||||||
|
{{this.htmlSolvedBy}}
|
||||||
|
</div>
|
||||||
|
<div class="accepted-answer--accepter">
|
||||||
|
{{this.htmlAccepter}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="quote-controls"></div>
|
||||||
|
</div>
|
||||||
|
{{#if this.hasExcerpt}}
|
||||||
|
<blockquote>
|
||||||
|
{{this.htmlExcerpt}}
|
||||||
|
</blockquote>
|
||||||
|
{{/if}}
|
||||||
|
</aside>
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { withSilencedDeprecations } from "discourse/lib/deprecated";
|
||||||
|
import { iconHTML } from "discourse/lib/icon-library";
|
||||||
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
import { formatUsername } from "discourse/lib/utilities";
|
||||||
|
import Topic from "discourse/models/topic";
|
||||||
|
import User from "discourse/models/user";
|
||||||
|
import PostCooked from "discourse/widgets/post-cooked";
|
||||||
|
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import SolvedAcceptAnswerButton from "../components/solved-accept-answer-button";
|
||||||
|
import SolvedAcceptedAnswer from "../components/solved-accepted-answer";
|
||||||
|
import SolvedUnacceptAnswerButton from "../components/solved-unaccept-answer-button";
|
||||||
|
|
||||||
|
function initializeWithApi(api) {
|
||||||
|
customizePost(api);
|
||||||
|
customizePostMenu(api);
|
||||||
|
|
||||||
|
if (api.addDiscoveryQueryParam) {
|
||||||
|
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizePost(api) {
|
||||||
|
api.addTrackedPostProperties(
|
||||||
|
"can_accept_answer",
|
||||||
|
"can_unaccept_answer",
|
||||||
|
"accepted_answer",
|
||||||
|
"topic_accepted_answer"
|
||||||
|
);
|
||||||
|
|
||||||
|
api.renderAfterWrapperOutlet(
|
||||||
|
"post-content-cooked-html",
|
||||||
|
class extends Component {
|
||||||
|
static shouldRender(args) {
|
||||||
|
return args.post.post_number === 1 && args.post.topic.accepted_answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template><SolvedAcceptedAnswer @post={{@outletArgs.post}} /></template>
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
withSilencedDeprecations("discourse.post-stream-widget-overrides", () =>
|
||||||
|
customizeWidgetPost(api)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizeWidgetPost(api) {
|
||||||
|
api.decorateWidget("post-contents:after-cooked", (helper) => {
|
||||||
|
let post = helper.getModel();
|
||||||
|
|
||||||
|
if (helper.attrs.post_number === 1 && post?.topic?.accepted_answer) {
|
||||||
|
return new RenderGlimmer(
|
||||||
|
helper.widget,
|
||||||
|
"div",
|
||||||
|
<template><SolvedAcceptedAnswer @post={{@data.post}} /></template>,
|
||||||
|
{ post }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizePostMenu(api) {
|
||||||
|
api.registerValueTransformer(
|
||||||
|
"post-menu-buttons",
|
||||||
|
({
|
||||||
|
value: dag,
|
||||||
|
context: {
|
||||||
|
post,
|
||||||
|
firstButtonKey,
|
||||||
|
secondLastHiddenButtonKey,
|
||||||
|
lastHiddenButtonKey,
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
let solvedButton;
|
||||||
|
|
||||||
|
if (post.can_accept_answer) {
|
||||||
|
solvedButton = SolvedAcceptAnswerButton;
|
||||||
|
} else if (post.accepted_answer) {
|
||||||
|
solvedButton = SolvedUnacceptAnswerButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
solvedButton &&
|
||||||
|
dag.add(
|
||||||
|
"solved",
|
||||||
|
solvedButton,
|
||||||
|
post.topic_accepted_answer && !post.accepted_answer
|
||||||
|
? {
|
||||||
|
before: lastHiddenButtonKey,
|
||||||
|
after: secondLastHiddenButtonKey,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
before: [
|
||||||
|
"assign", // button added by the assign plugin
|
||||||
|
firstButtonKey,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "extend-for-solved-button",
|
||||||
|
initialize() {
|
||||||
|
withPluginApi("1.34.0", initializeWithApi);
|
||||||
|
|
||||||
|
withPluginApi("0.8.10", (api) => {
|
||||||
|
api.replaceIcon(
|
||||||
|
"notification.solved.accepted_notification",
|
||||||
|
"square-check"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
withPluginApi("0.11.0", (api) => {
|
||||||
|
api.addAdvancedSearchOptions({
|
||||||
|
statusOptions: [
|
||||||
|
{
|
||||||
|
name: i18n("search.advanced.statuses.solved"),
|
||||||
|
value: "solved",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n("search.advanced.statuses.unsolved"),
|
||||||
|
value: "unsolved",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
withPluginApi("0.11.7", (api) => {
|
||||||
|
api.addSearchSuggestion("status:solved");
|
||||||
|
api.addSearchSuggestion("status:unsolved");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,186 +0,0 @@
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import { iconHTML } from "discourse/lib/icon-library";
|
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
|
||||||
import { formatUsername } from "discourse/lib/utilities";
|
|
||||||
import Topic from "discourse/models/topic";
|
|
||||||
import User from "discourse/models/user";
|
|
||||||
import PostCooked from "discourse/widgets/post-cooked";
|
|
||||||
import { i18n } from "discourse-i18n";
|
|
||||||
import SolvedAcceptAnswerButton, {
|
|
||||||
acceptAnswer,
|
|
||||||
} from "../components/solved-accept-answer-button";
|
|
||||||
import SolvedUnacceptAnswerButton, {
|
|
||||||
unacceptAnswer,
|
|
||||||
} from "../components/solved-unaccept-answer-button";
|
|
||||||
|
|
||||||
function initializeWithApi(api) {
|
|
||||||
customizePostMenu(api);
|
|
||||||
|
|
||||||
api.includePostAttributes(
|
|
||||||
"can_accept_answer",
|
|
||||||
"can_unaccept_answer",
|
|
||||||
"accepted_answer",
|
|
||||||
"topic_accepted_answer"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (api.addDiscoveryQueryParam) {
|
|
||||||
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
api.decorateWidget("post-contents:after-cooked", (dec) => {
|
|
||||||
if (dec.attrs.post_number === 1) {
|
|
||||||
const postModel = dec.getModel();
|
|
||||||
if (postModel) {
|
|
||||||
const topic = postModel.topic;
|
|
||||||
if (topic.accepted_answer) {
|
|
||||||
const hasExcerpt = !!topic.accepted_answer.excerpt;
|
|
||||||
const excerpt = hasExcerpt
|
|
||||||
? ` <blockquote> ${topic.accepted_answer.excerpt} </blockquote> `
|
|
||||||
: "";
|
|
||||||
const solvedQuote = `
|
|
||||||
<aside class='quote accepted-answer' data-post="${topic.get("accepted_answer").post_number}" data-topic="${topic.id}">
|
|
||||||
<div class='title ${hasExcerpt ? "" : "title-only"}'>
|
|
||||||
<div class="accepted-answer--solver-accepter">
|
|
||||||
<div class="accepted-answer--solver">
|
|
||||||
${topic.solvedByHtml}
|
|
||||||
<\/div>
|
|
||||||
<div class="accepted-answer--accepter">
|
|
||||||
${topic.accepterHtml}
|
|
||||||
<\/div>
|
|
||||||
</div>
|
|
||||||
<div class="quote-controls"><\/div>
|
|
||||||
</div>
|
|
||||||
${excerpt}
|
|
||||||
</aside>`;
|
|
||||||
|
|
||||||
const cooked = new PostCooked({ cooked: solvedQuote }, dec);
|
|
||||||
return dec.rawHtml(cooked.init());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
api.attachWidgetAction("post", "acceptAnswer", function () {
|
|
||||||
acceptAnswer(this.model, this.appEvents, this.currentUser);
|
|
||||||
});
|
|
||||||
|
|
||||||
api.attachWidgetAction("post", "unacceptAnswer", function () {
|
|
||||||
unacceptAnswer(this.model, this.appEvents);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function customizePostMenu(api) {
|
|
||||||
api.registerValueTransformer(
|
|
||||||
"post-menu-buttons",
|
|
||||||
({
|
|
||||||
value: dag,
|
|
||||||
context: {
|
|
||||||
post,
|
|
||||||
firstButtonKey,
|
|
||||||
secondLastHiddenButtonKey,
|
|
||||||
lastHiddenButtonKey,
|
|
||||||
},
|
|
||||||
}) => {
|
|
||||||
let solvedButton;
|
|
||||||
|
|
||||||
if (post.can_accept_answer) {
|
|
||||||
solvedButton = SolvedAcceptAnswerButton;
|
|
||||||
} else if (post.accepted_answer) {
|
|
||||||
solvedButton = SolvedUnacceptAnswerButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
solvedButton &&
|
|
||||||
dag.add(
|
|
||||||
"solved",
|
|
||||||
solvedButton,
|
|
||||||
post.topic_accepted_answer && !post.accepted_answer
|
|
||||||
? {
|
|
||||||
before: lastHiddenButtonKey,
|
|
||||||
after: secondLastHiddenButtonKey,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
before: [
|
|
||||||
"assign", // button added by the assign plugin
|
|
||||||
firstButtonKey,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "extend-for-solved-button",
|
|
||||||
initialize() {
|
|
||||||
Topic.reopen({
|
|
||||||
// keeping this here cause there is complex localization
|
|
||||||
solvedByHtml: computed("accepted_answer", "id", function () {
|
|
||||||
const username = this.get("accepted_answer.username");
|
|
||||||
const name = this.get("accepted_answer.name");
|
|
||||||
const postNumber = this.get("accepted_answer.post_number");
|
|
||||||
|
|
||||||
if (!username || !postNumber) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayedUser =
|
|
||||||
this.siteSettings.display_name_on_posts && name
|
|
||||||
? name
|
|
||||||
: formatUsername(username);
|
|
||||||
|
|
||||||
return i18n("solved.accepted_html", {
|
|
||||||
icon: iconHTML("square-check", { class: "accepted" }),
|
|
||||||
username_lower: username.toLowerCase(),
|
|
||||||
username: displayedUser,
|
|
||||||
post_path: `${this.url}/${postNumber}`,
|
|
||||||
post_number: postNumber,
|
|
||||||
user_path: User.create({ username }).path,
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
accepterHtml: computed("accepted_answer", function () {
|
|
||||||
const username = this.get("accepted_answer.accepter_username");
|
|
||||||
const name = this.get("accepted_answer.accepter_name");
|
|
||||||
if (!this.siteSettings.show_who_marked_solved) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const formattedUsername =
|
|
||||||
this.siteSettings.display_name_on_posts && name
|
|
||||||
? name
|
|
||||||
: formatUsername(username);
|
|
||||||
return i18n("solved.marked_solved_by", {
|
|
||||||
username: formattedUsername,
|
|
||||||
username_lower: username.toLowerCase(),
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
withPluginApi("1.34.0", initializeWithApi);
|
|
||||||
|
|
||||||
withPluginApi("0.8.10", (api) => {
|
|
||||||
api.replaceIcon(
|
|
||||||
"notification.solved.accepted_notification",
|
|
||||||
"square-check"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
withPluginApi("0.11.0", (api) => {
|
|
||||||
api.addAdvancedSearchOptions({
|
|
||||||
statusOptions: [
|
|
||||||
{
|
|
||||||
name: i18n("search.advanced.statuses.solved"),
|
|
||||||
value: "solved",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18n("search.advanced.statuses.unsolved"),
|
|
||||||
value: "unsolved",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
withPluginApi("0.11.7", (api) => {
|
|
||||||
api.addSearchSuggestion("status:solved");
|
|
||||||
api.addSearchSuggestion("status:unsolved");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
Loading…
Reference in New Issue