mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
59695: Starts-with implementation for browse-by date
This commit is contained in:
@@ -72,5 +72,14 @@ module.exports = {
|
||||
code: 'nl',
|
||||
label: 'Nederlands',
|
||||
active: false,
|
||||
}]
|
||||
}],
|
||||
// Browse-By Pages
|
||||
browseBy: {
|
||||
// Amount of years to display using jumps of one year (current year - oneYearLimit)
|
||||
oneYearLimit: 10,
|
||||
// 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
|
||||
}
|
||||
};
|
||||
|
@@ -281,6 +281,11 @@
|
||||
},
|
||||
"browse": {
|
||||
"title": "Browsing {{ collection }} by {{ field }} {{ value }}",
|
||||
"startsWith": {
|
||||
"choose_year": "(Choose year)",
|
||||
"type_year": "Or type in a year:",
|
||||
"submit": "Go"
|
||||
},
|
||||
"metadata": {
|
||||
"title": "Title",
|
||||
"author": "Author",
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import {
|
||||
BrowseByMetadataPageComponent,
|
||||
browseParamsToOptions
|
||||
@@ -6,6 +6,14 @@ import {
|
||||
import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-options.model';
|
||||
import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest';
|
||||
import { BrowseByStartsWithType } from '../../shared/browse-by/browse-by.component';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BrowseService } from '../../core/browse/browse.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-browse-by-date-page',
|
||||
@@ -19,8 +27,15 @@ import { BrowseByStartsWithType } from '../../shared/browse-by/browse-by.compone
|
||||
*/
|
||||
export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
||||
|
||||
oneYearLimit = 10;
|
||||
fiveYearLimit = 30;
|
||||
defaultMetadataField = 'dc.date.issued';
|
||||
|
||||
public constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
|
||||
protected route: ActivatedRoute,
|
||||
protected browseService: BrowseService,
|
||||
protected dsoService: DSpaceObjectDataService,
|
||||
protected router: Router) {
|
||||
super(route, browseService, dsoService, router);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.startsWithType = BrowseByStartsWithType.date;
|
||||
@@ -34,29 +49,53 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
|
||||
return Object.assign({}, params, queryParams, data);
|
||||
})
|
||||
.subscribe((params) => {
|
||||
const metadataField = params.metadataField || this.defaultMetadataField;
|
||||
this.metadata = params.metadata || this.defaultMetadata;
|
||||
this.startsWith = +params.startsWith || params.startsWith;
|
||||
const searchOptions = browseParamsToOptions(params, Object.assign({}), this.sortConfig, this.metadata);
|
||||
this.updatePageWithItems(searchOptions, this.value);
|
||||
this.updateParent(params.scope);
|
||||
this.updateStartsWithOptions(this.metadata, metadataField, params.scope);
|
||||
}));
|
||||
const options = [];
|
||||
const currentYear = new Date().getFullYear();
|
||||
const oneYearBreak = Math.floor((currentYear - this.oneYearLimit) / 5) * 5;
|
||||
const fiveYearBreak = Math.floor((currentYear - this.fiveYearLimit) / 10) * 10;
|
||||
const lowerLimit = 1900; // Hardcoded atm, this should be the lowest date issued
|
||||
let i = currentYear;
|
||||
while (i > lowerLimit) {
|
||||
options.push(i);
|
||||
if (i <= fiveYearBreak) {
|
||||
i -= 10;
|
||||
} else if (i <= oneYearBreak) {
|
||||
i -= 5;
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
console.log(options);
|
||||
}
|
||||
|
||||
updateStartsWithOptions(definition: string, metadataField: string, scope?: string) {
|
||||
this.subs.push(
|
||||
this.browseService.getFirstItemFor(definition, scope).subscribe((firstItemRD: RemoteData<PaginatedList<Item>>) => {
|
||||
let lowerLimit = this.config.browseBy.defaultLowerLimit;
|
||||
if (firstItemRD.payload.page.length > 0) {
|
||||
const date = firstItemRD.payload.page[0].findMetadata(metadataField);
|
||||
if (hasValue(date) && hasValue(+date.split('-')[0])) {
|
||||
lowerLimit = +date.split('-')[0];
|
||||
}
|
||||
}
|
||||
const options = [];
|
||||
const currentYear = new Date().getFullYear();
|
||||
const oneYearBreak = Math.floor((currentYear - this.config.browseBy.oneYearLimit) / 5) * 5;
|
||||
const fiveYearBreak = Math.floor((currentYear - this.config.browseBy.fiveYearLimit) / 10) * 10;
|
||||
if (lowerLimit <= fiveYearBreak) {
|
||||
lowerLimit -= 10;
|
||||
} else if (lowerLimit <= oneYearBreak) {
|
||||
lowerLimit -= 5;
|
||||
} else {
|
||||
lowerLimit -= 1;
|
||||
}
|
||||
let i = currentYear;
|
||||
while (i > lowerLimit) {
|
||||
options.push(i);
|
||||
if (i <= fiveYearBreak) {
|
||||
i -= 10;
|
||||
} else if (i <= oneYearBreak) {
|
||||
i -= 5;
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (isNotEmpty(options)) {
|
||||
this.startsWithOptions = options;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{ path: 'title', component: BrowseByTitlePageComponent },
|
||||
{ path: 'dateissued', component: BrowseByDatePageComponent, data: { metadata: 'dateissued' } },
|
||||
{ path: 'dateissued', component: BrowseByDatePageComponent, data: { metadata: 'dateissued', metadataField: 'dc.date.issued' } },
|
||||
{ path: ':metadata', component: BrowseByMetadataPageComponent }
|
||||
])
|
||||
]
|
||||
|
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { distinctUntilChanged, map, startWith, take } from 'rxjs/operators';
|
||||
import {
|
||||
ensureArrayHasValue,
|
||||
ensureArrayHasValue, hasValue,
|
||||
hasValueOperator,
|
||||
isEmpty,
|
||||
isNotEmpty,
|
||||
@@ -162,6 +162,28 @@ export class BrowseService {
|
||||
);
|
||||
}
|
||||
|
||||
getFirstItemFor(definition: string, scope?: string): Observable<RemoteData<PaginatedList<Item>>> {
|
||||
return this.getBrowseDefinitions().pipe(
|
||||
getBrowseDefinitionLinks(definition),
|
||||
hasValueOperator(),
|
||||
map((_links: any) => _links.items),
|
||||
hasValueOperator(),
|
||||
map((href: string) => {
|
||||
const args = [];
|
||||
if (hasValue(scope)) {
|
||||
args.push(`scope=${scope}`);
|
||||
}
|
||||
args.push('page=0');
|
||||
args.push('size=1');
|
||||
if (isNotEmpty(args)) {
|
||||
href = new URLCombiner(href, `?${args.join('&')}`).toString();
|
||||
}
|
||||
return href;
|
||||
}),
|
||||
getBrowseItemsFor(this.requestService, this.responseCache, this.rdb)
|
||||
);
|
||||
}
|
||||
|
||||
getPrevBrowseItems(items: RemoteData<PaginatedList<Item>>): Observable<RemoteData<PaginatedList<Item>>> {
|
||||
return observableOf(items.payload.prev).pipe(
|
||||
getBrowseItemsFor(this.requestService, this.responseCache, this.rdb)
|
||||
|
@@ -1,6 +1,56 @@
|
||||
import { Inject } from '@angular/core';
|
||||
import { Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { hasValue } from '../../empty.util';
|
||||
import { Subscription } from 'rxjs/internal/Subscription';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
|
||||
export class BrowseByStartsWithAbstractComponent {
|
||||
public constructor(@Inject('startsWithOptions') public startsWithOptions: any[]) {
|
||||
export class BrowseByStartsWithAbstractComponent implements OnInit, OnDestroy {
|
||||
startsWith: string;
|
||||
|
||||
formData: FormGroup;
|
||||
|
||||
/**
|
||||
* List of subscriptions
|
||||
*/
|
||||
subs: Subscription[] = [];
|
||||
|
||||
public constructor(@Inject('startsWithOptions') public startsWithOptions: any[],
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subs.push(
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
this.startsWith = params.startsWith;
|
||||
})
|
||||
);
|
||||
this.formData = new FormGroup({
|
||||
startsWith: new FormControl()
|
||||
});
|
||||
}
|
||||
|
||||
setStartsWith(event: Event) {
|
||||
this.startsWith = (event.target as HTMLInputElement).value;
|
||||
this.setStartsWithParam();
|
||||
}
|
||||
|
||||
setStartsWithParam() {
|
||||
if (this.startsWith === '-1') {
|
||||
this.startsWith = undefined;
|
||||
}
|
||||
this.router.navigate([], {
|
||||
queryParams: Object.assign({ startsWith: this.startsWith }),
|
||||
queryParamsHandling: 'merge'
|
||||
});
|
||||
}
|
||||
|
||||
submitForm(data) {
|
||||
this.startsWith = data.startsWith;
|
||||
this.setStartsWithParam();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,22 @@
|
||||
<h3>Test Starts-With Date</h3>
|
||||
<p>
|
||||
<span *ngFor="let element of startsWithOptions">{{element}}, </span>
|
||||
</p>
|
||||
<form class="w-100" [formGroup]="formData" (ngSubmit)="submitForm(formData.value)">
|
||||
<div class="container">
|
||||
<div class="row mb-2">
|
||||
<select class="form-control col-xs-5 col-sm-3" (change)="setStartsWith($event)">
|
||||
<option [value]="-1" [selected]="!startsWith">
|
||||
{{'browse.startsWith.choose_year' | translate}}
|
||||
</option>
|
||||
<option *ngFor="let option of startsWithOptions"
|
||||
[value]="option"
|
||||
[selected]="option === startsWith || option === +startsWith ? 'selected': null">
|
||||
{{option}}
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-group input-group col-xs-7 col-sm-6">
|
||||
<input class="form-control" placeholder="{{'browse.startsWith.type_year' | translate}}" type="number" name="startsWith" formControlName="startsWith" [value]="+startsWith" />
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-secondary" type="submit">{{'browse.startsWith.submit' | translate}}</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@@ -0,0 +1,7 @@
|
||||
@import '../../../../../styles/variables.scss';
|
||||
|
||||
// temporary fix for bootstrap 4 beta btn color issue
|
||||
.btn-secondary {
|
||||
background-color: $input-bg;
|
||||
color: $input-color;
|
||||
}
|
||||
|
@@ -1,4 +1 @@
|
||||
<h3>Test Starts-With Text</h3>
|
||||
<p>
|
||||
<span *ngFor="let element of startsWithOptions">{{element}}, </span>
|
||||
</p>
|
||||
<!-- To be implemented -->
|
||||
|
7
src/config/browse-by-config.interface.ts
Normal file
7
src/config/browse-by-config.interface.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Config } from './config.interface';
|
||||
|
||||
export interface BrowseByConfig extends Config {
|
||||
oneYearLimit: number;
|
||||
fiveYearLimit: number;
|
||||
defaultLowerLimit: number;
|
||||
}
|
@@ -5,6 +5,7 @@ import { UniversalConfig } from './universal-config.interface';
|
||||
import { INotificationBoardOptions } from './notifications-config.interfaces';
|
||||
import { FormConfig } from './form-config.interfaces';
|
||||
import {LangConfig} from './lang-config.interface';
|
||||
import { BrowseByConfig } from './browse-by-config.interface';
|
||||
|
||||
export interface GlobalConfig extends Config {
|
||||
ui: ServerConfig;
|
||||
@@ -19,4 +20,5 @@ export interface GlobalConfig extends Config {
|
||||
debug: boolean;
|
||||
defaultLanguage: string;
|
||||
languages: LangConfig[];
|
||||
browseBy: BrowseByConfig;
|
||||
}
|
||||
|
Reference in New Issue
Block a user