mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
62063: Configurable browse-by
This commit is contained in:
@@ -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: {
|
||||
|
@@ -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 = [];
|
||||
|
@@ -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 {
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
@@ -0,0 +1 @@
|
||||
<ng-container *ngComponentOutlet="getComponent() | async"></ng-container>
|
@@ -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<BrowseByTypeConfig>;
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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' } }
|
||||
])
|
||||
]
|
||||
})
|
||||
|
@@ -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 {
|
||||
|
@@ -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[];
|
||||
}
|
||||
|
8
src/config/browse-by-type-config.interface.ts
Normal file
8
src/config/browse-by-type-config.interface.ts
Normal file
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user