diff --git a/config/environment.default.js b/config/environment.default.js
index f70f132fa4..3013705a2e 100644
--- a/config/environment.default.js
+++ b/config/environment.default.js
@@ -149,7 +149,26 @@ module.exports = {
// Limit for years to display using jumps of five years (current year - fiveYearLimit)
fiveYearLimit: 30,
// The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
- defaultLowerLimit: 1900
+ defaultLowerLimit: 1900,
+ types: [
+ {
+ metadata: 'title',
+ type: 'title'
+ },
+ {
+ metadata: 'dateissued',
+ type: 'date',
+ metadataField: 'dc.date.issued'
+ },
+ {
+ metadata: 'author',
+ type: 'metadata'
+ },
+ {
+ metadata: 'subject',
+ type: 'metadata'
+ }
+ ]
},
item: {
edit: {
diff --git a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts
index 2acd96adb0..ab22216afa 100644
--- a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts
+++ b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts
@@ -13,6 +13,7 @@ import { BrowseService } from '../../core/browse/browse.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
+import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({
selector: 'ds-browse-by-date-page',
@@ -24,6 +25,7 @@ import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
* A metadata definition is a short term used to describe one or multiple metadata fields.
* An example would be 'dateissued' for 'dc.date.issued'
*/
+@rendersBrowseBy(BrowseByType.Date)
export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
/**
@@ -78,8 +80,9 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
let lowerLimit = this.config.browseBy.defaultLowerLimit;
if (hasValue(firstItemRD.payload)) {
const date = firstItemRD.payload.firstMetadataValue(metadataField);
- if (hasValue(date) && hasValue(+date.split('-')[0])) {
- lowerLimit = +date.split('-')[0];
+ if (hasValue(date)) {
+ const dateObj = new Date(date);
+ lowerLimit = dateObj.getFullYear();
}
}
const options = [];
diff --git a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.ts
index 52c63341bd..7a85cc258f 100644
--- a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.ts
+++ b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.ts
@@ -15,6 +15,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { take } from 'rxjs/operators';
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
+import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({
selector: 'ds-browse-by-metadata-page',
@@ -26,6 +27,7 @@ import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
* A metadata definition is a short term used to describe one or multiple metadata fields.
* An example would be 'author' for 'dc.contributor.*'
*/
+@rendersBrowseBy(BrowseByType.Metadata)
export class BrowseByMetadataPageComponent implements OnInit {
/**
diff --git a/src/app/+browse-by/+browse-by-switcher/browse-by-decorator.ts b/src/app/+browse-by/+browse-by-switcher/browse-by-decorator.ts
new file mode 100644
index 0000000000..fe61a2edd2
--- /dev/null
+++ b/src/app/+browse-by/+browse-by-switcher/browse-by-decorator.ts
@@ -0,0 +1,29 @@
+import { hasNoValue } from '../../shared/empty.util';
+
+export enum BrowseByType {
+ Title = 'title',
+ Metadata = 'metadata',
+ Date = 'date'
+}
+
+export const DEFAULT_BROWSE_BY_TYPE = BrowseByType.Metadata;
+
+const map = new Map();
+
+export function rendersBrowseBy(browseByType: BrowseByType) {
+ return function decorator(component: any) {
+ if (hasNoValue(map.get(browseByType))) {
+ map.set(browseByType, component);
+ } else {
+ throw new Error(`There can't be more than one component to render Browse-By of type "${browseByType}"`);
+ }
+ };
+}
+
+export function getComponentByBrowseByType(browseByType) {
+ const comp = map.get(browseByType);
+ if (hasNoValue(comp)) {
+ map.get(DEFAULT_BROWSE_BY_TYPE);
+ }
+ return comp;
+}
diff --git a/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.html b/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.html
new file mode 100644
index 0000000000..c7eab882d4
--- /dev/null
+++ b/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.ts b/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.ts
new file mode 100644
index 0000000000..c3af4ddf52
--- /dev/null
+++ b/src/app/+browse-by/+browse-by-switcher/browse-by-switcher.component.ts
@@ -0,0 +1,36 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Observable } from 'rxjs/internal/Observable';
+import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
+import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
+import { map, tap } from 'rxjs/operators';
+import { getComponentByBrowseByType } from './browse-by-decorator';
+
+@Component({
+ selector: 'ds-browse-by-switcher',
+ templateUrl: './browse-by-switcher.component.html'
+})
+export class BrowseBySwitcherComponent implements OnInit {
+
+ browseByTypeConfig: Observable;
+
+ public constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
+ protected route: ActivatedRoute) {
+ }
+
+ ngOnInit(): void {
+ this.browseByTypeConfig = this.route.params.pipe(
+ map((params) => {
+ const metadata = params.metadata;
+ return this.config.browseBy.types.find((config: BrowseByTypeConfig) => config.metadata === metadata);
+ })
+ );
+ }
+
+ getComponent() {
+ return this.browseByTypeConfig.pipe(
+ map((config: BrowseByTypeConfig) => getComponentByBrowseByType(config.type))
+ );
+ }
+
+}
diff --git a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts
index 717275bf8b..92f9569d38 100644
--- a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts
+++ b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.ts
@@ -1,6 +1,5 @@
import { combineLatest as observableCombineLatest } from 'rxjs';
import { Component } from '@angular/core';
-import { ItemDataService } from '../../core/data/item-data.service';
import { ActivatedRoute, Router } from '@angular/router';
import { hasValue } from '../../shared/empty.util';
import {
@@ -11,6 +10,7 @@ import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { BrowseService } from '../../core/browse/browse.service';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
+import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({
selector: 'ds-browse-by-title-page',
@@ -20,6 +20,7 @@ import { SortDirection, SortOptions } from '../../core/cache/models/sort-options
/**
* Component for browsing items by title (dc.title)
*/
+@rendersBrowseBy(BrowseByType.Title)
export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
public constructor(protected route: ActivatedRoute,
diff --git a/src/app/+browse-by/browse-by-guard.ts b/src/app/+browse-by/browse-by-guard.ts
index 5d3dad2b0f..520d23c772 100644
--- a/src/app/+browse-by/browse-by-guard.ts
+++ b/src/app/+browse-by/browse-by-guard.ts
@@ -1,11 +1,12 @@
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
-import { Injectable } from '@angular/core';
+import { Inject, Injectable } from '@angular/core';
import { DSpaceObjectDataService } from '../core/data/dspace-object-data.service';
-import { hasValue } from '../shared/empty.util';
+import { hasNoValue, hasValue } from '../shared/empty.util';
import { map } from 'rxjs/operators';
import { getSucceededRemoteData } from '../core/shared/operators';
import { TranslateService } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
+import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
@Injectable()
/**
@@ -13,14 +14,21 @@ import { of as observableOf } from 'rxjs';
*/
export class BrowseByGuard implements CanActivate {
- constructor(protected dsoService: DSpaceObjectDataService,
+ constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
+ protected dsoService: DSpaceObjectDataService,
protected translate: TranslateService) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const title = route.data.title;
const metadata = route.params.metadata || route.queryParams.metadata || route.data.metadata;
- const metadataField = route.data.metadataField;
+ let metadataField = route.data.metadataField;
+ if (hasNoValue(metadataField) && hasValue(metadata)) {
+ const config = this.config.browseBy.types.find((conf) => conf.metadata === metadata);
+ if (hasValue(config) && hasValue(config.metadataField)) {
+ metadataField = config.metadataField;
+ }
+ }
const scope = route.queryParams.scope;
const value = route.queryParams.value;
const metadataTranslated = this.translate.instant('browse.metadata.' + metadata);
diff --git a/src/app/+browse-by/browse-by-routing.module.ts b/src/app/+browse-by/browse-by-routing.module.ts
index 9ba15ecfe9..0b20cd4466 100644
--- a/src/app/+browse-by/browse-by-routing.module.ts
+++ b/src/app/+browse-by/browse-by-routing.module.ts
@@ -1,16 +1,12 @@
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
-import { BrowseByTitlePageComponent } from './+browse-by-title-page/browse-by-title-page.component';
-import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-page.component';
-import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component';
import { BrowseByGuard } from './browse-by-guard';
+import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
@NgModule({
imports: [
RouterModule.forChild([
- { path: 'title', component: BrowseByTitlePageComponent, canActivate: [BrowseByGuard], data: { metadata: 'title', title: 'browse.title' } },
- { path: 'dateissued', component: BrowseByDatePageComponent, canActivate: [BrowseByGuard], data: { metadata: 'dateissued', metadataField: 'dc.date.issued', title: 'browse.title' } },
- { path: ':metadata', component: BrowseByMetadataPageComponent, canActivate: [BrowseByGuard], data: { title: 'browse.title' } }
+ { path: ':metadata', component: BrowseBySwitcherComponent, canActivate: [BrowseByGuard], data: { title: 'browse.title' } }
])
]
})
diff --git a/src/app/+browse-by/browse-by.module.ts b/src/app/+browse-by/browse-by.module.ts
index 30d4617c16..4938b0df15 100644
--- a/src/app/+browse-by/browse-by.module.ts
+++ b/src/app/+browse-by/browse-by.module.ts
@@ -8,6 +8,7 @@ import { BrowseService } from '../core/browse/browse.service';
import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-page.component';
import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component';
import { BrowseByGuard } from './browse-by-guard';
+import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
@NgModule({
imports: [
@@ -18,12 +19,18 @@ import { BrowseByGuard } from './browse-by-guard';
declarations: [
BrowseByTitlePageComponent,
BrowseByMetadataPageComponent,
- BrowseByDatePageComponent
+ BrowseByDatePageComponent,
+ BrowseBySwitcherComponent
],
providers: [
ItemDataService,
BrowseService,
BrowseByGuard
+ ],
+ entryComponents: [
+ BrowseByTitlePageComponent,
+ BrowseByMetadataPageComponent,
+ BrowseByDatePageComponent
]
})
export class BrowseByModule {
diff --git a/src/config/browse-by-config.interface.ts b/src/config/browse-by-config.interface.ts
index 6adba66b92..dec2f1bcf5 100644
--- a/src/config/browse-by-config.interface.ts
+++ b/src/config/browse-by-config.interface.ts
@@ -1,4 +1,5 @@
import { Config } from './config.interface';
+import { BrowseByTypeConfig } from './browse-by-type-config.interface';
/**
* Config that determines how the dropdown list of years are created for browse-by-date components
@@ -18,4 +19,6 @@ export interface BrowseByConfig extends Config {
* The absolute lowest year to display in the dropdown when no lowest date can be found for all items
*/
defaultLowerLimit: number;
+
+ types: BrowseByTypeConfig[];
}
diff --git a/src/config/browse-by-type-config.interface.ts b/src/config/browse-by-type-config.interface.ts
new file mode 100644
index 0000000000..d9ecc14704
--- /dev/null
+++ b/src/config/browse-by-type-config.interface.ts
@@ -0,0 +1,8 @@
+import { Config } from './config.interface';
+import { BrowseByType } from '../app/+browse-by/+browse-by-switcher/browse-by-decorator';
+
+export interface BrowseByTypeConfig extends Config {
+ metadata: string;
+ type: BrowseByType;
+ metadataField: string;
+}