From 7c3ad27de6e51e52b5e24078e287c783147c841d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9rgio=20Saquetim?=
<1108771+megothss@users.noreply.github.com>
Date: Wed, 4 Sep 2024 14:50:53 -0300
Subject: [PATCH] DEV: Remove the old header widgets code (#28390)
Remove the header widget code.
More info can be found in https://meta.discourse.org/t/upcoming-header-changes-preparing-themes-and-plugins/296544
---
.../discourse/app/components/site-header.js | 558 -------------
.../discourse/app/lib/plugin-api.gjs | 86 +-
.../discourse/app/services/header.js | 27 -
.../discourse/app/templates/application.hbs | 37 +-
.../app/widgets/after-header-panel-outlet.js | 8 -
.../app/widgets/before-header-logo-outlet.js | 8 -
.../app/widgets/before-header-panel-outlet.js | 8 -
.../app/widgets/header-bootstrap-mode.js | 8 -
.../discourse/app/widgets/header-contents.js | 36 -
.../app/widgets/header-topic-info.js | 260 -------
.../app/widgets/header-user-tip-shim.js | 8 -
.../discourse/app/widgets/header.js | 735 ------------------
.../app/widgets/home-logo-wrapper-outlet.js | 12 -
.../discourse/app/widgets/home-logo.js | 152 ----
.../discourse/app/widgets/sidebar-toggle.js | 25 -
.../app/widgets/user-status-bubble.js | 20 -
.../tests/acceptance/header-api-test.gjs | 31 -
.../tests/acceptance/mobile-pan-test.js | 3 -
.../discourse/tests/helpers/qunit-helpers.js | 6 -
.../components/site-header-test.js | 235 ------
.../components/widgets/header-test.js | 87 ---
.../components/widgets/home-logo-test.gjs | 231 ------
config/locales/server.en.yml | 1 -
config/site_settings.yml | 8 -
...4500_remove_glimmer_header_mode_setting.rb | 14 +
spec/system/header_spec.rb | 1 -
spec/system/legacy_widget_header_spec.rb | 22 -
27 files changed, 54 insertions(+), 2573 deletions(-)
delete mode 100644 app/assets/javascripts/discourse/app/components/site-header.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/after-header-panel-outlet.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/before-header-logo-outlet.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/before-header-panel-outlet.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/header-bootstrap-mode.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/header-contents.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/header-topic-info.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/header-user-tip-shim.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/header.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/home-logo-wrapper-outlet.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/home-logo.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/sidebar-toggle.js
delete mode 100644 app/assets/javascripts/discourse/app/widgets/user-status-bubble.js
delete mode 100644 app/assets/javascripts/discourse/tests/integration/components/site-header-test.js
delete mode 100644 app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js
delete mode 100644 app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs
create mode 100644 db/migrate/20240815234500_remove_glimmer_header_mode_setting.rb
delete mode 100644 spec/system/legacy_widget_header_spec.rb
diff --git a/app/assets/javascripts/discourse/app/components/site-header.js b/app/assets/javascripts/discourse/app/components/site-header.js
deleted file mode 100644
index d51061671df..00000000000
--- a/app/assets/javascripts/discourse/app/components/site-header.js
+++ /dev/null
@@ -1,558 +0,0 @@
-import { DEBUG } from "@glimmer/env";
-import { getOwner } from "@ember/owner";
-import { schedule } from "@ember/runloop";
-import { waitForPromise } from "@ember/test-waiters";
-import ItsATrap from "@discourse/itsatrap";
-import MountWidget from "discourse/components/mount-widget";
-import { topicTitleDecorators } from "discourse/components/topic-title";
-import scrollLock from "discourse/lib/scroll-lock";
-import SwipeEvents, {
- getMaxAnimationTimeMs,
- shouldCloseMenu,
-} from "discourse/lib/swipe-events";
-import { isDocumentRTL } from "discourse/lib/text-direction";
-import Docking from "discourse/mixins/docking";
-import RerenderOnDoNotDisturbChange from "discourse/mixins/rerender-on-do-not-disturb-change";
-import { isTesting } from "discourse-common/config/environment";
-import discourseLater from "discourse-common/lib/later";
-import { bind, observes } from "discourse-common/utils/decorators";
-
-let _menuPanelClassesToForceDropdown = [];
-
-const SiteHeaderComponent = MountWidget.extend(
- Docking,
- RerenderOnDoNotDisturbChange,
- {
- widget: "header",
- docAt: null,
- dockedHeader: null,
- _animate: false,
- _swipeMenuOrigin: "right",
- _topic: null,
- _itsatrap: null,
- _applicationElement: null,
- _PANEL_WIDTH: 340,
- _swipeEvents: null,
-
- @observes(
- "currentUser.unread_notifications",
- "currentUser.unread_high_priority_notifications",
- "currentUser.all_unread_notifications_count",
- "currentUser.reviewable_count",
- "currentUser.unseen_reviewable_count",
- "session.defaultColorSchemeIsDark",
- "session.darkModeAvailable"
- )
- notificationsChanged() {
- this.queueRerender();
- },
-
- @observes("site.narrowDesktopView")
- narrowDesktopViewChanged() {
- this.eventDispatched("dom:clean", "header");
-
- if (this._dropDownHeaderEnabled()) {
- this.appEvents.on(
- "sidebar-hamburger-dropdown:rendered",
- this,
- "_animateMenu"
- );
- }
- },
-
- _animateOpening(panel, event = null) {
- const headerCloak = document.querySelector(".header-cloak");
- let durationMs = getMaxAnimationTimeMs();
- if (event && this.pxClosed > 0) {
- durationMs = getMaxAnimationTimeMs(
- this.pxClosed / Math.abs(event.velocityX)
- );
- }
- const timing = {
- duration: durationMs,
- fill: "forwards",
- easing: "ease-out",
- };
- panel.animate([{ transform: `translate3d(0, 0, 0)` }], timing);
- headerCloak.animate([{ opacity: 1 }], timing);
- this.pxClosed = null;
- },
-
- _animateClosing(event, panel, menuOrigin) {
- this._animate = true;
- const headerCloak = document.querySelector(".header-cloak");
- let durationMs = getMaxAnimationTimeMs();
- if (event && this.pxClosed > 0) {
- const distancePx = this._PANEL_WIDTH - this.pxClosed;
- durationMs = getMaxAnimationTimeMs(
- distancePx / Math.abs(event.velocityX)
- );
- }
- const timing = {
- duration: durationMs,
- fill: "forwards",
- };
-
- let endPosition = -this._PANEL_WIDTH; //origin left
- if (menuOrigin === "right") {
- endPosition = this._PANEL_WIDTH;
- }
- panel
- .animate([{ transform: `translate3d(${endPosition}px, 0, 0)` }], timing)
- .finished.then(() => {
- schedule("afterRender", () => {
- this.eventDispatched("dom:clean", "header");
- });
- });
-
- headerCloak.animate([{ opacity: 0 }], timing);
- this.pxClosed = null;
- },
-
- _leftMenuClass() {
- return isDocumentRTL() ? "user-menu" : "hamburger-panel";
- },
-
- @bind
- onSwipeStart(event) {
- const e = event.detail;
- const center = e.center;
- const swipeOverValidElement = document
- .elementsFromPoint(center.x, center.y)
- .some(
- (ele) =>
- ele.classList.contains("panel-body") ||
- ele.classList.contains("header-cloak")
- );
- if (
- swipeOverValidElement &&
- (e.direction === "left" || e.direction === "right")
- ) {
- this.movingElement = document.querySelector(".menu-panel");
- this.cloakElement = document.querySelector(".header-cloak");
- scrollLock(true, document.querySelector(".panel-body"));
- } else {
- event.preventDefault();
- }
- },
-
- @bind
- onSwipeEnd(event) {
- const e = event.detail;
- const menuPanels = document.querySelectorAll(".menu-panel");
- const menuOrigin = this._swipeMenuOrigin;
- scrollLock(false, document.querySelector(".panel-body"));
- menuPanels.forEach((panel) => {
- if (shouldCloseMenu(e, menuOrigin)) {
- this._animateClosing(e, panel, menuOrigin);
- } else {
- this._animateOpening(panel, e);
- }
- });
- },
-
- @bind
- onSwipeCancel() {
- const menuPanels = document.querySelectorAll(".menu-panel");
- scrollLock(false, document.querySelector(".panel-body"));
- menuPanels.forEach((panel) => {
- this._animateOpening(panel);
- });
- },
-
- @bind
- onSwipe(event) {
- const e = event.detail;
- const panel = this.movingElement;
- const headerCloak = this.cloakElement;
-
- //origin left
- this.pxClosed = Math.max(0, -e.deltaX);
- let translation = -this.pxClosed;
- if (this._swipeMenuOrigin === "right") {
- this.pxClosed = Math.max(0, e.deltaX);
- translation = this.pxClosed;
- }
- panel.animate([{ transform: `translate3d(${translation}px, 0, 0)` }], {
- fill: "forwards",
- });
- headerCloak.animate(
- [
- {
- opacity: (this._PANEL_WIDTH - this.pxClosed) / this._PANEL_WIDTH,
- },
- ],
- { fill: "forwards" }
- );
- },
-
- dockCheck() {
- const header = this.header;
-
- if (this.docAt === null) {
- if (!header) {
- return;
- }
- this.docAt = header.offsetTop;
- }
-
- const main = (this._applicationElement ??=
- document.querySelector(".ember-application"));
- const offsetTop = main ? main.offsetTop : 0;
- const offset = window.pageYOffset - offsetTop;
- if (offset >= this.docAt) {
- if (!this.dockedHeader) {
- document.body.classList.add("docked");
- this.dockedHeader = true;
- }
- } else {
- if (this.dockedHeader) {
- document.body.classList.remove("docked");
- this.dockedHeader = false;
- }
- }
- },
-
- setTopic() {
- const header = getOwner(this).lookup("service:header");
- if (header.topicInfoVisible) {
- this._topic = header.topicInfo;
- } else {
- this._topic = null;
- }
- this.eventDispatched("dom:clean", "header");
- this.queueRerender();
- },
-
- willRender() {
- this._super(...arguments);
-
- if (this.get("currentUser.staff")) {
- document.body.classList.add("staff");
- }
- },
-
- didInsertElement() {
- this._super(...arguments);
- this._resizeDiscourseMenuPanel = () => this.afterRender();
- window.addEventListener("resize", this._resizeDiscourseMenuPanel);
-
- const headerService = getOwner(this).lookup("service:header");
- headerService.addObserver("topicInfoVisible", this, "setTopic");
- this.setTopic();
-
- this.appEvents.on("user-menu:rendered", this, "_animateMenu");
-
- if (this._dropDownHeaderEnabled()) {
- this.appEvents.on(
- "sidebar-hamburger-dropdown:rendered",
- this,
- "_animateMenu"
- );
- }
-
- this.dispatch("notifications:changed", "user-notifications");
- this.dispatch("header:keyboard-trigger", "header");
- this.dispatch("user-menu:navigation", "user-menu");
-
- this.appEvents.on("dom:clean", this, "_cleanDom");
-
- if (this.currentUser) {
- this.currentUser.on("status-changed", this, "queueRerender");
- }
-
- const header = document.querySelector("header.d-header");
- this._itsatrap = new ItsATrap(header);
- const dirs = ["up", "down"];
- this._itsatrap.bind(dirs, (e) => this._handleArrowKeysNav(e));
- },
-
- _handleArrowKeysNav(event) {
- const activeTab = document.querySelector(
- ".menu-tabs-container .btn.active"
- );
- if (activeTab) {
- let activeTabNumber = Number(
- document.activeElement.dataset.tabNumber ||
- activeTab.dataset.tabNumber
- );
- const maxTabNumber =
- document.querySelectorAll(".menu-tabs-container .btn").length - 1;
- const isNext = event.key === "ArrowDown";
- let nextTab = isNext ? activeTabNumber + 1 : activeTabNumber - 1;
- if (isNext && nextTab > maxTabNumber) {
- nextTab = 0;
- }
- if (!isNext && nextTab < 0) {
- nextTab = maxTabNumber;
- }
- event.preventDefault();
- document
- .querySelector(
- `.menu-tabs-container .btn[data-tab-number='${nextTab}']`
- )
- .focus();
- }
- },
-
- _cleanDom() {
- // For performance, only trigger a re-render if any menu panels are visible
- if (this.element.querySelector(".menu-panel")) {
- this.eventDispatched("dom:clean", "header");
- }
- },
-
- willDestroyElement() {
- this._super(...arguments);
-
- window.removeEventListener("resize", this._resizeDiscourseMenuPanel);
- getOwner(this)
- .lookup("service:header")
- .removeObserver("topicInfoVisible", this, "setTopic");
- this.appEvents.off("dom:clean", this, "_cleanDom");
- this.appEvents.off("user-menu:rendered", this, "_animateMenu");
-
- if (this._dropDownHeaderEnabled()) {
- this.appEvents.off(
- "sidebar-hamburger-dropdown:rendered",
- this,
- "_animateMenu"
- );
- }
-
- if (this.currentUser) {
- this.currentUser.off("status-changed", this, "queueRerender");
- }
-
- this._itsatrap?.destroy();
- this._itsatrap = null;
- },
-
- buildArgs() {
- return {
- topic: this._topic,
- canSignUp: this.canSignUp,
- sidebarEnabled: this.sidebarEnabled,
- showSidebar: this.showSidebar,
- navigationMenuQueryParamOverride: this.navigationMenuQueryParamOverride,
- };
- },
-
- afterRender() {
- const headerTitle = document.querySelector(".header-title .topic-link");
- if (headerTitle && this._topic) {
- topicTitleDecorators.forEach((cb) =>
- cb(this._topic, headerTitle, "header-title")
- );
- }
- this._animateMenu();
- },
-
- _animateMenu() {
- const menuPanels = document.querySelectorAll(".menu-panel");
-
- if (menuPanels.length === 0) {
- this._animate = this.site.mobileView || this.site.narrowDesktopView;
- return;
- }
-
- let viewMode =
- this.site.mobileView || this.site.narrowDesktopView
- ? "slide-in"
- : "drop-down";
-
- menuPanels.forEach((panel) => {
- if (menuPanelContainsClass(panel)) {
- viewMode = "drop-down";
- this._animate = false;
- }
-
- const headerCloak = document.querySelector(".header-cloak");
-
- panel.classList.remove("drop-down");
- panel.classList.remove("slide-in");
- panel.classList.add(viewMode);
-
- if (this._animate) {
- let animationFinished = null;
- let finalPosition = this._PANEL_WIDTH;
- this._swipeMenuOrigin = "right";
- if (
- (this.site.mobileView || this.site.narrowDesktopView) &&
- panel.parentElement.classList.contains(this._leftMenuClass())
- ) {
- this._swipeMenuOrigin = "left";
- finalPosition = -this._PANEL_WIDTH;
- }
- animationFinished = panel.animate(
- [{ transform: `translate3d(${finalPosition}px, 0, 0)` }],
- {
- fill: "forwards",
- }
- ).finished;
-
- if (isTesting()) {
- waitForPromise(animationFinished);
- }
-
- headerCloak.animate([{ opacity: 0 }], { fill: "forwards" });
- headerCloak.style.display = "block";
-
- animationFinished.then(() => {
- if (isTesting()) {
- this._animateOpening(panel);
- } else {
- discourseLater(() => this._animateOpening(panel));
- }
- });
- }
-
- this._animate = false;
- });
- },
-
- _dropDownHeaderEnabled() {
- return !this.sidebarEnabled || this.site.narrowDesktopView;
- },
- }
-);
-
-function menuPanelContainsClass(menuPanel) {
- if (!_menuPanelClassesToForceDropdown) {
- return false;
- }
-
- // Check if any of the classNames are present in the node's classList
- for (let className of _menuPanelClassesToForceDropdown) {
- if (menuPanel.classList.contains(className)) {
- // Found a matching class
- return true;
- }
- }
-
- // No matching class found
- return false;
-}
-
-export function forceDropdownForMenuPanels(classNames) {
- // If classNames is a string, convert it to an array
- if (typeof classNames === "string") {
- classNames = [classNames];
- }
- return _menuPanelClassesToForceDropdown.push(...classNames);
-}
-
-export default SiteHeaderComponent.extend({
- classNames: ["d-header-wrap"],
- classNameBindings: ["site.mobileView::drop-down-mode"],
- headerWrap: null,
- header: null,
-
- init() {
- this._super(...arguments);
- this._resizeObserver = null;
- },
-
- @bind
- updateHeaderOffset() {
- // Safari likes overscolling the page (on both iOS and macOS).
- // This shows up as a negative value in window.scrollY.
- // We can use this to offset the headerWrap's top offset to avoid
- // jitteriness and bad positioning.
- const windowOverscroll = Math.min(0, window.scrollY);
-
- // The headerWrap's top offset can also be a negative value on Safari,
- // because of the changing height of the viewport (due to the URL bar).
- // For our use case, it's best to ensure this is clamped to 0.
- const headerWrapTop = Math.max(
- 0,
- Math.floor(this.headerWrap.getBoundingClientRect().top)
- );
- let offsetTop = headerWrapTop + windowOverscroll;
-
- if (DEBUG && isTesting()) {
- offsetTop -= document
- .getElementById("ember-testing-container")
- .getBoundingClientRect().top;
-
- offsetTop -= 1; // For 1px border on testing container
- }
-
- const documentStyle = document.documentElement.style;
-
- const currentValue =
- parseInt(documentStyle.getPropertyValue("--header-offset"), 10) || 0;
- const newValue = this.headerWrap.offsetHeight + offsetTop;
-
- if (currentValue !== newValue) {
- documentStyle.setProperty("--header-offset", `${newValue}px`);
- }
- },
-
- @bind
- onScroll() {
- schedule("afterRender", this.updateHeaderOffset);
- },
-
- didInsertElement() {
- this._super(...arguments);
-
- this.appEvents.on("site-header:force-refresh", this, "queueRerender");
-
- this.headerWrap = document.querySelector(".d-header-wrap");
-
- if (this.headerWrap) {
- schedule("afterRender", () => {
- this.header = this.headerWrap.querySelector("header.d-header");
- this.updateHeaderOffset();
- const headerTop = this.header.offsetTop;
- document.documentElement.style.setProperty(
- "--header-top",
- `${headerTop}px`
- );
- });
-
- window.addEventListener("scroll", this.onScroll, {
- passive: true,
- });
- }
-
- this._resizeObserver = new ResizeObserver((entries) => {
- for (let entry of entries) {
- if (entry.contentRect) {
- const headerTop = this.header?.offsetTop;
- document.documentElement.style.setProperty(
- "--header-top",
- `${headerTop}px`
- );
- this.updateHeaderOffset();
- }
- }
- });
-
- this._resizeObserver.observe(this.headerWrap);
-
- this._swipeEvents = new SwipeEvents(this.element);
- if (this.site.mobileView) {
- this._swipeEvents.addTouchListeners();
- this.element.addEventListener("swipestart", this.onSwipeStart);
- this.element.addEventListener("swipeend", this.onSwipeEnd);
- this.element.addEventListener("swipecancel", this.onSwipeCancel);
- this.element.addEventListener("swipe", this.onSwipe);
- }
- },
-
- willDestroyElement() {
- this._super(...arguments);
- window.removeEventListener("scroll", this.onScroll);
- this._resizeObserver?.disconnect();
- this.appEvents.off("site-header:force-refresh", this, "queueRerender");
- if (this.site.mobileView) {
- this.element.removeEventListener("swipestart", this.onSwipeStart);
- this.element.removeEventListener("swipeend", this.onSwipeEnd);
- this.element.removeEventListener("swipecancel", this.onSwipeCancel);
- this.element.removeEventListener("swipe", this.onSwipe);
- this._swipeEvents.removeTouchListeners();
- }
- },
-});
diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
index 470fe28a53e..a923fa31214 100644
--- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
+++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
@@ -23,9 +23,7 @@ import { forceDropdownForMenuPanels as glimmerForceDropdownForMenuPanels } from
import { addGlobalNotice } from "discourse/components/global-notice";
import { headerButtonsDAG } from "discourse/components/header";
import { headerIconsDAG } from "discourse/components/header/icons";
-import MountWidget, {
- addWidgetCleanCallback,
-} from "discourse/components/mount-widget";
+import { addWidgetCleanCallback } from "discourse/components/mount-widget";
import { addPluginOutletDecorator } from "discourse/components/plugin-connector";
import {
addPluginReviewableParam,
@@ -40,7 +38,6 @@ import {
} from "discourse/components/search-menu/results/random-quick-tip";
import { addOnKeyUpCallback } from "discourse/components/search-menu/search-term";
import { REFRESH_COUNTS_APP_EVENT_NAME as REFRESH_USER_SIDEBAR_CATEGORIES_SECTION_COUNTS_APP_EVENT_NAME } from "discourse/components/sidebar/user/categories-section";
-import { forceDropdownForMenuPanels } from "discourse/components/site-header";
import { addTopicParticipantClassesCallback } from "discourse/components/topic-map/topic-participant";
import { setDesktopScrollAreaHeight } from "discourse/components/topic-timeline/container";
import { addTopicTitleDecorator } from "discourse/components/topic-title";
@@ -127,7 +124,6 @@ import {
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
import { setNotificationsLimit } from "discourse/routes/user-notifications";
import { addComposerSaveErrorCallback } from "discourse/services/composer";
-import { attachAdditionalPanel } from "discourse/widgets/header";
import { addPostClassesCallback } from "discourse/widgets/post";
import { addDecorator } from "discourse/widgets/post-cooked";
import {
@@ -165,20 +161,6 @@ import { addImageWrapperButton } from "discourse-markdown-it/features/image-cont
import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser";
import { modifySelectKit } from "select-kit/mixins/plugin-api";
-const DEPRECATED_HEADER_WIDGETS = [
- "header",
- "site-header",
- "header-contents",
- "header-buttons",
- "user-status-bubble",
- "sidebar-toggle",
- "header-icons",
- "header-topic-info",
- "header-notifications",
- "home-logo",
- "user-dropdown",
-];
-
const appliedModificationIds = new WeakMap();
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
@@ -732,7 +714,7 @@ class PluginApi {
**/
decorateWidget(name, fn) {
const widgetName = name.split(":")[0];
- this.#deprecatedHeaderWidgetOverride(widgetName, "decorateWidget");
+ this.#deprecatedWidgetOverride(widgetName, "decorateWidget");
decorateWidget(name, fn);
}
@@ -763,7 +745,7 @@ class PluginApi {
return;
}
- this.#deprecatedHeaderWidgetOverride(widget, "attachWidgetAction");
+ this.#deprecatedWidgetOverride(widget, "attachWidgetAction");
widgetClass.prototype[actionName] = fn;
}
@@ -1108,7 +1090,7 @@ class PluginApi {
*
**/
changeWidgetSetting(widgetName, settingName, newValue) {
- this.#deprecatedHeaderWidgetOverride(widgetName, "changeWidgetSetting");
+ this.#deprecatedWidgetOverride(widgetName, "changeWidgetSetting");
changeSetting(widgetName, settingName, newValue);
}
@@ -1142,7 +1124,7 @@ class PluginApi {
**/
reopenWidget(name, args) {
- this.#deprecatedHeaderWidgetOverride(name, "reopenWidget");
+ this.#deprecatedWidgetOverride(name, "reopenWidget");
return reopenWidget(name, args);
}
@@ -1169,16 +1151,12 @@ class PluginApi {
* and returns a hash of values to pass to attach
*
**/
- addHeaderPanel(name, toggle, transformAttrs) {
- deprecated(
- "addHeaderPanel will be removed as part of the glimmer header upgrade. Use api.headerIcons instead.",
- {
- id: "discourse.add-header-panel",
- url: "https://meta.discourse.org/t/296544",
- }
+ addHeaderPanel() {
+ // eslint-disable-next-line no-console
+ console.error(
+ consolePrefix(),
+ `api.addHeaderPanel: This API was decommissioned. Use api.headerIcons instead.`
);
- this.container.lookup("service:header").anyWidgetHeaderOverrides = true;
- attachAdditionalPanel(name, toggle, transformAttrs);
}
/**
@@ -2141,19 +2119,12 @@ class PluginApi {
* ```
*
**/
+ // eslint-disable-next-line no-unused-vars
addToHeaderIcons(icon) {
- deprecated(
- "addToHeaderIcons has been deprecated. Use api.headerIcons instead.",
- {
- id: "discourse.add-header-icons",
- url: "https://meta.discourse.org/t/296544",
- }
- );
-
- this.headerIcons.add(
- icon,
- ,
- { before: "search" }
+ // eslint-disable-next-line no-console
+ console.error(
+ consolePrefix(),
+ `api.addToHeaderIcons: This API was decommissioned. Use api.headerIcons instead.`
);
}
@@ -2397,7 +2368,6 @@ class PluginApi {
*
*/
forceDropdownForMenuPanels(classNames) {
- forceDropdownForMenuPanels(classNames);
glimmerForceDropdownForMenuPanels(classNames);
}
@@ -3282,18 +3252,20 @@ class PluginApi {
addLegacyAboutPageStat(name);
}
- #deprecatedHeaderWidgetOverride(widgetName, override) {
- if (DEPRECATED_HEADER_WIDGETS.includes(widgetName)) {
- this.container.lookup("service:header").anyWidgetHeaderOverrides = true;
- deprecated(
- `The ${widgetName} widget has been deprecated and ${override} is no longer a supported override.`,
- {
- since: "v3.3.0.beta1-dev",
- id: "discourse.header-widget-overrides",
- url: "https://meta.discourse.org/t/316549",
- }
- );
- }
+ // eslint-disable-next-line no-unused-vars
+ #deprecatedWidgetOverride(widgetName, override) {
+ // insert here the code to handle widget deprecations, e.g. for the header widgets we used:
+ // if (DEPRECATED_HEADER_WIDGETS.includes(widgetName)) {
+ // this.container.lookup("service:header").anyWidgetHeaderOverrides = true;
+ // deprecated(
+ // `The ${widgetName} widget has been deprecated and ${override} is no longer a supported override.`,
+ // {
+ // since: "v3.3.0.beta1-dev",
+ // id: "discourse.header-widget-overrides",
+ // url: "https://meta.discourse.org/t/316549",
+ // }
+ // );
+ // }
}
}
diff --git a/app/assets/javascripts/discourse/app/services/header.js b/app/assets/javascripts/discourse/app/services/header.js
index dafe0cf9e88..57992494915 100644
--- a/app/assets/javascripts/discourse/app/services/header.js
+++ b/app/assets/javascripts/discourse/app/services/header.js
@@ -28,7 +28,6 @@ export default class Header extends Service {
@tracked hamburgerVisible = false;
@tracked userVisible = false;
- @tracked anyWidgetHeaderOverrides = false;
#hiders = new TrackedMap();
@@ -72,32 +71,6 @@ export default class Header extends Service {
return true;
}
- get useGlimmerHeader() {
- if (this.siteSettings.glimmer_header_mode === "disabled") {
- return false;
- } else if (this.siteSettings.glimmer_header_mode === "enabled") {
- if (this.anyWidgetHeaderOverrides) {
- // eslint-disable-next-line no-console
- console.error(
- "Using modern 'glimmer' header, even though there are themes and/or plugins using deprecated APIs. Deprecated header customizations will be broken. (glimmer_header_mode: enabled) https://meta.discourse.org/t/316549"
- );
- }
-
- return true;
- } else {
- // Auto
- if (this.anyWidgetHeaderOverrides) {
- // eslint-disable-next-line no-console
- console.warn(
- "Using legacy 'widget' header because themes and/or plugins are using deprecated APIs. (glimmer_header_mode: auto) https://meta.discourse.org/t/316549"
- );
- return false;
- } else {
- return true;
- }
- }
- }
-
registerHider(ref, buttons) {
const validButtons = buttons
.map((button) => {
diff --git a/app/assets/javascripts/discourse/app/templates/application.hbs b/app/assets/javascripts/discourse/app/templates/application.hbs
index 73159bb226b..c14292ae9c4 100644
--- a/app/assets/javascripts/discourse/app/templates/application.hbs
+++ b/app/assets/javascripts/discourse/app/templates/application.hbs
@@ -12,32 +12,17 @@
/>
{{#if this.showSiteHeader}}
- {{#if this.header.useGlimmerHeader}}
-
- {{else}}
-
- {{/if}}
+
{{/if}}
diff --git a/app/assets/javascripts/discourse/app/widgets/after-header-panel-outlet.js b/app/assets/javascripts/discourse/app/widgets/after-header-panel-outlet.js
deleted file mode 100644
index a293e58d9e6..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/after-header-panel-outlet.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "after-header-panel-outlet",
- "div.after-header-panel-outlet",
- hbs` `
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/before-header-logo-outlet.js b/app/assets/javascripts/discourse/app/widgets/before-header-logo-outlet.js
deleted file mode 100644
index 1fdf13214ef..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/before-header-logo-outlet.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "before-header-logo-outlet",
- "div.before-header-logo-outlet",
- hbs` `
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/before-header-panel-outlet.js b/app/assets/javascripts/discourse/app/widgets/before-header-panel-outlet.js
deleted file mode 100644
index 334dbdd13e7..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/before-header-panel-outlet.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "before-header-panel-outlet",
- "div.before-header-panel-outlet",
- hbs` `
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/header-bootstrap-mode.js b/app/assets/javascripts/discourse/app/widgets/header-bootstrap-mode.js
deleted file mode 100644
index 0f11aeed11c..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/header-bootstrap-mode.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "header-bootstrap-mode",
- "div.d-header-mode",
- hbs``
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/header-contents.js b/app/assets/javascripts/discourse/app/widgets/header-contents.js
deleted file mode 100644
index 203b78c2ddd..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/header-contents.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import hbs from "discourse/widgets/hbs-compiler";
-import { createWidget } from "discourse/widgets/widget";
-
-createWidget("header-contents", {
- tagName: "div.contents",
- transform() {
- return {
- showBootstrapMode: this.currentUser?.staff && this.site.desktopView,
- };
- },
- template: hbs`
- {{#if this.site.desktopView}}
- {{#if attrs.sidebarEnabled}}
- {{sidebar-toggle attrs=attrs}}
- {{/if}}
- {{/if}}
-
- {{before-header-logo-outlet attrs=attrs}}
-
- {{home-logo-wrapper-outlet attrs=attrs}}
-
- {{#if attrs.topic}}
- {{header-topic-info attrs=attrs}}
- {{else if this.siteSettings.bootstrap_mode_enabled}}
- {{#if transformed.showBootstrapMode}}
- {{header-bootstrap-mode attrs=attrs}}
- {{/if}}
- {{/if}}
-
- {{before-header-panel-outlet attrs=attrs}}
-
-
{{yield}}
-
- {{after-header-panel-outlet attrs=attrs}}
- `,
-});
diff --git a/app/assets/javascripts/discourse/app/widgets/header-topic-info.js b/app/assets/javascripts/discourse/app/widgets/header-topic-info.js
deleted file mode 100644
index 77585b1fad1..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/header-topic-info.js
+++ /dev/null
@@ -1,260 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { h } from "virtual-dom";
-import renderTags from "discourse/lib/render-tags";
-import { topicFeaturedLinkNode } from "discourse/lib/render-topic-featured-link";
-import DiscourseURL from "discourse/lib/url";
-import { avatarImg } from "discourse/widgets/post";
-import RawHtml from "discourse/widgets/raw-html";
-import RenderGlimmer from "discourse/widgets/render-glimmer";
-import { applyDecorators, createWidget } from "discourse/widgets/widget";
-import getURL from "discourse-common/lib/get-url";
-import { iconNode } from "discourse-common/lib/icon-library";
-import I18n from "discourse-i18n";
-
-createWidget("topic-header-participant", {
- tagName: "span",
-
- buildClasses(attrs) {
- return `trigger-${attrs.type}-card`;
- },
-
- html(attrs) {
- const { user, group } = attrs;
- let content, url;
-
- if (attrs.type === "user") {
- content = avatarImg("tiny", {
- template: user.avatar_template,
- username: user.username,
- });
- url = user.get("path");
- } else {
- content = [iconNode("users")];
- url = getURL(`/g/${group.name}`);
- content.push(h("span", group.name));
- }
-
- return h(
- "a.icon",
- {
- attributes: {
- href: url,
- "data-auto-route": true,
- title: attrs.username,
- },
- },
- content
- );
- },
-
- click(e) {
- this.appEvents.trigger(
- `topic-header:trigger-${this.attrs.type}-card`,
- this.attrs.username,
- e.target,
- e
- );
- e.preventDefault();
- },
-});
-
-export default createWidget("header-topic-info", {
- tagName: "div.extra-info-wrapper",
- contents: null,
- title: null,
-
- buildClasses(attrs, state) {
- this.buildAttributes(attrs, state);
- return this.containerClassName();
- },
-
- buildFancyTitleClass() {
- const baseClass = ["topic-link"];
- const flatten = (array) => [].concat.apply([], array);
- const extraClass = flatten(
- applyDecorators(this, "fancyTitleClass", this.attrs, this.state)
- );
- return baseClass.concat(extraClass).filter(Boolean).join(" ");
- },
-
- buildAttributes(attrs, state) {
- const topic = attrs.topic;
-
- const heading = [];
-
- const showPM = !topic.get("is_warning") && topic.get("isPrivateMessage");
- if (showPM) {
- const href = this.currentUser && this.currentUser.pmPath(topic);
- if (href) {
- heading.push(
- h(
- "a.private-message-glyph-wrapper",
- {
- attributes: { href, "aria-label": I18n.t("user.messages.inbox") },
- },
- iconNode("envelope", { class: "private-message-glyph" })
- )
- );
- }
- }
- const loaded = topic.get("details.loaded");
- const fancyTitle = topic.get("fancyTitle");
- const href = topic.get("url");
-
- if (fancyTitle && href) {
- heading.push(this.attach("topic-status", attrs));
-
- const titleHTML = new RawHtml({ html: `${fancyTitle}` });
- heading.push(
- this.attach("link", {
- className: this.buildFancyTitleClass(),
- action: "jumpToTopPost",
- href,
- attributes: { "data-topic-id": topic.get("id") },
- contents: () => titleHTML,
- })
- );
-
- heading.push(
- new RenderGlimmer(
- this,
- "span.header-topic-title-suffix",
- hbs``,
- {
- outletArgs: {
- topic,
- },
- }
- )
- );
- }
-
- this.headerElements = [h("h1.header-title", heading)];
- const category = topic.get("category");
-
- if (loaded || category) {
- if (
- category &&
- (!category.isUncategorizedCategory ||
- !this.siteSettings.suppress_uncategorized_badge)
- ) {
- const parentCategory = category.get("parentCategory");
- const categories = [];
- if (parentCategory) {
- if (
- this.siteSettings.max_category_nesting > 2 &&
- this.site.desktopView
- ) {
- const grandParentCategory = parentCategory.get("parentCategory");
- if (grandParentCategory) {
- categories.push(
- this.attach("category-link", { category: grandParentCategory })
- );
- }
- }
-
- categories.push(
- this.attach("category-link", { category: parentCategory })
- );
- }
- categories.push(
- this.attach("category-link", { category, hideParent: true })
- );
-
- this.headerElements.push(h("div.categories-wrapper", categories));
- }
-
- let extra = [];
- const tags = renderTags(topic);
- if (tags && tags.length > 0) {
- extra.push(new RawHtml({ html: tags }));
- }
-
- if (showPM) {
- const maxHeaderParticipants = extra.length > 0 ? 5 : 10;
- const participants = [];
- const topicDetails = topic.get("details");
- const totalParticipants =
- topicDetails.allowed_users.length +
- topicDetails.allowed_groups.length;
-
- topicDetails.allowed_users.some((user) => {
- if (participants.length >= maxHeaderParticipants) {
- return true;
- }
-
- participants.push(
- this.attach("topic-header-participant", {
- type: "user",
- user,
- username: user.username,
- })
- );
- });
-
- topicDetails.allowed_groups.some((group) => {
- if (participants.length >= maxHeaderParticipants) {
- return true;
- }
-
- participants.push(
- this.attach("topic-header-participant", {
- type: "group",
- group,
- username: group.name,
- })
- );
- });
-
- if (totalParticipants > maxHeaderParticipants) {
- const remaining = totalParticipants - maxHeaderParticipants;
- participants.push(
- this.attach("link", {
- className: "more-participants",
- action: "jumpToTopPost",
- href,
- attributes: { "data-topic-id": topic.get("id") },
- contents: () => `+${remaining}`,
- })
- );
- }
-
- extra.push(h("div.topic-header-participants", participants));
- }
-
- extra = extra.concat(applyDecorators(this, "after-tags", attrs, state));
-
- if (this.siteSettings.topic_featured_link_enabled) {
- const featured = topicFeaturedLinkNode(attrs.topic);
- if (featured) {
- extra.push(featured);
- }
- }
- if (extra.length) {
- this.headerElements.push(h("div.topic-header-extra", extra));
- }
- }
- this.contents = h("div.title-wrapper", this.headerElements);
- },
-
- html() {
- return h(
- "div.extra-info",
- { className: this.containerClassName() },
- this.contents
- );
- },
-
- containerClassName() {
- return this.headerElements.length > 1 ? "two-rows" : "";
- },
-
- jumpToTopPost() {
- const topic = this.attrs.topic;
- if (topic) {
- DiscourseURL.routeTo(topic.get("firstPostUrl"), {
- keepFilter: true,
- });
- }
- },
-});
diff --git a/app/assets/javascripts/discourse/app/widgets/header-user-tip-shim.js b/app/assets/javascripts/discourse/app/widgets/header-user-tip-shim.js
deleted file mode 100644
index 949350e5d27..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/header-user-tip-shim.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "header-user-tip-shim",
- "div.header-user-tip-shim",
- hbs``
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js
deleted file mode 100644
index 7f6b42d5695..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/header.js
+++ /dev/null
@@ -1,735 +0,0 @@
-import { schedule } from "@ember/runloop";
-import { hbs } from "ember-cli-htmlbars";
-import $ from "jquery";
-import { h } from "virtual-dom";
-import { headerButtonsDAG } from "discourse/components/header";
-import { headerIconsDAG } from "discourse/components/header/icons";
-import { addExtraUserClasses } from "discourse/helpers/user-avatar";
-import { wantsNewWindow } from "discourse/lib/intercept-click";
-import scrollLock from "discourse/lib/scroll-lock";
-import { isDocumentRTL } from "discourse/lib/text-direction";
-import DiscourseURL from "discourse/lib/url";
-import { scrollTop } from "discourse/mixins/scroll-top";
-import { avatarImg } from "discourse/widgets/post";
-import RenderGlimmer, {
- registerWidgetShim,
-} from "discourse/widgets/render-glimmer";
-import { createWidget } from "discourse/widgets/widget";
-import { isTesting } from "discourse-common/config/environment";
-import getURL from "discourse-common/lib/get-url";
-import { iconNode } from "discourse-common/lib/icon-library";
-import discourseLater from "discourse-common/lib/later";
-import I18n from "discourse-i18n";
-
-const SEARCH_BUTTON_ID = "search-button";
-
-let _extraHeaderIcons;
-clearExtraHeaderIcons();
-
-let _extraHeaderButtons;
-clearExtraHeaderButtons();
-
-export function clearExtraHeaderIcons() {
- _extraHeaderIcons = headerIconsDAG();
-}
-
-export function clearExtraHeaderButtons() {
- _extraHeaderButtons = headerButtonsDAG();
-}
-
-export const dropdown = {
- buildClasses(attrs) {
- let classes = attrs.classNames || [];
- if (attrs.active) {
- classes.push("active");
- }
-
- return classes;
- },
-
- click(e) {
- if (wantsNewWindow(e)) {
- return;
- }
- e.preventDefault();
- if (!this.attrs.active) {
- this.sendWidgetAction(this.attrs.action);
- }
- },
-};
-
-createWidget("header-notifications", {
- services: ["user-tips"],
-
- settings: {
- avatarSize: "medium",
- },
-
- html(attrs) {
- const { user } = attrs;
-
- let avatarAttrs = {
- template: user.get("avatar_template"),
- username: user.get("username"),
- };
-
- if (this.siteSettings.enable_names) {
- avatarAttrs.name = user.get("name");
- }
-
- const contents = [
- avatarImg(
- this.settings.avatarSize,
- Object.assign(
- { alt: "user.avatar.header_title" },
- addExtraUserClasses(user, avatarAttrs)
- )
- ),
- ];
-
- if (this.currentUser && this._shouldHighlightAvatar()) {
- contents.push(this.attach("header-user-tip-shim"));
- }
-
- if (this.currentUser.status) {
- contents.push(this.attach("user-status-bubble", this.currentUser.status));
- }
-
- if (user.isInDoNotDisturb()) {
- contents.push(
- h("div.do-not-disturb-background", iconNode("discourse-dnd"))
- );
- } else {
- if (user.new_personal_messages_notifications_count) {
- contents.push(
- this.attach("link", {
- action: attrs.action,
- className: "badge-notification with-icon new-pms",
- icon: "envelope",
- omitSpan: true,
- title: "notifications.tooltip.new_message_notification",
- titleOptions: {
- count: user.new_personal_messages_notifications_count,
- },
- attributes: {
- "aria-label": I18n.t(
- "notifications.tooltip.new_message_notification",
- {
- count: user.new_personal_messages_notifications_count,
- }
- ),
- },
- })
- );
- } else if (user.unseen_reviewable_count) {
- contents.push(
- this.attach("link", {
- action: attrs.action,
- className: "badge-notification with-icon new-reviewables",
- icon: "flag",
- omitSpan: true,
- title: "notifications.tooltip.new_reviewable",
- titleOptions: { count: user.unseen_reviewable_count },
- attributes: {
- "aria-label": I18n.t("notifications.tooltip.new_reviewable", {
- count: user.unseen_reviewable_count,
- }),
- },
- })
- );
- } else if (user.all_unread_notifications_count) {
- contents.push(
- this.attach("link", {
- action: attrs.action,
- className: "badge-notification unread-notifications",
- rawLabel: user.all_unread_notifications_count,
- omitSpan: true,
- title: "notifications.tooltip.regular",
- titleOptions: { count: user.all_unread_notifications_count },
- attributes: {
- "aria-label": I18n.t("user.notifications"),
- },
- })
- );
- }
- }
-
- return contents;
- },
-
- _shouldHighlightAvatar() {
- const attrs = this.attrs;
- const { user } = attrs;
- return (
- !user.read_first_notification &&
- !user.enforcedSecondFactor &&
- !attrs.active
- );
- },
-});
-
-createWidget(
- "user-dropdown",
- Object.assign(
- {
- tagName: "li.header-dropdown-toggle.current-user",
-
- buildId() {
- return "current-user";
- },
-
- html(attrs) {
- return h(
- "button.icon.btn.no-text.btn-flat",
- {
- attributes: {
- "aria-haspopup": true,
- "aria-expanded": attrs.active,
- "aria-label": I18n.t("user.account_possessive", {
- name: attrs.user.name || attrs.user.username,
- }),
- },
- },
- this.attach("header-notifications", attrs)
- );
- },
- },
- dropdown
- )
-);
-
-createWidget(
- "header-dropdown",
- Object.assign(
- {
- tagName: "li.header-dropdown-toggle",
-
- html(attrs) {
- const title = I18n.t(attrs.title);
-
- const body = [iconNode(attrs.icon)];
- if (attrs.contents) {
- body.push(attrs.contents.call(this));
- }
-
- return h(
- "button.icon.btn.no-text.btn-flat",
- {
- attributes: {
- "aria-expanded": attrs.active,
- "aria-haspopup": true,
- title,
- "aria-label": title,
- id: attrs.iconId,
- },
- },
- body
- );
- },
- },
- dropdown
- )
-);
-
-createWidget("header-icons", {
- services: ["search", "header"],
- tagName: "ul.icons.d-header-icons",
-
- init() {
- registerWidgetShim("extra-icon", "span.wrapper", hbs`<@data.component />`);
- },
-
- html(attrs) {
- if (this.siteSettings.login_required && !this.currentUser) {
- return [];
- }
-
- const icons = [];
-
- const resolvedIcons = _extraHeaderIcons.resolve();
-
- resolvedIcons.forEach((icon) => {
- if (icon.key === "search") {
- if (!this.header.headerButtonsHidden.includes("search")) {
- icons.push(
- this.attach("header-dropdown", {
- title: "search.title",
- icon: "search",
- iconId: SEARCH_BUTTON_ID,
- action: "toggleSearchMenu",
- active: this.search.visible,
- href: getURL("/search"),
- classNames: ["search-dropdown"],
- })
- );
- }
- } else if (icon.key === "user-menu" && attrs.user) {
- icons.push(
- this.attach("user-dropdown", {
- active: attrs.userVisible,
- action: "toggleUserMenu",
- user: attrs.user,
- })
- );
- } else if (
- icon.key === "hamburger" &&
- (!attrs.sidebarEnabled || this.site.mobileView)
- ) {
- icons.push(
- this.attach("header-dropdown", {
- title: "hamburger_menu",
- icon: "bars",
- iconId: "toggle-hamburger-menu",
- active: attrs.hamburgerVisible,
- action: "toggleHamburger",
- href: "",
- classNames: ["hamburger-dropdown"],
- })
- );
- } else {
- icons.push(this.attach("extra-icon", { component: icon.value }));
- }
- });
-
- return icons;
- },
-});
-
-createWidget("header-buttons", {
- services: ["header"],
- tagName: "span.auth-buttons",
-
- html(attrs) {
- if (this.currentUser) {
- return;
- }
-
- const buttons = [];
-
- if (
- attrs.canSignUp &&
- !attrs.topic &&
- !this.header.headerButtonsHidden.includes("signup")
- ) {
- buttons.push(
- this.attach("button", {
- label: "sign_up",
- className: "btn-primary btn-small sign-up-button",
- action: "showCreateAccount",
- })
- );
- }
-
- if (!this.header.headerButtonsHidden.includes("login")) {
- buttons.push(
- this.attach("button", {
- label: "log_in",
- className: "btn-primary btn-small login-button",
- action: "showLogin",
- icon: "user",
- })
- );
- }
-
- return buttons;
- },
-});
-
-createWidget("header-cloak", {
- tagName: "div.header-cloak",
- html() {
- return "";
- },
- click() {},
- scheduleRerender() {},
-});
-
-let additionalPanels = [];
-export function attachAdditionalPanel(name, toggle, transformAttrs) {
- additionalPanels.push({ name, toggle, transformAttrs });
-}
-
-createWidget("hamburger-dropdown-wrapper", {
- buildAttributes() {
- return { "data-click-outside": true };
- },
-
- html() {
- return [
- new RenderGlimmer(
- this,
- "div.widget-component-connector",
- hbs``
- ),
- ];
- },
-
- click(event) {
- if (
- event.target.closest(".sidebar-section-header-button") ||
- event.target.closest(".sidebar-section-link")
- ) {
- this.sendWidgetAction("toggleHamburger");
- }
- },
-
- clickOutside(e) {
- if (
- e.target.classList.contains("header-cloak") &&
- !window.matchMedia("(prefers-reduced-motion: reduce)").matches
- ) {
- const panel = document.querySelector(".menu-panel");
- const headerCloak = document.querySelector(".header-cloak");
- const finishPosition = isDocumentRTL() ? "340px" : "-340px";
- panel
- .animate([{ transform: `translate3d(${finishPosition}, 0, 0)` }], {
- duration: 200,
- fill: "forwards",
- easing: "ease-in",
- })
- .finished.then(() => {
- if (isTesting()) {
- this.sendWidgetAction("toggleHamburger");
- } else {
- discourseLater(() => this.sendWidgetAction("toggleHamburger"));
- }
- });
- headerCloak.animate([{ opacity: 0 }], {
- duration: 200,
- fill: "forwards",
- easing: "ease-in",
- });
- } else {
- this.sendWidgetAction("toggleHamburger");
- }
- },
-});
-
-createWidget("revamped-user-menu-wrapper", {
- buildAttributes() {
- return { "data-click-outside": true };
- },
-
- html() {
- return [
- new RenderGlimmer(
- this,
- "div.widget-component-connector",
- hbs``,
- {
- closeUserMenu: this.closeUserMenu.bind(this),
- }
- ),
- ];
- },
-
- closeUserMenu() {
- this.sendWidgetAction("toggleUserMenu");
- },
-
- clickOutside(e) {
- if (
- e.target.classList.contains("header-cloak") &&
- !window.matchMedia("(prefers-reduced-motion: reduce)").matches
- ) {
- const panel = document.querySelector(".menu-panel");
- const headerCloak = document.querySelector(".header-cloak");
- const finishPosition = isDocumentRTL() ? "-340px" : "340px";
- panel
- .animate([{ transform: `translate3d(${finishPosition}, 0, 0)` }], {
- duration: 200,
- fill: "forwards",
- easing: "ease-in",
- })
- .finished.then(() => {
- if (isTesting) {
- this.closeUserMenu();
- } else {
- discourseLater(() => this.closeUserMenu());
- }
- });
- headerCloak.animate([{ opacity: 0 }], {
- duration: 200,
- fill: "forwards",
- easing: "ease-in",
- });
- } else {
- this.closeUserMenu();
- }
- },
-});
-
-createWidget("search-menu-wrapper", {
- services: ["search"],
- buildAttributes() {
- return { "aria-live": "polite" };
- },
-
- buildClasses() {
- return ["search-menu"];
- },
-
- html() {
- return [
- new RenderGlimmer(
- this,
- "div.widget-component-connector",
- hbs``,
- {
- closeSearchMenu: this.closeSearchMenu.bind(this),
- }
- ),
- ];
- },
-
- closeSearchMenu() {
- this.sendWidgetAction("toggleSearchMenu");
- document.getElementById(SEARCH_BUTTON_ID)?.focus();
- },
-
- clickOutside() {
- this.closeSearchMenu();
- },
-});
-
-export default createWidget("header", {
- tagName: "header.d-header",
- buildKey: () => `header`,
- services: ["router", "search"],
-
- init() {
- registerWidgetShim(
- "extra-button",
- "span.wrapper",
- hbs`<@data.component />`
- );
- },
-
- defaultState() {
- let states = {
- searchVisible: false,
- hamburgerVisible: false,
- userVisible: false,
- inTopicContext: false,
- };
-
- if (this.site.mobileView) {
- states.skipSearchContext = true;
- }
-
- return states;
- },
-
- html(attrs, state) {
- let inTopicRoute = false;
- if (this.search.inTopicContext) {
- inTopicRoute = this.router.currentRouteName.startsWith("topic.");
- }
-
- let contents = () => {
- const headerIcons = this.attach("header-icons", {
- hamburgerVisible: state.hamburgerVisible,
- userVisible: state.userVisible,
- searchVisible: this.search.visible,
- flagCount: attrs.flagCount,
- user: this.currentUser,
- sidebarEnabled: attrs.sidebarEnabled,
- });
-
- if (attrs.onlyIcons) {
- return headerIcons;
- }
-
- const buttons = [];
- const resolvedButtons = _extraHeaderButtons.resolve();
- resolvedButtons.forEach((button) => {
- if (button.key === "auth") {
- buttons.push(this.attach("header-buttons", attrs));
- }
- buttons.push(this.attach("extra-button", { component: button.value }));
- });
-
- const panels = [];
- panels.push(h("span.header-buttons", buttons), headerIcons);
-
- if (this.search.visible) {
- this.search.inTopicContext = this.search.inTopicContext && inTopicRoute;
- panels.push(this.attach("search-menu-wrapper"));
- } else if (state.hamburgerVisible) {
- panels.push(this.attach("hamburger-dropdown-wrapper", {}));
- } else if (state.userVisible) {
- panels.push(this.attach("revamped-user-menu-wrapper", {}));
- }
-
- additionalPanels.map((panel) => {
- if (this.state[panel.toggle]) {
- panels.push(
- this.attach(
- panel.name,
- panel.transformAttrs.call(this, attrs, state)
- )
- );
- }
- });
-
- if (this.site.mobileView || this.site.narrowDesktopView) {
- panels.push(this.attach("header-cloak"));
- }
-
- return panels;
- };
-
- const contentsAttrs = {
- contents,
- minimized: !!attrs.topic,
- };
-
- return [
- h(
- "div.wrap",
- this.attach("header-contents", { ...attrs, ...contentsAttrs })
- ),
- new RenderGlimmer(
- this,
- "div.widget-component-connector",
- hbs`
-
- `,
- { minimized: !!attrs.topic }
- ),
- ];
- },
-
- updateHighlight() {
- if (!this.search.visible) {
- this.search.highlightTerm = "";
- }
- },
-
- closeAll() {
- this.state.userVisible = false;
- this.state.hamburgerVisible = false;
- this.search.visible = false;
- this.toggleBodyScrolling(false);
- },
-
- toggleSearchMenu() {
- if (this.site.mobileView) {
- const context = this.search.searchContext;
- let params = "";
-
- if (context) {
- params = `?context=${context.type}&context_id=${context.id}&skip_context=${this.state.skipSearchContext}`;
- }
-
- if (this.router.currentRouteName === "full-page-search") {
- scrollTop();
- $(".full-page-search").focus();
- return false;
- } else {
- return DiscourseURL.routeTo("/search" + params);
- }
- }
-
- this.search.visible = !this.search.visible;
- this.updateHighlight();
-
- if (!this.search.searchVisible) {
- this.search.inTopicContext = false;
- }
- },
-
- toggleUserMenu() {
- this.state.userVisible = !this.state.userVisible;
- this.toggleBodyScrolling(this.state.userVisible);
-
- // auto focus on first button in dropdown
- schedule("afterRender", () =>
- document.querySelector(".user-menu button")?.focus()
- );
- },
-
- toggleHamburger() {
- if (this.attrs.sidebarEnabled && !this.site.narrowDesktopView) {
- if (!this.attrs.showSidebar) {
- this.sendWidgetAction("toggleSidebar");
- this.closeAll();
- } else {
- this.state.hamburgerVisible = !this.state.hamburgerVisible;
- }
- } else {
- this.state.hamburgerVisible = !this.state.hamburgerVisible;
- this.toggleBodyScrolling(this.state.hamburgerVisible);
- schedule("afterRender", () => {
- // Remove focus from hamburger toggle button
- document.querySelector("#toggle-hamburger-menu")?.blur();
- });
- }
- },
-
- toggleBodyScrolling(bool) {
- if (this.site.mobileView) {
- scrollLock(bool);
- }
- },
-
- togglePageSearch() {
- this.search.inTopicContext = false;
- let showSearch = this.router.currentRouteName.startsWith("topic.");
-
- // If we're viewing a topic, only intercept search if there are cloaked posts
- if (showSearch) {
- const controller = this.register.lookup("controller:topic");
- const total = controller.get("model.postStream.stream.length") || 0;
- const chunkSize = controller.get("model.chunk_size") || 0;
-
- showSearch =
- total > chunkSize &&
- $(".topic-post .cooked, .small-action:not(.time-gap)").length < total;
- }
-
- if (this.search.visible) {
- this.toggleSearchMenu();
- return showSearch;
- }
-
- if (showSearch) {
- this.search.inTopicContext = true;
- this.toggleSearchMenu();
- return false;
- }
-
- return true;
- },
-
- domClean() {
- const { state } = this;
-
- if (this.search.visible || state.hamburgerVisible || state.userVisible) {
- this.closeAll();
- }
- },
-
- headerKeyboardTrigger(msg) {
- switch (msg.type) {
- case "search":
- this.toggleSearchMenu();
- break;
- case "user":
- this.toggleUserMenu();
- break;
- case "hamburger":
- this.toggleHamburger();
- break;
- case "page-search":
- if (!this.togglePageSearch()) {
- msg.event.preventDefault();
- msg.event.stopPropagation();
- }
- break;
- }
- },
-});
diff --git a/app/assets/javascripts/discourse/app/widgets/home-logo-wrapper-outlet.js b/app/assets/javascripts/discourse/app/widgets/home-logo-wrapper-outlet.js
deleted file mode 100644
index 60c472db2f2..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/home-logo-wrapper-outlet.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { hbs } from "ember-cli-htmlbars";
-import { registerWidgetShim } from "discourse/widgets/render-glimmer";
-
-registerWidgetShim(
- "home-logo-wrapper-outlet",
- "div.home-logo-wrapper-outlet",
- hbs`
-
-
-
- `
-);
diff --git a/app/assets/javascripts/discourse/app/widgets/home-logo.js b/app/assets/javascripts/discourse/app/widgets/home-logo.js
deleted file mode 100644
index eb1d1b2fd0a..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/home-logo.js
+++ /dev/null
@@ -1,152 +0,0 @@
-// deprecated in favor of components/header/home-logo.gjs
-import { h } from "virtual-dom";
-import { wantsNewWindow } from "discourse/lib/intercept-click";
-import { applyValueTransformer } from "discourse/lib/transformer";
-import DiscourseURL from "discourse/lib/url";
-import Session from "discourse/models/session";
-import { createWidget } from "discourse/widgets/widget";
-import getURL from "discourse-common/lib/get-url";
-import { iconNode } from "discourse-common/lib/icon-library";
-
-export default createWidget("home-logo", {
- services: ["session"],
- tagName: "div.title",
-
- settings: {
- href: getURL("/"),
- },
-
- buildClasses() {
- if (this.attrs.minimized) {
- return "title--minimized";
- }
- },
-
- href() {
- const href = this.settings.href;
-
- return applyValueTransformer(
- "home-logo-href",
- typeof href === "function" ? href() : href
- );
- },
-
- logoUrl(opts = {}) {
- return this.logoResolver("logo", opts);
- },
-
- mobileLogoUrl(opts = {}) {
- return this.logoResolver("mobile_logo", opts);
- },
-
- smallLogoUrl(opts = {}) {
- return this.logoResolver("logo_small", opts);
- },
-
- logo() {
- const darkModeOptions = this.session.darkModeAvailable
- ? { dark: true }
- : {};
-
- const mobileLogoUrl = this.mobileLogoUrl(),
- mobileLogoUrlDark = this.mobileLogoUrl(darkModeOptions);
-
- const showMobileLogo = this.site.mobileView && mobileLogoUrl.length > 0;
-
- const logoUrl = this.logoUrl(),
- logoUrlDark = this.logoUrl(darkModeOptions);
- const title = this.siteSettings.title;
-
- if (this.attrs.minimized) {
- const logoSmallUrl = this.smallLogoUrl(),
- logoSmallUrlDark = this.smallLogoUrl(darkModeOptions);
- if (logoSmallUrl.length) {
- return this.logoElement(
- "logo-small",
- logoSmallUrl,
- title,
- logoSmallUrlDark
- );
- } else {
- return iconNode("home");
- }
- } else if (showMobileLogo) {
- return this.logoElement(
- "logo-mobile",
- mobileLogoUrl,
- title,
- mobileLogoUrlDark
- );
- } else if (logoUrl.length) {
- return this.logoElement("logo-big", logoUrl, title, logoUrlDark);
- } else {
- return h("h1#site-text-logo.text-logo", { key: "logo-text" }, title);
- }
- },
-
- logoResolver(name, opts = {}) {
- const { siteSettings } = this;
-
- // get alternative logos for browser dark dark mode switching
- if (opts.dark) {
- return siteSettings[`site_${name}_dark_url`];
- }
-
- // try dark logos first when color scheme is dark
- // this is independent of browser dark mode
- // hence the fallback to normal logos
- if (Session.currentProp("defaultColorSchemeIsDark")) {
- return (
- siteSettings[`site_${name}_dark_url`] ||
- siteSettings[`site_${name}_url`] ||
- ""
- );
- }
-
- return siteSettings[`site_${name}_url`] || "";
- },
-
- logoElement(key, url, title, darkUrl = null) {
- const attributes =
- key === "logo-small"
- ? { src: getURL(url), width: 36, alt: title }
- : { src: getURL(url), alt: title };
-
- const imgElement = h(`img#site-logo.${key}`, {
- key,
- attributes,
- });
-
- if (darkUrl && url !== darkUrl) {
- return h("picture", [
- h("source", {
- attributes: {
- srcset: getURL(darkUrl),
- media: "(prefers-color-scheme: dark)",
- },
- }),
- imgElement,
- ]);
- }
-
- return imgElement;
- },
-
- html() {
- return h(
- "a",
- { attributes: { href: this.href(), "data-auto-route": true } },
- this.logo()
- );
- },
-
- click(e) {
- if (wantsNewWindow(e)) {
- return false;
- }
- e.preventDefault();
-
- DiscourseURL.routeToTag(e.target.closest("a"));
- return false;
- },
-});
diff --git a/app/assets/javascripts/discourse/app/widgets/sidebar-toggle.js b/app/assets/javascripts/discourse/app/widgets/sidebar-toggle.js
deleted file mode 100644
index 2555300db39..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/sidebar-toggle.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Deprecated in favor of app/assets/javascripts/discourse/app/components/header/sidebar-toggle.gjs
-import { createWidget } from "discourse/widgets/widget";
-
-export default createWidget("sidebar-toggle", {
- tagName: "span.header-sidebar-toggle",
-
- html() {
- const attrs = this.attrs;
-
- return [
- this.attach("button", {
- title: "sidebar.title",
- icon: "bars",
- action: this.site.narrowDesktopView
- ? "toggleHamburger"
- : "toggleSidebar",
- className: `btn btn-flat btn-sidebar-toggle ${
- this.site.narrowDesktopView ? "narrow-desktop" : ""
- }`,
- ariaExpanded: attrs.showSidebar ? "true" : "false",
- ariaControls: "d-sidebar",
- }),
- ];
- },
-});
diff --git a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js b/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js
deleted file mode 100644
index 4f772f69ab4..00000000000
--- a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// deprecated in favor of app/components/header/user-dropdown/user-status-bubble.gjs
-
-import { createWidget } from "discourse/widgets/widget";
-import I18n from "discourse-i18n";
-
-export default createWidget("user-status-bubble", {
- tagName: "div.user-status-background",
-
- html(attrs) {
- let title = attrs.description;
- if (attrs.ends_at) {
- const until = moment
- .tz(attrs.ends_at, this.currentUser.user_option.timezone)
- .format(I18n.t("dates.long_date_without_year"));
- title += `\n${I18n.t("until")} ${until}`;
- }
-
- return this.attach("emoji", { name: attrs.emoji, title });
- },
-});
diff --git a/app/assets/javascripts/discourse/tests/acceptance/header-api-test.gjs b/app/assets/javascripts/discourse/tests/acceptance/header-api-test.gjs
index ea31b972aee..d31f1c8202f 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/header-api-test.gjs
+++ b/app/assets/javascripts/discourse/tests/acceptance/header-api-test.gjs
@@ -6,34 +6,6 @@ import { acceptance } from "discourse/tests/helpers/qunit-helpers";
// TODO: Consolidate these tests into a single acceptance test once the Glimmer
// header is the default.
-acceptance("Header API - authenticated", function (needs) {
- needs.user();
- needs.settings({
- glimmer_header_mode: "disabled",
- });
-
- test("can add buttons to the header", async function (assert) {
- withPluginApi("1.29.0", (api) => {
- api.headerButtons.add("test",
-
- );
- });
-
- await visit("/");
- assert.dom("button.test-button").exists("button is displayed");
- });
-
- test("can add icons to the header", async function (assert) {
- withPluginApi("1.29.0", (api) => {
- api.headerIcons.add("test",
- Test
- );
- });
-
- await visit("/");
- assert.dom(".test-icon").exists("icon is displayed");
- });
-});
acceptance("Header API - anonymous", function () {
test("can add buttons to the header", async function (assert) {
@@ -95,9 +67,6 @@ acceptance("Header API - anonymous", function () {
acceptance("Glimmer Header API - authenticated", function (needs) {
needs.user({ groups: AUTO_GROUPS.everyone });
- needs.settings({
- glimmer_header_mode: "enabled",
- });
test("can add buttons to the header", async function (assert) {
withPluginApi("1.29.0", (api) => {
diff --git a/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js b/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js
index cebb1b3d7a2..c04f78493b5 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/mobile-pan-test.js
@@ -65,9 +65,6 @@ async function triggerSwipeEnd({ x, y, touchTarget }) {
acceptance("Mobile - menu swipes", function (needs) {
needs.mobileView();
needs.user();
- needs.settings({
- glimmer_header_mode: "enabled",
- });
chromeTest("swipe to close hamburger", async function (assert) {
await visit("/");
diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
index c661d7eef65..60e56b37e0f 100644
--- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
+++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
@@ -89,10 +89,6 @@ import {
currentSettings,
mergeSettings,
} from "discourse/tests/helpers/site-settings";
-import {
- clearExtraHeaderButtons,
- clearExtraHeaderIcons,
-} from "discourse/widgets/header";
import { resetDecorators as resetPostCookedDecorators } from "discourse/widgets/post-cooked";
import { resetPostMenuExtraButtons } from "discourse/widgets/post-menu";
import { resetDecorators } from "discourse/widgets/widget";
@@ -236,8 +232,6 @@ export function testCleanup(container, app) {
resetSidebarPanels();
clearExtraGlimmerHeaderIcons();
clearExtraGlimmerHeaderButtons();
- clearExtraHeaderIcons();
- clearExtraHeaderButtons();
resetOnKeyUpCallbacks();
resetLogSearchLinkClickedCallbacks();
resetItemSelectCallbacks();
diff --git a/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js b/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js
deleted file mode 100644
index aad268db647..00000000000
--- a/app/assets/javascripts/discourse/tests/integration/components/site-header-test.js
+++ /dev/null
@@ -1,235 +0,0 @@
-// deprecated in favor of spec/system/header/site_header_spec.rb
-
-import {
- click,
- render,
- settled,
- triggerKeyEvent,
- waitUntil,
-} from "@ember/test-helpers";
-import { hbs } from "ember-cli-htmlbars";
-import { module, test } from "qunit";
-import { setupRenderingTest } from "discourse/tests/helpers/component-test";
-import { exists, query } from "discourse/tests/helpers/qunit-helpers";
-import I18n from "discourse-i18n";
-
-module("Integration | Component | site-header", function (hooks) {
- setupRenderingTest(hooks);
-
- hooks.beforeEach(function () {
- this.currentUser.set("unread_high_priority_notifications", 1);
- this.currentUser.set("read_first_notification", false);
- });
-
- test("unread notifications count rerenders when user's notifications count is updated", async function (assert) {
- this.currentUser.set("all_unread_notifications_count", 1);
-
- await render(hbs``);
- let unreadBadge = query(
- ".header-dropdown-toggle.current-user .unread-notifications"
- );
- assert.strictEqual(unreadBadge.textContent, "1");
-
- this.currentUser.set("all_unread_notifications_count", 5);
- await settled();
-
- unreadBadge = query(
- ".header-dropdown-toggle.current-user .unread-notifications"
- );
- assert.strictEqual(unreadBadge.textContent, "5");
- });
-
- test("hamburger menu icon doesn't show pending reviewables count for non-legacy navigation menu", async function (assert) {
- this.currentUser.set("reviewable_count", 1);
- this.siteSettings.navigation_menu = "sidebar";
- await render(hbs``);
- assert.ok(!exists(".hamburger-dropdown .badge-notification"));
- });
-
- test("clicking outside the revamped menu closes it", async function (assert) {
- await render(hbs``);
- await click(".header-dropdown-toggle.current-user");
- assert.ok(exists(".user-menu.revamped"));
- await click("header.d-header");
- assert.ok(!exists(".user-menu.revamped"));
- });
-
- test("header's height is setting css property", async function (assert) {
- await render(hbs``);
-
- function getProperty() {
- const rawValue = getComputedStyle(document.body).getPropertyValue(
- "--header-offset"
- );
- const roundedValue = Math.floor(parseFloat(rawValue));
- return roundedValue + "px";
- }
-
- document.querySelector(".d-header").style.height = 90 + "px";
- await waitUntil(() => getProperty() === "90px", { timeout: 100 });
- assert.strictEqual(getProperty(), "90px");
-
- document.querySelector(".d-header").style.height = 60 + "px";
- await waitUntil(() => getProperty() === "60px", { timeout: 100 });
- assert.strictEqual(getProperty(), "60px");
- });
-
- test("arrow up/down keys move focus between the tabs", async function (assert) {
- this.currentUser.set("can_send_private_messages", true);
- await render(hbs``);
- await click(".header-dropdown-toggle.current-user");
- let activeTab = query(".menu-tabs-container .btn.active");
- assert.strictEqual(activeTab.id, "user-menu-button-all-notifications");
-
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- let focusedTab = document.activeElement;
- assert.strictEqual(
- focusedTab.id,
- "user-menu-button-replies",
- "pressing the down arrow key moves focus to the next tab towards the bottom"
- );
-
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- await triggerKeyEvent(document, "keydown", "ArrowDown");
-
- focusedTab = document.activeElement;
- assert.strictEqual(
- focusedTab.id,
- "user-menu-button-profile",
- "the down arrow key can move the focus to the bottom tabs"
- );
-
- await triggerKeyEvent(document, "keydown", "ArrowDown");
- focusedTab = document.activeElement;
- assert.strictEqual(
- focusedTab.id,
- "user-menu-button-all-notifications",
- "the focus moves back to the top after reaching the bottom"
- );
-
- await triggerKeyEvent(document, "keydown", "ArrowUp");
- focusedTab = document.activeElement;
- assert.strictEqual(
- focusedTab.id,
- "user-menu-button-profile",
- "the up arrow key moves the focus in the opposite direction"
- );
- });
-
- test("new personal messages bubble is prioritized over unseen reviewables and regular notifications bubbles", async function (assert) {
- this.currentUser.set("all_unread_notifications_count", 5);
- this.currentUser.set("new_personal_messages_notifications_count", 2);
- this.currentUser.set("unseen_reviewable_count", 3);
-
- await render(hbs``);
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.unread-notifications"
- ),
- "regular notifications bubble isn't displayed when there are new personal messages notifications"
- );
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-reviewables"
- ),
- "reviewables bubble isn't displayed when there are new personal messages notifications"
- );
-
- const pmsBubble = query(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-pms"
- );
- assert.strictEqual(
- pmsBubble.textContent.trim(),
- "",
- "personal messages bubble has no count"
- );
- assert.ok(
- pmsBubble.querySelector(".d-icon-envelope"),
- "personal messages bubble has envelope icon"
- );
- assert.strictEqual(
- pmsBubble.title,
- I18n.t("notifications.tooltip.new_message_notification", { count: 2 }),
- "personal messages bubble bubble has a title"
- );
- });
-
- test("unseen reviewables bubble is prioritized over regular notifications", async function (assert) {
- this.currentUser.set("all_unread_notifications_count", 5);
- this.currentUser.set("new_personal_messages_notifications_count", 0);
- this.currentUser.set("unseen_reviewable_count", 3);
- await render(hbs``);
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.unread-notifications"
- ),
- "regular notifications bubble isn't displayed when there are unseen reviewables notifications"
- );
-
- const reviewablesBubble = query(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-reviewables"
- );
- assert.strictEqual(
- reviewablesBubble.textContent.trim(),
- "",
- "reviewables bubble has no count"
- );
- assert.ok(
- reviewablesBubble.querySelector(".d-icon-flag"),
- "reviewables bubble has flag icon"
- );
- assert.strictEqual(
- reviewablesBubble.title,
- I18n.t("notifications.tooltip.new_reviewable", { count: 3 }),
- "reviewables bubble has a title"
- );
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-pms"
- ),
- "personal messages bubble isn't displayed"
- );
- });
-
- test("regular notifications bubble is shown if there are neither new personal messages nor unseen reviewables", async function (assert) {
- this.currentUser.set("all_unread_notifications_count", 5);
- this.currentUser.set("new_personal_messages_notifications_count", 0);
- this.currentUser.set("unseen_reviewable_count", 0);
- await render(hbs``);
-
- const regularNotificationsBubble = query(
- ".header-dropdown-toggle.current-user .badge-notification.unread-notifications"
- );
- assert.strictEqual(
- regularNotificationsBubble.textContent,
- "5",
- "regular notifications bubble has a count"
- );
- assert.strictEqual(
- regularNotificationsBubble.title,
- I18n.t("notifications.tooltip.regular", { count: 5 }),
- "regular notifications bubble has a title"
- );
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-reviewables"
- ),
- "reviewables bubble isn't displayed"
- );
-
- assert.notOk(
- exists(
- ".header-dropdown-toggle.current-user .badge-notification.with-icon.new-pms"
- ),
- "personal messages bubble isn't displayed"
- );
- });
-});
diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js b/app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js
deleted file mode 100644
index 28a2c1161fe..00000000000
--- a/app/assets/javascripts/discourse/tests/integration/components/widgets/header-test.js
+++ /dev/null
@@ -1,87 +0,0 @@
-// deprecated in favor of spec/system/header/header_spec.rb
-
-import { click, render } from "@ember/test-helpers";
-import { hbs } from "ember-cli-htmlbars";
-import { module, test } from "qunit";
-import { setupRenderingTest } from "discourse/tests/helpers/component-test";
-import { exists } from "discourse/tests/helpers/qunit-helpers";
-
-module("Integration | Component | Widget | header", function (hooks) {
- setupRenderingTest(hooks);
-
- test("rendering basics", async function (assert) {
- await render(hbs``);
-
- assert.ok(exists("header.d-header"));
- assert.ok(exists("#site-logo"));
- });
-
- test("sign up / login buttons", async function (assert) {
- this.owner.unregister("service:current-user");
- this.set("args", { canSignUp: true });
- this.set("showCreateAccount", () => (this.signupShown = true));
- this.set("showLogin", () => (this.loginShown = true));
-
- await render(hbs`
-
- `);
-
- assert.ok(exists("button.sign-up-button"));
- assert.ok(exists("button.login-button"));
-
- await click("button.sign-up-button");
- assert.ok(this.signupShown);
-
- await click("button.login-button");
- assert.ok(this.loginShown);
- });
-
- test("anon when login required", async function (assert) {
- this.owner.unregister("service:current-user");
- this.set("args", { canSignUp: true });
- this.set("showCreateAccount", () => (this.signupShown = true));
- this.set("showLogin", () => (this.loginShown = true));
- this.siteSettings.login_required = true;
-
- await render(hbs`
-
- `);
-
- assert.ok(exists("button.login-button"));
- assert.ok(exists("button.sign-up-button"));
- assert.ok(!exists("#search-button"));
- assert.ok(!exists("#toggle-hamburger-menu"));
- });
-
- test("logged in when login required", async function (assert) {
- this.set("args", { canSignUp: true });
- this.set("showCreateAccount", () => (this.signupShown = true));
- this.set("showLogin", () => (this.loginShown = true));
- this.siteSettings.login_required = true;
-
- await render(hbs`
-
- `);
-
- assert.ok(!exists("button.login-button"));
- assert.ok(!exists("button.sign-up-button"));
- assert.ok(exists("#search-button"));
- assert.ok(exists("#toggle-hamburger-menu"));
- assert.ok(exists("#current-user"));
- });
-});
diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs
deleted file mode 100644
index 93fdf82617d..00000000000
--- a/app/assets/javascripts/discourse/tests/integration/components/widgets/home-logo-test.gjs
+++ /dev/null
@@ -1,231 +0,0 @@
-// deprecated in favor of discourse/tests/integration/components/home-logo-test.gjs
-import { getOwner } from "@ember/owner";
-import { render } from "@ember/test-helpers";
-import { module, test } from "qunit";
-import MountWidget from "discourse/components/mount-widget";
-import { withPluginApi } from "discourse/lib/plugin-api";
-import { setupRenderingTest } from "discourse/tests/helpers/component-test";
-import { count, exists, query } from "discourse/tests/helpers/qunit-helpers";
-
-const bigLogo = "/images/d-logo-sketch.png?test";
-const smallLogo = "/images/d-logo-sketch-small.png?test";
-const mobileLogo = "/images/d-logo-sketch.png?mobile";
-const darkLogo = "/images/d-logo-sketch.png?dark";
-const title = "Cool Forum";
-const prefersDark = "(prefers-color-scheme: dark)";
-
-module("Integration | Component | Widget | home-logo", function (hooks) {
- setupRenderingTest(hooks);
-
- hooks.afterEach(function () {
- this.session = getOwner(this).lookup("service:session");
- this.session.set("darkModeAvailable", null);
- this.session.set("defaultColorSchemeIsDark", null);
- });
-
- test("basics", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_small_url = smallLogo;
- this.siteSettings.title = title;
- const args = { minimized: false };
-
- await render(
-
- );
-
- assert.strictEqual(count(".title"), 1);
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
- assert.strictEqual(query("#site-logo").getAttribute("alt"), title);
- });
-
- test("basics - minimized", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_small_url = smallLogo;
- this.siteSettings.title = title;
- const args = { minimized: true };
-
- await render(
-
- );
-
- assert.strictEqual(count("img.logo-small"), 1);
- assert.strictEqual(query("img.logo-small").getAttribute("src"), smallLogo);
- assert.strictEqual(query("img.logo-small").getAttribute("alt"), title);
- assert.strictEqual(query("img.logo-small").getAttribute("width"), "36");
- });
-
- test("no logo", async function (assert) {
- this.siteSettings.site_logo_url = "";
- this.siteSettings.site_logo_small_url = "";
- this.siteSettings.title = title;
- const args = { minimized: false };
-
- await render(
-
- );
-
- assert.strictEqual(count("h1#site-text-logo.text-logo"), 1);
- assert.strictEqual(query("#site-text-logo").innerText, title);
- });
-
- test("no logo - minimized", async function (assert) {
- this.siteSettings.site_logo_url = "";
- this.siteSettings.site_logo_small_url = "";
- this.siteSettings.title = title;
- const args = { minimized: true };
-
- await render(
-
- );
-
- assert.strictEqual(count(".d-icon-home"), 1);
- });
-
- test("mobile logo", async function (assert) {
- this.siteSettings.site_mobile_logo_url = mobileLogo;
- this.siteSettings.site_logo_small_url = smallLogo;
- this.site.mobileView = true;
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-mobile"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), mobileLogo);
- });
-
- test("mobile without logo", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.site.mobileView = true;
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
- });
-
- test("logo with dark mode alternative", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_dark_url = darkLogo;
- this.session.set("darkModeAvailable", true);
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
-
- assert.strictEqual(
- query("picture source").getAttribute("media"),
- prefersDark,
- "includes dark mode media attribute"
- );
- assert.strictEqual(
- query("picture source").getAttribute("srcset"),
- darkLogo,
- "includes dark mode alternative logo source"
- );
- });
-
- test("mobile logo with dark mode alternative", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_mobile_logo_url = mobileLogo;
- this.siteSettings.site_mobile_logo_dark_url = darkLogo;
- this.session.set("darkModeAvailable", true);
-
- this.site.mobileView = true;
-
- await render();
-
- assert.strictEqual(query("#site-logo").getAttribute("src"), mobileLogo);
-
- assert.strictEqual(
- query("picture source").getAttribute("media"),
- prefersDark,
- "includes dark mode media attribute"
- );
- assert.strictEqual(
- query("picture source").getAttribute("srcset"),
- darkLogo,
- "includes dark mode alternative logo source"
- );
- });
-
- test("dark mode enabled but no dark logo set", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_dark_url = "";
- this.session.set("darkModeAvailable", true);
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
- assert.ok(!exists("picture"), "does not include alternative logo");
- });
-
- test("dark logo set but no dark mode", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_dark_url = darkLogo;
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(query("#site-logo").getAttribute("src"), bigLogo);
- assert.ok(!exists("picture"), "does not include alternative logo");
- });
-
- test("dark color scheme and dark logo set", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_dark_url = darkLogo;
- this.session.set("defaultColorSchemeIsDark", true);
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(
- query("#site-logo").getAttribute("src"),
- darkLogo,
- "uses dark logo"
- );
- assert.ok(!exists("picture"), "does not add dark mode alternative");
- });
-
- test("dark color scheme and dark logo not set", async function (assert) {
- this.siteSettings.site_logo_url = bigLogo;
- this.siteSettings.site_logo_dark_url = "";
- this.session.set("defaultColorSchemeIsDark", true);
-
- await render();
-
- assert.strictEqual(count("img#site-logo.logo-big"), 1);
- assert.strictEqual(
- query("#site-logo").getAttribute("src"),
- bigLogo,
- "uses regular logo on dark scheme if no dark logo"
- );
- });
-
- test("the home logo href url defaults to /", async function (assert) {
- await render();
-
- const anchorElement = query("#site-logo").closest("a");
- assert.strictEqual(
- anchorElement.getAttribute("href"),
- "/",
- "home logo href equals /"
- );
- });
-
- test("api.registerHomeLogoHrefCallback can be used to change the logo href url", async function (assert) {
- withPluginApi("1.32.0", (api) => {
- api.registerHomeLogoHrefCallback(() => "https://example.com");
- });
-
- await render();
-
- const anchorElement = query("#site-logo").closest("a");
- assert.strictEqual(
- anchorElement.getAttribute("href"),
- "https://example.com",
- "home logo href equals the one set by the callback"
- );
- });
-});
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 7ef6271d897..c9c9b1c40b1 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2692,7 +2692,6 @@ en:
enable_experimental_lightbox: "EXPERIMENTAL: Replace the default image lightbox with the revamped design."
enable_experimental_bookmark_redesign_groups: "EXPERIMENTAL: Show a quick access menu for bookmarks on posts and a new redesigned modal"
experimental_redesigned_about_page_groups: "EXPERIMENTAL: Enable the redesigned /about page for specific groups."
- glimmer_header_mode: "Control whether the new 'glimmer' header implementation is used. 'auto' will enable automatically once all your themes and plugins are ready. https://meta.discourse.org/t/316549"
experimental_glimmer_topic_list_groups: "EXPERIMENTAL: Enable the new 'glimmer' topic list implementation. This implementation is under active development, and is not intended for production use. Do not develop themes/plugins against it until the implementation is finalized and announced."
experimental_form_templates: "EXPERIMENTAL: Enable the form templates feature. After enabled, manage the templates at Customize / Templates."
admin_sidebar_enabled_groups: "Enable sidebar navigation for the admin UI for the specified groups, which replaces the top-level admin navigation buttons."
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 253dd41bc5c..fcdcf2af574 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -2432,14 +2432,6 @@ developer:
instrument_gc_stat_per_request:
default: false
hidden: true
- glimmer_header_mode:
- client: true
- type: enum
- choices:
- - disabled
- - auto
- - enabled
- default: enabled
admin_sidebar_enabled_groups:
type: group_list
list_type: compact
diff --git a/db/migrate/20240815234500_remove_glimmer_header_mode_setting.rb b/db/migrate/20240815234500_remove_glimmer_header_mode_setting.rb
new file mode 100644
index 00000000000..91877d2e771
--- /dev/null
+++ b/db/migrate/20240815234500_remove_glimmer_header_mode_setting.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+#
+class RemoveGlimmerHeaderModeSetting < ActiveRecord::Migration[7.1]
+ def up
+ execute <<~SQL
+ DELETE FROM site_settings
+ WHERE name = 'glimmer_header_mode'
+ SQL
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
diff --git a/spec/system/header_spec.rb b/spec/system/header_spec.rb
index 84850b3e7e2..04452e54176 100644
--- a/spec/system/header_spec.rb
+++ b/spec/system/header_spec.rb
@@ -5,7 +5,6 @@ RSpec.describe "Glimmer Header", type: :system do
let(:search) { PageObjects::Pages::Search.new }
fab!(:current_user) { Fabricate(:user) }
fab!(:topic)
- before { SiteSetting.glimmer_header_mode = "enabled" }
it "renders basics" do
visit "/"
diff --git a/spec/system/legacy_widget_header_spec.rb b/spec/system/legacy_widget_header_spec.rb
deleted file mode 100644
index 6b0ce779d2e..00000000000
--- a/spec/system/legacy_widget_header_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "Legacy Widget Header", type: :system do
- before { SiteSetting.glimmer_header_mode = "disabled" }
-
- context "when resetting password" do
- fab!(:current_user) { Fabricate(:user) }
-
- it "does not show search, login, or signup buttons" do
- email_token =
- current_user.email_tokens.create!(
- email: current_user.email,
- scope: EmailToken.scopes[:password_reset],
- )
-
- visit "/u/password-reset/#{email_token.token}"
- expect(page).not_to have_css("button.login-button")
- expect(page).not_to have_css("button.sign-up-button")
- expect(page).not_to have_css(".search-dropdown #search-button")
- end
- end
-end