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)
|
// Limit for years to display using jumps of five years (current year - fiveYearLimit)
|
||||||
fiveYearLimit: 30,
|
fiveYearLimit: 30,
|
||||||
// The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
|
// 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: {
|
item: {
|
||||||
edit: {
|
edit: {
|
||||||
|
@@ -13,6 +13,7 @@ import { BrowseService } from '../../core/browse/browse.service';
|
|||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||||
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
|
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
|
||||||
|
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-browse-by-date-page',
|
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.
|
* A metadata definition is a short term used to describe one or multiple metadata fields.
|
||||||
* An example would be 'dateissued' for 'dc.date.issued'
|
* An example would be 'dateissued' for 'dc.date.issued'
|
||||||
*/
|
*/
|
||||||
|
@rendersBrowseBy(BrowseByType.Date)
|
||||||
export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,8 +80,9 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
|||||||
let lowerLimit = this.config.browseBy.defaultLowerLimit;
|
let lowerLimit = this.config.browseBy.defaultLowerLimit;
|
||||||
if (hasValue(firstItemRD.payload)) {
|
if (hasValue(firstItemRD.payload)) {
|
||||||
const date = firstItemRD.payload.firstMetadataValue(metadataField);
|
const date = firstItemRD.payload.firstMetadataValue(metadataField);
|
||||||
if (hasValue(date) && hasValue(+date.split('-')[0])) {
|
if (hasValue(date)) {
|
||||||
lowerLimit = +date.split('-')[0];
|
const dateObj = new Date(date);
|
||||||
|
lowerLimit = dateObj.getFullYear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const options = [];
|
const options = [];
|
||||||
|
@@ -15,6 +15,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
|
|||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
|
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
|
||||||
|
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-browse-by-metadata-page',
|
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.
|
* A metadata definition is a short term used to describe one or multiple metadata fields.
|
||||||
* An example would be 'author' for 'dc.contributor.*'
|
* An example would be 'author' for 'dc.contributor.*'
|
||||||
*/
|
*/
|
||||||
|
@rendersBrowseBy(BrowseByType.Metadata)
|
||||||
export class BrowseByMetadataPageComponent implements OnInit {
|
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 { combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { ItemDataService } from '../../core/data/item-data.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import {
|
import {
|
||||||
@@ -11,6 +10,7 @@ import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-
|
|||||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||||
import { BrowseService } from '../../core/browse/browse.service';
|
import { BrowseService } from '../../core/browse/browse.service';
|
||||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
|
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-browse-by-title-page',
|
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)
|
* Component for browsing items by title (dc.title)
|
||||||
*/
|
*/
|
||||||
|
@rendersBrowseBy(BrowseByType.Title)
|
||||||
export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
|
export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
|
||||||
|
|
||||||
public constructor(protected route: ActivatedRoute,
|
public constructor(protected route: ActivatedRoute,
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
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 { 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 { map } from 'rxjs/operators';
|
||||||
import { getSucceededRemoteData } from '../core/shared/operators';
|
import { getSucceededRemoteData } from '../core/shared/operators';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
/**
|
/**
|
||||||
@@ -13,14 +14,21 @@ import { of as observableOf } from 'rxjs';
|
|||||||
*/
|
*/
|
||||||
export class BrowseByGuard implements CanActivate {
|
export class BrowseByGuard implements CanActivate {
|
||||||
|
|
||||||
constructor(protected dsoService: DSpaceObjectDataService,
|
constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
|
||||||
|
protected dsoService: DSpaceObjectDataService,
|
||||||
protected translate: TranslateService) {
|
protected translate: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
const title = route.data.title;
|
const title = route.data.title;
|
||||||
const metadata = route.params.metadata || route.queryParams.metadata || route.data.metadata;
|
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 scope = route.queryParams.scope;
|
||||||
const value = route.queryParams.value;
|
const value = route.queryParams.value;
|
||||||
const metadataTranslated = this.translate.instant('browse.metadata.' + metadata);
|
const metadataTranslated = this.translate.instant('browse.metadata.' + metadata);
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { NgModule } from '@angular/core';
|
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 { BrowseByGuard } from './browse-by-guard';
|
||||||
|
import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'title', component: BrowseByTitlePageComponent, canActivate: [BrowseByGuard], data: { metadata: 'title', title: 'browse.title' } },
|
{ path: ':metadata', component: BrowseBySwitcherComponent, canActivate: [BrowseByGuard], data: { 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' } }
|
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -8,6 +8,7 @@ import { BrowseService } from '../core/browse/browse.service';
|
|||||||
import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-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 { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component';
|
||||||
import { BrowseByGuard } from './browse-by-guard';
|
import { BrowseByGuard } from './browse-by-guard';
|
||||||
|
import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -18,12 +19,18 @@ import { BrowseByGuard } from './browse-by-guard';
|
|||||||
declarations: [
|
declarations: [
|
||||||
BrowseByTitlePageComponent,
|
BrowseByTitlePageComponent,
|
||||||
BrowseByMetadataPageComponent,
|
BrowseByMetadataPageComponent,
|
||||||
BrowseByDatePageComponent
|
BrowseByDatePageComponent,
|
||||||
|
BrowseBySwitcherComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ItemDataService,
|
ItemDataService,
|
||||||
BrowseService,
|
BrowseService,
|
||||||
BrowseByGuard
|
BrowseByGuard
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
BrowseByTitlePageComponent,
|
||||||
|
BrowseByMetadataPageComponent,
|
||||||
|
BrowseByDatePageComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class BrowseByModule {
|
export class BrowseByModule {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Config } from './config.interface';
|
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
|
* 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
|
* The absolute lowest year to display in the dropdown when no lowest date can be found for all items
|
||||||
*/
|
*/
|
||||||
defaultLowerLimit: number;
|
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