Commit 45c750b2 authored by Paul Slaughter's avatar Paul Slaughter Committed by Ezekiel Kigbo

Fix race condition of `menu-expanded` and top nav

parent fa8f391c
...@@ -203,6 +203,9 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -203,6 +203,9 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
$('.navbar-toggler').on('click', () => { $('.navbar-toggler').on('click', () => {
// The order is important. The `menu-expanded` is used as a source of truth for now.
// This can be simplified when the :combined_menu feature flag is removed.
// https://gitlab.com/gitlab-org/gitlab/-/issues/333180
$('.header-content').toggleClass('menu-expanded'); $('.header-content').toggleClass('menu-expanded');
navEventHub.$emit(EVENT_RESPONSIVE_TOGGLE); navEventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
}); });
......
...@@ -3,7 +3,7 @@ import { FREQUENT_ITEMS_PROJECTS, FREQUENT_ITEMS_GROUPS } from '~/frequent_items ...@@ -3,7 +3,7 @@ import { FREQUENT_ITEMS_PROJECTS, FREQUENT_ITEMS_GROUPS } from '~/frequent_items
import { BV_DROPDOWN_SHOW, BV_DROPDOWN_HIDE } from '~/lib/utils/constants'; import { BV_DROPDOWN_SHOW, BV_DROPDOWN_HIDE } from '~/lib/utils/constants';
import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue'; import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '../event_hub'; import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '../event_hub';
import { resetMenuItemsActive } from '../utils/reset_menu_items_active'; import { resetMenuItemsActive, hasMenuExpanded } from '../utils';
import ResponsiveHeader from './responsive_header.vue'; import ResponsiveHeader from './responsive_header.vue';
import ResponsiveHome from './responsive_home.vue'; import ResponsiveHome from './responsive_home.vue';
import TopNavContainerView from './top_nav_container_view.vue'; import TopNavContainerView from './top_nav_container_view.vue';
...@@ -33,9 +33,11 @@ export default { ...@@ -33,9 +33,11 @@ export default {
}, },
}, },
created() { created() {
eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.onToggle); eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.updateResponsiveOpen);
this.$root.$on(BV_DROPDOWN_SHOW, this.showMobileOverlay); this.$root.$on(BV_DROPDOWN_SHOW, this.showMobileOverlay);
this.$root.$on(BV_DROPDOWN_HIDE, this.hideMobileOverlay); this.$root.$on(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
this.updateResponsiveOpen();
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off(EVENT_RESPONSIVE_TOGGLE, this.onToggle); eventHub.$off(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
...@@ -43,8 +45,12 @@ export default { ...@@ -43,8 +45,12 @@ export default {
this.$root.$off(BV_DROPDOWN_HIDE, this.hideMobileOverlay); this.$root.$off(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
}, },
methods: { methods: {
onToggle() { updateResponsiveOpen() {
document.body.classList.toggle('top-nav-responsive-open'); if (hasMenuExpanded()) {
document.body.classList.add('top-nav-responsive-open');
} else {
document.body.classList.remove('top-nav-responsive-open');
}
}, },
onMenuItemClick({ view }) { onMenuItemClick({ view }) {
if (view) { if (view) {
......
export const hasMenuExpanded = () => {
const header = document.querySelector('.header-content');
return Boolean(header?.classList.contains('menu-expanded'));
};
export * from './has_menu_expanded';
export * from './reset_menu_items_active';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { range } from 'lodash';
import ResponsiveApp from '~/nav/components/responsive_app.vue'; import ResponsiveApp from '~/nav/components/responsive_app.vue';
import ResponsiveHeader from '~/nav/components/responsive_header.vue'; import ResponsiveHeader from '~/nav/components/responsive_header.vue';
import ResponsiveHome from '~/nav/components/responsive_home.vue'; import ResponsiveHome from '~/nav/components/responsive_home.vue';
...@@ -32,6 +31,7 @@ describe('~/nav/components/responsive_app.vue', () => { ...@@ -32,6 +31,7 @@ describe('~/nav/components/responsive_app.vue', () => {
const hasMobileOverlayVisible = () => findMobileOverlay().classes('mobile-nav-open'); const hasMobileOverlayVisible = () => findMobileOverlay().classes('mobile-nav-open');
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = '';
// Add test class to reset state + assert that we're adding classes correctly // Add test class to reset state + assert that we're adding classes correctly
document.body.className = 'test-class'; document.body.className = 'test-class';
}); });
...@@ -53,14 +53,17 @@ describe('~/nav/components/responsive_app.vue', () => { ...@@ -53,14 +53,17 @@ describe('~/nav/components/responsive_app.vue', () => {
}); });
it.each` it.each`
times | expectation bodyHtml | expectation
${0} | ${false} ${''} | ${false}
${1} | ${true} ${'<div class="header-content"></div>'} | ${false}
${2} | ${false} ${'<div class="menu-expanded"></div>'} | ${false}
${'<div></div><div class="header-content menu-expanded"></div>}'} | ${true}
`( `(
'with responsive toggle event triggered $times, body responsive open = $expectation', 'with responsive toggle event and html set to $bodyHtml, responsive open = $expectation',
({ times, expectation }) => { ({ bodyHtml, expectation }) => {
range(times).forEach(triggerResponsiveToggle); document.body.innerHTML = bodyHtml;
triggerResponsiveToggle();
expect(hasBodyResponsiveOpen()).toBe(expectation); expect(hasBodyResponsiveOpen()).toBe(expectation);
}, },
...@@ -88,6 +91,17 @@ describe('~/nav/components/responsive_app.vue', () => { ...@@ -88,6 +91,17 @@ describe('~/nav/components/responsive_app.vue', () => {
); );
}); });
describe('with menu expanded in body', () => {
beforeEach(() => {
document.body.innerHTML = '<div></div><div class="header-content menu-expanded"></div>';
createComponent();
});
it('sets the body responsive open', () => {
expect(hasBodyResponsiveOpen()).toBe(true);
});
});
const projectsContainerProps = { const projectsContainerProps = {
containerClass: 'gl-px-3', containerClass: 'gl-px-3',
frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace, frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment