-
Notifications
You must be signed in to change notification settings - Fork 529
Expand file tree
/
Copy pathbrowse-by-date.component.ts
More file actions
208 lines (198 loc) · 7.95 KB
/
browse-by-date.component.ts
File metadata and controls
208 lines (198 loc) · 7.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import {
AsyncPipe,
isPlatformServer,
NgIf,
} from '@angular/common';
import {
ChangeDetectorRef,
Component,
Inject,
OnInit,
PLATFORM_ID,
} from '@angular/core';
import {
ActivatedRoute,
Params,
Router,
} from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import {
combineLatest as observableCombineLatest,
Observable,
of as observableOf,
} from 'rxjs';
import {
distinctUntilChanged,
filter,
map,
switchMap,
} from 'rxjs/operators';
import { ThemedBrowseByComponent } from 'src/app/shared/browse-by/themed-browse-by.component';
import {
APP_CONFIG,
AppConfig,
} from '../../../config/app-config.interface';
import { environment } from '../../../environments/environment';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { BrowseService } from '../../core/browse/browse.service';
import {
SortDirection,
SortOptions,
} from '../../core/cache/models/sort-options.model';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { RemoteData } from '../../core/data/remote-data';
import { PaginationService } from '../../core/pagination/pagination.service';
import { Item } from '../../core/shared/item.model';
import {
getAllSucceededRemoteDataPayload,
getFirstSucceededRemoteDataPayload,
} from '../../core/shared/operators';
import { SearchService } from '../../core/shared/search/search.service';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { isValidDate } from '../../shared/date.util';
import {
hasValue,
isNotEmpty,
} from '../../shared/empty.util';
import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { StartsWithType } from '../../shared/starts-with/starts-with-type';
import {
BrowseByMetadataComponent,
browseParamsToOptions,
} from '../browse-by-metadata/browse-by-metadata.component';
@Component({
selector: 'ds-browse-by-date',
styleUrls: ['../browse-by-metadata/browse-by-metadata.component.scss'],
templateUrl: '../browse-by-metadata/browse-by-metadata.component.html',
standalone: true,
imports: [
AsyncPipe,
NgIf,
TranslateModule,
ThemedLoadingComponent,
ThemedBrowseByComponent,
],
})
/**
* Component for browsing items by metadata definition of type 'date'
* A metadata definition (a.k.a. browse id) is a short term used to describe one or multiple metadata fields.
* An example would be 'dateissued' for 'dc.date.issued'
*/
export class BrowseByDateComponent extends BrowseByMetadataComponent implements OnInit {
/**
* The default metadata keys to use for determining the lower limit of the StartsWith dropdown options
*/
defaultMetadataKeys = ['dc.date.issued'];
public constructor(
protected route: ActivatedRoute,
protected browseService: BrowseService,
protected dsoService: DSpaceObjectDataService,
protected paginationService: PaginationService,
protected router: Router,
@Inject(APP_CONFIG) public appConfig: AppConfig,
public dsoNameService: DSONameService,
protected cdRef: ChangeDetectorRef,
@Inject(PLATFORM_ID) public platformId: any,
public searchConfigService: SearchConfigurationService,
public searchService: SearchService,
) {
super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService, platformId);
}
ngOnInit(): void {
if (!this.renderOnServerSide && !environment.ssr.enableBrowseComponent && isPlatformServer(this.platformId)) {
this.loading$ = observableOf(false);
return;
}
const sortConfig = new SortOptions('default', SortDirection.ASC);
this.startsWithType = StartsWithType.date;
this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig);
this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig);
const routeParams$: Observable<Params> = observableCombineLatest([
this.route.params,
this.route.queryParams,
]).pipe(
map(([params, queryParams]: [Params, Params]) => Object.assign({}, params, queryParams)),
distinctUntilChanged((prev: Params, curr: Params) => prev.id === curr.id && prev.startsWith === curr.startsWith),
);
this.subs.push(
observableCombineLatest([
routeParams$,
this.scope$,
this.currentPagination$,
this.currentSort$,
]).subscribe(([params, scope, currentPage, currentSort]: [Params, string, PaginationComponentOptions, SortOptions]) => {
const metadataKeys = params.browseDefinition ? params.browseDefinition.metadataKeys : this.defaultMetadataKeys;
this.browseId = params.id || this.defaultBrowseId;
this.startsWith = +params.startsWith || params.startsWith;
const searchOptions = browseParamsToOptions(params, scope, currentPage, currentSort, this.browseId, this.fetchThumbnails);
this.updatePageWithItems(searchOptions, this.value, undefined);
this.updateStartsWithOptions(this.browseId, metadataKeys, params.scope);
}));
}
/**
* Update the StartsWith options
* In this implementation, it creates a list of years starting from the most recent item or the current year, going
* all the way back to the earliest date found on an item within this scope. The further back in time, the bigger
* the change in years become to avoid extremely long lists with a one-year difference.
* To determine the change in years, the config found under GlobalConfig.BrowseBy is used for this.
* @param definition The metadata definition to fetch the first item for
* @param metadataKeys The metadata fields to fetch the earliest date from (expects a date field)
* @param scope The scope under which to fetch the earliest item for
*/
updateStartsWithOptions(definition: string, metadataKeys: string[], scope?: string) {
this.searchConfigService.getConfig(null,definition).pipe(
getFirstSucceededRemoteDataPayload(),
filter( configs => configs.length > 0 ),
map( configs => configs.filter( filterConfig => filterConfig.name?.toUpperCase() === definition.toUpperCase() ) ),
map( findConfig => findConfig[0]),
switchMap( config => {
return this.searchService.getFacetValuesFor(config, 10).pipe(
getAllSucceededRemoteDataPayload(),
);
}),
map( facetValue => facetValue.page ),
).subscribe(
values => {
const options = this.generateYearFromFacetValue(values);
if (isNotEmpty(options)) {
this.startsWithOptions = options;
this.cdRef.detectChanges();
}
});
}
/**
* Prepare options
* @param data The facets values
*/
generateYearFromFacetValue = (data: any[]) => {
const years: number[] = [];
if (!hasValue(data)) {return [];}
data.forEach(item => {
const [start, end] = item.value.split(' - ').map(Number);
for (let year = start; year <= end; year++) {
years.push(year);
}
});
return years;
};
/**
* Returns the year from the item metadata field or the limit.
* @param itemRD the item remote data
* @param metadataKeys The metadata fields to fetch the earliest date from (expects a date field)
* @param limit the limit to use if the year can't be found in metadata
* @private
*/
private getLimit(itemRD: RemoteData<Item>, metadataKeys: string[], limit: number): number {
if (hasValue(itemRD.payload)) {
const date = itemRD.payload.firstMetadataValue(metadataKeys);
if (isNotEmpty(date) && isValidDate(date)) {
const dateObj = new Date(date);
// TODO: it appears that getFullYear (based on local time) is sometimes unreliable. Switching to UTC.
return isNaN(dateObj.getUTCFullYear()) ? limit : dateObj.getUTCFullYear();
} else {
return new Date().getUTCFullYear();
}
}
}
}