Skip to content
Open
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 @@ -51,7 +51,7 @@
[resultTemplate]="rt"
[type]="model.inputType"
[(ngModel)]="currentValue"
(blur)="onBlur($event)"
(blur)="onBlur($event, false)"
(focus)="onFocus($event)"
(change)="onChange($event)"
(input)="onInput($event)"
Expand Down Expand Up @@ -79,6 +79,7 @@
[disabled]="model.readOnly"
[type]="model.inputType"
[value]="currentValue?.display"
(blur)="onBlur($event, true)"
(focus)="onFocus($event)"
(change)="onChange($event)"
(click)="openTree($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function init() {
};
}

describe('DsDynamicOneboxComponent test suite', () => {
describe('DsDynamicOneboxComponent', () => {

let scheduler: TestScheduler;
let testComp: TestComponent;
Expand Down Expand Up @@ -262,7 +262,9 @@ 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);
oneboxComponent.onBlur(new Event('blur'));

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});

Expand All @@ -281,7 +283,9 @@ describe('DsDynamicOneboxComponent test suite', () => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.change.emit).toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});
Expand All @@ -294,7 +298,9 @@ describe('DsDynamicOneboxComponent test suite', () => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.change.emit).not.toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});
Expand All @@ -307,7 +313,9 @@ describe('DsDynamicOneboxComponent test suite', () => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent.change, 'emit');
spyOn(oneboxComponent.instance, 'isPopupOpen').and.returnValue(false);
oneboxComponent.onBlur(new Event('blur'));

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.change.emit).not.toHaveBeenCalled();
expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});
Expand Down Expand Up @@ -429,6 +437,29 @@ describe('DsDynamicOneboxComponent test suite', () => {
expect((oneboxComponent as any).modalService.open).toHaveBeenCalled();
done();
});

it('should emit the blur event when the popup is closed', () => {
spyOn(oneboxComponent.blur, 'emit');

oneboxComponent.vocabularyTreeOpen = false;
oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});

it('should not emit the blur event when the popup is open', fakeAsync(() => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent, 'onBlur').and.callThrough();

scheduler.schedule(() => oneboxComponent.openTree(new Event('click')));
scheduler.flush();
expect(oneboxComponent.vocabularyTreeOpen).toBeTrue();

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.onBlur).toHaveBeenCalled();
expect(oneboxComponent.blur.emit).not.toHaveBeenCalled();
}));
});

describe('when init model value is not empty', () => {
Expand Down Expand Up @@ -464,6 +495,28 @@ describe('DsDynamicOneboxComponent test suite', () => {
expect((oneboxComponent as any).modalService.open).toHaveBeenCalled();
done();
});

it('should emit the blur event when the popup is closed', () => {
spyOn(oneboxComponent.blur, 'emit');

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.blur.emit).toHaveBeenCalled();
});

it('should not emit the blur event when the popup is open', fakeAsync(() => {
spyOn(oneboxComponent.blur, 'emit');
spyOn(oneboxComponent, 'onBlur').and.callThrough();

scheduler.schedule(() => oneboxComponent.openTree(new Event('click')));
scheduler.flush();
expect(oneboxComponent.vocabularyTreeOpen).toBeTrue();

oneboxCompFixture.debugElement.query(By.css('input')).triggerEventHandler('blur', new Event('blur'));

expect(oneboxComponent.onBlur).toHaveBeenCalled();
expect(oneboxComponent.blur.emit).not.toHaveBeenCalled();
}));
});

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@
inputValue: any;
preloadLevel: number;

/**
* Whether the controlled vocabulary tree popup modal is open. We use this to know whether the loss of focus was
* caused by opening the modal or if it was caused by the user.
*/
vocabularyTreeOpen = false;

private vocabulary$: Observable<Vocabulary>;
private isHierarchicalVocabulary$: Observable<boolean>;
private subs: Subscription[] = [];
Expand Down Expand Up @@ -230,26 +236,33 @@
/**
* Emits a blur event containing a given value.
* @param event The value to emit.
* @param hierarchical Whether this event was emitted from a hierarchical vocabulary field
*/
onBlur(event: Event) {
if (!this.instance.isPopupOpen()) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.dispatchUpdate(this.inputValue);
}
this.inputValue = null;
onBlur(event: Event, hierarchical: boolean = false): void {
if (hierarchical) {
if (!this.vocabularyTreeOpen) {
super.onBlur(event);
}
this.blur.emit(event);
} else {
// prevent on blur propagation if typeahed suggestions are showed
event.preventDefault();
event.stopImmediatePropagation();
// update the value with the searched text if the user hasn't selected any suggestion
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.dispatchUpdate(this.inputValue);
if (!this.instance.isPopupOpen()) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.dispatchUpdate(this.inputValue);
}
this.inputValue = null;
}
super.onBlur(event);
} else {
// prevent on blur propagation if typeahed suggestions are showed
event.preventDefault();
event.stopImmediatePropagation();

Check warning on line 258 in src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts

View check run for this annotation

Codecov / codecov/patch

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

Added lines #L257 - L258 were not covered by tests
// update the value with the searched text if the user hasn't selected any suggestion
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.dispatchUpdate(this.inputValue);

Check warning on line 262 in src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L262 was not covered by tests
}
this.inputValue = null;

Check warning on line 264 in src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L264 was not covered by tests
}
this.inputValue = null;
}
}
}
Expand Down Expand Up @@ -290,6 +303,7 @@
take(1),
).subscribe((preloadLevel) => {
const modalRef: NgbModalRef = this.modalService.open(VocabularyTreeviewModalComponent, { size: 'lg', windowClass: 'treeview' });
this.vocabularyTreeOpen = true;
modalRef.componentInstance.vocabularyOptions = this.model.vocabularyOptions;
modalRef.componentInstance.preloadLevel = preloadLevel;
modalRef.componentInstance.selectedItems = this.currentValue ? [this.currentValue] : [];
Expand All @@ -298,8 +312,9 @@
this.currentValue = result;
this.dispatchUpdate(result);
}
this.vocabularyTreeOpen = false;
}, () => {
return;
this.vocabularyTreeOpen = false;

Check warning on line 317 in src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L317 was not covered by tests
});
}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ <h2 class="h4 text-center text-muted mt-4" >
container="body"
(click)="onSelect(node.item)"
role="button"
tabindex="0">
tabindex="0"
type="button">
<span>{{node.item.display}}</span>
</button>
}
Expand Down Expand Up @@ -118,22 +119,25 @@ <h2 class="h4 text-center text-muted mt-4" >
container="body"
(click)="onSelect(node.item)"
role="button"
tabindex="0">
tabindex="0"
type="button">
<span>{{node.item.display}}</span>
</button>
}
</cdk-tree-node>

<cdk-tree-node *cdkTreeNodeDef="let node; when: isLoadMore" cdkTreeNodePadding>
<button class="btn btn-outline-secondary btn-sm" (click)="loadMore(node.loadMoreParentItem)"
[attr.aria-label]="'vocabulary-treeview.load-more' | translate" role="button" tabindex="0">
[attr.aria-label]="'vocabulary-treeview.load-more' | translate"
role="button" tabindex="0" type="button">
{{'vocabulary-treeview.load-more' | translate}}...
</button>
</cdk-tree-node>

<cdk-tree-node *cdkTreeNodeDef="let node; when: isLoadMoreRoot">
<button class="btn btn-outline-secondary btn-sm" (click)="loadMoreRoot(node)"
[attr.aria-label]="'vocabulary-treeview.load-more' | translate" role="button" tabindex="0">
[attr.aria-label]="'vocabulary-treeview.load-more' | translate"
role="button" tabindex="0" type="button">
{{'vocabulary-treeview.load-more' | translate}}...
</button>
</cdk-tree-node>
Expand Down
Loading