DEV: allows to alter category name/description (#28263)

This commit adds two new getters to the category model:
- `displayName`
- `descriptionText`

These getters are used instead of `name` and `description_text` where appropriate.

On top of this two transformers have been added to allow plugins to alter these getters:

```javascript
api.registerValueTransformer(
  "category-display-name",
  ({ value, context }) =>
    value + "-" + context.category.id + "-transformed"
);
```

```javascript
api.registerValueTransformer(
  "category-description-text",
  ({ value, context }) =>
    value + "-" + context.category.id + "-transformed"
);
```
This commit is contained in:
Joffrey JAFFEUX 2024-08-08 17:33:23 +02:00 committed by GitHub
parent 86bb07f619
commit c197daa04c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 104 additions and 30 deletions

View File

@ -19,7 +19,7 @@
@type="checkbox"
@checked={{category.selected}}
/>
<span>{{category.name}}</span>
<span>{{category.displayName}}</span>
</label>
{{/each}}
</fieldset>

View File

@ -18,9 +18,9 @@
@route="adminSiteSettingsCategory"
@model={{category.nameKey}}
class={{category.nameKey}}
title={{category.name}}
title={{category.displayName}}
>
{{category.name}}
{{category.displayName}}
{{#if category.count}}
<span class="count">({{category.count}})</span>
{{/if}}

View File

@ -19,7 +19,7 @@
{{#if c.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
{{c.name}}
{{c.displayName}}
</h3>
</a>
</div>

View File

@ -29,7 +29,7 @@
{{#if c.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
{{c.name}}
{{c.displayName}}
</h3>
</a>
</div>

View File

@ -4,7 +4,7 @@
{{#if this.category.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
<span class="category-name">{{dir-span this.category.name}}</span>
<span class="category-name">{{dir-span this.category.displayName}}</span>
</div>
{{#if this.category.uploaded_logo.url}}
<CategoryLogo @category={{this.category}} />

View File

@ -112,7 +112,7 @@ function buildTopicCount(count) {
}
export function defaultCategoryLinkRenderer(category, opts) {
let descriptionText = escapeExpression(get(category, "description_text"));
let descriptionText = escapeExpression(get(category, "descriptionText"));
let restricted = get(category, "read_restricted");
let url = opts.url
? opts.url
@ -156,7 +156,7 @@ export function defaultCategoryLinkRenderer(category, opts) {
${descriptionText ? 'title="' + descriptionText + '" ' : ""}
>`;
let categoryName = escapeExpression(get(category, "name"));
let categoryName = escapeExpression(get(category, "displayName"));
if (siteSettings.support_mixed_text_direction) {
categoryDir = 'dir="auto"';

View File

@ -1537,8 +1537,8 @@ class PluginApi {
* displayName: "bugs"
* href: "/c/bugs",
* init: (navItem, category) => { if (category) { navItem.set("category", category) } }
* customFilter: (category, args, router) => { return category && category.name !== 'bug' }
* customHref: (category, args, router) => { if (category && category.name) === 'not-a-bug') return "/a-feature"; },
* customFilter: (category, args, router) => { return category && category.displayName !== 'bug' }
* customHref: (category, args, router) => { if (category && category.displayName) === 'not-a-bug') return "/a-feature"; },
* before: "top",
* forceActive: (category, args, router) => router.currentURL === "/a/b/c/d",
* })

View File

@ -178,11 +178,11 @@ export default class CategorySectionLink {
}
get title() {
return this.category.description_text;
return this.category.descriptionText;
}
get text() {
return this.category.name;
return this.category.displayName;
}
get prefixType() {

View File

@ -5,6 +5,8 @@ export const BEHAVIOR_TRANSFORMERS = Object.freeze([
export const VALUE_TRANSFORMERS = Object.freeze([
// use only lowercase names
"category-description-text",
"category-display-name",
"header-notifications-avatar-size",
"home-logo-href",
"home-logo-image-url",

View File

@ -3,6 +3,7 @@ import { computed, get } from "@ember/object";
import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import { NotificationLevels } from "discourse/lib/notification-levels";
import { applyValueTransformer } from "discourse/lib/transformer";
import PermissionType from "discourse/models/permission-type";
import RestModel from "discourse/models/rest";
import Site from "discourse/models/site";
@ -475,6 +476,22 @@ export default class Category extends RestModel {
}
}
get descriptionText() {
return applyValueTransformer(
"category-description-text",
this.get("description_text"),
{
category: this,
}
);
}
get displayName() {
return applyValueTransformer("category-display-name", this.get("name"), {
category: this,
});
}
@computed("parent_category_id", "site.categories.[]")
get parentCategory() {
if (this.parent_category_id) {

View File

@ -117,11 +117,11 @@ class AbstractCategoryRoute extends DiscourseRoute {
"filters." + this.filter(category).replace("/", ".") + ".title"
);
let categoryName = category.name;
let categoryName = category.displayName;
if (category.parent_category_id) {
const list = Category.list();
const parentCategory = list.findBy("id", category.parent_category_id);
categoryName = `${parentCategory.name}/${categoryName}`;
categoryName = `${parentCategory.displayName}/${categoryName}`;
}
return I18n.t("filters.with_category", {

View File

@ -179,7 +179,7 @@ export default class TagShowRoute extends DiscourseRoute {
return I18n.t("tagging.filters.with_category", {
filter: filterText,
tag: model.tag.id,
category: model.category.name,
category: model.category.displayName,
});
} else {
return I18n.t("tagging.filters.without_category", {
@ -191,7 +191,7 @@ export default class TagShowRoute extends DiscourseRoute {
if (model.category) {
return I18n.t("tagging.filters.untagged_with_category", {
filter: filterText,
category: model.category.name,
category: model.category.displayName,
});
} else {
return I18n.t("tagging.filters.untagged_without_category", {

View File

@ -73,7 +73,7 @@ export default PreviewBaseComponent.extend({
ctx.font = `Bold ${badgeSize * 1.2}px '${font}'`;
ctx.fillStyle = colors.primary;
ctx.fillText(
category.name,
category.displayName,
afterLogo + badgeSize * 1.5,
headerHeight * 0.7 + badgeSize * 0.9
);

View File

@ -85,7 +85,11 @@ export default PreviewBaseComponent.extend({
ctx.font = `Bold ${bodyFontSize * 1.3}em '${font}'`;
ctx.fillStyle = colors.primary;
ctx.textAlign = "center";
ctx.fillText(category.name, boxStartX + boxWidth / 2, boxStartY + 25);
ctx.fillText(
category.displayName,
boxStartX + boxWidth / 2,
boxStartY + 25
);
ctx.textAlign = "left";
if (opts.topics) {
@ -167,7 +171,7 @@ export default PreviewBaseComponent.extend({
const textPos = y + categoryHeight * 0.35;
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
ctx.fillStyle = colors.primary;
ctx.fillText(category.name, cols[0], textPos);
ctx.fillText(category.displayName, cols[0], textPos);
ctx.font = `${bodyFontSize * 0.8}em '${font}'`;
ctx.fillStyle = textColor;
@ -263,7 +267,7 @@ export default PreviewBaseComponent.extend({
const textPos = y + categoryHeight * 0.35;
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
ctx.fillStyle = colors.primary;
ctx.fillText(category.name, cols[0], textPos);
ctx.fillText(category.displayName, cols[0], textPos);
ctx.font = `${bodyFontSize * 0.8}em '${font}'`;
ctx.fillStyle = textColor;
@ -328,7 +332,7 @@ export default PreviewBaseComponent.extend({
ctx.fillStyle = colors.primary;
ctx.fillText(
category.name,
category.displayName,
cols[3] + badgeSize * 3,
y + topicHeight * 0.76
);
@ -409,7 +413,7 @@ export default PreviewBaseComponent.extend({
ctx.fillStyle = colors.primary;
ctx.fillText(
category.name,
category.displayName,
cols[0] + badgeSize * 2,
y + rowHeight * 0.73
);

View File

@ -543,9 +543,9 @@ acceptance("Sidebar - Plugin API", function (needs) {
route: "discovery.latestCategory",
routeQuery: { status: "open" },
shouldRegister: ({ category }) => {
if (category.name === category1.name) {
if (category.displayName === category1.displayName) {
return true;
} else if (category.name === category2.name) {
} else if (category.displayName === category2.displayName) {
return false;
}
},

View File

@ -177,7 +177,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
exists(
`.sidebar-section-link-wrapper[data-category-id=${category.id}]`
),
`${category.name} section link is shown`
`${category.displayName} section link is shown`
);
});
});
@ -677,7 +677,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
query(
`.sidebar-section-link-wrapper[data-category-id="${category.id}"] a`
).title,
category.description_text,
category.descriptionText,
"category description without HTML entity is used as the link's title"
);
});

View File

@ -0,0 +1,26 @@
import { visit } from "@ember/test-helpers";
import { test } from "qunit";
import { withPluginApi } from "discourse/lib/plugin-api";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
acceptance("category-description-text transformer", function () {
test("applying a value transformation", async function (assert) {
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"category-description-text",
({ value, context }) =>
value[0] + "-" + context.category.id + "-transformed"
);
});
await visit("/");
assert
.dom("[data-topic-id='11994'] .badge-category")
.hasAttribute(
"title",
"A-1-transformed",
"it transforms the category description text"
);
});
});

View File

@ -0,0 +1,25 @@
import { visit } from "@ember/test-helpers";
import { test } from "qunit";
import { withPluginApi } from "discourse/lib/plugin-api";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
acceptance("category-display-name transformer", function () {
test("applying a value transformation", async function (assert) {
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer(
"category-display-name",
({ value, context }) =>
value + "-" + context.category.id + "-transformed"
);
});
await visit("/");
assert
.dom("[data-topic-id='11997'] .badge-category__name")
.hasText(
"feature-2-transformed",
"it transforms the category display name"
);
});
});

View File

@ -15,7 +15,7 @@ module("Integration | Helper | category-badge", function (hooks) {
assert.strictEqual(
query(".badge-category__name").innerText.trim(),
this.category.name
this.category.displayName
);
});

View File

@ -152,7 +152,7 @@ export default ComboBoxComponent.extend({
return content;
},
parentCategoryName: readOnly("selectKit.options.parentCategory.name"),
parentCategoryName: readOnly("selectKit.options.parentCategory.displayName"),
allCategoriesLabel: computed(
"parentCategoryName",

View File

@ -83,11 +83,11 @@ export default class CategoryRow extends Component {
}
get categoryName() {
return this.category.name;
return this.category.displayName;
}
get categoryDescriptionText() {
return this.category.description_text;
return this.category.descriptionText;
}
@cached