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:
parent
86bb07f619
commit
c197daa04c
|
@ -19,7 +19,7 @@
|
||||||
@type="checkbox"
|
@type="checkbox"
|
||||||
@checked={{category.selected}}
|
@checked={{category.selected}}
|
||||||
/>
|
/>
|
||||||
<span>{{category.name}}</span>
|
<span>{{category.displayName}}</span>
|
||||||
</label>
|
</label>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
@route="adminSiteSettingsCategory"
|
@route="adminSiteSettingsCategory"
|
||||||
@model={{category.nameKey}}
|
@model={{category.nameKey}}
|
||||||
class={{category.nameKey}}
|
class={{category.nameKey}}
|
||||||
title={{category.name}}
|
title={{category.displayName}}
|
||||||
>
|
>
|
||||||
{{category.name}}
|
{{category.displayName}}
|
||||||
{{#if category.count}}
|
{{#if category.count}}
|
||||||
<span class="count">({{category.count}})</span>
|
<span class="count">({{category.count}})</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{{#if c.read_restricted}}
|
{{#if c.read_restricted}}
|
||||||
{{d-icon this.lockIcon}}
|
{{d-icon this.lockIcon}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{c.name}}
|
{{c.displayName}}
|
||||||
</h3>
|
</h3>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
{{#if c.read_restricted}}
|
{{#if c.read_restricted}}
|
||||||
{{d-icon this.lockIcon}}
|
{{d-icon this.lockIcon}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{c.name}}
|
{{c.displayName}}
|
||||||
</h3>
|
</h3>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{{#if this.category.read_restricted}}
|
{{#if this.category.read_restricted}}
|
||||||
{{d-icon this.lockIcon}}
|
{{d-icon this.lockIcon}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span class="category-name">{{dir-span this.category.name}}</span>
|
<span class="category-name">{{dir-span this.category.displayName}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{#if this.category.uploaded_logo.url}}
|
{{#if this.category.uploaded_logo.url}}
|
||||||
<CategoryLogo @category={{this.category}} />
|
<CategoryLogo @category={{this.category}} />
|
||||||
|
|
|
@ -112,7 +112,7 @@ function buildTopicCount(count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defaultCategoryLinkRenderer(category, opts) {
|
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 restricted = get(category, "read_restricted");
|
||||||
let url = opts.url
|
let url = opts.url
|
||||||
? opts.url
|
? opts.url
|
||||||
|
@ -156,7 +156,7 @@ export function defaultCategoryLinkRenderer(category, opts) {
|
||||||
${descriptionText ? 'title="' + descriptionText + '" ' : ""}
|
${descriptionText ? 'title="' + descriptionText + '" ' : ""}
|
||||||
>`;
|
>`;
|
||||||
|
|
||||||
let categoryName = escapeExpression(get(category, "name"));
|
let categoryName = escapeExpression(get(category, "displayName"));
|
||||||
|
|
||||||
if (siteSettings.support_mixed_text_direction) {
|
if (siteSettings.support_mixed_text_direction) {
|
||||||
categoryDir = 'dir="auto"';
|
categoryDir = 'dir="auto"';
|
||||||
|
|
|
@ -1537,8 +1537,8 @@ class PluginApi {
|
||||||
* displayName: "bugs"
|
* displayName: "bugs"
|
||||||
* href: "/c/bugs",
|
* href: "/c/bugs",
|
||||||
* init: (navItem, category) => { if (category) { navItem.set("category", category) } }
|
* init: (navItem, category) => { if (category) { navItem.set("category", category) } }
|
||||||
* customFilter: (category, args, router) => { return category && category.name !== 'bug' }
|
* customFilter: (category, args, router) => { return category && category.displayName !== 'bug' }
|
||||||
* customHref: (category, args, router) => { if (category && category.name) === 'not-a-bug') return "/a-feature"; },
|
* customHref: (category, args, router) => { if (category && category.displayName) === 'not-a-bug') return "/a-feature"; },
|
||||||
* before: "top",
|
* before: "top",
|
||||||
* forceActive: (category, args, router) => router.currentURL === "/a/b/c/d",
|
* forceActive: (category, args, router) => router.currentURL === "/a/b/c/d",
|
||||||
* })
|
* })
|
||||||
|
|
|
@ -178,11 +178,11 @@ export default class CategorySectionLink {
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return this.category.description_text;
|
return this.category.descriptionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
get text() {
|
get text() {
|
||||||
return this.category.name;
|
return this.category.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
get prefixType() {
|
get prefixType() {
|
||||||
|
|
|
@ -5,6 +5,8 @@ export const BEHAVIOR_TRANSFORMERS = Object.freeze([
|
||||||
|
|
||||||
export const VALUE_TRANSFORMERS = Object.freeze([
|
export const VALUE_TRANSFORMERS = Object.freeze([
|
||||||
// use only lowercase names
|
// use only lowercase names
|
||||||
|
"category-description-text",
|
||||||
|
"category-display-name",
|
||||||
"header-notifications-avatar-size",
|
"header-notifications-avatar-size",
|
||||||
"home-logo-href",
|
"home-logo-href",
|
||||||
"home-logo-image-url",
|
"home-logo-image-url",
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { computed, get } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||||
|
import { applyValueTransformer } from "discourse/lib/transformer";
|
||||||
import PermissionType from "discourse/models/permission-type";
|
import PermissionType from "discourse/models/permission-type";
|
||||||
import RestModel from "discourse/models/rest";
|
import RestModel from "discourse/models/rest";
|
||||||
import Site from "discourse/models/site";
|
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.[]")
|
@computed("parent_category_id", "site.categories.[]")
|
||||||
get parentCategory() {
|
get parentCategory() {
|
||||||
if (this.parent_category_id) {
|
if (this.parent_category_id) {
|
||||||
|
|
|
@ -117,11 +117,11 @@ class AbstractCategoryRoute extends DiscourseRoute {
|
||||||
"filters." + this.filter(category).replace("/", ".") + ".title"
|
"filters." + this.filter(category).replace("/", ".") + ".title"
|
||||||
);
|
);
|
||||||
|
|
||||||
let categoryName = category.name;
|
let categoryName = category.displayName;
|
||||||
if (category.parent_category_id) {
|
if (category.parent_category_id) {
|
||||||
const list = Category.list();
|
const list = Category.list();
|
||||||
const parentCategory = list.findBy("id", category.parent_category_id);
|
const parentCategory = list.findBy("id", category.parent_category_id);
|
||||||
categoryName = `${parentCategory.name}/${categoryName}`;
|
categoryName = `${parentCategory.displayName}/${categoryName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return I18n.t("filters.with_category", {
|
return I18n.t("filters.with_category", {
|
||||||
|
|
|
@ -179,7 +179,7 @@ export default class TagShowRoute extends DiscourseRoute {
|
||||||
return I18n.t("tagging.filters.with_category", {
|
return I18n.t("tagging.filters.with_category", {
|
||||||
filter: filterText,
|
filter: filterText,
|
||||||
tag: model.tag.id,
|
tag: model.tag.id,
|
||||||
category: model.category.name,
|
category: model.category.displayName,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return I18n.t("tagging.filters.without_category", {
|
return I18n.t("tagging.filters.without_category", {
|
||||||
|
@ -191,7 +191,7 @@ export default class TagShowRoute extends DiscourseRoute {
|
||||||
if (model.category) {
|
if (model.category) {
|
||||||
return I18n.t("tagging.filters.untagged_with_category", {
|
return I18n.t("tagging.filters.untagged_with_category", {
|
||||||
filter: filterText,
|
filter: filterText,
|
||||||
category: model.category.name,
|
category: model.category.displayName,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return I18n.t("tagging.filters.untagged_without_category", {
|
return I18n.t("tagging.filters.untagged_without_category", {
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default PreviewBaseComponent.extend({
|
||||||
ctx.font = `Bold ${badgeSize * 1.2}px '${font}'`;
|
ctx.font = `Bold ${badgeSize * 1.2}px '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
category.name,
|
category.displayName,
|
||||||
afterLogo + badgeSize * 1.5,
|
afterLogo + badgeSize * 1.5,
|
||||||
headerHeight * 0.7 + badgeSize * 0.9
|
headerHeight * 0.7 + badgeSize * 0.9
|
||||||
);
|
);
|
||||||
|
|
|
@ -85,7 +85,11 @@ export default PreviewBaseComponent.extend({
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.3}em '${font}'`;
|
ctx.font = `Bold ${bodyFontSize * 1.3}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.fillText(category.name, boxStartX + boxWidth / 2, boxStartY + 25);
|
ctx.fillText(
|
||||||
|
category.displayName,
|
||||||
|
boxStartX + boxWidth / 2,
|
||||||
|
boxStartY + 25
|
||||||
|
);
|
||||||
ctx.textAlign = "left";
|
ctx.textAlign = "left";
|
||||||
|
|
||||||
if (opts.topics) {
|
if (opts.topics) {
|
||||||
|
@ -167,7 +171,7 @@ export default PreviewBaseComponent.extend({
|
||||||
const textPos = y + categoryHeight * 0.35;
|
const textPos = y + categoryHeight * 0.35;
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
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.font = `${bodyFontSize * 0.8}em '${font}'`;
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
|
@ -263,7 +267,7 @@ export default PreviewBaseComponent.extend({
|
||||||
const textPos = y + categoryHeight * 0.35;
|
const textPos = y + categoryHeight * 0.35;
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
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.font = `${bodyFontSize * 0.8}em '${font}'`;
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
|
@ -328,7 +332,7 @@ export default PreviewBaseComponent.extend({
|
||||||
|
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
category.name,
|
category.displayName,
|
||||||
cols[3] + badgeSize * 3,
|
cols[3] + badgeSize * 3,
|
||||||
y + topicHeight * 0.76
|
y + topicHeight * 0.76
|
||||||
);
|
);
|
||||||
|
@ -409,7 +413,7 @@ export default PreviewBaseComponent.extend({
|
||||||
|
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
category.name,
|
category.displayName,
|
||||||
cols[0] + badgeSize * 2,
|
cols[0] + badgeSize * 2,
|
||||||
y + rowHeight * 0.73
|
y + rowHeight * 0.73
|
||||||
);
|
);
|
||||||
|
|
|
@ -543,9 +543,9 @@ acceptance("Sidebar - Plugin API", function (needs) {
|
||||||
route: "discovery.latestCategory",
|
route: "discovery.latestCategory",
|
||||||
routeQuery: { status: "open" },
|
routeQuery: { status: "open" },
|
||||||
shouldRegister: ({ category }) => {
|
shouldRegister: ({ category }) => {
|
||||||
if (category.name === category1.name) {
|
if (category.displayName === category1.displayName) {
|
||||||
return true;
|
return true;
|
||||||
} else if (category.name === category2.name) {
|
} else if (category.displayName === category2.displayName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -177,7 +177,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
|
||||||
exists(
|
exists(
|
||||||
`.sidebar-section-link-wrapper[data-category-id=${category.id}]`
|
`.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(
|
query(
|
||||||
`.sidebar-section-link-wrapper[data-category-id="${category.id}"] a`
|
`.sidebar-section-link-wrapper[data-category-id="${category.id}"] a`
|
||||||
).title,
|
).title,
|
||||||
category.description_text,
|
category.descriptionText,
|
||||||
"category description without HTML entity is used as the link's title"
|
"category description without HTML entity is used as the link's title"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -15,7 +15,7 @@ module("Integration | Helper | category-badge", function (hooks) {
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
query(".badge-category__name").innerText.trim(),
|
query(".badge-category__name").innerText.trim(),
|
||||||
this.category.name
|
this.category.displayName
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default ComboBoxComponent.extend({
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
parentCategoryName: readOnly("selectKit.options.parentCategory.name"),
|
parentCategoryName: readOnly("selectKit.options.parentCategory.displayName"),
|
||||||
|
|
||||||
allCategoriesLabel: computed(
|
allCategoriesLabel: computed(
|
||||||
"parentCategoryName",
|
"parentCategoryName",
|
||||||
|
|
|
@ -83,11 +83,11 @@ export default class CategoryRow extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get categoryName() {
|
get categoryName() {
|
||||||
return this.category.name;
|
return this.category.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
get categoryDescriptionText() {
|
get categoryDescriptionText() {
|
||||||
return this.category.description_text;
|
return this.category.descriptionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
|
|
Loading…
Reference in New Issue