diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html index f6bff2dc8f..8706b40ee0 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.html @@ -1,10 +1,23 @@ - + diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts index a19a1f95e4..50f9f8a79e 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts @@ -5,12 +5,15 @@ import { MenuService } from '../../../shared/menu/menu.service'; import { rendersSectionForMenu } from '../../../shared/menu/menu-section.decorator'; import { LinkMenuItemModel } from '../../../shared/menu/menu-item/models/link.model'; import { MenuSection } from '../../../shared/menu/menu.reducer'; +import { isNotEmpty } from '../../../shared/empty.util'; +import { Router } from '@angular/router'; /** * Represents a non-expandable section in the admin sidebar */ @Component({ - selector: 'ds-admin-sidebar-section', + /* tslint:disable:component-selector */ + selector: 'li[ds-admin-sidebar-section]', templateUrl: './admin-sidebar-section.component.html', styleUrls: ['./admin-sidebar-section.component.scss'], @@ -23,12 +26,26 @@ export class AdminSidebarSectionComponent extends MenuSectionComponent implement */ menuID: MenuID = MenuID.ADMIN; itemModel; - constructor(@Inject('sectionDataProvider') menuSection: MenuSection, protected menuService: MenuService, protected injector: Injector,) { + hasLink: boolean; + constructor( + @Inject('sectionDataProvider') menuSection: MenuSection, + protected menuService: MenuService, + protected injector: Injector, + protected router: Router, + ) { super(menuSection, menuService, injector); this.itemModel = menuSection.model as LinkMenuItemModel; } ngOnInit(): void { + this.hasLink = isNotEmpty(this.itemModel?.link); super.ngOnInit(); } + + navigate(event: any): void { + event.preventDefault(); + if (this.hasLink) { + this.router.navigate(this.itemModel.link); + } + } } diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.html b/src/app/admin/admin-sidebar/admin-sidebar.component.html index d3d8031994..84402c64e9 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.html +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.html @@ -4,24 +4,26 @@ value: (!(sidebarExpanded | async) ? 'collapsed' : 'expanded'), params: {sidebarWidth: (sidebarWidth | async)} }" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)" - *ngIf="menuVisible | async" (mouseenter)="expandPreview($event)" - (mouseleave)="collapsePreview($event)" + *ngIf="menuVisible | async" + (mouseenter)="handleMouseEnter($event)" + (mouseleave)="handleMouseLeave($event)" role="navigation" [attr.aria-label]="'menu.header.admin.description' |translate"> diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.scss b/src/app/admin/admin-sidebar/admin-sidebar.component.scss index e6eb4a7037..5ed0142c7f 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.scss +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.scss @@ -25,6 +25,11 @@ .navbar-nav { .admin-menu-header { background-color: var(--ds-admin-sidebar-header-bg); + + .sidebar-section { + background-color: inherit; + } + .logo-wrapper { img { height: 20px; @@ -34,6 +39,10 @@ line-height: 1.5; } + .navbar-brand { + margin-right: 0; + } + } } @@ -44,26 +53,64 @@ display: flex; align-content: stretch; background-color: var(--ds-admin-sidebar-bg); + overflow-x: visible; + .nav-item { padding-top: var(--bs-spacer); padding-bottom: var(--bs-spacer); + background-color: inherit; + + &:focus-visible { + // since links fill the whole sidebar, we _inset_ the outline + outline-offset: -4px; + + // replace padding with margins so it doesn't extend over the :focus-visible outline + // → can't remove the padding altogether; the icon needs to fill out + // the collapsed width of the sidebar for the slide animation to look decent. + .shortcut-icon { + padding-left: 0; + padding-right: 0; + margin-left: var(--ds-icon-padding); + margin-right: var(--ds-icon-padding); + } + .logo-wrapper { + margin-right: var(--bs-navbar-padding-x) !important; + } + .navbar-brand { + padding-top: 0; + padding-bottom: 0; + margin-top: var(--bs-navbar-brand-padding-y); + margin-bottom: var(--bs-navbar-brand-padding-y); + } + } } + .shortcut-icon { + background-color: inherit; padding-left: var(--ds-icon-padding); padding-right: var(--ds-icon-padding); - } - .shortcut-icon, .icon-wrapper { - background-color: inherit; z-index: var(--ds-icon-z-index); + align-self: baseline; } + .sidebar-collapsible { + padding-left: 0; + padding-right: var(--bs-spacer); width: var(--ds-sidebar-items-width); position: relative; - a { - padding-right: var(--bs-spacer); - width: 100%; + .toggle { + width: 100%; + } + + ul { + padding-top: var(--bs-spacer); + + li a { + padding-left: var(--bs-spacer); + } } } + &.active > .sidebar-collapsible > .nav-link { color: var(--bs-navbar-dark-active-color); } diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts index 0a9ef512d7..948d7d86bc 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts @@ -113,25 +113,10 @@ describe('AdminSidebarComponent', () => { }); }); - describe('when the collapse icon is clicked', () => { - beforeEach(() => { - spyOn(menuService, 'toggleMenu'); - const sidebarToggler = fixture.debugElement.query(By.css('#sidebar-collapse-toggle')).query(By.css('a.shortcut-icon')); - sidebarToggler.triggerEventHandler('click', { - preventDefault: () => {/**/ - } - }); - }); - - it('should call toggleMenu on the menuService', () => { - expect(menuService.toggleMenu).toHaveBeenCalled(); - }); - }); - describe('when the collapse link is clicked', () => { beforeEach(() => { spyOn(menuService, 'toggleMenu'); - const sidebarToggler = fixture.debugElement.query(By.css('#sidebar-collapse-toggle')).query(By.css('.sidebar-collapsible')).query(By.css('a')); + const sidebarToggler = fixture.debugElement.query(By.css('#sidebar-collapse-toggle > a')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index 53a9ecb2ab..f0d583744c 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -1,7 +1,7 @@ -import { Component, Injector, OnInit } from '@angular/core'; +import { Component, HostListener, Injector, OnInit } from '@angular/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { combineLatest, combineLatest as observableCombineLatest, Observable } from 'rxjs'; -import { first, map, take } from 'rxjs/operators'; +import { combineLatest, combineLatest as observableCombineLatest, Observable, BehaviorSubject } from 'rxjs'; +import { debounceTime, first, map, take, distinctUntilChanged, withLatestFrom } from 'rxjs/operators'; import { AuthService } from '../../core/auth/auth.service'; import { ScriptDataService } from '../../core/data/processes/script-data.service'; import { slideHorizontal, slideSidebar } from '../../shared/animations/slide'; @@ -60,6 +60,8 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { */ sidebarExpanded: Observable; + inFocus$: BehaviorSubject; + constructor(protected menuService: MenuService, protected injector: Injector, private variableService: CSSVariableService, @@ -69,6 +71,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { private scriptDataService: ScriptDataService, ) { super(menuService, injector); + this.inFocus$ = new BehaviorSubject(false); } /** @@ -89,10 +92,25 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { this.sidebarOpen = !collapsed; this.sidebarClosed = collapsed; }); - this.sidebarExpanded = observableCombineLatest(this.menuCollapsed, this.menuPreviewCollapsed) + this.sidebarExpanded = combineLatest([this.menuCollapsed, this.menuPreviewCollapsed]) .pipe( map(([collapsed, previewCollapsed]) => (!collapsed || !previewCollapsed)) ); + this.inFocus$.pipe( + debounceTime(50), + distinctUntilChanged(), // disregard focusout in situations like --(focusout)-(focusin)-- + withLatestFrom( + combineLatest([this.menuCollapsed, this.menuPreviewCollapsed]) + ), + ).subscribe(([inFocus, [collapsed, previewCollapsed]]) => { + if (collapsed) { + if (inFocus && previewCollapsed) { + this.expandPreview(new Event('focusin → expand')); + } else if (!inFocus && !previewCollapsed) { + this.collapsePreview(new Event('focusout → collapse')); + } + } + }); } /** @@ -590,6 +608,32 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { }); } + @HostListener('focusin') + public handleFocusIn() { + this.inFocus$.next(true); + } + + @HostListener('focusout') + public handleFocusOut() { + this.inFocus$.next(false); + } + + public handleMouseEnter(event: any) { + if (!this.inFocus$.getValue()) { + this.expandPreview(event); + } else { + event.preventDefault(); + } + } + + public handleMouseLeave(event: any) { + if (!this.inFocus$.getValue()) { + this.collapsePreview(event); + } else { + event.preventDefault(); + } + } + /** * Method to change this.collapsed to false when the slide animation ends and is sliding open * @param event The animation event diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html index af014f3e1b..734c3d2ef9 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.html @@ -1,27 +1,36 @@ - + + diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.scss b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.scss index 8670cf19aa..802fade8c1 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.scss +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.scss @@ -9,7 +9,7 @@ list-style: disc; color: var(--bs-navbar-dark-color); overflow: hidden; - + margin-bottom: calc(-1 * var(--bs-spacer)); // the bottom-most nav-item is padded, no need for double spacing } .sidebar-collapsible { diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.spec.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.spec.ts index 33374f1f46..b1f3a63c06 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.spec.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.spec.ts @@ -10,6 +10,8 @@ import { Component } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { By } from '@angular/platform-browser'; import { TranslateModule } from '@ngx-translate/core'; +import { Router } from '@angular/router'; +import { RouterStub } from '../../../shared/testing/router.stub'; describe('ExpandableAdminSidebarSectionComponent', () => { let component: ExpandableAdminSidebarSectionComponent; @@ -24,6 +26,7 @@ describe('ExpandableAdminSidebarSectionComponent', () => { { provide: 'sectionDataProvider', useValue: { icon: iconString } }, { provide: MenuService, useValue: menuService }, { provide: CSSVariableService, useClass: CSSVariableServiceStub }, + { provide: Router, useValue: new RouterStub() }, ] }).overrideComponent(ExpandableAdminSidebarSectionComponent, { set: { @@ -46,29 +49,14 @@ describe('ExpandableAdminSidebarSectionComponent', () => { }); it('should set the right icon', () => { - const icon = fixture.debugElement.query(By.css('.icon-wrapper')).query(By.css('i.fas')); + const icon = fixture.debugElement.query(By.css('.shortcut-icon > i.fas')); expect(icon.nativeElement.getAttribute('class')).toContain('fa-' + iconString); }); - describe('when the icon is clicked', () => { - beforeEach(() => { - spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('a.shortcut-icon')); - sidebarToggler.triggerEventHandler('click', { - preventDefault: () => {/**/ - } - }); - }); - - it('should call toggleActiveSection on the menuService', () => { - expect(menuService.toggleActiveSection).toHaveBeenCalled(); - }); - }); - describe('when the header text is clicked', () => { beforeEach(() => { spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('.sidebar-collapsible')).query(By.css('a')); + const sidebarToggler = fixture.debugElement.query(By.css('.sidebar-section > div.nav-item')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts index 112560de16..aaa6a85c51 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts @@ -9,12 +9,14 @@ import { MenuService } from '../../../shared/menu/menu.service'; import { combineLatest as combineLatestObservable, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { rendersSectionForMenu } from '../../../shared/menu/menu-section.decorator'; +import { Router } from '@angular/router'; /** * Represents a expandable section in the sidebar */ @Component({ - selector: 'ds-expandable-admin-sidebar-section', + /* tslint:disable:component-selector */ + selector: 'li[ds-expandable-admin-sidebar-section]', templateUrl: './expandable-admin-sidebar-section.component.html', styleUrls: ['./expandable-admin-sidebar-section.component.scss'], animations: [rotate, slide, bgColor] @@ -48,9 +50,14 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC */ expanded: Observable; - constructor(@Inject('sectionDataProvider') menuSection, protected menuService: MenuService, - private variableService: CSSVariableService, protected injector: Injector) { - super(menuSection, menuService, injector); + constructor( + @Inject('sectionDataProvider') menuSection, + protected menuService: MenuService, + private variableService: CSSVariableService, + protected injector: Injector, + protected router: Router, + ) { + super(menuSection, menuService, injector, router); } /** diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html index bfefcb5a6c..cb96435b77 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts index 1cc138b53e..8eea76e5c6 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts @@ -49,7 +49,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse enters the section header', () => { beforeEach(() => { spyOn(menuService, 'activateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown')); sidebarToggler.triggerEventHandler('mouseenter', { preventDefault: () => {/**/ } @@ -64,7 +64,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse leaves the section header', () => { beforeEach(() => { spyOn(menuService, 'deactivateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown')); sidebarToggler.triggerEventHandler('mouseleave', { preventDefault: () => {/**/ } @@ -79,7 +79,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when a click occurs on the section header', () => { beforeEach(() => { spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')).query(By.css('a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } @@ -122,7 +122,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse enters the section header', () => { beforeEach(() => { spyOn(menuService, 'activateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); sidebarToggler.triggerEventHandler('mouseenter', { preventDefault: () => {/**/ } @@ -137,7 +137,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse leaves the section header', () => { beforeEach(() => { spyOn(menuService, 'deactivateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); sidebarToggler.triggerEventHandler('mouseleave', { preventDefault: () => {/**/ } @@ -152,7 +152,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when a click occurs on the section header link', () => { beforeEach(() => { spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('li.nav-item.dropdown')).query(By.css('a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index 068854d6f8..a0c0240159 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -11,7 +11,8 @@ import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator' * Represents an expandable section in the navbar */ @Component({ - selector: 'ds-expandable-navbar-section', + /* tslint:disable:component-selector */ + selector: 'li[ds-expandable-navbar-section]', templateUrl: './expandable-navbar-section.component.html', styleUrls: ['./expandable-navbar-section.component.scss'], animations: [slide] diff --git a/src/app/navbar/navbar-section/navbar-section.component.html b/src/app/navbar/navbar-section/navbar-section.component.html index 00461995bc..b5f6848050 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.html +++ b/src/app/navbar/navbar-section/navbar-section.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/navbar/navbar-section/navbar-section.component.ts b/src/app/navbar/navbar-section/navbar-section.component.ts index e1488de3d3..89d1653bbc 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.ts +++ b/src/app/navbar/navbar-section/navbar-section.component.ts @@ -8,7 +8,8 @@ import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator' * Represents a non-expandable section in the navbar */ @Component({ - selector: 'ds-navbar-section', + /* tslint:disable:component-selector */ + selector: 'li[ds-navbar-section]', templateUrl: './navbar-section.component.html', styleUrls: ['./navbar-section.component.scss'] }) diff --git a/src/app/shared/menu/menu-item/link-menu-item.component.html b/src/app/shared/menu/menu-item/link-menu-item.component.html index e4b92284d2..b2cc73bcf4 100644 --- a/src/app/shared/menu/menu-item/link-menu-item.component.html +++ b/src/app/shared/menu/menu-item/link-menu-item.component.html @@ -1 +1,10 @@ -{{item.text | translate}} \ No newline at end of file +{{item.text | translate}} diff --git a/src/app/shared/menu/menu-item/link-menu-item.component.spec.ts b/src/app/shared/menu/menu-item/link-menu-item.component.spec.ts index 43e17b8f03..c15cd08725 100644 --- a/src/app/shared/menu/menu-item/link-menu-item.component.spec.ts +++ b/src/app/shared/menu/menu-item/link-menu-item.component.spec.ts @@ -5,6 +5,8 @@ import { By } from '@angular/platform-browser'; import { LinkMenuItemComponent } from './link-menu-item.component'; import { RouterLinkDirectiveStub } from '../../testing/router-link-directive.stub'; import { environment } from '../../../../environments/environment'; +import { RouterStub } from '../../testing/router.stub'; +import { Router } from '@angular/router'; describe('LinkMenuItemComponent', () => { let component: LinkMenuItemComponent; @@ -25,6 +27,7 @@ describe('LinkMenuItemComponent', () => { declarations: [LinkMenuItemComponent, RouterLinkDirectiveStub], providers: [ { provide: 'itemModelProvider', useValue: { text: text, link: link } }, + { provide: Router, useValue: RouterStub }, ], schemas: [NO_ERRORS_SCHEMA] }) diff --git a/src/app/shared/menu/menu-item/link-menu-item.component.ts b/src/app/shared/menu/menu-item/link-menu-item.component.ts index e5b66c5aab..42314bd362 100644 --- a/src/app/shared/menu/menu-item/link-menu-item.component.ts +++ b/src/app/shared/menu/menu-item/link-menu-item.component.ts @@ -4,6 +4,7 @@ import { MenuItemType } from '../initial-menus-state'; import { rendersMenuItemForType } from '../menu-item.decorator'; import { isNotEmpty } from '../../empty.util'; import { environment } from '../../../../environments/environment'; +import { Router } from '@angular/router'; /** * Component that renders a menu section of type LINK @@ -16,7 +17,10 @@ import { environment } from '../../../../environments/environment'; export class LinkMenuItemComponent implements OnInit { item: LinkMenuItemModel; hasLink: boolean; - constructor(@Inject('itemModelProvider') item: LinkMenuItemModel) { + constructor( + @Inject('itemModelProvider') item: LinkMenuItemModel, + private router: Router, + ) { this.item = item; } @@ -31,4 +35,12 @@ export class LinkMenuItemComponent implements OnInit { return undefined; } + navigate(event: any) { + event.preventDefault(); + if (this.getRouterLink()) { + this.router.navigate([this.getRouterLink()]); + } + event.stopPropagation(); + } + } diff --git a/src/app/shared/menu/menu-item/onclick-menu-item.component.html b/src/app/shared/menu/menu-item/onclick-menu-item.component.html index 950b80f10f..fd0192ad5f 100644 --- a/src/app/shared/menu/menu-item/onclick-menu-item.component.html +++ b/src/app/shared/menu/menu-item/onclick-menu-item.component.html @@ -1 +1,8 @@ -{{item.text | translate}} \ No newline at end of file +{{item.text | translate}} diff --git a/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts b/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts index c36b46a20d..18ae66b23d 100644 --- a/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts +++ b/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts @@ -44,8 +44,8 @@ describe('OnClickMenuItemComponent', () => { expect(textContent).toEqual(text); }); - it('should contain call the function on the item when clicked', () => { - debugElement.query(By.css('a.nav-link')).triggerEventHandler('click', {}); + it('should call the function on the item when clicked', () => { + debugElement.query(By.css('a.nav-link')).triggerEventHandler('click', new Event(('click'))); expect(item.function).toHaveBeenCalled(); }); }); diff --git a/src/app/shared/menu/menu-item/onclick-menu-item.component.ts b/src/app/shared/menu/menu-item/onclick-menu-item.component.ts index 95b896ed64..002bfbc819 100644 --- a/src/app/shared/menu/menu-item/onclick-menu-item.component.ts +++ b/src/app/shared/menu/menu-item/onclick-menu-item.component.ts @@ -17,4 +17,10 @@ export class OnClickMenuItemComponent { constructor(@Inject('itemModelProvider') item: OnClickMenuItemModel) { this.item = item; } + + public activate(event: any) { + event.preventDefault(); + this.item.function(); + event.stopPropagation(); + } } diff --git a/src/themes/dspace/styles/_global-styles.scss b/src/themes/dspace/styles/_global-styles.scss index 72fac11156..8682e3dcdf 100644 --- a/src/themes/dspace/styles/_global-styles.scss +++ b/src/themes/dspace/styles/_global-styles.scss @@ -23,8 +23,8 @@ } header { - ds-navbar-section > li, - ds-expandable-navbar-section > li { + li > .navbar-section, + li > .expandable-navbar-section { display: flex; flex-direction: column; justify-content: center;