From df264e49a9392c1b14651585d49d384829199f17 Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Tue, 2 Aug 2022 15:30:13 +0800 Subject: [PATCH] DEV: Supports href attribute for hamburger links API bridge to sidebar (#17750) In the old `decorateWidget("hamburger-menu:generalLinks", callbackFn)` API, the return value of the callback function can either return a `route` or `href`. The API bridge added in de54bdd73d2c501cb22902d638a14cddd2c15520 supported `route` but not `href` and hence the need for this commit. --- .../components/sidebar/community-section.js | 4 + .../app/components/sidebar/section-link.js | 2 + .../discourse/app/lib/plugin-api.js | 24 ++++-- .../community-section/base-section-link.js | 8 +- .../sidebar/custom-community-section-links.js | 81 ++++++++++++++++--- .../components/sidebar/community-section.hbs | 3 +- .../components/sidebar/more-section-links.hbs | 6 +- .../acceptance/sidebar-plugin-api-test.js | 31 +++++++ 8 files changed, 140 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js b/app/assets/javascripts/discourse/app/components/sidebar/community-section.js index dd4668febcc..1ec1ca63c08 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js +++ b/app/assets/javascripts/discourse/app/components/sidebar/community-section.js @@ -9,6 +9,7 @@ import MyPostsSectionLink from "discourse/lib/sidebar/community-section/my-posts import GroupsSectionLink from "discourse/lib/sidebar/community-section/groups-section-link"; import UsersSectionLink from "discourse/lib/sidebar/community-section/users-section-link"; +import { inject as service } from "@ember/service"; import { action } from "@ember/object"; import { next } from "@ember/runloop"; @@ -21,12 +22,15 @@ const MAIN_SECTION_LINKS = [ const MORE_SECTION_LINKS = [GroupsSectionLink, UsersSectionLink]; export default class SidebarCommunitySection extends GlimmerComponent { + @service router; + moreSectionLinks = [...MORE_SECTION_LINKS, ...customSectionLinks].map( (sectionLinkClass) => { return new sectionLinkClass({ topicTrackingState: this.topicTrackingState, currentUser: this.currentUser, appEvents: this.appEvents, + router: this.router, }); } ); diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section-link.js b/app/assets/javascripts/discourse/app/components/sidebar/section-link.js index 1a1b51c6319..6e638f8a85f 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/section-link.js +++ b/app/assets/javascripts/discourse/app/components/sidebar/section-link.js @@ -10,9 +10,11 @@ export default class SectionLink extends GlimmerComponent { get prefixCSS() { const color = this.args.prefixColor; + if (!color || !color.match(/^\w{6}$/)) { return htmlSafe(""); } + return htmlSafe("color: #" + color); } } diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index 63aa424dfcb..cb577ae8d47 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -97,6 +97,7 @@ import { downloadCalendar } from "discourse/lib/download-calendar"; import { consolePrefix } from "discourse/lib/source-identifier"; import { addSectionLink } from "discourse/lib/sidebar/custom-community-section-links"; import { addSidebarSection } from "discourse/lib/sidebar/custom-sections"; +import DiscourseURL from "discourse/lib/url"; // If you add any methods to the API ensure you bump up the version number // based on Semantic Versioning 2.0.0. Please update the changelog at @@ -484,15 +485,27 @@ class PluginApi { if (siteSettings.enable_experimental_sidebar_hamburger) { try { - const { route, label, rawLabel, className } = fn(); + const { href, route, label, rawLabel, className } = fn(); const textContent = rawLabel || I18n.t(label); - this.addCommunitySectionLink({ + const args = { name: className || textContent.replace(/\s+/g, "-").toLowerCase(), - route, title: textContent, text: textContent, - }); + }; + + if (href) { + if (DiscourseURL.isInternal(href)) { + args.href = href; + } else { + // Skip external links support for now + return; + } + } else { + args.route = route; + } + + this.addCommunitySectionLink(args); } catch { deprecated( `Usage of \`api.decorateWidget('hamburger-menu:generalLinks')\` is incompatible with the \`enable_experimental_sidebar_hamburger\` site setting. Please use \`api.addCommunitySectionLink\` instead.` @@ -1699,7 +1712,8 @@ class PluginApi { * * @param {(addCommunitySectionLinkCallback|Object)} arg - A callback function or an Object. * @param {string} arg.name - The name of the link. Needs to be dasherized and lowercase. - * @param {string} arg.route - The Ember route of the link. + * @param {string=} arg.route - The Ember route name to generate the href attribute for the link. + * @param {string=} arg.href - The href attribute for the link. * @param {string} arg.title - The title attribute for the link. * @param {string} arg.text - The text to display for the link. */ diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/community-section/base-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/community-section/base-section-link.js index 69c6e56cdfb..0d91a6959ea 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/community-section/base-section-link.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/community-section/base-section-link.js @@ -2,7 +2,8 @@ * Base class representing a sidebar topics section link interface. */ export default class BaseSectionLink { - constructor({ topicTrackingState, currentUser, appEvents } = {}) { + constructor({ topicTrackingState, currentUser, appEvents, router } = {}) { + this.router = router; this.topicTrackingState = topicTrackingState; this.currentUser = currentUser; this.appEvents = appEvents; @@ -32,6 +33,11 @@ export default class BaseSectionLink { */ get model() {} + /** + * @returns {Object} Models for component. See https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/LinkTo?anchor=LinkTo + */ + get models() {} + /** * @returns {Object} Query parameters for component. See https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/LinkTo?anchor=LinkTo */ diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/custom-community-section-links.js b/app/assets/javascripts/discourse/app/lib/sidebar/custom-community-section-links.js index eb674d16279..fe09ec2fa6a 100644 --- a/app/assets/javascripts/discourse/app/lib/sidebar/custom-community-section-links.js +++ b/app/assets/javascripts/discourse/app/lib/sidebar/custom-community-section-links.js @@ -1,6 +1,42 @@ import BaseSectionLink from "discourse/lib/sidebar/community-section/base-section-link"; export let customSectionLinks = []; +class RouteInfoHelper { + constructor(router, url) { + this.routeInfo = router.recognize(url); + } + + get route() { + return this.routeInfo.name; + } + + get models() { + return this.#getParameters; + } + + get query() { + return this.routeInfo.queryParams; + } + + /** + * Extracted from https://github.com/emberjs/rfcs/issues/658 + * Retrieves all parameters for a `RouteInfo` object and its parents in + * correct oder, so that you can pass them to e.g. + * `transitionTo(routeName, ...params)`. + */ + get #getParameters() { + let allParameters = []; + let current = this.routeInfo; + + do { + const { params, paramNames } = current; + const currentParameters = paramNames.map((n) => params[n]); + allParameters = [...currentParameters, ...allParameters]; + } while ((current = current.parent)); + + return allParameters; + } +} /** * Appends an additional section link under the topics section @@ -8,31 +44,56 @@ export let customSectionLinks = []; * @param {BaseSectionLink} baseSectionLink Factory class to inherit from. * @returns {BaseSectionLink} A class that extends BaseSectionLink. * - * @param {(addSectionLinkCallback|Object)} arg - A callback function or an Object. + * @param {(addSectionLinkCallback|Object)} args - A callback function or an Object. * @param {string} arg.name - The name of the link. Needs to be dasherized and lowercase. - * @param {string} arg.route - The Ember route of the link. - * @param {string} arg.title - The title attribute for the link. + * @param {string=} arg.route - The Ember route name to generate the href attribute for the link. + * @param {string=} arg.href - The href attribute for the link. + * @param {string=} arg.title - The title attribute for the link. * @param {string} arg.text - The text to display for the link. */ -export function addSectionLink(arg) { - if (typeof arg === "function") { - customSectionLinks.push(arg.call(this, BaseSectionLink)); +export function addSectionLink(args) { + if (typeof args === "function") { + customSectionLinks.push(args.call(this, BaseSectionLink)); } else { const klass = class extends BaseSectionLink { + constructor() { + super(...arguments); + + if (args.href) { + this.routeInfoHelper = new RouteInfoHelper(this.router, args.href); + } + } + get name() { - return arg.name; + return args.name; } get route() { - return arg.route; + if (args.href) { + return this.routeInfoHelper.route; + } else { + return args.route; + } + } + + get models() { + if (args.href) { + return this.routeInfoHelper.models; + } + } + + get query() { + if (args.href) { + return this.routeInfoHelper.query; + } } get text() { - return arg.text; + return args.text; } get title() { - return arg.title; + return args.title; } }; diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs index 93dcb3a8bc2..8042f0e4bd4 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs @@ -17,7 +17,8 @@ @content={{sectionLink.text}} @currentWhen={{sectionLink.currentWhen}} @badgeText={{sectionLink.badgeText}} - @model={{sectionLink.model}} /> + @model={{sectionLink.model}} + @models={{sectionLink.models}} /> {{/each}} diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs index 79a1163a8a0..6d27bc7b6bb 100644 --- a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs @@ -7,7 +7,8 @@ @content={{this.activeSectionLink.text}} @currentWhen={{this.activeSectionLink.currentWhen}} @badgeText={{this.activeSectionLink.badgeText}} - @model={{this.activeSectionLink.model}} /> + @model={{this.activeSectionLink.model}} + @models={{this.activeSectionLink.models}} /> {{/if}}