Skip to content

Commit a7437a9

Browse files
author
Andrea Barbasso
committed
Merged dspace-cris-2023_02_x into task/dspace-cris-2023_02_x/DSC-1575
2 parents 9310879 + 04e20f0 commit a7437a9

5 files changed

Lines changed: 187 additions & 16 deletions

File tree

src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-vocabulary.component.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
5555
*/
5656
public abstract pageInfo: PageInfo;
5757

58+
protected otherInfoValue: string;
59+
protected otherName: string;
60+
protected otherInfoKey: string;
61+
public otherInfoValues: string[] = [];
62+
public otherInfoValuesUnformatted: string[] = [];
63+
5864
protected constructor(protected vocabularyService: VocabularyService,
5965
protected layoutService: DynamicFormLayoutService,
6066
protected validationService: DynamicFormValidationService,
@@ -202,11 +208,11 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
202208
* @param authority
203209
*/
204210
updateAuthority(authority: string) {
205-
const currentValue: string = (this.model.value instanceof FormFieldMetadataValueObject
211+
const currentValue: string = (this.model.value instanceof FormFieldMetadataValueObject
206212
|| this.model.value instanceof VocabularyEntry) ? this.model.value.value : this.model.value;
207213
let security = null;
208214
if ( this.model.value instanceof VocabularyEntry) {
209-
security = this.model.value.securityLevel;
215+
security = this.model.value.securityLevel;
210216
} else {
211217
if (this.model.metadataValue) {
212218
security = this.model.metadataValue.securityLevel;
@@ -250,7 +256,7 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
250256
for (const key in otherInformation) {
251257
if (otherInformation.hasOwnProperty(key) && key.startsWith('data-')) {
252258
const fieldId = key.replace('data-', '');
253-
const newValue: FormFieldMetadataValueObject = this.getOtherInformationValue(otherInformation[key]);
259+
const newValue: FormFieldMetadataValueObject = this.getOtherInformationValue(otherInformation[key], key);
254260
if (isNotEmpty(newValue)) {
255261
const updatedModel = this.formBuilderService.updateModelValue(fieldId, newValue);
256262
if (isNotEmpty(updatedModel)) {
@@ -270,23 +276,42 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
270276
}
271277
}
272278

273-
getOtherInformationValue(value: string): FormFieldMetadataValueObject {
274-
if (isEmpty(value)) {
279+
getOtherInformationValue(value: string, key: string): FormFieldMetadataValueObject {
280+
if (isEmpty(value) || key === 'alternative-names' ) {
275281
return null;
276282
}
277283

278284
let returnValue;
279285
if (value.indexOf('::') === -1) {
280286
returnValue = new FormFieldMetadataValueObject(value);
281-
} else {
287+
} else if (value.indexOf('|||') === -1) {
282288
returnValue = new FormFieldMetadataValueObject(
283289
value.substring(0, value.lastIndexOf('::')),
284290
null,
285291
null,
286292
value.substring(value.lastIndexOf('::') + 2)
287293
);
294+
} else if (value.indexOf('|||') !== -1 && this.otherInfoValue) {
295+
const unformattedValue = this.otherInfoValuesUnformatted.find(otherInfoValue => otherInfoValue.includes(this.otherInfoValue || this.otherName));
296+
const authorityValue = hasValue(unformattedValue) ? unformattedValue.substring(unformattedValue.lastIndexOf('::') + 2) : null;
297+
let otherInfo = {};
298+
let alternativeValue;
299+
otherInfo[key] = value;
300+
if (hasValue(this.otherName)) {
301+
const otherValues = value.split('|||');
302+
alternativeValue = otherValues[0].substring(0, otherValues[0].lastIndexOf('::'));
303+
}
304+
returnValue = new FormFieldMetadataValueObject(
305+
hasValue(alternativeValue) ? alternativeValue : this.otherInfoValue,
306+
null,
307+
null,
308+
authorityValue,
309+
null,
310+
null,
311+
null,
312+
otherInfo
313+
);
288314
}
289-
290315
return returnValue;
291316
}
292317

src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<li class="list-item text-truncate text-primary font-weight-bold">{{entry.value}}</li>
1111
<ng-container *ngFor="let item of entry.otherInformation | dsObjNgFor">
1212
<li *ngIf="!item.key.startsWith('data-')" class="list-item text-truncate text-secondary" >
13-
{{ 'form.other-information.' + item.key | translate }} : {{item.value !== '' ? getOtherInfoValue(item.value) : ('form.other-information.not-available' | translate)}}
13+
{{ 'form.other-information.' + item.key | translate }} : {{item.value !== '' ? getOtherInfoValue(item.value, item.key) : ('form.other-information.not-available' | translate)}}
1414
</li>
1515
</ng-container>
1616
</ul>
@@ -31,9 +31,14 @@
3131
aria-hidden="true"
3232
[authorityValue]="currentValue"
3333
(whenClickOnConfidenceNotAccepted)="whenClickOnConfidenceNotAccepted($event)"></i>
34+
<i *ngIf="otherInfoValues.length > 0 && (model.id === otherInfoKey || otherInfoKey === alternativeNamesKey || 'data-' + model.id === otherInfoKey)"
35+
class="fa-solid fa-angle-down fa-fw fa-2x fa-fw position-absolute mt-1 p-0 additional-items-icon"
36+
(click)="toggleOtherInfoSelection()"
37+
></i>
38+
3439
<input #instance="ngbTypeahead"
3540
class="form-control"
36-
[attr.aria-labelledby]="'label_' + model.id"
41+
[attr.aria-labelledby]="'label_' + model.id"
3742
[attr.autoComplete]="model.autoComplete"
3843
[class.is-invalid]="showErrorMessages"
3944
[id]="model.id"
@@ -86,3 +91,15 @@
8691
(keypress)="$event.preventDefault()"
8792
(keyup)="$event.preventDefault()">
8893
</div>
94+
95+
96+
<div *ngIf="additionalInfoSelectIsOpen" class="bg-white border border-primary position-absolute additional-info-selection">
97+
<span class="m-2 text-muted">{{'form.other-information.selection.' + otherInfoKey | translate}}</span>
98+
<ul class="list-unstyled mb-0">
99+
<ng-container *ngFor="let info of otherInfoValues">
100+
<li [class.font-weight-bold]="(info === otherInfoValue && otherInfoKey !== alternativeNamesKey) || (info === otherName && otherInfoKey === alternativeNamesKey) || (model.value && info === model.value['display'] && !otherInfoValue && !otherName)" class="list-item d-flex align-items-center p-2" (click)="selectAlternativeInfo(info)">
101+
{{info}}
102+
</li>
103+
</ng-container>
104+
</ul>
105+
</div>

src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,20 @@
4040
background-color: #fff;
4141
cursor: pointer;
4242
}
43+
44+
.additional-items-icon {
45+
padding-right: 5rem !important;
46+
cursor: pointer;
47+
}
48+
.additional-info-selection {
49+
z-index: 9999;
50+
width: calc(100% - 10px);
51+
border-radius: 4px;
52+
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.175);
53+
.list-item {
54+
cursor: pointer;
55+
}
56+
.list-item:hover {
57+
background-color: var(--bs-dropdown-link-hover-bg);
58+
}
59+
}

src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
1+
import {
2+
ChangeDetectorRef,
3+
Component,
4+
EventEmitter,
5+
Input,
6+
OnInit,
7+
Output,
8+
ViewChild
9+
} from '@angular/core';
210
import { UntypedFormGroup } from '@angular/forms';
311

412
import {
@@ -67,6 +75,9 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
6775
previousValue: any;
6876
inputValue: any;
6977
preloadLevel: number;
78+
additionalInfoSelectIsOpen = false;
79+
alternativeNamesKey = 'alternative-names';
80+
7081

7182
private isHierarchicalVocabulary$: Observable<boolean>;
7283
private subs: Subscription[] = [];
@@ -94,6 +105,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
94105
* to display in the onebox popup.
95106
*/
96107
search = (text$: Observable<string>) => {
108+
this.additionalInfoSelectIsOpen = false;
97109
return text$.pipe(
98110
merge(this.click$),
99111
debounceTime(300),
@@ -167,7 +179,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
167179
* @param event
168180
*/
169181
onInput(event) {
170-
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
182+
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
171183
this.inputValue = new FormFieldMetadataValueObject(event.target.value);
172184
if (this.model.value) {
173185
if ((this.model.value as any).securityLevel != null) {
@@ -187,7 +199,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
187199
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
188200
this.dispatchUpdate(this.inputValue);
189201
}
190-
this.inputValue = null;
202+
this.inputValue = null;
191203
}
192204
this.blur.emit(event);
193205
} else {
@@ -221,8 +233,23 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
221233
*/
222234
onSelectItem(event: NgbTypeaheadSelectItemEvent) {
223235
this.inputValue = null;
224-
this.setCurrentValue(event.item);
225-
this.dispatchUpdate(event.item);
236+
const item = event.item;
237+
238+
if ( hasValue(item.otherInformation)) {
239+
const otherInfoKeys = Object.keys(item.otherInformation).filter((key) => !key.startsWith('data'));
240+
const hasMultipleValues = otherInfoKeys.some(key => hasValue(item.otherInformation[key]) && item.otherInformation[key].includes('|||'));
241+
242+
if (hasMultipleValues) {
243+
this.setMultipleValuesForOtherInfo(otherInfoKeys, item);
244+
} else {
245+
this.resetMultipleValuesForOtherInfo();
246+
}
247+
} else {
248+
this.resetMultipleValuesForOtherInfo();
249+
}
250+
251+
this.setCurrentValue(item);
252+
this.dispatchUpdate(item);
226253
}
227254

228255
/**
@@ -287,22 +314,37 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
287314
} else {
288315
result = value;
289316
}
317+
this.currentValue = null;
318+
this.cdr.detectChanges();
290319

291320
this.currentValue = result;
292321
this.previousValue = result;
293322
this.cdr.detectChanges();
294323
}
295-
324+
if (hasValue(this.currentValue.otherInformation)) {
325+
const infoKeys = Object.keys(this.currentValue.otherInformation);
326+
this.setMultipleValuesForOtherInfo(infoKeys, this.currentValue);
327+
}
296328
}
297329

298330
/**
299331
* Get the other information value removing the authority section (after the last ::)
300332
* @param itemValue the initial item value
333+
* @param itemKey
301334
*/
302-
getOtherInfoValue(itemValue: string): string {
335+
getOtherInfoValue(itemValue: string, itemKey: string): string {
303336
if (!itemValue || !itemValue.includes('::')) {
304337
return itemValue;
305338
}
339+
340+
if (itemValue.includes('|||')) {
341+
let result = '';
342+
const values = itemValue.split('|||').map(item => item.substring(0, item.lastIndexOf('::')));
343+
const lastIndex = values.length - 1;
344+
values.forEach((value, i) => result += i === lastIndex ? value : value + ' · ');
345+
return result;
346+
}
347+
306348
return itemValue.substring(0, itemValue.lastIndexOf('::'));
307349
}
308350

@@ -311,4 +353,64 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
311353
.filter((sub) => hasValue(sub))
312354
.forEach((sub) => sub.unsubscribe());
313355
}
356+
357+
toggleOtherInfoSelection() {
358+
this.additionalInfoSelectIsOpen = !this.additionalInfoSelectIsOpen;
359+
}
360+
361+
selectAlternativeInfo(info: string) {
362+
this.searching = true;
363+
364+
if (this.otherInfoKey !== this.alternativeNamesKey) {
365+
this.otherInfoValue = info;
366+
} else {
367+
this.otherName = info;
368+
}
369+
370+
const temp = this.createVocabularyObject(info, info, this.currentValue.otherInformation);
371+
this.currentValue = null;
372+
this.currentValue = temp;
373+
374+
const event = {
375+
item: this.currentValue
376+
} as any;
377+
378+
this.onSelectItem(event);
379+
this.searching = false;
380+
this.toggleOtherInfoSelection();
381+
}
382+
383+
384+
setMultipleValuesForOtherInfo(keys: string[], item: any) {
385+
const hasAlternativeNames = keys.includes(this.alternativeNamesKey);
386+
387+
this.otherInfoKey = hasAlternativeNames ? this.alternativeNamesKey : keys.find(key => hasValue(item.otherInformation[key]) && item.otherInformation[key].includes('|||'));
388+
this.otherInfoValuesUnformatted = item.otherInformation[this.otherInfoKey] ? item.otherInformation[this.otherInfoKey].split('|||') : [];
389+
this.otherInfoValues = this.otherInfoValuesUnformatted.map(unformattedItem => unformattedItem.substring(0, unformattedItem.lastIndexOf('::')));
390+
391+
if (hasAlternativeNames) {
392+
this.otherName = hasValue(this.otherName) ? this.otherName : this.otherInfoValues[0];
393+
}
394+
395+
if (keys.length > 1) {
396+
this.otherInfoValue = hasValue(this.otherInfoValue) ? this.otherInfoValue : this.otherInfoValues[0];
397+
}
398+
}
399+
400+
resetMultipleValuesForOtherInfo() {
401+
this.otherInfoKey = undefined;
402+
this.otherInfoValuesUnformatted = [];
403+
this.otherInfoValues = [];
404+
this.otherInfoValue = undefined;
405+
this.otherName = undefined;
406+
}
407+
408+
createVocabularyObject(display, value, otherInformation) {
409+
return Object.assign(new VocabularyEntry(), this.model.value, {
410+
display: display,
411+
value: value,
412+
otherInformation: otherInformation,
413+
type: 'vocabularyEntry'
414+
});
415+
}
314416
}

src/assets/i18n/en.json5

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7358,4 +7358,14 @@
73587358
"third-party-metrics-cookies.consent-settings": "consent settings",
73597359

73607360
"third-party-metrics-blocked": "Some of the metrics are blocked by your",
7361+
7362+
"form.other-information.alternative-names": "Alternative names",
7363+
7364+
"form.other-information.selection.data-oairecerif_author_affiliation": "Select alternative affiliation",
7365+
7366+
"form.other-information.data-oairecerif_author_affiliation": "Affiliation",
7367+
7368+
"form.other-information.selection.data-crispj_coinvestigator_affiliation": "Affiliation",
7369+
7370+
"form.other-information.selection.alternative-names": "Select alternative name",
73617371
}

0 commit comments

Comments
 (0)