Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class BrowseByTaxonomyComponent implements OnInit, OnChanges, OnDestroy {
this.selectedItems = [];
this.facetType = browseDefinition.facetType;
this.vocabularyName = browseDefinition.vocabulary;
this.vocabularyOptions = { name: this.vocabularyName, closed: true };
this.vocabularyOptions = { name: this.vocabularyName, closed: true, type: 'xml' };
this.description = this.translate.instant(`browse.metadata.${this.vocabularyName}.tree.description`);
}));
this.subs.push(this.scope$.subscribe(() => {
Expand Down
5 changes: 5 additions & 0 deletions src/app/core/shared/form/models/form-field.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface SelectableMetadata {
* A boolean representing if value is closely related to the controlled vocabulary entry or not
*/
closed: boolean;

/**
* The type (source) of the vocabulary: xml, authority, suggest
*/
vocabularyType: string;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ export class VocabularyOptions {
*/
closed: boolean;

/**
* The type of the vocabulary (source): xml, authority, suggest
*/
type?: string;

constructor(name: string,
closed: boolean = false) {
closed: boolean = false, type: string = 'xml') {
this.name = name;
this.closed = closed;
this.type = type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import { Item } from '@dspace/core/shared/item.model';
import { MetadataValue } from '@dspace/core/shared/metadata.models';
import { Vocabulary } from '@dspace/core/submission/vocabularies/models/vocabulary.model';
import { VocabularyService } from '@dspace/core/submission/vocabularies/vocabulary.service';
import { SearchServiceStub } from '@dspace/core/testing/search-service.stub';
import { createPaginatedList } from '@dspace/core/testing/utils.test';
import { VocabularyServiceStub } from '@dspace/core/testing/vocabulary-service.stub';
import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils';
import { TranslateModule } from '@ngx-translate/core';
import { SearchService } from 'src/app/shared/search/search.service';

import { RegistryService } from '../../../../admin/admin-registries/registry/registry.service';
import { DynamicOneboxModel } from '../../../../shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.model';
Expand All @@ -32,6 +34,7 @@ describe('DsoEditMetadataAuthorityFieldComponent', () => {
let fixture: ComponentFixture<DsoEditMetadataAuthorityFieldComponent>;

let vocabularyService: any;
let searchService: any;
let itemService: ItemDataService;
let registryService: RegistryService;
let notificationsService: NotificationsService;
Expand Down Expand Up @@ -112,6 +115,7 @@ describe('DsoEditMetadataAuthorityFieldComponent', () => {
findByHref: createSuccessfulRemoteDataObject$(item),
});
vocabularyService = new VocabularyServiceStub();
searchService = new SearchServiceStub();
registryService = jasmine.createSpyObj('registryService', {
queryMetadataFields: createSuccessfulRemoteDataObject$(createPaginatedList(metadataFields)),
});
Expand Down Expand Up @@ -150,6 +154,7 @@ describe('DsoEditMetadataAuthorityFieldComponent', () => {
],
providers: [
{ provide: VocabularyService, useValue: vocabularyService },
{ provide: SearchService, useValue: searchService },
{ provide: ItemDataService, useValue: itemService },
{ provide: RegistryService, useValue: registryService },
{ provide: NotificationsService, useValue: notificationsService },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,91 +1,94 @@
<ng-template #rt let-listEntry="result" let-t="term">
<ng-container
[ngTemplateOutlet]="(listEntry.hasOtherInformation()) ? hasInfo : noInfo"
[ngTemplateOutletContext]="{entry: listEntry}">
</ng-container>
</ng-template>

<ng-template #hasInfo let-entry="entry">
<ng-template #rt let-listEntry="result">
<ul class="list-unstyled mb-0">
<li class="list-item text-truncate text-primary fw-bold">{{entry.value}}</li>
@for (item of entry.otherInformation | dsObjNgFor; track item) {
<li class="list-item text-truncate text-secondary" >
{{ 'form.other-information.' + item.key | translate }} : {{item.value}}
</li>
@if (listEntry.display) {
<li
class="list-item text-truncate text-primary"
[innerHtml]="listEntry.display">
</li>
} @else {
<li class="list-item text-truncate text-primary fw-bold">
{{listEntry.value}}
</li>
}
</ul>
</ng-template>

<ng-template #noInfo let-entry="entry">
<ul class="list-unstyled mb-0">
<li class="list-item text-truncate text-primary fw-bold">{{entry.value}}</li>
@if (listEntry.hasOtherInformation()) {
@for (item of listEntry.otherInformation | dsObjNgFor; track item.key) {

<li class="list-item text-truncate text-secondary" >
{{ 'form.other-information.' + item.key | translate }} : {{item.value}}
</li>

}}
</ul>
</ng-template>

@if ((isHierarchicalVocabulary() | async) !== true) {
<div class="position-relative right-addon">
<div class="authority-icons position-absolute d-flex align-items-center">
@if (searching || loadingInitialValue) {
<i class="fas fa-circle-notch fa-spin fa-2x fa-fw text-primary my-auto p-0" aria-hidden="true"></i>
}
@if (!searching && !loadingInitialValue) {
<i
dsAuthorityConfidenceState
class="far fa-circle fa-2x fa-fw my-auto p-0"
aria-hidden="true"
[authorityValue]="currentValue"
(whenClickOnConfidenceNotAccepted)="whenClickOnConfidenceNotAccepted($event)"></i>
}
</div>
<input #instance="ngbTypeahead"
class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[class.is-invalid]="showErrorMessages"
[id]="model.id"
[inputFormatter]="formatter"
[name]="model.name"
[ngbTypeahead]="search"
[placeholder]="model.placeholder"
[readonly]="model.readOnly"
[disabled]="model.readOnly"
[resultTemplate]="rt"
[type]="model.inputType"
[(ngModel)]="currentValue"
(blur)="onBlur($event)"
(focus)="onFocus($event)"
(change)="onChange($event)"
(input)="onInput($event)"
(selectItem)="onSelectItem($event)">
@if (searchFailed) {
<div class="invalid-feedback">Sorry, suggestions could not be loaded.</div>
}
</div>
}
<div class="position-relative right-addon">

@if ((vocabulary$ | async)?.hierarchical) {

<i class="dropdown-toggle position-absolute tree-toggle" (click)="openTree($event)"
aria-hidden="true"></i>
<input class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[class.is-invalid]="showErrorMessages"
[class.tree-input]="!model.readOnly"
[id]="id"
[name]="model.name"
[placeholder]="model.placeholder"
[readonly]="true"
[disabled]="model.readOnly"
[type]="model.inputType"
[value]="currentValue?.display"
(focus)="onFocus($event)"
(change)="onChange($event)"
(click)="openTree($event)"
(keydown)="$event.preventDefault()"
(keypress)="$event.preventDefault()"
(keyup)="$event.preventDefault()">

} @else {

@if (loading) {
<i
class="fas fa-circle-notch fa-spin fa-2x fa-fw text-primary position-absolute mt-1 p-0"
aria-hidden="true">
</i>
} @else {
<i
dsAuthorityConfidenceState
class="far fa-circle fa-2x fa-fw position-absolute mt-1 p-0"
aria-hidden="true"
[authorityValue]="currentValue"
(whenClickOnConfidenceNotAccepted)="whenClickOnConfidenceNotAccepted($event)">
</i>
}

<input #typeahead="ngbTypeahead"
class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[class.is-invalid]="showErrorMessages"
[id]="model.id"
[name]="model.name"
[ngbTypeahead]="search"
[placeholder]="model.placeholder"
[readonly]="model.readOnly"
[disabled]="model.readOnly"
[resultTemplate]="rt"
[type]="model.inputType"
[(ngModel)]="currentValue"
(blur)="onBlur($event)"
(focus)="onFocus($event)"
(change)="onChange($event)"
(input)="onInput($event)"
(selectItem)="onSelectItem($event)">

@if (searchFailed) {
<div class="invalid-feedback">Sorry, suggestions could not be loaded.</div>
}

@if ((isHierarchicalVocabulary() | async)) {
<div class="position-relative right-addon">
<i class="dropdown-toggle position-absolute tree-toggle" (click)="openTree($event)"
aria-hidden="true"></i>
<input class="form-control"
[attr.aria-labelledby]="'label_' + model.id"
[attr.autoComplete]="model.autoComplete"
[attr.aria-label]="model.label | translate"
[class.is-invalid]="showErrorMessages"
[class.tree-input]="!model.readOnly"
[id]="id"
[name]="model.name"
[placeholder]="model.placeholder"
[readonly]="true"
[disabled]="model.readOnly"
[type]="model.inputType"
[value]="currentValue?.display"
(focus)="onFocus($event)"
(change)="onChange($event)"
(click)="openTree($event)"
(keydown)="$event.preventDefault()"
(keypress)="$event.preventDefault()"
(keyup)="$event.preventDefault()">
</div>
}
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
mockDynamicFormLayoutService,
mockDynamicFormValidationService,
} from '@dspace/core/testing/dynamic-form-mock-services';
import { SearchServiceStub } from '@dspace/core/testing/search-service.stub';
import { createTestComponent } from '@dspace/core/testing/utils.test';
import { VocabularyServiceStub } from '@dspace/core/testing/vocabulary-service.stub';
import { createSuccessfulRemoteDataObject$ } from '@dspace/core/utilities/remote-data.utils';
Expand All @@ -44,6 +45,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { getTestScheduler } from 'jasmine-marbles';
import { of } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { SearchService } from 'src/app/shared/search/search.service';

import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
import { AuthorityConfidenceStateDirective } from '../../../../directives/authority-confidence-state.directive';
Expand Down Expand Up @@ -97,6 +99,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
let testFixture: ComponentFixture<TestComponent>;
let oneboxCompFixture: ComponentFixture<DsDynamicOneboxComponent>;
let vocabularyServiceStub: any;
let searchServiceStub: any;
let modalService: any;
let html;
let modal;
Expand Down Expand Up @@ -137,6 +140,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
// waitForAsync beforeEach
beforeEach(() => {
vocabularyServiceStub = new VocabularyServiceStub();
searchServiceStub = new SearchServiceStub();

modal = jasmine.createSpyObj('modal',
{
Expand Down Expand Up @@ -164,6 +168,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
ChangeDetectorRef,
DsDynamicOneboxComponent,
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: SearchService, useValue: searchServiceStub },
{ provide: DynamicFormLayoutService, useValue: mockDynamicFormLayoutService },
{ provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService },
{ provide: NgbModal, useValue: modal },
Expand Down Expand Up @@ -259,14 +264,14 @@ describe('DsDynamicOneboxComponent test suite', () => {

it('should emit blur Event onBlur when popup is closed', () => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
spyOn(oneboxComponent.typeahead, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});

it('should not emit blur Event onBlur when popup is opened', () => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(true);
spyOn(oneboxComponent.typeahead, 'isPopupOpen').and.returnValue(true);
const input = oneboxCompFixture.debugElement.query(By.css('input'));

input.nativeElement.blur();
Expand All @@ -278,7 +283,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
oneboxCompFixture.detectChanges();
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
spyOn(oneboxComponent.typeahead, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));
expect(oneboxComponent.change.emit).toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
Expand All @@ -291,7 +296,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
oneboxCompFixture.detectChanges();
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
spyOn(oneboxComponent.typeahead, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));
expect(oneboxComponent.change.emit).not.toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
Expand All @@ -304,7 +309,7 @@ describe('DsDynamicOneboxComponent test suite', () => {
oneboxCompFixture.detectChanges();
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
spyOn(oneboxComponent.typeahead, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));
expect(oneboxComponent.change.emit).not.toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
Expand Down
Loading
Loading