diff --git a/app/assets/javascripts/admin/addon/components/modal/reseed.hbs b/app/assets/javascripts/admin/addon/components/modal/reseed.hbs index 46d26972f48..eb746b98ada 100644 --- a/app/assets/javascripts/admin/addon/components/modal/reseed.hbs +++ b/app/assets/javascripts/admin/addon/components/modal/reseed.hbs @@ -19,7 +19,7 @@ @type="checkbox" @checked={{category.selected}} /> - {{category.name}} + {{category.displayName}} {{/each}} diff --git a/app/assets/javascripts/admin/addon/templates/site-settings.hbs b/app/assets/javascripts/admin/addon/templates/site-settings.hbs index a8225709bf4..f264afee288 100644 --- a/app/assets/javascripts/admin/addon/templates/site-settings.hbs +++ b/app/assets/javascripts/admin/addon/templates/site-settings.hbs @@ -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}} ({{category.count}}) {{/if}} diff --git a/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs b/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs index c9ffc514d9b..5e0c8831124 100644 --- a/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs +++ b/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs @@ -19,7 +19,7 @@ {{#if c.read_restricted}} {{d-icon this.lockIcon}} {{/if}} - {{c.name}} + {{c.displayName}} diff --git a/app/assets/javascripts/discourse/app/components/categories-boxes.hbs b/app/assets/javascripts/discourse/app/components/categories-boxes.hbs index d2a295d35ca..d5469e87332 100644 --- a/app/assets/javascripts/discourse/app/components/categories-boxes.hbs +++ b/app/assets/javascripts/discourse/app/components/categories-boxes.hbs @@ -29,7 +29,7 @@ {{#if c.read_restricted}} {{d-icon this.lockIcon}} {{/if}} - {{c.name}} + {{c.displayName}} diff --git a/app/assets/javascripts/discourse/app/components/category-title-link.hbs b/app/assets/javascripts/discourse/app/components/category-title-link.hbs index b5c08397d42..1284bf33c59 100644 --- a/app/assets/javascripts/discourse/app/components/category-title-link.hbs +++ b/app/assets/javascripts/discourse/app/components/category-title-link.hbs @@ -4,7 +4,7 @@ {{#if this.category.read_restricted}} {{d-icon this.lockIcon}} {{/if}} - {{dir-span this.category.name}} + {{dir-span this.category.displayName}} {{#if this.category.uploaded_logo.url}} diff --git a/app/assets/javascripts/discourse/app/helpers/category-link.js b/app/assets/javascripts/discourse/app/helpers/category-link.js index 91df2ebb679..9b65a52e38b 100644 --- a/app/assets/javascripts/discourse/app/helpers/category-link.js +++ b/app/assets/javascripts/discourse/app/helpers/category-link.js @@ -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"'; diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs index f800b02e0aa..83e3d21fb51 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs @@ -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", * }) diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js index cd350e8b7c8..d14bd6de981 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js @@ -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() { diff --git a/app/assets/javascripts/discourse/app/lib/transformer/registry.js b/app/assets/javascripts/discourse/app/lib/transformer/registry.js index 1f6ea052df3..f111349d31a 100644 --- a/app/assets/javascripts/discourse/app/lib/transformer/registry.js +++ b/app/assets/javascripts/discourse/app/lib/transformer/registry.js @@ -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", diff --git a/app/assets/javascripts/discourse/app/models/category.js b/app/assets/javascripts/discourse/app/models/category.js index 44080ed62f7..a6cf7a908d6 100644 --- a/app/assets/javascripts/discourse/app/models/category.js +++ b/app/assets/javascripts/discourse/app/models/category.js @@ -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) { diff --git a/app/assets/javascripts/discourse/app/routes/build-category-route.js b/app/assets/javascripts/discourse/app/routes/build-category-route.js index 678f7027534..f4a83abcf6d 100644 --- a/app/assets/javascripts/discourse/app/routes/build-category-route.js +++ b/app/assets/javascripts/discourse/app/routes/build-category-route.js @@ -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", { diff --git a/app/assets/javascripts/discourse/app/routes/tag-show.js b/app/assets/javascripts/discourse/app/routes/tag-show.js index c01eb9aa96a..fbd7ae19c68 100644 --- a/app/assets/javascripts/discourse/app/routes/tag-show.js +++ b/app/assets/javascripts/discourse/app/routes/tag-show.js @@ -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", { diff --git a/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js b/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js index 18f271481fb..f33e49318c0 100644 --- a/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js +++ b/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js @@ -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 ); diff --git a/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js b/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js index bb94e4c5930..d4a49e8dcd4 100644 --- a/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js +++ b/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js @@ -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 ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js index 161af3e3be8..727be141555 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js @@ -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; } }, diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js index d50d6032d19..ba24ce52761 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js @@ -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" ); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js new file mode 100644 index 00000000000..9a447fdc215 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js @@ -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" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js new file mode 100644 index 00000000000..df1f8634f61 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js @@ -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" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js b/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js index bbeaba056f0..2ae920de031 100644 --- a/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js +++ b/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js @@ -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 ); }); diff --git a/app/assets/javascripts/select-kit/addon/components/category-drop.js b/app/assets/javascripts/select-kit/addon/components/category-drop.js index a5e1aa1cca7..703a5521280 100644 --- a/app/assets/javascripts/select-kit/addon/components/category-drop.js +++ b/app/assets/javascripts/select-kit/addon/components/category-drop.js @@ -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", diff --git a/app/assets/javascripts/select-kit/addon/components/category-row.gjs b/app/assets/javascripts/select-kit/addon/components/category-row.gjs index aa2a44c017f..d775d34fdb8 100644 --- a/app/assets/javascripts/select-kit/addon/components/category-row.gjs +++ b/app/assets/javascripts/select-kit/addon/components/category-row.gjs @@ -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