initial simple breadcrumb implementation

This commit is contained in:
lotte
2020-02-20 13:37:23 +01:00
committed by Art Lowel
parent e60688b85e
commit 413f798f71
9 changed files with 120 additions and 6 deletions

View File

@@ -4,12 +4,13 @@ import { RouterModule } from '@angular/router';
import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'; import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
import { SearchPageComponent } from './search-page.component'; import { SearchPageComponent } from './search-page.component';
import { Breadcrumb } from '../breadcrumbs/breadcrumb/breadcrumb.model';
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild([ RouterModule.forChild([
{ path: '', component: SearchPageComponent, data: { title: 'search.title' } }, { path: '', component: SearchPageComponent, data: { title: 'search.title', breadcrumb: new Breadcrumb('Search', '/search') } },
{ path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard]} { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard] }
]) ])
] ]
}) })

View File

@@ -3,21 +3,28 @@ import { RouterModule } from '@angular/router';
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component'; import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
import { AuthenticatedGuard } from './core/auth/authenticated.guard'; import { AuthenticatedGuard } from './core/auth/authenticated.guard';
import { Breadcrumb } from './breadcrumbs/breadcrumb/breadcrumb.model';
const ITEM_MODULE_PATH = 'items'; const ITEM_MODULE_PATH = 'items';
export function getItemModulePath() { export function getItemModulePath() {
return `/${ITEM_MODULE_PATH}`; return `/${ITEM_MODULE_PATH}`;
} }
const COLLECTION_MODULE_PATH = 'collections'; const COLLECTION_MODULE_PATH = 'collections';
export function getCollectionModulePath() { export function getCollectionModulePath() {
return `/${COLLECTION_MODULE_PATH}`; return `/${COLLECTION_MODULE_PATH}`;
} }
const COMMUNITY_MODULE_PATH = 'communities'; const COMMUNITY_MODULE_PATH = 'communities';
export function getCommunityModulePath() { export function getCommunityModulePath() {
return `/${COMMUNITY_MODULE_PATH}`; return `/${COMMUNITY_MODULE_PATH}`;
} }
const ADMIN_MODULE_PATH = 'admin'; const ADMIN_MODULE_PATH = 'admin';
export function getAdminModulePath() { export function getAdminModulePath() {
return `/${ADMIN_MODULE_PATH}`; return `/${ADMIN_MODULE_PATH}`;
} }
@@ -26,7 +33,7 @@ export function getAdminModulePath() {
imports: [ imports: [
RouterModule.forRoot([ RouterModule.forRoot([
{ path: '', redirectTo: '/home', pathMatch: 'full' }, { path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule' }, { path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule', data: { showBreadcrumbs: false } },
{ path: 'community-list', loadChildren: './community-list-page/community-list-page.module#CommunityListPageModule' }, { path: 'community-list', loadChildren: './community-list-page/community-list-page.module#CommunityListPageModule' },
{ path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' }, { path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
{ path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' }, { path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
@@ -34,7 +41,7 @@ export function getAdminModulePath() {
{ path: COLLECTION_MODULE_PATH, loadChildren: './+collection-page/collection-page.module#CollectionPageModule' }, { path: COLLECTION_MODULE_PATH, loadChildren: './+collection-page/collection-page.module#CollectionPageModule' },
{ path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' }, { path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' },
{ path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] }, { path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] },
{ path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' }, { path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule', data: { breadcrumb: new Breadcrumb('Search', '/search') } },
{ path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' }, { path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' },
{ path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] }, { path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] },
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' }, { path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
@@ -45,7 +52,7 @@ export function getAdminModulePath() {
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent }, { path: '**', pathMatch: 'full', component: PageNotFoundComponent },
]) ])
], ],
exports: [RouterModule] exports: [RouterModule],
}) })
export class AppRoutingModule { export class AppRoutingModule {

View File

@@ -10,6 +10,10 @@
[options]="config.notifications"> [options]="config.notifications">
</ds-notifications-board> </ds-notifications-board>
<main class="main-content"> <main class="main-content">
<div class="container">
<ds-breadcrumbs></ds-breadcrumbs>
</div>
<div class="container" *ngIf="isLoading$ | async"> <div class="container" *ngIf="isLoading$ | async">
<ds-loading message="{{'loading.default' | translate}}"></ds-loading> <ds-loading message="{{'loading.default' | translate}}"></ds-loading>
</div> </div>

View File

@@ -39,6 +39,7 @@ import { DSpaceRouterStateSerializer } from './shared/ngrx/dspace-router-state-s
import { NotificationComponent } from './shared/notifications/notification/notification.component'; import { NotificationComponent } from './shared/notifications/notification/notification.component';
import { NotificationsBoardComponent } from './shared/notifications/notifications-board/notifications-board.component'; import { NotificationsBoardComponent } from './shared/notifications/notifications-board/notifications-board.component';
import { SharedModule } from './shared/shared.module'; import { SharedModule } from './shared/shared.module';
import { BreadcrumbsComponent } from './breadcrumbs/breadcrumbs.component';
export function getConfig() { export function getConfig() {
return ENV_CONFIG; return ENV_CONFIG;
@@ -128,6 +129,7 @@ const EXPORTS = [
], ],
declarations: [ declarations: [
...DECLARATIONS, ...DECLARATIONS,
BreadcrumbsComponent,
], ],
exports: [ exports: [
...EXPORTS ...EXPORTS

View File

@@ -0,0 +1,6 @@
export class Breadcrumb {
constructor(
public text: string,
public url?: string) {
}
}

View File

@@ -0,0 +1,16 @@
<nav *ngIf="showBreadcrumbs" aria-label="breadcrumb">
<ol class="breadcrumb">
<ng-container *ngTemplateOutlet="breadcrumbs.length > 0 ? breadcrumb : activeBreadcrumb; context: {text: 'Home', url: '/'}"></ng-container>
<ng-container *ngFor="let bc of breadcrumbs; let last;">
<ng-container *ngTemplateOutlet="!last ? breadcrumb : activeBreadcrumb; context: bc"></ng-container>
</ng-container>
</ol>
</nav>
<ng-template #breadcrumb let-text="text" let-url="url">
<li class="breadcrumb-item"><a [routerLink]="url">{{text}}</a></li>
</ng-template>
<ng-template #activeBreadcrumb let-text="text" >
<li class="breadcrumb-item active" aria-current="page">{{text}}</li>
</ng-template>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BreadcrumbsComponent } from './breadcrumbs.component';
describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent;
let fixture: ComponentFixture<BreadcrumbsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BreadcrumbsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BreadcrumbsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,53 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Breadcrumb } from './breadcrumb/breadcrumb.model';
import { hasValue, isNotUndefined } from '../shared/empty.util';
import { filter, map } from 'rxjs/operators';
import { Subscription } from 'rxjs';
@Component({
selector: 'ds-breadcrumbs',
templateUrl: './breadcrumbs.component.html',
styleUrls: ['./breadcrumbs.component.scss']
})
export class BreadcrumbsComponent implements OnDestroy {
breadcrumbs;
showBreadcrumbs;
subscription: Subscription;
constructor(
private route: ActivatedRoute,
private router: Router
) {
this.subscription = this.router.events.pipe(
filter((e): e is NavigationEnd => e instanceof NavigationEnd)
).subscribe(() => {
this.reset();
this.resolveBreadcrumb(this.route.root);
}
)
}
resolveBreadcrumb(route: ActivatedRoute) {
const data = route.snapshot.data;
if (hasValue(data) && hasValue(data.breadcrumb)) {
this.breadcrumbs.push(data.breadcrumb);
}
if (route.children.length > 0) {
this.resolveBreadcrumb(route.firstChild);
} else if (isNotUndefined(data.showBreadcrumbs)) {
this.showBreadcrumbs = data.showBreadcrumbs;
}
}
ngOnDestroy(): void {
if (hasValue(this.subscription)) {
this.subscription.unsubscribe();
}
}
reset() {
this.breadcrumbs = [];
this.showBreadcrumbs = true;
}
}