mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 02:40:53 -06:00
DEV: convert TopicMapExpanded widget to glimmer component (#26027)
* DEV: add topic-map-expanded glimmer component * DEV: remove topic-map-expanded widgets from topic-map * DEV: add noreferrer for _blank target and add table grouping to template * DEV: negate base styling of tbody element so expanded topic map retains current look * DEV: pass in title to TopicParticipants as internationalized string instead of renderable HTML and set TRUNCATED_LINKS_LIMIT constant
This commit is contained in:
parent
b3dce458d2
commit
6b46b9ab78
@ -0,0 +1,125 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import TopicParticipants from "discourse/components/topic-map/topic-participants";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import and from "truth-helpers/helpers/and";
|
||||
import lt from "truth-helpers/helpers/lt";
|
||||
import not from "truth-helpers/helpers/not";
|
||||
|
||||
const TRUNCATED_LINKS_LIMIT = 5;
|
||||
|
||||
export default class TopicMapExpanded extends Component {
|
||||
@tracked allLinksShown = false;
|
||||
|
||||
@action
|
||||
showAllLinks() {
|
||||
this.allLinksShown = true;
|
||||
}
|
||||
|
||||
get linksToShow() {
|
||||
return this.allLinksShown
|
||||
? this.args.postAttrs.topicLinks
|
||||
: this.args.postAttrs.topicLinks.slice(0, TRUNCATED_LINKS_LIMIT);
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if @postAttrs.participants}}
|
||||
<section class="avatars">
|
||||
<TopicParticipants
|
||||
@title={{i18n "topic_map.participants_title"}}
|
||||
@userFilters={{@postAttrs.userFilters}}
|
||||
@participants={{@postAttrs.participants}}
|
||||
/>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if @postAttrs.topicLinks}}
|
||||
<section class="links">
|
||||
<h3>{{i18n "topic_map.links_title"}}</h3>
|
||||
<table class="topic-links">
|
||||
<tbody>
|
||||
{{#each this.linksToShow as |link|}}
|
||||
<tr>
|
||||
<td>
|
||||
<span
|
||||
class="badge badge-notification clicks"
|
||||
title={{i18n "topic_map.clicks" count=link.clicks}}
|
||||
>
|
||||
{{link.clicks}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<TopicMapLink
|
||||
@attachment={{link.attachment}}
|
||||
@title={{link.title}}
|
||||
@rootDomain={{link.root_domain}}
|
||||
@url={{link.url}}
|
||||
@userId={{link.user_id}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{#if
|
||||
(and
|
||||
(not this.allLinksShown)
|
||||
(lt TRUNCATED_LINKS_LIMIT @postAttrs.topicLinks.length)
|
||||
)
|
||||
}}
|
||||
<div class="link-summary">
|
||||
<span>
|
||||
<DButton
|
||||
@action={{this.showAllLinks}}
|
||||
@title="topic_map.links_shown"
|
||||
@icon="chevron-down"
|
||||
class="btn-flat"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
|
||||
class TopicMapLink extends Component {
|
||||
get linkClasses() {
|
||||
return this.args.attachment
|
||||
? "topic-link track-link attachment"
|
||||
: "topic-link track-link";
|
||||
}
|
||||
|
||||
get truncatedContent() {
|
||||
const truncateLength = 85;
|
||||
const content = this.args.title || this.args.url;
|
||||
return content.length > truncateLength
|
||||
? `${content.slice(0, truncateLength).trim()}...`
|
||||
: content;
|
||||
}
|
||||
|
||||
<template>
|
||||
<a
|
||||
class={{this.linkClasses}}
|
||||
href={{@url}}
|
||||
title={{@url}}
|
||||
data-user-id={{@userId}}
|
||||
data-ignore-post-id="true"
|
||||
target="_blank"
|
||||
rel="nofollow ugc noopener noreferrer"
|
||||
>
|
||||
{{#if @title}}
|
||||
{{replaceEmoji this.truncatedContent}}
|
||||
{{else}}
|
||||
{{this.truncatedContent}}
|
||||
{{/if}}
|
||||
</a>
|
||||
{{#if (and @title @rootDomain)}}
|
||||
<span class="domain">
|
||||
{{@rootDomain}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
@ -2,11 +2,12 @@ import Component from "@glimmer/component";
|
||||
import TopicParticipant from "discourse/components/topic-map/topic-participant";
|
||||
|
||||
export default class TopicParticipants extends Component {
|
||||
// prettier-ignore
|
||||
toggledUsers = new Set(this.args.userFilters);
|
||||
|
||||
<template>
|
||||
{{@title}}
|
||||
{{#if @title}}
|
||||
<h3>{{@title}}</h3>
|
||||
{{/if}}
|
||||
{{#each @participants as |participant|}}
|
||||
<TopicParticipant
|
||||
@participant={{participant}}
|
||||
|
@ -1,155 +1,6 @@
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { h } from "virtual-dom";
|
||||
import { replaceEmoji } from "discourse/widgets/emoji";
|
||||
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const LINKS_SHOWN = 5;
|
||||
|
||||
function renderParticipants(wrapperElement, title, userFilters, participants) {
|
||||
return new RenderGlimmer(
|
||||
this,
|
||||
wrapperElement,
|
||||
hbs`<TopicMap::TopicParticipants
|
||||
@title={{@data.title}}
|
||||
@participants={{@data.participants}}
|
||||
@userFilters={{@data.userFilters}}
|
||||
/>`,
|
||||
{
|
||||
title,
|
||||
userFilters,
|
||||
participants,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
createWidget("topic-map-show-links", {
|
||||
tagName: "div.link-summary",
|
||||
html() {
|
||||
return h(
|
||||
"span",
|
||||
this.attach("button", {
|
||||
title: "topic_map.links_shown",
|
||||
icon: "chevron-down",
|
||||
action: "showLinks",
|
||||
className: "btn btn-flat",
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
showLinks() {
|
||||
this.sendWidgetAction("showAllLinks");
|
||||
},
|
||||
});
|
||||
|
||||
createWidget("topic-map-link", {
|
||||
tagName: "a.topic-link.track-link",
|
||||
|
||||
buildClasses(attrs) {
|
||||
if (attrs.attachment) {
|
||||
return "attachment";
|
||||
}
|
||||
},
|
||||
|
||||
buildAttributes(attrs) {
|
||||
return {
|
||||
href: attrs.url,
|
||||
target: "_blank",
|
||||
"data-user-id": attrs.user_id,
|
||||
"data-ignore-post-id": "true",
|
||||
title: attrs.url,
|
||||
rel: "nofollow ugc noopener",
|
||||
};
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
let content = attrs.title || attrs.url;
|
||||
const truncateLength = 85;
|
||||
|
||||
if (content.length > truncateLength) {
|
||||
content = `${content.slice(0, truncateLength).trim()}...`;
|
||||
}
|
||||
|
||||
return attrs.title ? replaceEmoji(content) : content;
|
||||
},
|
||||
});
|
||||
|
||||
createWidget("topic-map-expanded", {
|
||||
tagName: "section.topic-map-expanded#topic-map-expanded",
|
||||
buildKey: (attrs) => `topic-map-expanded-${attrs.id}`,
|
||||
|
||||
defaultState() {
|
||||
return { allLinksShown: false };
|
||||
},
|
||||
|
||||
html(attrs, state) {
|
||||
let avatars;
|
||||
|
||||
if (attrs.participants && attrs.participants.length > 0) {
|
||||
avatars = renderParticipants.call(
|
||||
this,
|
||||
"section.avatars",
|
||||
htmlSafe(`<h3>${I18n.t("topic_map.participants_title")}</h3>`),
|
||||
attrs.userFilters,
|
||||
attrs.participants
|
||||
);
|
||||
}
|
||||
|
||||
const result = [avatars];
|
||||
if (attrs.topicLinks) {
|
||||
const toShow = state.allLinksShown
|
||||
? attrs.topicLinks
|
||||
: attrs.topicLinks.slice(0, LINKS_SHOWN);
|
||||
|
||||
const links = toShow.map((l) => {
|
||||
let host = "";
|
||||
|
||||
if (l.title && l.title.length) {
|
||||
const rootDomain = l.root_domain;
|
||||
|
||||
if (rootDomain && rootDomain.length) {
|
||||
host = h("span.domain", rootDomain);
|
||||
}
|
||||
}
|
||||
|
||||
return h("tr", [
|
||||
h(
|
||||
"td",
|
||||
h(
|
||||
"span.badge.badge-notification.clicks",
|
||||
{
|
||||
attributes: {
|
||||
title: I18n.t("topic_map.clicks", { count: l.clicks }),
|
||||
},
|
||||
},
|
||||
l.clicks.toString()
|
||||
)
|
||||
),
|
||||
h("td", [this.attach("topic-map-link", l), " ", host]),
|
||||
]);
|
||||
});
|
||||
|
||||
const showAllLinksContent = [
|
||||
h("h3", I18n.t("topic_map.links_title")),
|
||||
h("table.topic-links", links),
|
||||
];
|
||||
|
||||
if (!state.allLinksShown && links.length < attrs.topicLinks.length) {
|
||||
showAllLinksContent.push(this.attach("topic-map-show-links"));
|
||||
}
|
||||
|
||||
const section = h("section.links", showAllLinksContent);
|
||||
result.push(section);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
showAllLinks() {
|
||||
this.state.allLinksShown = true;
|
||||
},
|
||||
});
|
||||
|
||||
export default createWidget("topic-map", {
|
||||
tagName: "div.topic-map",
|
||||
@ -163,7 +14,7 @@ export default createWidget("topic-map", {
|
||||
const contents = [this.buildTopicMapSummary(attrs, state)];
|
||||
|
||||
if (!state.collapsed) {
|
||||
contents.push(this.attach("topic-map-expanded", attrs));
|
||||
contents.push(this.buildTopicMapExpanded(attrs));
|
||||
}
|
||||
|
||||
if (attrs.hasTopRepliesSummary || attrs.summarizable) {
|
||||
@ -203,6 +54,19 @@ export default createWidget("topic-map", {
|
||||
);
|
||||
},
|
||||
|
||||
buildTopicMapExpanded(attrs) {
|
||||
return new RenderGlimmer(
|
||||
this,
|
||||
"section.topic-map-expanded",
|
||||
hbs`<TopicMap::TopicMapExpanded
|
||||
@postAttrs={{@data.postAttrs}}
|
||||
/>`,
|
||||
{
|
||||
postAttrs: attrs,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
buildSummaryBox(attrs) {
|
||||
return new RenderGlimmer(
|
||||
this,
|
||||
|
@ -787,18 +787,10 @@ module("Integration | Component | Widget | post", function (hooks) {
|
||||
});
|
||||
|
||||
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
|
||||
|
||||
assert.ok(
|
||||
!exists("li.avatars a.poster"),
|
||||
"shows no participants when collapsed"
|
||||
);
|
||||
assert.dom("li.avatars a.poster").doesNotExist();
|
||||
|
||||
await click("nav.buttons button");
|
||||
assert.strictEqual(
|
||||
count(".topic-map-expanded a.poster"),
|
||||
2,
|
||||
"shows all when expanded"
|
||||
);
|
||||
assert.dom(".topic-map-expanded a.poster").exists({ count: 2 });
|
||||
});
|
||||
|
||||
test("topic map - participants", async function (assert) {
|
||||
@ -815,21 +807,12 @@ module("Integration | Component | Widget | post", function (hooks) {
|
||||
});
|
||||
|
||||
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
count("li.avatars a.poster"),
|
||||
3,
|
||||
"limits to three participants"
|
||||
);
|
||||
assert.dom("li.avatars a.poster").exists({ count: 3 });
|
||||
|
||||
await click("nav.buttons button");
|
||||
assert.ok(!exists("li.avatars a.poster"));
|
||||
assert.strictEqual(
|
||||
count(".topic-map-expanded a.poster"),
|
||||
4,
|
||||
"shows all when expanded"
|
||||
);
|
||||
assert.strictEqual(count("a.poster.toggled"), 2, "two are toggled");
|
||||
assert.dom("li.avatars a.poster").doesNotExist();
|
||||
assert.dom(".topic-map-expanded a.poster").exists({ count: 4 });
|
||||
assert.dom("a.poster.toggled").exists({ count: 2 });
|
||||
});
|
||||
|
||||
test("topic map - links", async function (assert) {
|
||||
@ -847,26 +830,18 @@ module("Integration | Component | Widget | post", function (hooks) {
|
||||
|
||||
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
|
||||
|
||||
assert.strictEqual(count(".topic-map"), 1);
|
||||
assert.strictEqual(count(".map.map-collapsed"), 1);
|
||||
assert.ok(!exists(".topic-map-expanded"));
|
||||
assert.dom(".topic-map").exists({ count: 1 });
|
||||
assert.dom(".map.map-collapsed").exists({ count: 1 });
|
||||
assert.dom(".topic-map-expanded").doesNotExist();
|
||||
|
||||
await click("nav.buttons button");
|
||||
assert.ok(!exists(".map.map-collapsed"));
|
||||
assert.strictEqual(count(".topic-map .d-icon-chevron-up"), 1);
|
||||
assert.strictEqual(count(".topic-map-expanded"), 1);
|
||||
assert.strictEqual(
|
||||
count(".topic-map-expanded .topic-link"),
|
||||
5,
|
||||
"it limits the links displayed"
|
||||
);
|
||||
assert.dom(".map.map-collapsed").doesNotExist();
|
||||
assert.dom(".topic-map .d-icon-chevron-up").exists({ count: 1 });
|
||||
assert.dom(".topic-map-expanded").exists({ count: 1 });
|
||||
assert.dom(".topic-map-expanded .topic-link").exists({ count: 5 });
|
||||
|
||||
await click(".link-summary button");
|
||||
assert.strictEqual(
|
||||
count(".topic-map-expanded .topic-link"),
|
||||
6,
|
||||
"all links now shown"
|
||||
);
|
||||
assert.dom(".topic-map-expanded .topic-link").exists({ count: 6 });
|
||||
});
|
||||
|
||||
test("topic map - no summary", async function (assert) {
|
||||
|
@ -751,6 +751,9 @@ aside.quote {
|
||||
}
|
||||
|
||||
.topic-links {
|
||||
tbody {
|
||||
border: none;
|
||||
}
|
||||
tr {
|
||||
border: none;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user