-
Notifications
You must be signed in to change notification settings - Fork 543
Expand file tree
/
Copy pathmetadata-values.component.ts
More file actions
231 lines (203 loc) · 7.16 KB
/
metadata-values.component.ts
File metadata and controls
231 lines (203 loc) · 7.16 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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
import {
AsyncPipe,
NgTemplateOutlet,
} from '@angular/common';
import {
Component,
Inject,
Input,
OnChanges,
SimpleChanges,
} from '@angular/core';
import { RouterLink } from '@angular/router';
import {
APP_CONFIG,
AppConfig,
} from '@dspace/config/app-config.interface';
import { BrowseDefinition } from '@dspace/core/shared/browse-definition.model';
import { MetadataValue } from '@dspace/core/shared/metadata.models';
import {
getFirstCompletedRemoteData,
getPaginatedListPayload,
getRemoteDataPayload,
} from '@dspace/core/shared/operators';
import { VALUE_LIST_BROWSE_DEFINITION } from '@dspace/core/shared/value-list-browse-definition.resource-type';
import { VocabularyService } from '@dspace/core/submission/vocabularies/vocabulary.service';
import { hasValue } from '@dspace/shared/utils/empty.util';
import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import {
map,
take,
} from 'rxjs/operators';
import { environment } from '../../../../environments/environment';
import { MetadataFieldWrapperComponent } from '../../../shared/metadata-field-wrapper/metadata-field-wrapper.component';
import { MarkdownDirective } from '../../../shared/utils/markdown.directive';
import { ImageField } from '../../simple/field-components/specific-field/image-field';
/**
* This component renders the configured 'values' into the ds-metadata-field-wrapper component.
* It puts the given 'separator' between each two values.
*/
@Component({
selector: 'ds-metadata-values',
styleUrls: ['./metadata-values.component.scss'],
templateUrl: './metadata-values.component.html',
imports: [
AsyncPipe,
MarkdownDirective,
MetadataFieldWrapperComponent,
NgTemplateOutlet,
RouterLink,
TranslateModule,
],
})
export class MetadataValuesComponent implements OnChanges {
constructor(
protected vocabularyService: VocabularyService,
@Inject(APP_CONFIG) private appConfig: AppConfig,
) {
}
/**
* The metadata values to display
*/
@Input() mdValues: MetadataValue[];
/**
* The separator used to split the metadata values (can contain HTML)
*/
@Input() separator: string;
/**
* The label for this iteration of metadata values
*/
@Input() label: string;
/**
* Whether the {@link MarkdownDirective} should be used to render these metadata values.
* This will only have effect if {@link MarkdownConfig#enabled} is true.
* Mathjax will only be rendered if {@link MarkdownConfig#mathjax} is true.
*/
@Input() enableMarkdown = false;
/**
* Whether any valid HTTP(S) URL should be rendered as a link
*/
@Input() urlRegex?;
/**
* This variable will be true if both {@link environment.markdown.enabled} and {@link enableMarkdown} are true.
*/
renderMarkdown;
@Input() browseDefinition?: BrowseDefinition;
/**
* Optional {@code ImageField} reference that represents an image to be displayed inline.
*/
@Input() img?: ImageField;
hasValue = hasValue;
/**
* Optional metadata field used to build search links for values.
* If defined, values will link to the search page using this field as filter.
*/
@Input() searchFilter?: string;
ngOnChanges(changes: SimpleChanges): void {
this.renderMarkdown = !!this.appConfig.markdown.enabled && this.enableMarkdown;
}
/**
* Determines whether a search filter has been configured for this metadata field.
* Used to decide if values should be rendered as search links.
*/
hasSearchFilter(): boolean {
return !!this.searchFilter;
}
/**
* Does this metadata value have a configured link to a browse definition?
*/
hasBrowseDefinition(): boolean {
return hasValue(this.browseDefinition);
}
/**
* Does this metadata value have a valid URL that should be rendered as a link?
* @param value A MetadataValue being displayed
*/
hasLink(value: MetadataValue): boolean {
if (hasValue(this.urlRegex)) {
const pattern = new RegExp(this.urlRegex);
return pattern.test(value.value);
}
return false;
}
/**
* Builds query parameters for the search page based on the configured search filter.
* The metadata value is used as the search term for the specified field.
*
* @param value The metadata value to search for.
* @returns Query parameters object for Angular router navigation.
*/
getSearchQueryParams(value: string): any {
return { [`f.${this.searchFilter}`]: `${value},equals` };
}
/**
* Whether the metadata is a controlled vocabulary
* @param value A MetadataValue being displayed
*/
isControlledVocabulary(metadataValue: MetadataValue): boolean {
const vocabularyId = this.getVocabularyIdFromAuthorityValue(metadataValue);
return hasValue(this.getVocabularyName(vocabularyId));
}
/**
* Return configured vocabulary name for this metadata value
*/
getVocabularyName(vocabularyId: string): string | null {
return this.appConfig.vocabularies.find(vocabulary => vocabulary.vocabulary === vocabularyId)?.vocabulary;
}
/**
* Get value from authority for vocabulary lookup
*/
getVocabularyIdFromAuthorityValue(metadataValue: MetadataValue): string {
const authority = metadataValue.authority ? metadataValue.authority.split(':') : undefined;
return authority?.length > 1 ? authority[0] : null;
}
/**
* Return a queryparams object for use in a link, with the key dependent on whether this browse
* definition is metadata browse, or item browse
* @param value the specific metadata value being linked
*/
getQueryParams(value) {
const queryParams = { startsWith: value };
// todo: should compare with type instead?
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (this.browseDefinition.getRenderType() === VALUE_LIST_BROWSE_DEFINITION.value) {
return { value: value };
}
return queryParams;
}
/**
* Checks if the given link value is an internal link.
* @param linkValue - The link value to check.
* @returns True if the link value starts with the base URL defined in the environment configuration, false otherwise.
*/
hasInternalLink(linkValue: string): boolean {
return linkValue.startsWith(environment.ui.baseUrl);
}
/**
* This method performs a validation and determines the target of the url.
* @returns - Returns the target url.
*/
getLinkAttributes(urlValue: string): { target: string, rel: string } {
if (this.hasInternalLink(urlValue)) {
return { target: '_self', rel: '' };
} else {
return { target: '_blank', rel: 'noopener noreferrer' };
}
}
/**
* Get vocabulary translated value from metadata value
*/
getVocabularyValue(metadataValue: MetadataValue): Observable<string> {
const vocabularyId = this.getVocabularyIdFromAuthorityValue(metadataValue);
const vocabularyName = this.getVocabularyName(vocabularyId);
return this.vocabularyService.getPublicVocabularyEntryByID(vocabularyName, metadataValue.authority.split(':')[1]).pipe(
getFirstCompletedRemoteData(),
getRemoteDataPayload(),
getPaginatedListPayload(),
map((res) => res?.length > 0 ? res[0] : null),
map((res) => res?.display ?? metadataValue.value),
take(1),
);
}
}