mirror of
https://github.com/discourse/discourse.git
synced 2025-04-26 16:44:27 +08:00
DEV: Refactor PostList cooked HTML rendering (#31307)
- Remove JQuery - Move decoration into `components/post-item`, instead of managing it from the top-level user-stream component - Use new `DecoratedHtml` component
This commit is contained in:
parent
b471e3d5ba
commit
35084d3089
@ -2,18 +2,22 @@ import Component from "@glimmer/component";
|
||||
import { fn } from "@ember/helper";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { or } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DecoratedHtml from "discourse/components/decorated-html";
|
||||
import ExpandPost from "discourse/components/expand-post";
|
||||
import PostListItemDetails from "discourse/components/post-list/item/details";
|
||||
import avatar from "discourse/helpers/avatar";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
|
||||
export default class PostListItem extends Component {
|
||||
@service site;
|
||||
@service siteSettings;
|
||||
@service currentUser;
|
||||
@service appEvents;
|
||||
|
||||
get moderatorActionClass() {
|
||||
return this.args.post.post_type === this.site.post_types.moderator_action
|
||||
@ -70,6 +74,15 @@ export default class PostListItem extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@bind
|
||||
decoratePostContent(element, helper) {
|
||||
this.appEvents.trigger(
|
||||
"decorate-non-stream-cooked-element",
|
||||
element,
|
||||
helper
|
||||
);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="post-list-item
|
||||
@ -147,11 +160,11 @@ export default class PostListItem extends Component {
|
||||
data-user-id={{@post.user_id}}
|
||||
class="excerpt"
|
||||
>
|
||||
{{#if @post.expandedExcerpt}}
|
||||
{{~htmlSafe @post.expandedExcerpt~}}
|
||||
{{else}}
|
||||
{{~htmlSafe @post.excerpt~}}
|
||||
{{/if}}
|
||||
<DecoratedHtml
|
||||
@html={{htmlSafe (or @post.expandedExcerpt @post.excerpt)}}
|
||||
@decorate={{this.decoratePostContent}}
|
||||
@className="cooked"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{{yield to="belowPostItem"}}
|
||||
|
@ -1,12 +1,9 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { hash } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { getOwner } from "@ember/owner";
|
||||
import { later } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { modifier } from "ember-modifier";
|
||||
import $ from "jquery";
|
||||
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||
import PostActionDescription from "discourse/components/post-action-description";
|
||||
import PostList from "discourse/components/post-list";
|
||||
@ -26,28 +23,6 @@ export default class UserStreamComponent extends Component {
|
||||
@service appEvents;
|
||||
@service currentUser;
|
||||
@service router;
|
||||
@tracked lastDecoratedElement;
|
||||
|
||||
eventListeners = modifier((element) => {
|
||||
$(element).on("click.details-disabled", "details.disabled", () => false);
|
||||
$(element).on("click.discourse-redirect", ".excerpt a", (e) => {
|
||||
return ClickTrack.trackClick(e, getOwner(this));
|
||||
});
|
||||
later(() => {
|
||||
this.updateLastDecoratedElement();
|
||||
this.appEvents.trigger("decorate-non-stream-cooked-element", element);
|
||||
});
|
||||
|
||||
return () => {
|
||||
$(element).off("click.details-disabled", "details.disabled");
|
||||
// Unbind link tracking
|
||||
$(element).off("click.discourse-redirect", ".excerpt a");
|
||||
};
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
}
|
||||
|
||||
get filterClassName() {
|
||||
const filter = this.args.stream?.filter;
|
||||
@ -68,20 +43,6 @@ export default class UserStreamComponent extends Component {
|
||||
return "username";
|
||||
}
|
||||
|
||||
@action
|
||||
updateLastDecoratedElement() {
|
||||
const nodes = document.querySelectorAll(".user-stream-item");
|
||||
if (!nodes || nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastElement = nodes[nodes.length - 1];
|
||||
if (lastElement === this.lastDecoratedElement) {
|
||||
return;
|
||||
}
|
||||
this.lastDecoratedElement = lastElement;
|
||||
}
|
||||
|
||||
@action
|
||||
async removeBookmark(userAction) {
|
||||
try {
|
||||
@ -140,19 +101,21 @@ export default class UserStreamComponent extends Component {
|
||||
return [];
|
||||
}
|
||||
|
||||
later(() => {
|
||||
let element = this.lastDecoratedElement?.nextElementSibling;
|
||||
while (element) {
|
||||
this.appEvents.trigger("user-stream:new-item-inserted", element);
|
||||
this.appEvents.trigger("decorate-non-stream-cooked-element", element);
|
||||
element = element.nextElementSibling;
|
||||
}
|
||||
this.updateLastDecoratedElement();
|
||||
});
|
||||
|
||||
return this.args.stream.content;
|
||||
}
|
||||
|
||||
@action
|
||||
handleClick(event) {
|
||||
if (event.target.matches("details.disabled")) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.matches(".excerpt a")) {
|
||||
return ClickTrack.trackClick(event, getOwner(this));
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
<PostList
|
||||
@posts={{@stream.content}}
|
||||
@ -166,7 +129,7 @@ export default class UserStreamComponent extends Component {
|
||||
@resumeDraft={{this.resumeDraft}}
|
||||
@removeDraft={{this.removeDraft}}
|
||||
class={{concatClass "user-stream" this.filterClassName}}
|
||||
{{this.eventListeners @stream}}
|
||||
{{on "click" this.handleClick}}
|
||||
>
|
||||
<:abovePostItemHeader as |post|>
|
||||
<PluginOutlet
|
||||
|
@ -165,6 +165,8 @@ export default class Post extends RestModel {
|
||||
@trackedPostProperty user_deleted;
|
||||
@trackedPostProperty user_id;
|
||||
@trackedPostProperty yours;
|
||||
@trackedPostProperty expandedExcerpt;
|
||||
@trackedPostProperty excerpt;
|
||||
|
||||
customShare = null;
|
||||
|
||||
|
@ -40,7 +40,7 @@ acceptance("User Drafts", function (needs) {
|
||||
assert.dom(".user-stream-item").exists("has drafts");
|
||||
assert.dom(".user-stream-item:nth-child(3) .category").hasText("meta");
|
||||
assert
|
||||
.dom(".user-stream-item:nth-child(3) .excerpt")
|
||||
.dom(".user-stream-item:nth-child(3) .excerpt .cooked")
|
||||
.hasHtml(
|
||||
`here goes a reply to a PM <img src="/images/emoji/twitter/slight_smile.png?v=${IMAGE_VERSION}" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20" style="aspect-ratio: 20 / 20;">`,
|
||||
"shows the excerpt"
|
||||
|
Loading…
x
Reference in New Issue
Block a user