DEV: Improve the sidebar section expansion handling ()

Handles the cases where the sections titles are Unicode only strings, allowing them to be expanded separately if the Unicode string contains letters.

Also prevents a sidebar section with the header hidden to be displayed collapsed.
This commit is contained in:
Sérgio Saquetim 2024-07-09 18:32:29 -03:00 committed by GitHub
parent dd67375de7
commit bbd67eff08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 123 additions and 9 deletions
app/assets/javascripts/discourse
spec/system
custom_sidebar_sections_spec.rb
page_objects/components/navigation_menu

@ -1,5 +1,5 @@
import SidebarCustomSection from "../common/custom-sections";
import SidebarCustomSections from "../common/custom-sections";
export default class SidebarAnonymousCustomSections extends SidebarCustomSection {
export default class SidebarAnonymousCustomSections extends SidebarCustomSections {
anonymous = true;
}

@ -2,7 +2,7 @@ import Component from "@glimmer/component";
import { service } from "@ember/service";
import CustomSection from "./custom-section";
export default class SidebarCustomSection extends Component {
export default class SidebarCustomSections extends Component {
@service currentUser;
@service router;
@service messageBus;

@ -5,6 +5,7 @@ import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import concatClass from "discourse/helpers/concat-class";
import {
getCollapsedSidebarSectionKey,
getSidebarSectionContentId,
@ -60,7 +61,7 @@ export default class SidebarSection extends Component {
}
get displaySectionContent() {
if (!isEmpty(this.sidebarState.filter)) {
if (this.args.hideSectionHeader || !isEmpty(this.sidebarState.filter)) {
return true;
}
@ -115,7 +116,15 @@ export default class SidebarSection extends Component {
<div
{{didInsert this.setExpandedState}}
data-section-name={{@sectionName}}
class="sidebar-section-wrapper sidebar-section"
class={{concatClass
"sidebar-section"
"sidebar-section-wrapper"
(if
this.displaySectionContent
"sidebar-section--expanded"
"sidebar-section--collapsed"
)
}}
...attributes
>
{{#unless @hideSectionHeader}}

@ -1,8 +1,8 @@
import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse-common/utils/decorators";
import SidebarCustomSection from "../common/custom-sections";
import SidebarCustomSections from "../common/custom-sections";
export default class SidebarUserCustomSections extends SidebarCustomSection {
export default class SidebarUserCustomSections extends SidebarCustomSections {
constructor() {
super(...arguments);
this.messageBus.subscribe("/refresh-sidebar-sections", this._refresh);

@ -1,9 +1,11 @@
import { tracked } from "@glimmer/tracking";
import { setOwner } from "@ember/application";
import { service } from "@ember/service";
import { isPresent } from "@ember/utils";
import SidebarSectionForm from "discourse/components/modal/sidebar-section-form";
import { ajax } from "discourse/lib/ajax";
import SectionLink from "discourse/lib/sidebar/section-link";
import { unicodeSlugify } from "discourse/lib/utilities";
import { bind } from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
@ -19,7 +21,9 @@ export default class Section {
setOwner(this, owner);
this.section = section;
this.slug = section.slug;
this.slug = isPresent(section.slug)
? section.slug
: unicodeSlugify(section.title);
this.links = this.section.links.map((link) => {
return new SectionLink(link, this, this.router);

@ -372,6 +372,24 @@ export function slugify(string) {
.replace(/-+$/, ""); // Remove trailing dashes
}
export function unicodeSlugify(string) {
try {
return string
.trim()
.toLowerCase()
.normalize("NFD") // normalize the string to remove diacritics
.replace(/\s|_+/g, "-") // replace spaces and underscores with dashes
.replace(/[^\p{Letter}\d\-]+/gu, "") // Remove non-letter characters except for dashes
.replace(/--+/g, "-") // replace multiple dashes with a single dash
.replace(/^-+/, "") // Remove leading dashes
.replace(/-+$/, ""); // Remove trailing dashes
} catch (e) {
// in case the regex construct \p{Letter} is not supported by the browser
// fall back to the basic slugify function
return slugify(string);
}
}
export function toNumber(input) {
return typeof input === "number" ? input : parseFloat(input);
}

@ -20,6 +20,7 @@ import {
setDefaultHomepage,
slugify,
toAsciiPrintable,
unicodeSlugify,
} from "discourse/lib/utilities";
import {
mdTable,
@ -202,6 +203,37 @@ module("Unit | Utilities", function (hooks) {
);
});
test("unicodeSlugify", function (assert) {
const asciiString = "--- 0__( Some--cool Discourse Site! )__0 --- ";
const accentedString = "Créme_Brûlée!";
const unicodeString = "談話";
const unicodeStringWithEmojis = "⌘😁 談話";
assert.strictEqual(
unicodeSlugify(asciiString),
"0-some-cool-discourse-site-0",
"it properly slugifies an ASCII string"
);
assert.strictEqual(
unicodeSlugify(accentedString),
"creme-brulee",
"it removes diacritics"
);
assert.strictEqual(
unicodeSlugify(unicodeString),
"談話",
"it keeps unicode letters"
);
assert.strictEqual(
unicodeSlugify(unicodeStringWithEmojis),
"談話",
"it removes emojis and symbols"
);
});
test("fillMissingDates", function (assert) {
const startDate = "2017-11-12"; // YYYY-MM-DD
const endDate = "2017-12-12"; // YYYY-MM-DD

@ -395,4 +395,39 @@ describe "Custom sidebar sections", type: :system do
expect(section_modal).to have_disabled_save
end
it "allows the user to expand/collapse section containing unicode titles separately" do
sidebar_section1 = Fabricate(:sidebar_section, title: "談話", user: user)
Fabricate(:sidebar_url, name: "Sidebar Latest", value: "/latest").tap do |sidebar_url|
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section1, linkable: sidebar_url)
end
sidebar_section2 = Fabricate(:sidebar_section, title: "", user: user)
Fabricate(:sidebar_url, name: "Sidebar Categories", value: "/categories").tap do |sidebar_url|
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section2, linkable: sidebar_url)
end
sign_in user
visit("/latest")
expect(sidebar).to have_section_expanded("談話")
expect(sidebar).to have_section_expanded("")
sidebar.click_section_header("談話")
expect(sidebar).to have_section_collapsed("談話")
expect(sidebar).to have_section_expanded("")
sidebar.click_section_header("")
expect(sidebar).to have_section_collapsed("談話")
expect(sidebar).to have_section_collapsed("")
sidebar.click_section_header("談話")
expect(sidebar).to have_section_expanded("談話")
expect(sidebar).to have_section_collapsed("")
sidebar.click_section_header("")
expect(sidebar).to have_section_expanded("談話")
expect(sidebar).to have_section_expanded("")
end
end

@ -19,7 +19,11 @@ module PageObjects
end
def find_section(name)
find(".sidebar-section[data-section-name='#{name}']")
find(sidebar_section_selector(name))
end
def click_section_header(name)
find("#{sidebar_section_selector(name)} .sidebar-section-header").click
end
def click_section_link(name)
@ -59,6 +63,14 @@ module PageObjects
has_no_css?(".sidebar-sections [data-section-name='#{name.parameterize}']")
end
def has_section_expanded?(name)
has_css?("#{sidebar_section_selector(name)}.sidebar-section--expanded")
end
def has_section_collapsed?(name)
has_css?("#{sidebar_section_selector(name)}.sidebar-section--collapsed")
end
def switch_to_chat
find(".sidebar__panel-switch-button[data-key='chat']").click
end
@ -183,6 +195,10 @@ module PageObjects
private
def sidebar_section_selector(name)
".sidebar-section[data-section-name='#{name}']"
end
def section_link_present?(name, href: nil, active: false, target: nil, count: 1, present:)
attributes = { exact_text: name }
attributes[:href] = href if href