diff --git a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
index 7a805814fd..3d4b0fc313 100644
--- a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
+++ b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts
@@ -1,18 +1,19 @@
import { Component, Injector, OnInit } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
-import { slideSidebar } from '../../shared/animations/slide';
+import { slide, slideHorizontal, slideSidebar } from '../../shared/animations/slide';
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
import { MenuService } from '../../shared/menu/menu.service';
import { MenuID, SectionType } from '../../shared/menu/initial-menus-state';
import { MenuComponent } from '../../shared/menu/menu.component';
import { TextSectionTypeModel } from '../../shared/menu/models/section-types/text.model';
import { LinkSectionTypeModel } from '../../shared/menu/models/section-types/link.model';
+import { AuthService } from '../../core/auth/auth.service';
@Component({
selector: 'ds-admin-sidebar',
templateUrl: './admin-sidebar.component.html',
styleUrls: ['./admin-sidebar.component.scss'],
- animations: [slideSidebar]
+ animations: [slideHorizontal, slideSidebar]
})
export class AdminSidebarComponent extends MenuComponent implements OnInit {
menuID = MenuID.ADMIN;
@@ -22,14 +23,22 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
constructor(protected menuService: MenuService,
protected injector: Injector,
- private variableService: CSSVariableService) {
+ private variableService: CSSVariableService,
+ private authService: AuthService
+ ) {
super(menuService, injector);
}
ngOnInit(): void {
+ this.createMenu();
super.ngOnInit();
this.sidebarWidth = this.variableService.getVariable('adminSidebarWidth');
- this.createMenu();
+ this.authService.isAuthenticated()
+ .subscribe((loggedIn: boolean) => {
+ if (loggedIn) {
+ this.menuService.showMenu(this.menuID);
+ }
+ });
}
createMenu() {
@@ -39,7 +48,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'new',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.new' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.new'
+ } as TextSectionTypeModel,
icon: 'plus-circle'
},
{
@@ -47,28 +59,44 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'new',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_community', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.new_community',
+ link: '/communities/submission'
+ } as LinkSectionTypeModel,
},
{
id: 'new_collection',
parentID: 'new',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_collection', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.new_collection',
+ link: '/collections/submission'
+ } as LinkSectionTypeModel,
},
{
id: 'new_item',
parentID: 'new',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_item', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.new_item',
+ link: '/items/submission'
+ } as LinkSectionTypeModel,
},
{
id: 'new_item_version',
parentID: 'new',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.new_item_version', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.new_item_version',
+ link: '#'
+ } as LinkSectionTypeModel,
},
/* Edit */
@@ -76,7 +104,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'edit',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.edit' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.edit'
+ } as TextSectionTypeModel,
icon: 'pencil-alt'
},
{
@@ -84,21 +115,33 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'edit',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_community', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.edit_community',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'edit_collection',
parentID: 'edit',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_collection', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.edit_collection',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'edit_item',
parentID: 'edit',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.edit_item', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.edit_item',
+ link: '#'
+ } as LinkSectionTypeModel,
},
/* Import */
@@ -106,22 +149,35 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'import',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.import' } as TextSectionTypeModel,
- icon: 'sign-in-alt'
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.import'
+ } as TextSectionTypeModel,
+ icon: 'sign-in-alt',
+ index: -1
},
{
id: 'import_metadata',
parentID: 'import',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.import_metadata', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.import_metadata',
+ link: '#'
+ } as LinkSectionTypeModel,
+ index: 1
},
{
id: 'import_batch',
parentID: 'import',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.import_batch', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.import_batch',
+ link: '#'
+ } as LinkSectionTypeModel,
},
/* Export */
@@ -129,7 +185,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'export',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.export' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.export'
+ } as TextSectionTypeModel,
icon: 'sign-out-alt'
},
{
@@ -137,27 +196,43 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'export',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_community', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.export_community',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'export_collection',
parentID: 'export',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_collection', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.export_collection',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'export_item',
parentID: 'export',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_item', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.export_item',
+ link: '#'
+ } as LinkSectionTypeModel,
}, {
id: 'export_metadata',
parentID: 'export',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.export_metadata', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.export_metadata',
+ link: '#'
+ } as LinkSectionTypeModel,
},
/* Access Control */
@@ -165,7 +240,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'access_control',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.access_control' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.access_control'
+ } as TextSectionTypeModel,
icon: 'key'
},
{
@@ -173,21 +251,33 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'access_control',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_people', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.access_control_people',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'access_control_groups',
parentID: 'access_control',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_groups', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.access_control_groups',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'access_control_authorizations',
parentID: 'access_control',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.access_control_authorizations', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.access_control_authorizations',
+ link: '#'
+ } as LinkSectionTypeModel,
},
/* Search */
@@ -195,7 +285,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'find',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.find' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.find'
+ } as TextSectionTypeModel,
icon: 'search'
},
{
@@ -203,21 +296,33 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'find',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_items', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.find_items',
+ link: '/search'
+ } as LinkSectionTypeModel,
},
{
id: 'find_withdrawn_items',
parentID: 'find',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_withdrawn_items', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.find_withdrawn_items',
+ link: '#'
+ } as LinkSectionTypeModel,
},
{
id: 'find_private_items',
parentID: 'find',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.find_private_items', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.find_private_items',
+ link: '/admin/items'
+ } as LinkSectionTypeModel,
},
/* Registries */
@@ -225,7 +330,10 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'registries',
active: false,
visible: true,
- model: { type: SectionType.TEXT, text: 'admin.sidebar.section.registries' } as TextSectionTypeModel,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.registries'
+ } as TextSectionTypeModel,
icon: 'list'
},
{
@@ -233,14 +341,22 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
parentID: 'registries',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.registries_metadata', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.registries_metadata',
+ link: '/registries/metadata'
+ } as LinkSectionTypeModel,
},
{
id: 'registries_format',
parentID: 'registries',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.registries_format', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.registries_format',
+ link: '/registries/format'
+ } as LinkSectionTypeModel,
},
/* Curation tasks */
@@ -248,16 +364,24 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'curation_tasks',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.curation_task', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.curation_task',
+ link: '/curation'
+ } as LinkSectionTypeModel,
icon: 'filter'
},
/* Statistics */
{
- id: 'statistics',
+ id: 'statistics_task',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.statistics', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.statistics_task',
+ link: '#'
+ } as LinkSectionTypeModel,
icon: 'chart-bar'
},
@@ -266,7 +390,11 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
id: 'control_panel',
active: false,
visible: true,
- model: { type: SectionType.LINK, text: 'admin.sidebar.section.control_panel', link: '#' } as LinkSectionTypeModel,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.control_panel',
+ link: '#'
+ } as LinkSectionTypeModel,
icon: 'cogs'
},
];
@@ -297,4 +425,5 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
this.sidebarOpen = true;
}
}
+
}
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 175a6f7be6..044293c823 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
@@ -10,15 +10,17 @@
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 a7168ce386..6b086524d7 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,7 +9,6 @@ import { rendersSectionForMenu } from '../../../shared/menu/menu.decorator';
import { MenuService } from '../../../shared/menu/menu.service';
import { MenuSection } from '../../../shared/menu/menu.reducer';
import { Observable } from 'rxjs';
-import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Component({
selector: 'ds-expandable-admin-sidebar-section',
@@ -22,22 +21,18 @@ import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionComponent implements OnInit {
subSections: Observable
;
menuID = MenuID.ADMIN;
- link = '#';
sidebarActiveBg;
sidebarCollapsed: Observable;
- c = 0;
- count = new BehaviorSubject(0);
constructor(@Inject('sectionDataProvider') menuSection, protected menuService: MenuService,
- private variableService: CSSVariableService, protected injector: Injector,) {
+ private variableService: CSSVariableService, protected injector: Injector) {
super(menuSection, menuService, injector);
+
}
ngOnInit(): void {
super.ngOnInit();
this.subSections = this.menuService.getSubSectionsByParentID(this.menuID, this.section.id);
- // this.active.subscribe((t) => console.log('section: ', this.section.id, this.c, t));
- // this.active.subscribe((t) => this.count.next(++this.c));
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index bc0a512358..8c4126f8ed 100755
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -31,11 +31,11 @@ import { DSpaceRouterStateSerializer } from './shared/ngrx/dspace-router-state-s
import { NotificationsBoardComponent } from './shared/notifications/notifications-board/notifications-board.component';
import { NotificationComponent } from './shared/notifications/notification/notification.component';
import { SharedModule } from './shared/shared.module';
-import { NavbarComponent } from './navbar/navbar.component';
import { HeaderNavbarWrapperComponent } from './header-nav-wrapper/header-navbar-wrapper.component';
import { AdminSidebarComponent } from './+admin/admin-sidebar/admin-sidebar.component';
import { AdminSidebarSectionComponent } from './+admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
import { ExpandableAdminSidebarSectionComponent } from './+admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
+import { NavbarModule } from './navbar/navbar.module';
export function getConfig() {
return ENV_CONFIG;
@@ -53,6 +53,7 @@ export function getMetaReducers(config: GlobalConfig): Array = {
router: fromRouter.routerReducer,
hostWindow: hostWindowReducer,
- navbar: navbarReducer,
forms: formReducer,
notifications: notificationsReducer,
searchSidebar: sidebarReducer,
diff --git a/src/app/core/index/index.reducer.spec.ts b/src/app/core/index/index.reducer.spec.ts
index a1cf92aeb3..4c30f118f1 100644
--- a/src/app/core/index/index.reducer.spec.ts
+++ b/src/app/core/index/index.reducer.spec.ts
@@ -20,6 +20,8 @@ describe('requestReducer', () => {
const testState: IndexState = {
[IndexName.OBJECT]: {
[key1]: val1
+ },
+ [IndexName.REQUEST]: {
}
};
deepFreeze(testState);
diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html
index 1eab1d9ffd..931ab36749 100644
--- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html
+++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts b/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts
index d041f41654..f93005218d 100644
--- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts
+++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts
@@ -1,13 +1,12 @@
import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core';
-import { createSelector, select, Store } from '@ngrx/store';
+import { Store } from '@ngrx/store';
import { AppState } from '../app.reducer';
-import { NavbarState } from '../navbar/navbar.reducer';
import { hasValue } from '../shared/empty.util';
import { Observable } from 'rxjs/internal/Observable';
import { Subscription } from 'rxjs/internal/Subscription';
+import { MenuService } from '../shared/menu/menu.service';
+import { MenuID } from '../shared/menu/initial-menus-state';
-const navbarStateSelector = (state: AppState) => state.navbar;
-const navCollapsedSelector = createSelector(navbarStateSelector, (navbar: NavbarState) => navbar.navCollapsed);
@Component({
selector: 'ds-header-navbar-wrapper',
styleUrls: ['header-navbar-wrapper.component.scss'],
@@ -17,14 +16,16 @@ export class HeaderNavbarWrapperComponent implements OnInit, OnDestroy {
@HostBinding('class.open') isOpen = false;
private sub: Subscription;
public isNavBarCollapsed: Observable;
+ menuID = MenuID.PUBLIC;
constructor(
- private store: Store
+ private store: Store,
+ private menuService: MenuService
) {
}
ngOnInit(): void {
- this.isNavBarCollapsed = this.store.pipe(select(navCollapsedSelector));
+ this.isNavBarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
this.sub = this.isNavBarCollapsed.subscribe((isCollapsed) => this.isOpen = !isCollapsed)
}
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index 7d84cf821e..6cd200a09c 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -9,7 +9,7 @@
-
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index 52eefbe510..336acc35df 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -1,8 +1,7 @@
import { Component } from '@angular/core';
-import { NavbarToggleAction } from '../navbar/navbar.actions';
-import { Store } from '@ngrx/store';
-import { AppState } from '../app.reducer';
import { Observable } from 'rxjs/internal/Observable';
+import { MenuService } from '../shared/menu/menu.service';
+import { MenuID } from '../shared/menu/initial-menus-state';
@Component({
selector: 'ds-header',
@@ -16,13 +15,14 @@ export class HeaderComponent {
*/
public isAuthenticated: Observable;
public showAuth = false;
+ menuID = MenuID.PUBLIC;
constructor(
- private store: Store,
+ private menuService: MenuService
) {
}
- public toggle(): void {
- this.store.dispatch(new NavbarToggleAction());
+ public toggleNavbar(): void {
+ this.menuService.toggleMenu(this.menuID);
}
}
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
new file mode 100644
index 0000000000..be09c687f3
--- /dev/null
+++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss
new file mode 100644
index 0000000000..1fb78bef0d
--- /dev/null
+++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss
@@ -0,0 +1,27 @@
+@import '../../../styles/variables.scss';
+
+.dropdown-menu {
+ overflow: hidden;
+ min-width: 100%;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ ::ng-deep a.nav-link {
+ padding-right: $spacer;
+ padding-left: $spacer;
+ white-space: nowrap;
+ }
+}
+
+/** Mobile menu styling **/
+@media screen and (max-width: map-get($grid-breakpoints, md)) {
+ .dropdown-toggle {
+ &:after {
+ float: right;
+ margin-top: $spacer/2;
+ }
+ }
+ .dropdown-menu {
+ border: 0;
+
+ }
+}
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
new file mode 100644
index 0000000000..dd055785ab
--- /dev/null
+++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ExpandableNavbarSectionComponent } from './expandable-navbar-section.component';
+
+describe('ExpandableNavbarSectionComponent', () => {
+ let component: ExpandableNavbarSectionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ExpandableNavbarSectionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ExpandableNavbarSectionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
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
new file mode 100644
index 0000000000..2d0091399c
--- /dev/null
+++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts
@@ -0,0 +1,66 @@
+import { Component, Inject, Injector, OnInit } from '@angular/core';
+import { NavbarSectionComponent } from '../navbar-section/navbar-section.component';
+import { MenuService } from '../../shared/menu/menu.service';
+import { MenuID } from '../../shared/menu/initial-menus-state';
+import { rendersSectionForMenu } from '../../shared/menu/menu.decorator';
+import { Observable } from 'rxjs/internal/Observable';
+import { MenuSection } from '../../shared/menu/menu.reducer';
+import { slide } from '../../shared/animations/slide';
+import { first } from 'rxjs/operators';
+import { HostWindowService } from '../../shared/host-window.service';
+import { GenericConstructor } from '../../core/shared/generic-constructor';
+import { MenuSectionComponent } from '../../shared/menu/menu-section/menu-section.component';
+
+@Component({
+ selector: 'ds-expandable-navbar-section',
+ templateUrl: './expandable-navbar-section.component.html',
+ styleUrls: ['./expandable-navbar-section.component.scss'],
+ animations: [slide]
+})
+@rendersSectionForMenu(MenuID.PUBLIC, true)
+export class ExpandableNavbarSectionComponent extends NavbarSectionComponent implements OnInit {
+ menuID = MenuID.PUBLIC;
+
+ constructor(@Inject('sectionDataProvider') menuSection,
+ protected menuService: MenuService,
+ protected injector: Injector,
+ private windowService: HostWindowService
+ ) {
+ super(menuSection, menuService, injector);
+ }
+
+ ngOnInit() {
+ super.ngOnInit();
+ }
+
+ activateSection(event): void {
+ this.windowService.isXsOrSm().pipe(
+ first()
+ ).subscribe((isMobile) => {
+ if (!isMobile) {
+ super.activateSection(event);
+ }
+ });
+ }
+
+ deactivateSection(event): void {
+ this.windowService.isXsOrSm().pipe(
+ first()
+ ).subscribe((isMobile) => {
+ if (!isMobile) {
+ super.deactivateSection(event);
+ }
+ });
+ }
+
+ toggleSection(event): void {
+ event.preventDefault();
+ this.windowService.isXsOrSm().pipe(
+ first()
+ ).subscribe((isMobile) => {
+ if (isMobile) {
+ super.toggleSection(event);
+ }
+ });
+ }
+}
diff --git a/src/app/navbar/navbar-section/navbar-section.component.html b/src/app/navbar/navbar-section/navbar-section.component.html
new file mode 100644
index 0000000000..b257a7bd57
--- /dev/null
+++ b/src/app/navbar/navbar-section/navbar-section.component.html
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/src/app/navbar/navbar-section/navbar-section.component.scss b/src/app/navbar/navbar-section/navbar-section.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/navbar/navbar-section/navbar-section.component.spec.ts b/src/app/navbar/navbar-section/navbar-section.component.spec.ts
new file mode 100644
index 0000000000..f6845145b3
--- /dev/null
+++ b/src/app/navbar/navbar-section/navbar-section.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NavbarSectionComponent } from './navbar-section.component';
+
+describe('NavbarSectionComponent', () => {
+ let component: NavbarSectionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ NavbarSectionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NavbarSectionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/navbar/navbar-section/navbar-section.component.ts b/src/app/navbar/navbar-section/navbar-section.component.ts
new file mode 100644
index 0000000000..60f270745b
--- /dev/null
+++ b/src/app/navbar/navbar-section/navbar-section.component.ts
@@ -0,0 +1,27 @@
+import { Component, Inject, Injector, OnInit } from '@angular/core';
+import { MenuSectionComponent } from '../../shared/menu/menu-section/menu-section.component';
+import { MenuService } from '../../shared/menu/menu.service';
+import { MenuID } from '../../shared/menu/initial-menus-state';
+import { rendersSectionForMenu } from '../../shared/menu/menu.decorator';
+import { HostWindowService } from '../../shared/host-window.service';
+
+@Component({
+ selector: 'ds-navbar-section',
+ templateUrl: './navbar-section.component.html',
+ styleUrls: ['./navbar-section.component.scss']
+})
+@rendersSectionForMenu(MenuID.PUBLIC, false)
+export class NavbarSectionComponent extends MenuSectionComponent implements OnInit {
+ menuID = MenuID.PUBLIC;
+
+ constructor(@Inject('sectionDataProvider') menuSection,
+ protected menuService: MenuService,
+ protected injector: Injector
+ ) {
+ super(menuSection, menuService, injector);
+ }
+
+ ngOnInit() {
+ super.ngOnInit();
+ }
+}
diff --git a/src/app/navbar/navbar.actions.ts b/src/app/navbar/navbar.actions.ts
deleted file mode 100644
index c588c41f0c..0000000000
--- a/src/app/navbar/navbar.actions.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Action } from '@ngrx/store';
-
-import { type } from '../shared/ngrx/type';
-
-/**
- * For each action type in an action group, make a simple
- * enum object for all of this group's action types.
- *
- * The 'type' utility function coerces strings into string
- * literal types and runs a simple check to guarantee all
- * action types in the application are unique.
- */
-export const NavbarActionTypes = {
- COLLAPSE: type('dspace/navbar/COLLAPSE'),
- EXPAND: type('dspace/navbar/EXPAND'),
- TOGGLE: type('dspace/navbar/TOGGLE')
-};
-
-/* tslint:disable:max-classes-per-file */
-export class NavbarCollapseAction implements Action {
- type = NavbarActionTypes.COLLAPSE;
-}
-
-export class NavbarExpandAction implements Action {
- type = NavbarActionTypes.EXPAND;
-}
-
-export class NavbarToggleAction implements Action {
- type = NavbarActionTypes.TOGGLE;
-}
-/* tslint:enable:max-classes-per-file */
-
-/**
- * Export a type alias of all actions in this action group
- * so that reducers can easily compose action types
- */
-export type NavbarAction
- = NavbarCollapseAction
- | NavbarExpandAction
- | NavbarToggleAction
diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html
index f80f74724c..eb6164b26f 100644
--- a/src/app/navbar/navbar.component.html
+++ b/src/app/navbar/navbar.component.html
@@ -1,46 +1,17 @@
-
+
diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss
index 97caea624b..d3c682d004 100644
--- a/src/app/navbar/navbar.component.scss
+++ b/src/app/navbar/navbar.component.scss
@@ -5,12 +5,6 @@ nav.navbar {
align-items: baseline;
}
-.dropdown-menu {
- min-width: 100%;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
-}
-
/** Mobile menu styling **/
@media screen and (max-width: map-get($grid-breakpoints, md)) {
.navbar {
@@ -23,15 +17,6 @@ nav.navbar {
&.open {
height: 100vh; //doesn't matter because wrapper is sticky
}
- .dropdown-toggle {
- &:after {
- float: right;
- margin-top: $spacer/2;
- }
- }
- .dropdown-menu {
- border: 0;
- }
}
}
diff --git a/src/app/navbar/navbar.component.spec.ts b/src/app/navbar/navbar.component.spec.ts
index 18a36b5a92..fac2b3cfe4 100644
--- a/src/app/navbar/navbar.component.spec.ts
+++ b/src/app/navbar/navbar.component.spec.ts
@@ -15,12 +15,13 @@ import { Router } from '@angular/router';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import * as ngrx from '@ngrx/store';
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { NavbarState } from './navbar.reducer';
-import { NavbarToggleAction } from './navbar.actions';
+import { ToggleMenuAction } from '../shared/menu/menu.actions';
+import { MenuID } from '../shared/menu/initial-menus-state';
+import { MenusState } from '../shared/menu/menu.reducer';
let comp: NavbarComponent;
let fixture: ComponentFixture;
-let store: Store;
+let store: Store;
describe('NavbarComponent', () => {
@@ -49,7 +50,7 @@ describe('NavbarComponent', () => {
comp = fixture.componentInstance;
- store = fixture.debugElement.injector.get(Store) as Store;
+ store = fixture.debugElement.injector.get(Store) as Store;
spyOn(store, 'dispatch');
});
@@ -61,7 +62,7 @@ describe('NavbarComponent', () => {
});
it('should dispatch a NavbarToggleAction', () => {
- expect(store.dispatch).toHaveBeenCalledWith(new NavbarToggleAction());
+ expect(store.dispatch).toHaveBeenCalledWith(new ToggleMenuAction(MenuID.PUBLIC));
});
});
diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts
index f25298ee64..0b6b4fef5c 100644
--- a/src/app/navbar/navbar.component.ts
+++ b/src/app/navbar/navbar.component.ts
@@ -1,10 +1,11 @@
-import { Component, Input } from '@angular/core';
-import { Store } from '@ngrx/store';
-import { AppState } from '../app.reducer';
+import { Component, Injector, OnInit } from '@angular/core';
import { slideMobileNav } from '../shared/animations/slide';
+import { MenuComponent } from '../shared/menu/menu.component';
+import { MenuService } from '../shared/menu/menu.service';
+import { MenuID, SectionType } from '../shared/menu/initial-menus-state';
+import { TextSectionTypeModel } from '../shared/menu/models/section-types/text.model';
+import { LinkSectionTypeModel } from '../shared/menu/models/section-types/link.model';
import { HostWindowService } from '../shared/host-window.service';
-import { first } from 'rxjs/operators';
-import { Observable } from 'rxjs/internal/Observable';
@Component({
selector: 'ds-navbar',
@@ -12,32 +13,81 @@ import { Observable } from 'rxjs/internal/Observable';
templateUrl: 'navbar.component.html',
animations: [slideMobileNav]
})
-export class NavbarComponent {
- @Input() isNavBarCollapsed: Observable;
+export class NavbarComponent extends MenuComponent implements OnInit {
+ menuID = MenuID.PUBLIC;
- constructor(
- private store: Store,
- public windowService: HostWindowService
+ constructor(protected menuService: MenuService,
+ protected injector: Injector,
+ public windowService: HostWindowService
) {
+ super(menuService, injector);
}
- openDropdownOnHover(dropdown: any): void {
- this.windowService.isXsOrSm().pipe(
- first()
- ).subscribe((isMobile) => {
- if (!isMobile) {
- dropdown.open();
- }
- });
+ ngOnInit(): void {
+ this.createMenu();
+ super.ngOnInit();
}
- closeDropdownOnHover(dropdown: any): void {
- this.windowService.isXsOrSm().pipe(
- first()
- ).subscribe((isMobile) => {
- if (!isMobile) {
- dropdown.close();
- }
- });
+ createMenu() {
+ const menuList = [
+ /* News */
+ {
+ id: 'browse_global',
+ active: false,
+ visible: true,
+ model: {
+ type: SectionType.TEXT,
+ text: 'admin.sidebar.section.browse_global'
+ } as TextSectionTypeModel,
+ },
+ {
+ id: 'browse_global_communities_and_collections',
+ parentID: 'browse_global',
+ active: false,
+ visible: true,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.browse_global_communities_and_collections',
+ link: '#'
+ } as LinkSectionTypeModel,
+ },
+ {
+ id: 'browse_global_global_by_issue_date',
+ parentID: 'browse_global',
+ active: false,
+ visible: true,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.browse_global_by_issue_date',
+ link: '#'
+ } as LinkSectionTypeModel,
+ },
+ {
+ id: 'browse_global_by_author',
+ parentID: 'browse_global',
+ active: false,
+ visible: true,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.browse_global_by_author',
+ link: '#'
+ } as LinkSectionTypeModel,
+ },
+
+ /* Statistics */
+ {
+ id: 'statistics',
+ active: false,
+ visible: true,
+ model: {
+ type: SectionType.LINK,
+ text: 'admin.sidebar.section.statistics',
+ link: '#'
+ } as LinkSectionTypeModel,
+ },
+ ];
+ menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, menuSection));
+
}
+
}
diff --git a/src/app/navbar/navbar.effects.spec.ts b/src/app/navbar/navbar.effects.spec.ts
index 720e258884..39960d90d5 100644
--- a/src/app/navbar/navbar.effects.spec.ts
+++ b/src/app/navbar/navbar.effects.spec.ts
@@ -1,11 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { NavbarEffects } from './navbar.effects';
-import { NavbarCollapseAction } from './navbar.actions';
import { HostWindowResizeAction } from '../shared/host-window.actions';
import { Observable } from 'rxjs';
import { provideMockActions } from '@ngrx/effects/testing';
import { cold, hot } from 'jasmine-marbles';
import * as fromRouter from '@ngrx/router-store';
+import { CollapseMenuAction } from '../shared/menu/menu.actions';
+import { MenuID } from '../shared/menu/initial-menus-state';
describe('NavbarEffects', () => {
let navbarEffects: NavbarEffects;
@@ -28,7 +29,7 @@ describe('NavbarEffects', () => {
it('should return a COLLAPSE action in response to a RESIZE action', () => {
actions = hot('--a-', { a: new HostWindowResizeAction(800, 600) });
- const expected = cold('--b-', { b: new NavbarCollapseAction() });
+ const expected = cold('--b-', { b: new CollapseMenuAction(MenuID.PUBLIC) });
expect(navbarEffects.resize$).toBeObservable(expected);
});
@@ -40,7 +41,7 @@ describe('NavbarEffects', () => {
it('should return a COLLAPSE action in response to an UPDATE_LOCATION action', () => {
actions = hot('--a-', { a: { type: fromRouter.ROUTER_NAVIGATION } });
- const expected = cold('--b-', { b: new NavbarCollapseAction() });
+ const expected = cold('--b-', { b: new CollapseMenuAction(MenuID.PUBLIC) });
expect(navbarEffects.routeChange$).toBeObservable(expected);
});
diff --git a/src/app/navbar/navbar.effects.ts b/src/app/navbar/navbar.effects.ts
index 89320f9cf6..b06518980e 100644
--- a/src/app/navbar/navbar.effects.ts
+++ b/src/app/navbar/navbar.effects.ts
@@ -1,24 +1,25 @@
import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
-import { Effect, Actions, ofType } from '@ngrx/effects'
+import { Actions, Effect, ofType } from '@ngrx/effects'
import * as fromRouter from '@ngrx/router-store';
import { HostWindowActionTypes } from '../shared/host-window.actions';
-import { NavbarCollapseAction } from './navbar.actions';
+import { CollapseMenuAction } from '../shared/menu/menu.actions';
+import { MenuID } from '../shared/menu/initial-menus-state';
@Injectable()
export class NavbarEffects {
-
+ menuID = MenuID.PUBLIC;
@Effect() resize$ = this.actions$
.pipe(
ofType(HostWindowActionTypes.RESIZE),
- map(() => new NavbarCollapseAction())
+ map(() => new CollapseMenuAction(this.menuID))
);
@Effect() routeChange$ = this.actions$
.pipe(
ofType(fromRouter.ROUTER_NAVIGATION),
- map(() => new NavbarCollapseAction())
+ map(() => new CollapseMenuAction(this.menuID))
);
constructor(private actions$: Actions) {
diff --git a/src/app/navbar/navbar.module.ts b/src/app/navbar/navbar.module.ts
new file mode 100644
index 0000000000..adb8b2d8ea
--- /dev/null
+++ b/src/app/navbar/navbar.module.ts
@@ -0,0 +1,45 @@
+import { SharedModule } from '../shared/shared.module';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { EffectsModule } from '@ngrx/effects';
+import { CoreModule } from '../core/core.module';
+import { NavbarEffects } from './navbar.effects';
+import { NavbarSectionComponent } from './navbar-section/navbar-section.component';
+import { ExpandableNavbarSectionComponent } from './expandable-navbar-section/expandable-navbar-section.component';
+import { NavbarComponent } from './navbar.component';
+
+const effects = [
+ NavbarEffects
+];
+
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ EffectsModule.forFeature(effects),
+ CoreModule.forRoot()
+ ],
+ declarations: [
+ NavbarComponent,
+ NavbarSectionComponent,
+ ExpandableNavbarSectionComponent
+ ],
+ providers: [
+
+ ],
+ entryComponents: [
+ NavbarSectionComponent,
+ ExpandableNavbarSectionComponent
+ ],
+ exports: [
+ NavbarComponent,
+ NavbarSectionComponent,
+ ExpandableNavbarSectionComponent
+ ]
+})
+
+/**
+ * This module handles all components and pipes that are necessary for the search page
+ */
+export class NavbarModule {
+}
diff --git a/src/app/navbar/navbar.reducer.spec.ts b/src/app/navbar/navbar.reducer.spec.ts
deleted file mode 100644
index b9afbd743e..0000000000
--- a/src/app/navbar/navbar.reducer.spec.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import * as deepFreeze from 'deep-freeze';
-
-import { navbarReducer } from './navbar.reducer';
-import { NavbarCollapseAction, NavbarExpandAction, NavbarToggleAction } from './navbar.actions';
-
-class NullAction extends NavbarCollapseAction {
- type = null;
-
- constructor() {
- super();
- }
-}
-
-describe('navbarReducer', () => {
- it('should return the current state when no valid actions have been made', () => {
- const state = { navCollapsed: false };
- const action = new NullAction();
- const newState = navbarReducer(state, action);
-
- expect(newState).toEqual(state);
- });
-
- it('should start with navCollapsed = true', () => {
- const action = new NullAction();
- const initialState = navbarReducer(undefined, action);
-
- // The navigation starts collapsed
- expect(initialState.navCollapsed).toEqual(true);
- });
-
- it('should set navCollapsed to true in response to the COLLAPSE action', () => {
- const state = { navCollapsed: false };
- const action = new NavbarCollapseAction();
- const newState = navbarReducer(state, action);
-
- expect(newState.navCollapsed).toEqual(true);
- });
-
- it('should perform the COLLAPSE action without affecting the previous state', () => {
- const state = { navCollapsed: false };
- deepFreeze(state);
-
- const action = new NavbarCollapseAction();
- navbarReducer(state, action);
-
- // no expect required, deepFreeze will ensure an exception is thrown if the state
- // is mutated, and any uncaught exception will cause the test to fail
- });
-
- it('should set navCollapsed to false in response to the EXPAND action', () => {
- const state = { navCollapsed: true };
- const action = new NavbarExpandAction();
- const newState = navbarReducer(state, action);
-
- expect(newState.navCollapsed).toEqual(false);
- });
-
- it('should perform the EXPAND action without affecting the previous state', () => {
- const state = { navCollapsed: true };
- deepFreeze(state);
-
- const action = new NavbarExpandAction();
- navbarReducer(state, action);
- });
-
- it('should flip the value of navCollapsed in response to the TOGGLE action', () => {
- const state1 = { navCollapsed: true };
- const action = new NavbarToggleAction();
-
- const state2 = navbarReducer(state1, action);
- const state3 = navbarReducer(state2, action);
-
- expect(state2.navCollapsed).toEqual(false);
- expect(state3.navCollapsed).toEqual(true);
- });
-
- it('should perform the TOGGLE action without affecting the previous state', () => {
- const state = { navCollapsed: true };
- deepFreeze(state);
-
- const action = new NavbarToggleAction();
- navbarReducer(state, action);
- });
-
-});
diff --git a/src/app/navbar/navbar.reducer.ts b/src/app/navbar/navbar.reducer.ts
deleted file mode 100644
index c3edc80115..0000000000
--- a/src/app/navbar/navbar.reducer.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { NavbarAction, NavbarActionTypes } from './navbar.actions';
-
-export interface NavbarState {
- navCollapsed: boolean;
-}
-
-const initialState: NavbarState = {
- navCollapsed: true
-};
-
-export function navbarReducer(state = initialState, action: NavbarAction): NavbarState {
- switch (action.type) {
-
- case NavbarActionTypes.COLLAPSE: {
- return Object.assign({}, state, {
- navCollapsed: true
- });
- }
-
- case NavbarActionTypes.EXPAND: {
- return Object.assign({}, state, {
- navCollapsed: false
- });
-
- }
-
- case NavbarActionTypes.TOGGLE: {
- return Object.assign({}, state, {
- navCollapsed: !state.navCollapsed
- });
-
- }
-
- default: {
- return state;
- }
- }
-}
diff --git a/src/app/shared/animations/slide.ts b/src/app/shared/animations/slide.ts
index c20d077b7a..1d07bd1dc5 100644
--- a/src/app/shared/animations/slide.ts
+++ b/src/app/shared/animations/slide.ts
@@ -1,7 +1,8 @@
import {
animate,
animateChild,
- group, query, sequence,
+ group,
+ query,
state,
style,
transition,
@@ -11,8 +12,15 @@ import {
export const slide = trigger('slide', [
state('void', style({ height: 0 })),
state('*', style({ height: '*' })),
- transition(':enter', [animate('2000ms')]),
- transition(':leave', [animate('2000ms')])
+ transition(':enter', [animate('200ms')]),
+ transition(':leave', [animate('200ms')])
+]);
+
+export const slideHorizontal = trigger('slideHorizontal', [
+ state('void', style({ width: 0 })),
+ state('*', style({ width: '*' })),
+ transition(':enter', [animate('200ms')]),
+ transition(':leave', [animate('200ms')])
]);
export const slideMobileNav = trigger('slideMobileNav', [
diff --git a/src/app/shared/menu/menu-section/menu-section.component.ts b/src/app/shared/menu/menu-section/menu-section.component.ts
index 119ae218d5..0c794ab9ce 100644
--- a/src/app/shared/menu/menu-section/menu-section.component.ts
+++ b/src/app/shared/menu/menu-section/menu-section.component.ts
@@ -6,6 +6,8 @@ import { MenuID, SectionType } from '../initial-menus-state';
import { hasNoValue, hasValue } from '../../empty.util';
import { Observable } from 'rxjs/internal/Observable';
import { SectionTypeModel } from '../models/section-types/section-type.model';
+import { distinctUntilChanged } from 'rxjs/operators';
+import { GenericConstructor } from '../../../core/shared/generic-constructor';
@Component({
selector: 'ds-menu-section',
@@ -14,12 +16,16 @@ import { SectionTypeModel } from '../models/section-types/section-type.model';
export class MenuSectionComponent {
active: Observable;
menuID: MenuID;
+ itemInjectors: Map = new Map();
+ itemComponents: Map> = new Map>();
+ subSections: Observable;
- constructor(protected section: MenuSection, protected menuService: MenuService, protected injector: Injector) {
+ constructor(public section: MenuSection, protected menuService: MenuService, protected injector: Injector) {
}
ngOnInit(): void {
- this.active = this.menuService.isSectionActive(this.menuID, this.section.id);
+ this.active = this.menuService.isSectionActive(this.menuID, this.section.id).pipe(distinctUntilChanged());
+ this.initializeInjectorData();
}
toggleSection(event: Event) {
@@ -27,6 +33,28 @@ export class MenuSectionComponent {
this.menuService.toggleActiveSection(this.menuID, this.section.id);
}
+ activateSection(event: Event) {
+ event.preventDefault();
+ this.menuService.activateSection(this.menuID, this.section.id);
+ }
+
+ deactivateSection(event: Event) {
+ event.preventDefault();
+ this.menuService.deactivateSection(this.menuID, this.section.id);
+ }
+
+ initializeInjectorData() {
+ this.itemInjectors.set(this.section.id, this.getItemModelInjector(this.section.model));
+ this.itemComponents.set(this.section.id, this.getMenuItemComponent(this.section.model));
+ this.subSections = this.menuService.getSubSectionsByParentID(this.menuID, this.section.id);
+ this.subSections.subscribe((sections: MenuSection[]) => {
+ sections.forEach((section: MenuSection) => {
+ this.itemInjectors.set(section.id, this.getItemModelInjector(section.model));
+ this.itemComponents.set(section.id, this.getMenuItemComponent(section.model));
+ })
+ })
+ }
+
getMenuItemComponent(itemModel?: SectionTypeModel) {
if (hasNoValue(itemModel)) {
itemModel = this.section.model;
diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts
index 6285f84ed0..34c7f205b3 100644
--- a/src/app/shared/menu/menu.component.ts
+++ b/src/app/shared/menu/menu.component.ts
@@ -1,9 +1,9 @@
-import { Component, Injector, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, Component, Injector, OnInit } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { MenuService } from '../../shared/menu/menu.service';
import { MenuID } from '../../shared/menu/initial-menus-state';
import { MenuSection } from '../../shared/menu/menu.reducer';
-import { map, tap } from 'rxjs/operators';
+import { first, map } from 'rxjs/operators';
import { getComponentForMenu } from './menu.decorator';
import { GenericConstructor } from '../../core/shared/generic-constructor';
import { MenuSectionComponent } from './menu-section/menu-section.component';
@@ -15,14 +15,25 @@ import { MenuSectionComponent } from './menu-section/menu-section.component';
export class MenuComponent implements OnInit {
menuID: MenuID;
menuCollapsed: Observable;
+ menuVisible: Observable;
sections: Observable;
+ sectionInjectors: Map = new Map();
+ sectionComponents: Map> = new Map>();
+ changeDetection: ChangeDetectionStrategy.OnPush;
constructor(protected menuService: MenuService, protected injector: Injector) {
}
ngOnInit(): void {
this.menuCollapsed = this.menuService.isMenuCollapsed(this.menuID);
- this.sections = this.menuService.getMenuTopSections(this.menuID);
+ this.menuVisible = this.menuService.isMenuVisible(this.menuID);
+ this.sections = this.menuService.getMenuTopSections(this.menuID).pipe(first());
+ this.sections.subscribe((sections: MenuSection[]) => {
+ sections.forEach((section: MenuSection) => {
+ this.sectionInjectors.set(section.id, this.getSectionDataInjector(section));
+ this.getSectionComponent(section).pipe(first()).subscribe((constr) => this.sectionComponents.set(section.id, constr));
+ })
+ })
}
toggle(event: Event) {
diff --git a/src/app/shared/menu/menu.module.ts b/src/app/shared/menu/menu.module.ts
new file mode 100644
index 0000000000..9768fb946d
--- /dev/null
+++ b/src/app/shared/menu/menu.module.ts
@@ -0,0 +1,54 @@
+import { MenuSectionComponent } from './menu-section/menu-section.component';
+import { MenuComponent } from './menu.component';
+import { LinkTypeMenuItemComponent } from './type-components/link-type.component';
+import { TextTypeMenuItemComponent } from './type-components/text-type.component';
+import { NgModule } from '@angular/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { RouterModule } from '@angular/router';
+
+const COMPONENTS = [
+ MenuSectionComponent,
+ MenuComponent,
+ LinkTypeMenuItemComponent,
+ TextTypeMenuItemComponent
+];
+
+const ENTRY_COMPONENTS = [
+ LinkTypeMenuItemComponent,
+ TextTypeMenuItemComponent
+];
+
+const MODULES = [
+ TranslateModule,
+ RouterModule
+];
+const PROVIDERS = [
+
+];
+
+@NgModule({
+ imports: [
+ ...MODULES
+ ],
+ declarations: [
+ ...COMPONENTS,
+ ...ENTRY_COMPONENTS,
+ ],
+ providers: [
+ ...PROVIDERS
+ ],
+ exports: [
+ ...COMPONENTS,
+ ...MODULES
+ ],
+ entryComponents: [
+ ...ENTRY_COMPONENTS
+ ]
+})
+
+/**
+ * This module handles all components and pipes that need to be shared among multiple other modules
+ */
+export class MenuModule {
+
+}
diff --git a/src/app/shared/menu/menu.reducer.ts b/src/app/shared/menu/menu.reducer.ts
index 0e75256d61..f5cf909cf3 100644
--- a/src/app/shared/menu/menu.reducer.ts
+++ b/src/app/shared/menu/menu.reducer.ts
@@ -94,22 +94,31 @@ export function menusReducer(state: MenusState = initialMenusState, action: Menu
}
function addSection(state: MenusState, action: AddMenuSectionAction) {
- const newState = addToIndex(state, action.section, action.menuID);
- return putSectionState(newState, action, action.section);
+ // let newState = addToIndex(state, action.section, action.menuID);
+ const newState = putSectionState(state, action, action.section);
+ return reorderSections(newState, action)
}
-function addToIndex(state: MenusState, section: MenuSection, menuID: MenuID) {
- const sectionID = section.id;
- const parentID = section.parentID;
- if (hasValue(parentID)) {
- const menuState: MenuState = state[menuID];
- const index = menuState.sectionToSubsectionIndex;
- const parentIndex = hasValue(index[parentID]) ? index[parentID] : [];
- const newIndex = Object.assign({}, index, { [parentID]: [...parentIndex, sectionID] });
- const newMenuState = Object.assign({}, menuState, { sectionToSubsectionIndex: newIndex });
- return Object.assign({}, state, { [menuID]: newMenuState });
- }
- return state;
+function reorderSections(state: MenusState, action: MenuSectionAction) {
+ const menuState: MenuState = state[action.menuID];
+ const newSectionState: MenuSections = {};
+ const newSectionIndexState: MenuSectionIndex = {};
+ Object.values(menuState.sections).sort((sectionA: MenuSection, sectionB: MenuSection) => {
+ const indexA = sectionA.index || 0;
+ const indexB = sectionB.index || 0;
+ return indexA - indexB;
+ }).forEach((section: MenuSection) => {
+ newSectionState[section.id] = section;
+ if (hasValue(section.parentID)) {
+ const parentIndex = hasValue(newSectionIndexState[section.parentID]) ? newSectionIndexState[section.parentID] : [];
+ newSectionIndexState[section.parentID] = [...parentIndex, section.id];
+ }
+ });
+ const newMenuState = Object.assign({}, menuState, {
+ sections: newSectionState,
+ sectionToSubsectionIndex: newSectionIndexState
+ });
+ return Object.assign({}, state, { [action.menuID]: newMenuState });
}
function removeSection(state: MenusState, action: RemoveMenuSectionAction) {
@@ -167,11 +176,11 @@ function toggleActiveSection(state: MenusState, action: ToggleActiveMenuSectionA
function putSectionState(state: MenusState, action: MenuAction, section: MenuSection): MenusState {
const menuState: MenuState = state[action.menuID];
- const newTopSections = Object.assign({}, menuState.sections, {
+ const newSections = Object.assign({}, menuState.sections, {
[section.id]: section
});
const newMenuState = Object.assign({}, menuState, {
- sections: newTopSections
+ sections: newSections
});
return Object.assign({}, state, { [action.menuID]: newMenuState });
}
diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts
index 644374e058..8b586ee980 100644
--- a/src/app/shared/menu/menu.service.ts
+++ b/src/app/shared/menu/menu.service.ts
@@ -4,10 +4,11 @@ import { MenuSection, MenuSectionIndex, MenuSections, MenusState, MenuState } fr
import { AppState, keySelector } from '../../app.reducer';
import { MenuID } from './initial-menus-state';
import { Observable } from 'rxjs/internal/Observable';
-import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
+import { map, switchMap } from 'rxjs/operators';
import {
- AddMenuSectionAction,
- RemoveMenuSectionAction,
+ ActivateMenuSectionAction,
+ AddMenuSectionAction, DeactivateMenuSectionAction, HideMenuAction,
+ RemoveMenuSectionAction, ShowMenuAction,
ToggleActiveMenuSectionAction,
ToggleMenuAction,
} from './menu.actions';
@@ -42,23 +43,28 @@ export class MenuService {
return this.store.pipe(select(menuByIDSelector(id)));
}
- getMenuTopSections(menuID: MenuID): Observable {
+ getMenuTopSections(menuID: MenuID, mustBeVisible = true): Observable {
return this.store.pipe(
select(menuByIDSelector(menuID)),
select(menuSectionStateSelector),
map((sections: MenuSections) => {
- return Object.values(sections).filter((section: MenuSection) => hasNoValue(section.parentID))
+ return Object.values(sections)
+ .filter((section: MenuSection) => hasNoValue(section.parentID))
+ .filter((section: MenuSection) => !mustBeVisible || section.visible)
}
)
);
}
- getSubSectionsByParentID(menuID: MenuID, parentID: string): Observable {
+ getSubSectionsByParentID(menuID: MenuID, parentID: string, mustBeVisible = true): Observable {
return this.store.pipe(
select(menuByIDSelector(menuID)),
select(getSubSectionsFromSectionSelector(parentID)),
map((ids: string[]) => isNotEmpty(ids) ? ids : []),
- switchMap((ids: string[]) => observableCombineLatest(ids.map((id: string) => this.getMenuSection(menuID, id)))),
+ switchMap((ids: string[]) =>
+ observableCombineLatest(ids.map((id: string) => this.getMenuSection(menuID, id)))
+ ),
+ map((sections: MenuSection[]) => sections.filter((section: MenuSection) => !mustBeVisible || section.visible))
);
}
@@ -91,20 +97,38 @@ export class MenuService {
);
}
+ isMenuVisible(menuID: MenuID): Observable {
+ return this.getMenu(menuID).pipe(
+ map((state: MenuState) => state.visible)
+ );
+ }
+
toggleMenu(menuID: MenuID): void {
this.store.dispatch(new ToggleMenuAction(menuID));
}
+ showMenu(menuID: MenuID): void {
+ this.store.dispatch(new ShowMenuAction(menuID));
+ }
+
+ hideMenu(menuID: MenuID): void {
+ this.store.dispatch(new HideMenuAction(menuID));
+ }
+
toggleActiveSection(menuID: MenuID, id: string): void {
this.store.dispatch(new ToggleActiveMenuSectionAction(menuID, id));
}
+ activateSection(menuID: MenuID, id: string): void {
+ this.store.dispatch(new ActivateMenuSectionAction(menuID, id));
+ }
+
+ deactivateSection(menuID: MenuID, id: string): void {
+ this.store.dispatch(new DeactivateMenuSectionAction(menuID, id));
+ }
+
isSectionActive(menuID: MenuID, id: string): Observable {
- return this.getMenuSection(menuID, id).pipe(tap((section) => console.log(section.id)), map((section) => section.active),
- distinctUntilChanged((a, b) => {
- console.log('DISTINCT', a, b);
- return a === b
- }));
+ return this.getMenuSection(menuID, id).pipe(map((section) => section.active));
}
isSectionVisible(menuID: MenuID, id: string): Observable {
diff --git a/src/app/shared/menu/type-components/link-type.component.html b/src/app/shared/menu/type-components/link-type.component.html
index 1c6c88cca9..adfb4fffbf 100644
--- a/src/app/shared/menu/type-components/link-type.component.html
+++ b/src/app/shared/menu/type-components/link-type.component.html
@@ -1 +1 @@
-{{item.text | translate}}
\ No newline at end of file
+{{item.text | translate}}
\ No newline at end of file
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index ce6e630f0d..b7d42e4856 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -85,10 +85,7 @@ import { InputSuggestionsComponent } from './input-suggestions/input-suggestions
import { CapitalizePipe } from './utils/capitalize.pipe';
import { ObjectKeysPipe } from './utils/object-keys-pipe';
import { MomentModule } from 'ngx-moment';
-import { MenuSectionComponent } from './menu/menu-section/menu-section.component';
-import { MenuComponent } from './menu/menu.component';
-import { LinkTypeMenuItemComponent } from './menu/type-components/link-type.component';
-import { TextTypeMenuItemComponent } from './menu/type-components/text-type.component';
+import { MenuModule } from './menu/menu.module';
const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -109,7 +106,8 @@ const MODULES = [
TranslateModule,
NouisliderModule,
MomentModule,
- TextMaskModule
+ TextMaskModule,
+ MenuModule
];
const PIPES = [
@@ -163,10 +161,6 @@ const COMPONENTS = [
TruncatablePartComponent,
BrowseByComponent,
InputSuggestionsComponent,
- MenuSectionComponent,
- MenuComponent,
- LinkTypeMenuItemComponent,
- TextTypeMenuItemComponent
];
const ENTRY_COMPONENTS = [
@@ -179,9 +173,7 @@ const ENTRY_COMPONENTS = [
CollectionGridElementComponent,
CommunityGridElementComponent,
SearchResultGridElementComponent,
- BrowseEntryListElementComponent,
- LinkTypeMenuItemComponent,
- TextTypeMenuItemComponent
+ BrowseEntryListElementComponent
];
const PROVIDERS = [