Skip to content

Commit

Permalink
Merged dspace-cris-2023_02_x into task/dspace-cris-2023_02_x/DSC-1601
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrea Barbasso committed May 2, 2024
2 parents de85023 + d2b6c3e commit 926f76d
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
*/
public abstract pageInfo: PageInfo;

protected otherInfoValue: string;
protected otherName: string;
protected otherInfoKey: string;
public otherInfoValues: string[] = [];
public otherInfoValuesUnformatted: string[] = [];

protected constructor(protected vocabularyService: VocabularyService,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService,
Expand Down Expand Up @@ -202,11 +208,11 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
* @param authority
*/
updateAuthority(authority: string) {
const currentValue: string = (this.model.value instanceof FormFieldMetadataValueObject
const currentValue: string = (this.model.value instanceof FormFieldMetadataValueObject
|| this.model.value instanceof VocabularyEntry) ? this.model.value.value : this.model.value;
let security = null;
if ( this.model.value instanceof VocabularyEntry) {
security = this.model.value.securityLevel;
security = this.model.value.securityLevel;
} else {
if (this.model.metadataValue) {
security = this.model.metadataValue.securityLevel;
Expand Down Expand Up @@ -250,7 +256,7 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
for (const key in otherInformation) {
if (otherInformation.hasOwnProperty(key) && key.startsWith('data-')) {
const fieldId = key.replace('data-', '');
const newValue: FormFieldMetadataValueObject = this.getOtherInformationValue(otherInformation[key]);
const newValue: FormFieldMetadataValueObject = this.getOtherInformationValue(otherInformation[key], key);
if (isNotEmpty(newValue)) {
const updatedModel = this.formBuilderService.updateModelValue(fieldId, newValue);
if (isNotEmpty(updatedModel)) {
Expand All @@ -270,23 +276,42 @@ export abstract class DsDynamicVocabularyComponent extends DynamicFormControlCom
}
}

getOtherInformationValue(value: string): FormFieldMetadataValueObject {
if (isEmpty(value)) {
getOtherInformationValue(value: string, key: string): FormFieldMetadataValueObject {
if (isEmpty(value) || key === 'alternative-names' ) {
return null;
}

let returnValue;
if (value.indexOf('::') === -1) {
returnValue = new FormFieldMetadataValueObject(value);
} else {
} else if (value.indexOf('|||') === -1) {
returnValue = new FormFieldMetadataValueObject(
value.substring(0, value.lastIndexOf('::')),
null,
null,
value.substring(value.lastIndexOf('::') + 2)
);
} else if (value.indexOf('|||') !== -1 && this.otherInfoValue) {
const unformattedValue = this.otherInfoValuesUnformatted.find(otherInfoValue => otherInfoValue.includes(this.otherInfoValue || this.otherName));
const authorityValue = hasValue(unformattedValue) ? unformattedValue.substring(unformattedValue.lastIndexOf('::') + 2) : null;
let otherInfo = {};
let alternativeValue;
otherInfo[key] = value;
if (hasValue(this.otherName)) {
const otherValues = value.split('|||');
alternativeValue = otherValues[0].substring(0, otherValues[0].lastIndexOf('::'));
}
returnValue = new FormFieldMetadataValueObject(
hasValue(alternativeValue) ? alternativeValue : this.otherInfoValue,
null,
null,
authorityValue,
null,
null,
null,
otherInfo
);
}

return returnValue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<li class="list-item text-truncate text-primary font-weight-bold">{{entry.value}}</li>
<ng-container *ngFor="let item of entry.otherInformation | dsObjNgFor">
<li *ngIf="!item.key.startsWith('data-')" class="list-item text-truncate text-secondary" >
{{ 'form.other-information.' + item.key | translate }} : {{item.value !== '' ? getOtherInfoValue(item.value) : ('form.other-information.not-available' | translate)}}
{{ 'form.other-information.' + item.key | translate }} : {{item.value !== '' ? getOtherInfoValue(item.value, item.key) : ('form.other-information.not-available' | translate)}}
</li>
</ng-container>
</ul>
Expand All @@ -31,9 +31,14 @@
aria-hidden="true"
[authorityValue]="currentValue"
(whenClickOnConfidenceNotAccepted)="whenClickOnConfidenceNotAccepted($event)"></i>
<i *ngIf="otherInfoValues.length > 0 && (model.id === otherInfoKey || otherInfoKey === alternativeNamesKey || 'data-' + model.id === otherInfoKey)"
class="fa-solid fa-angle-down fa-fw fa-2x fa-fw position-absolute mt-1 p-0 additional-items-icon"
(click)="toggleOtherInfoSelection()"
></i>

<input #instance="ngbTypeahead"
class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[class.is-invalid]="showErrorMessages"
[id]="model.id"
Expand Down Expand Up @@ -86,3 +91,15 @@
(keypress)="$event.preventDefault()"
(keyup)="$event.preventDefault()">
</div>


<div *ngIf="additionalInfoSelectIsOpen" class="bg-white border border-primary position-absolute additional-info-selection">
<span class="m-2 text-muted">{{'form.other-information.selection.' + otherInfoKey | translate}}</span>
<ul class="list-unstyled mb-0">
<ng-container *ngFor="let info of otherInfoValues">
<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)">
{{info}}
</li>
</ng-container>
</ul>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@
background-color: #fff;
cursor: pointer;
}

.additional-items-icon {
padding-right: 5rem !important;
cursor: pointer;
}
.additional-info-selection {
z-index: 9999;
width: calc(100% - 10px);
border-radius: 4px;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.175);
.list-item {
cursor: pointer;
}
.list-item:hover {
background-color: var(--bs-dropdown-link-hover-bg);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import {
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';

import {
Expand Down Expand Up @@ -67,6 +75,9 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
previousValue: any;
inputValue: any;
preloadLevel: number;
additionalInfoSelectIsOpen = false;
alternativeNamesKey = 'alternative-names';


private isHierarchicalVocabulary$: Observable<boolean>;
private subs: Subscription[] = [];
Expand Down Expand Up @@ -94,6 +105,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
* to display in the onebox popup.
*/
search = (text$: Observable<string>) => {
this.additionalInfoSelectIsOpen = false;
return text$.pipe(
merge(this.click$),
debounceTime(300),
Expand Down Expand Up @@ -167,7 +179,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
* @param event
*/
onInput(event) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
this.inputValue = new FormFieldMetadataValueObject(event.target.value);
if (this.model.value) {
if ((this.model.value as any).securityLevel != null) {
Expand All @@ -187,7 +199,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.dispatchUpdate(this.inputValue);
}
this.inputValue = null;
this.inputValue = null;
}
this.blur.emit(event);
} else {
Expand Down Expand Up @@ -221,8 +233,23 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
*/
onSelectItem(event: NgbTypeaheadSelectItemEvent) {
this.inputValue = null;
this.setCurrentValue(event.item);
this.dispatchUpdate(event.item);
const item = event.item;

if ( hasValue(item.otherInformation)) {
const otherInfoKeys = Object.keys(item.otherInformation).filter((key) => !key.startsWith('data'));
const hasMultipleValues = otherInfoKeys.some(key => hasValue(item.otherInformation[key]) && item.otherInformation[key].includes('|||'));

if (hasMultipleValues) {
this.setMultipleValuesForOtherInfo(otherInfoKeys, item);
} else {
this.resetMultipleValuesForOtherInfo();
}
} else {
this.resetMultipleValuesForOtherInfo();
}

this.setCurrentValue(item);
this.dispatchUpdate(item);
}

/**
Expand Down Expand Up @@ -287,22 +314,37 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
} else {
result = value;
}
this.currentValue = null;
this.cdr.detectChanges();

this.currentValue = result;
this.previousValue = result;
this.cdr.detectChanges();
}

if (hasValue(this.currentValue.otherInformation)) {
const infoKeys = Object.keys(this.currentValue.otherInformation);
this.setMultipleValuesForOtherInfo(infoKeys, this.currentValue);
}
}

/**
* Get the other information value removing the authority section (after the last ::)
* @param itemValue the initial item value
* @param itemKey
*/
getOtherInfoValue(itemValue: string): string {
getOtherInfoValue(itemValue: string, itemKey: string): string {
if (!itemValue || !itemValue.includes('::')) {
return itemValue;
}

if (itemValue.includes('|||')) {
let result = '';
const values = itemValue.split('|||').map(item => item.substring(0, item.lastIndexOf('::')));
const lastIndex = values.length - 1;
values.forEach((value, i) => result += i === lastIndex ? value : value + ' · ');
return result;
}

return itemValue.substring(0, itemValue.lastIndexOf('::'));
}

Expand All @@ -311,4 +353,64 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}

toggleOtherInfoSelection() {
this.additionalInfoSelectIsOpen = !this.additionalInfoSelectIsOpen;
}

selectAlternativeInfo(info: string) {
this.searching = true;

if (this.otherInfoKey !== this.alternativeNamesKey) {
this.otherInfoValue = info;
} else {
this.otherName = info;
}

const temp = this.createVocabularyObject(info, info, this.currentValue.otherInformation);
this.currentValue = null;
this.currentValue = temp;

const event = {
item: this.currentValue
} as any;

this.onSelectItem(event);
this.searching = false;
this.toggleOtherInfoSelection();
}


setMultipleValuesForOtherInfo(keys: string[], item: any) {
const hasAlternativeNames = keys.includes(this.alternativeNamesKey);

this.otherInfoKey = hasAlternativeNames ? this.alternativeNamesKey : keys.find(key => hasValue(item.otherInformation[key]) && item.otherInformation[key].includes('|||'));
this.otherInfoValuesUnformatted = item.otherInformation[this.otherInfoKey] ? item.otherInformation[this.otherInfoKey].split('|||') : [];
this.otherInfoValues = this.otherInfoValuesUnformatted.map(unformattedItem => unformattedItem.substring(0, unformattedItem.lastIndexOf('::')));

if (hasAlternativeNames) {
this.otherName = hasValue(this.otherName) ? this.otherName : this.otherInfoValues[0];
}

if (keys.length > 1) {
this.otherInfoValue = hasValue(this.otherInfoValue) ? this.otherInfoValue : this.otherInfoValues[0];
}
}

resetMultipleValuesForOtherInfo() {
this.otherInfoKey = undefined;
this.otherInfoValuesUnformatted = [];
this.otherInfoValues = [];
this.otherInfoValue = undefined;
this.otherName = undefined;
}

createVocabularyObject(display, value, otherInformation) {
return Object.assign(new VocabularyEntry(), this.model.value, {
display: display,
value: value,
otherInformation: otherInformation,
type: 'vocabularyEntry'
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ds-chips [chips]="chips"
[editable]="!model.readOnly"
[showIcons]="model.hasAuthority"
[wrapperClass]="'border-bottom border-light'">
[wrapperClass]="'border-bottom'">

<input *ngIf="!model.hasAuthority"
class="border-0 form-control-plaintext tag-input flex-grow-1 mt-1 mb-1"
Expand Down
15 changes: 9 additions & 6 deletions src/app/shared/form/builder/parsers/tag-field-parser.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { FieldParser } from './field-parser';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { DynamicTagModel, DynamicTagModelConfig } from '../ds-dynamic-form-ui/models/tag/dynamic-tag.model';

import {DynamicFormControlLayout} from '@ng-dynamic-forms/core';
export class TagFieldParser extends FieldParser {

public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
let clsTag: DynamicFormControlLayout;
clsTag = {
grid: {
container: 'mb-3 mt-3',
}
};
const tagModelConfig: DynamicTagModelConfig = this.initModel(null, label);
if (this.configData.selectableMetadata[0].controlledVocabulary
&& this.configData.selectableMetadata[0].controlledVocabulary.length > 0) {
this.setVocabularyOptions(tagModelConfig, this.parserOptions.collectionUUID);
}

this.setValues(tagModelConfig, fieldValue, null, true);

const tagModel = new DynamicTagModel(tagModelConfig);

tagModelConfig.placeholder = 'Enter the Keywords';
const tagModel = new DynamicTagModel(tagModelConfig, clsTag);
return tagModel;
}

Expand Down
Loading

0 comments on commit 926f76d

Please sign in to comment.