Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee62932

Browse files
committed
Prettified the DOI metadata field - removed the DOI resolver from metadata value (#539)
* Prettify the DOI metadata field. Remove the DOI resolver from that metadata value. * Fixed failing unit test
1 parent 8a7329a commit ee62932

File tree

9 files changed

+161
-51
lines changed

9 files changed

+161
-51
lines changed

src/app/item-page/simple/field-components/clarin-generic-item-field/clarin-generic-item-field.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="row clarin-item-page-field justify-content-start" *ngIf="hasMetadataValue()">
1+
<div class="row clarin-item-page-field justify-content-start" *ngIf="showMetadataValue | async">
22
<div class="col-lg-3 col-2-5 d-flex">
33
<div><i [class]="'fas ' + iconName + ' fa-xs'"></i></div>
44
<div class="pl-1"><b>{{label | translate}}</b></div>

src/app/item-page/simple/field-components/clarin-generic-item-field/clarin-generic-item-field.component.ts

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import { ConfigurationProperty } from '../../../../core/shared/configuration-pro
55
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
66
import { convertMetadataFieldIntoSearchType, getBaseUrl } from '../../../../shared/clarin-shared-util';
77
import { ConfigurationDataService } from '../../../../core/data/configuration-data.service';
8+
import { BehaviorSubject, firstValueFrom } from 'rxjs';
9+
import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators';
10+
import { map } from 'rxjs/operators';
11+
12+
export const DOI_METADATA_FIELD = 'dc.identifier.doi';
13+
const SHOW_HANDLE_AND_DOI_PROPERTY_NAME = 'item-page.show-handle-and-doi';
14+
const HANDLE_METADATA_FIELD = 'dc.identifier.uri';
815

916
@Component({
1017
selector: 'ds-clarin-generic-item-field',
@@ -56,12 +63,21 @@ export class ClarinGenericItemFieldComponent implements OnInit {
5663
*/
5764
baseUrl = '';
5865

66+
/**
67+
* Show or hide the metadata value. The default value is `true`.
68+
*/
69+
showMetadataValue: BehaviorSubject<boolean> = new BehaviorSubject(true);
70+
71+
/**
72+
* Enable or disable showing both the handle and DOI identifiers in the item page. The default value is `false` to
73+
* show only the DOI identifier if it exists in the Item. If there is no DOI identifier,
74+
* the handle identifier is shown.
75+
*/
76+
showHandleAndDOI = 'false';
5977

60-
// tslint:disable-next-line:no-empty
6178
constructor(protected dsoNameService: DSONameService,
6279
protected configurationService: ConfigurationDataService) { }
6380

64-
// tslint:disable-next-line:no-empty
6581
async ngOnInit(): Promise<void> {
6682
await this.assignBaseUrl();
6783
if (isEmpty(this.separator)) {
@@ -72,6 +88,9 @@ export class ClarinGenericItemFieldComponent implements OnInit {
7288
if (isEmpty(this.replaceCharacter)) {
7389
this.replaceCharacter = [';', ' '];
7490
}
91+
92+
// Do not show metadata value if some conditions are met
93+
await this.shouldShowMetadataValue();
7594
}
7695

7796
/**
@@ -81,6 +100,38 @@ export class ClarinGenericItemFieldComponent implements OnInit {
81100
return isNotUndefined(this.item.firstMetadataValue(this.fields));
82101
}
83102

103+
/**
104+
* The method disable showing the metadata value if one of the following conditions is met:
105+
* - The metadata value is empty
106+
* - The metadata field is not allowed to be shown by the configuration
107+
*/
108+
public async shouldShowMetadataValue() {
109+
// Do not show metadata value if it is empty
110+
if (!this.hasMetadataValue()) {
111+
this.showMetadataValue.next(false);
112+
return;
113+
}
114+
115+
// Do not show DOI and Item Identifier (handle) if it is not allowed by the configuration
116+
await this.shouldShowBothIdentifiers();
117+
}
118+
119+
/**
120+
* Do not show DOI and Item Identifier (handle) if it is not allowed by the configuration property
121+
* `item-page.show-handle-and-doi`.
122+
* @private
123+
*/
124+
private async shouldShowBothIdentifiers() {
125+
// If the metadata field is Handle and the Item contains DOI identifier, do not show the handle identifier if the
126+
// configuration is set to show only the DOI identifier.
127+
if (this.fields.includes(HANDLE_METADATA_FIELD) && this.item.allMetadata(DOI_METADATA_FIELD)?.length > 0){
128+
await this.loadShowHandleAndDoiConfiguration();
129+
if (this.showHandleAndDOI === 'false') {
130+
this.showMetadataValue.next(false);
131+
}
132+
}
133+
}
134+
84135
/**
85136
* Return current metadata value. The metadata field could have more metadata values, often the metadata
86137
* field has only one metadata value - index is 0, but sometimes it has more values e.g. `Author`.
@@ -129,4 +180,16 @@ export class ClarinGenericItemFieldComponent implements OnInit {
129180
return baseUrlResponse?.values?.[0];
130181
});
131182
}
183+
184+
/**
185+
* Load the configuration value for showing both the handle and DOI identifiers
186+
* @private
187+
*/
188+
private async loadShowHandleAndDoiConfiguration() {
189+
// Get the configuration value for showing both the handle and DOI identifiers
190+
this.showHandleAndDOI = await firstValueFrom(this.configurationService.findByPropertyName(SHOW_HANDLE_AND_DOI_PROPERTY_NAME)
191+
.pipe(
192+
getFirstSucceededRemoteDataPayload(),
193+
map((cfgValues) => cfgValues?.values?.[0])));
194+
}
132195
}
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
<div *ngFor="let identifier of (identifiers | async)">
2-
<div class="justify-content-between d-flex">
3-
<a [href]="identifier">{{identifier}}</a>
4-
<i class="far fa-copy cursor-pointer"
5-
(click)="copyToClipboard(identifier)"
6-
[ngbTooltip]="'Copied!'" #copyButton="ngbTooltip"></i>
7-
</div>
1+
<div class="justify-content-between d-flex">
2+
<a [href]="identifier">{{ prettifiedIdentifier | async }}</a>
3+
<i class="far fa-copy cursor-pointer"
4+
(click)="copyToClipboard(identifier)"
5+
[ngbTooltip]="'Copied!'" #copyButton="ngbTooltip"></i>
86
</div>

src/app/item-page/simple/field-components/clarin-identifier-item-field/clarin-identifier-item-field.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-dat
66
import { ConfigurationProperty } from '../../../../core/shared/configuration-property.model';
77
import { Item } from '../../../../core/shared/item.model';
88
import { createPaginatedList } from '../../../../shared/testing/utils.test';
9+
import { DOI_METADATA_FIELD } from '../clarin-generic-item-field/clarin-generic-item-field.component';
910

1011
describe('ClarinIdentifierItemFieldComponent', () => {
1112
let component: ClarinIdentifierItemFieldComponent;
@@ -47,6 +48,7 @@ describe('ClarinIdentifierItemFieldComponent', () => {
4748
fixture = TestBed.createComponent(ClarinIdentifierItemFieldComponent);
4849
component = fixture.componentInstance;
4950
component.item = mockItem;
51+
component.fields = [DOI_METADATA_FIELD];
5052
fixture.detectChanges();
5153
});
5254

Lines changed: 71 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { Component, Input, OnInit, ViewChild } from '@angular/core';
22
import { Item } from '../../../../core/shared/item.model';
3-
import { ConfigurationDataService } from '../../../../core/data/configuration-data.service';
4-
import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators';
5-
import { map } from 'rxjs/operators';
63
import { BehaviorSubject, firstValueFrom } from 'rxjs';
74
import { Clipboard } from '@angular/cdk/clipboard';
85
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
6+
import { ConfigurationDataService } from '../../../../core/data/configuration-data.service';
7+
import { isEmpty, isNotEmpty } from '../../../../shared/empty.util';
8+
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
9+
import { map } from 'rxjs/operators';
10+
import { DOI_METADATA_FIELD } from '../clarin-generic-item-field/clarin-generic-item-field.component';
911

10-
const SHOW_HANDLE_AND_DOI_PROPERTY_NAME = 'item-page.show-handle-and-doi';
11-
const DOI_METADATA_FIELD = 'dc.identifier.doi';
12-
const HANDLE_METADATA_FIELD = 'dc.identifier.uri';
12+
const DEFAULT_DOI_RESOLVER = 'https://doi.org/';
13+
const DOI_RESOLVER_CFG_PROPERTY = 'identifier.doi.resolver';
1314

1415
@Component({
1516
selector: 'ds-clarin-identifier-item-field',
@@ -34,51 +35,29 @@ export class ClarinIdentifierItemFieldComponent implements OnInit {
3435
@Input() fields: string[];
3536

3637
/**
37-
* Enable or disable showing both the handle and DOI identifiers in the item page. The default value is `false` to
38-
* show only the DOI identifier if it exists in the Item. If there is no DOI identifier,
39-
* the handle identifier is shown.
38+
* The DOI resolver URL. It is a `identifier.doi.resolver` property or the default resolver (constant).
4039
*/
41-
showHandleAndDOI = 'false';
40+
doiResolver: string;
4241

4342
/**
44-
* The identifiers to display (DOI and/or handle)
43+
* The identifier of the item. DOI or handle.
4544
*/
46-
identifiers: BehaviorSubject<string[]> = new BehaviorSubject(['']);
45+
identifier: string;
46+
47+
/**
48+
* BehaviorSubject to store the prettified identifier.
49+
*/
50+
prettifiedIdentifier: BehaviorSubject<string> = new BehaviorSubject<string>(null);
4751

4852
constructor(private configurationService: ConfigurationDataService,
4953
private clipboard: Clipboard) {
5054
}
5155

52-
async ngOnInit(): Promise<void> {
53-
// Get the configuration value for showing both the handle and DOI identifiers
54-
this.showHandleAndDOI = await firstValueFrom(this.configurationService.findByPropertyName(SHOW_HANDLE_AND_DOI_PROPERTY_NAME)
55-
.pipe(
56-
getFirstSucceededRemoteDataPayload(),
57-
map((cfgValues) => cfgValues?.values?.[0])));
58-
59-
// Set the identifiers to display
60-
this.setIdentifiersToDisplay();
56+
ngOnInit(): void {
57+
this.identifier = this.item?.firstMetadataValue(this.fields);
58+
void this.prettifyIdentifier(this.identifier);
6159
}
6260

63-
private setIdentifiersToDisplay() {
64-
let tempIdentifiers: string[] = [];
65-
const containsDOI = this.item.allMetadata(DOI_METADATA_FIELD)?.length > 0;
66-
this.fields?.forEach(field => {
67-
// Show handle identifier if there is DOI identifier in the Item and the configuration is set to show both
68-
if (field === HANDLE_METADATA_FIELD) {
69-
if (containsDOI && this.showHandleAndDOI === 'true') {
70-
tempIdentifiers.push(...this.item.allMetadataValues(HANDLE_METADATA_FIELD));
71-
} else if (!containsDOI) {
72-
tempIdentifiers.push(...this.item.allMetadataValues(HANDLE_METADATA_FIELD));
73-
}
74-
}
75-
// Every time show DOI identifier if it exists in the Item
76-
if (field === DOI_METADATA_FIELD) {
77-
tempIdentifiers.push(...this.item.allMetadataValues(DOI_METADATA_FIELD));
78-
}
79-
});
80-
this.identifiers.next(tempIdentifiers);
81-
}
8261

8362
/**
8463
* Copy the metadata value to the clipboard. After clicking on the `Copy` icon the message `Copied` is popped up.
@@ -91,4 +70,56 @@ export class ClarinIdentifierItemFieldComponent implements OnInit {
9170
this.copyButtonRef.close();
9271
}, 700);
9372
}
73+
74+
/**
75+
* Prettify the identifier. If the identifier is DOI, remove the DOI resolver from it.
76+
*
77+
* @param identifier
78+
*/
79+
async prettifyIdentifier(identifier: string) {
80+
if (isEmpty(identifier)) {
81+
this.prettifiedIdentifier.next(null);
82+
return;
83+
}
84+
85+
// Do not prettify the identifier if it is not DOI.
86+
if (!this.fields.includes(DOI_METADATA_FIELD)) {
87+
this.prettifiedIdentifier.next(identifier);
88+
return;
89+
}
90+
91+
// If the DOI resolver is set, use it. It is not set by default.
92+
if (isNotEmpty(this.doiResolver)) {
93+
this.removeDoiResolverFromIdentifier(identifier);
94+
return;
95+
}
96+
97+
// Get the DOI resolver from the configuration.
98+
const cfgDoiResolver = await firstValueFrom(this.loadDoiResolverConfiguration());
99+
100+
// If the configuration is not set, use the default resolver.
101+
this.doiResolver = isEmpty(cfgDoiResolver) ? DEFAULT_DOI_RESOLVER : cfgDoiResolver;
102+
103+
// Remove the DOI resolver from the identifier.
104+
this.removeDoiResolverFromIdentifier(identifier);
105+
}
106+
107+
/**
108+
* Remove the DOI resolver from the identifier.
109+
*
110+
* @param identifier
111+
*/
112+
removeDoiResolverFromIdentifier(identifier: string) {
113+
this.prettifiedIdentifier.next(identifier.replace(this.doiResolver, ''));
114+
}
115+
116+
/**
117+
* Load the DOI resolver from the configuration. It is a `identifier.doi.resolver` property.
118+
*/
119+
loadDoiResolverConfiguration() {
120+
return this.configurationService.findByPropertyName(DOI_RESOLVER_CFG_PROPERTY)
121+
.pipe(
122+
getFirstCompletedRemoteData(),
123+
map((config) => config?.payload?.values?.[0]));
124+
}
94125
}

src/app/item-page/simple/item-types/publication/publication.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
[iconName]="'fa-share'"
3232
[type]="'identifier'">
3333
</ds-clarin-generic-item-field>
34+
<ds-clarin-generic-item-field [item]="object"
35+
[fields]="['dc.identifier.doi']"
36+
[label]="'item.page.doi'"
37+
[iconName]="'fa-share'"
38+
[type]="'identifier'">
39+
</ds-clarin-generic-item-field>
3440
<ds-clarin-generic-item-field [item]="object"
3541
[fields]="['dc.source.uri']"
3642
[label]="'item.page.project-url'"

src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,17 @@
2828
[type]="'author'">
2929
</ds-clarin-generic-item-field>
3030
<ds-clarin-generic-item-field [item]="object"
31-
[fields]="['dc.identifier.uri', 'dc.identifier.doi']"
31+
[fields]="['dc.identifier.uri']"
3232
[label]="'item.page.uri'"
3333
[iconName]="'fa-share'"
3434
[type]="'identifier'">
3535
</ds-clarin-generic-item-field>
36+
<ds-clarin-generic-item-field [item]="object"
37+
[fields]="['dc.identifier.doi']"
38+
[label]="'item.page.doi'"
39+
[iconName]="'fa-share'"
40+
[type]="'identifier'">
41+
</ds-clarin-generic-item-field>
3642
<ds-clarin-generic-item-field [item]="object"
3743
[fields]="['dc.source.uri']"
3844
[label]="'item.page.project-url'"

src/assets/i18n/cs.json5

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,8 @@
25792579
"item.page.subject": "Klíčová slova",
25802580
// "item.page.uri": "Item identifier",
25812581
"item.page.uri": "Identifikátor",
2582+
// "item.page.doi": "DOI",
2583+
"item.page.doi": "DOI",
25822584
// "item.page.bitstreams.view-more": "Show more",
25832585
"item.page.bitstreams.view-more": "Zobrazit více",
25842586
// "item.page.bitstreams.collapse": "Collapse",

src/assets/i18n/en.json5

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,8 @@
27252725

27262726
"item.page.uri": "Item identifier",
27272727

2728+
"item.page.doi": "DOI",
2729+
27282730
"item.page.bitstreams.view-more": "Show more",
27292731

27302732
"item.page.bitstreams.collapse": "Collapse",

0 commit comments

Comments
 (0)