From 3a33e02083647ea20e85cf30717d533a068b59c1 Mon Sep 17 00:00:00 2001
From: Ryan Mathis
Date: Tue, 3 Dec 2019 13:00:02 -0700
Subject: [PATCH 1/2] SHIBUI-1663 Fixed issue with announcing list items
---
.../autocomplete/autocomplete.component.html | 25 +++++++++++++------
.../autocomplete/autocomplete.component.ts | 12 +++++++--
.../shared/autocomplete/autocomplete.model.ts | 6 ++---
3 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/ui/src/app/shared/autocomplete/autocomplete.component.html b/ui/src/app/shared/autocomplete/autocomplete.component.html
index 735b3bc48..558dcb454 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.component.html
+++ b/ui/src/app/shared/autocomplete/autocomplete.component.html
@@ -6,32 +6,38 @@
[id]="fieldId"
class="form-control"
autocomplete="off"
+ autocorrect="off"
+ aria-autocomplete="list"
role="combobox"
type="text"
[placeholder]="placeholder"
[attr.aria-activedescendant]="activeDescendant"
- aria-autocomplete="both"
[attr.aria-owns]="fieldId + '__listbox'"
[attr.aria-expanded]="(menuIsVisible$ | async) ? 'true' : 'false'"
+ [attr.aria-haspopup]="fieldId + '__listbox'"
(focus)="handleInputFocus()"
(blur)="handleInputBlur()"
/>
-
+
+
diff --git a/ui/src/app/shared/autocomplete/autocomplete.component.ts b/ui/src/app/shared/autocomplete/autocomplete.component.ts
index 28a4c0365..472db6dd5 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.component.ts
+++ b/ui/src/app/shared/autocomplete/autocomplete.component.ts
@@ -153,6 +153,12 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
});
}
+ handleDropdown($event: MouseEvent | KeyboardEvent | Event): void {
+ const open = this.state.currentState.menuOpen;
+ this.state.setState({menuOpen: !open});
+ this.handleOptionFocus(0);
+ }
+
handleViewMore($event: MouseEvent | KeyboardEvent | Event): void {
$event.preventDefault();
$event.stopPropagation();
@@ -235,6 +241,8 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
focused: index,
selected: index
});
+
+ console.log(this.activeDescendant);
}
handleOptionClick(index: number): void {
const selectedOption = this.matches[index];
@@ -278,7 +286,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
}
handleDownArrow(event: KeyboardEvent): void {
- event.preventDefault();
let isNotAtBottom = this.state.currentState.selected !== this.matches.length - 1;
if (this.showMoreAvailable) {
isNotAtBottom = this.state.currentState.selected !== this.matches.length;
@@ -287,6 +294,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
if (allowMoveDown) {
this.handleOptionFocus(this.state.currentState.selected + 1);
}
+ event.preventDefault();
}
handleSpace(event: KeyboardEvent): void {
@@ -344,7 +352,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
}
getOptionId(index): string {
- return `${this.fieldId}__option--${index}`;
+ return `${this.fieldId}__option--${index}`.replace('/', '');
}
get hasAutoselect(): boolean {
diff --git a/ui/src/app/shared/autocomplete/autocomplete.model.ts b/ui/src/app/shared/autocomplete/autocomplete.model.ts
index 8e96dae05..83c003d91 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.model.ts
+++ b/ui/src/app/shared/autocomplete/autocomplete.model.ts
@@ -9,9 +9,9 @@ export const defaultState: AutoCompleteState = {
};
export interface AutoCompleteState {
- focused: number | null;
- selected: number | null;
- hovered: number | null;
+ focused: number;
+ selected: number;
+ hovered: number;
menuOpen: boolean;
}
From 0a29a2136a5d368bf1dd411634031280e191983e Mon Sep 17 00:00:00 2001
From: Ryan Mathis
Date: Wed, 4 Dec 2019 10:07:23 -0700
Subject: [PATCH 2/2] SHIBUI-1663 fixed live announcement
---
.../filter-target.component.html | 3 +-
.../filter-target/filter-target.component.ts | 28 ++++++++-----------
.../autocomplete/autocomplete.component.html | 3 +-
.../autocomplete/autocomplete.component.ts | 14 ++++------
.../shared/autocomplete/autocomplete.model.ts | 6 ++--
5 files changed, 24 insertions(+), 30 deletions(-)
diff --git a/ui/src/app/schema-form/widget/filter-target/filter-target.component.html b/ui/src/app/schema-form/widget/filter-target/filter-target.component.html
index 059d0acdd..005ae6e37 100644
--- a/ui/src/app/schema-form/widget/filter-target/filter-target.component.html
+++ b/ui/src/app/schema-form/widget/filter-target/filter-target.component.html
@@ -52,7 +52,8 @@
class="component-control"
limit="10"
[formControl]="search"
- [matches]="ids"
+ [matches]="ids$ | async"
+ [count]="idCount$ | async"
(keydown.enter)="onSelectValue(search.value)">
diff --git a/ui/src/app/schema-form/widget/filter-target/filter-target.component.ts b/ui/src/app/schema-form/widget/filter-target/filter-target.component.ts
index 835e2f005..7eed2fca9 100644
--- a/ui/src/app/schema-form/widget/filter-target/filter-target.component.ts
+++ b/ui/src/app/schema-form/widget/filter-target/filter-target.component.ts
@@ -3,7 +3,7 @@ import { FormControl, Validators, AbstractControl, ValidatorFn } from '@angular/
import { ObjectWidget } from 'ngx-schema-form';
import { Store } from '@ngrx/store';
import { Observable, Subject } from 'rxjs';
-import { distinctUntilChanged, skipWhile, takeUntil, map } from 'rxjs/operators';
+import { distinctUntilChanged, skipWhile, takeUntil, map, withLatestFrom, filter, switchMap, startWith } from 'rxjs/operators';
import * as fromRoot from '../../../app.reducer';
import * as fromFilters from '../../../metadata/filter/reducer';
@@ -19,7 +19,7 @@ import { QueryEntityIds, ClearSearch } from '../../../metadata/filter/action/sea
export class FilterTargetComponent extends ObjectWidget implements OnDestroy, AfterViewInit {
private ngUnsubscribe: Subject = new Subject();
ids$: Observable;
- ids: string[];
+ idCount$: Observable;
search: FormControl = new FormControl(
'',
@@ -40,17 +40,22 @@ export class FilterTargetComponent extends ObjectWidget implements OnDestroy, Af
) {
super();
this.ids$ = this.store.select(fromFilters.getEntityCollection);
- this.ids$.subscribe(ids => {
- this.ids = [...ids];
- });
+
+ this.idCount$ = this.ids$.pipe(map(list => list.length));
this.search
.valueChanges
.pipe(
takeUntil(this.ngUnsubscribe),
- distinctUntilChanged()
+ distinctUntilChanged(),
+ withLatestFrom(this.ids$),
+ filter(([term, ids]) => term && term.length >= 4 && ids.indexOf(term) < 0),
+ map(([term]) => new QueryEntityIds({
+ term,
+ limit: 10
+ }))
)
- .subscribe(query => this.searchEntityIds(query));
+ .subscribe(action => this.store.dispatch(action));
this.script
.valueChanges
@@ -101,15 +106,6 @@ export class FilterTargetComponent extends ObjectWidget implements OnDestroy, Af
};
}
- searchEntityIds(term: string): void {
- if (term && term.length >= 4 && this.ids.indexOf(term) < 0) {
- this.store.dispatch(new QueryEntityIds({
- term,
- limit: 10
- }));
- }
- }
-
getButtonConfig(id: string): any {
let buttons = this.formProperty.getProperty('value').schema.buttons;
return (buttons || []).map(btn => ({
diff --git a/ui/src/app/shared/autocomplete/autocomplete.component.html b/ui/src/app/shared/autocomplete/autocomplete.component.html
index 2611cfc28..7800382cd 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.component.html
+++ b/ui/src/app/shared/autocomplete/autocomplete.component.html
@@ -54,8 +54,7 @@
[attr.aria-label]="this.input.value"
[innerHTML]="option | highlight:this.input.value">
-
{{ noneFoundText }}
diff --git a/ui/src/app/shared/autocomplete/autocomplete.component.ts b/ui/src/app/shared/autocomplete/autocomplete.component.ts
index 80e360114..cda5d6406 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.component.ts
+++ b/ui/src/app/shared/autocomplete/autocomplete.component.ts
@@ -51,6 +51,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
@Input() processing = false;
@Input() dropdown = false;
@Input() placeholder = '';
+ @Input() count = null;
@Output() more: EventEmitter = new EventEmitter();
@Output() onChange: EventEmitter = new EventEmitter();
@@ -118,14 +119,16 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
}
ngOnChanges(changes: SimpleChanges): void {
- if (changes.matches && this.matches) {
+ if (changes.matches && this.matches && this.state.currentState.menuOpen) {
this.announceResults();
}
}
announceResults(): void {
const count = this.matches.length;
- this.live.announce(count === 0 ? 'No results available' : `${count} result${count === 1 ? '' : 's'} available`);
+ this.live.announce(count === 0 ?
+ `${this.noneFoundText}` :
+ `${count} result${count === 1 ? '' : 's'} available`, 'polite', 5000);
}
writeValue(value: any): void {
@@ -222,7 +225,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
handleInputChange(query: string): void {
query = query || '';
-
const queryEmpty = query.length === 0;
const autoselect = this.hasAutoselect;
const optionsAvailable = this.matches.length > 0;
@@ -233,8 +235,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
selected: searchForOptions ? ((autoselect && optionsAvailable) ? 0 : -1) : null
});
this.propagateChange(query);
-
- setTimeout(() => this.announceResults(), 250);
}
handleInputFocus(): void {
@@ -247,8 +247,6 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
focused: index,
selected: index
});
-
- console.log(this.activeDescendant);
}
handleOptionClick(index: number): void {
const selectedOption = this.matches[index];
@@ -357,7 +355,7 @@ export class AutoCompleteComponent implements OnInit, OnDestroy, OnChanges, Afte
return !!(agent.match(/(iPod|iPhone|iPad)/g) && agent.match(/AppleWebKit/g));
}
- getOptionId(index): string {
+ getOptionId(index: string | number): string {
return `${this.fieldId}__option--${index}`.replace('/', '');
}
diff --git a/ui/src/app/shared/autocomplete/autocomplete.model.ts b/ui/src/app/shared/autocomplete/autocomplete.model.ts
index 83c003d91..8e96dae05 100644
--- a/ui/src/app/shared/autocomplete/autocomplete.model.ts
+++ b/ui/src/app/shared/autocomplete/autocomplete.model.ts
@@ -9,9 +9,9 @@ export const defaultState: AutoCompleteState = {
};
export interface AutoCompleteState {
- focused: number;
- selected: number;
- hovered: number;
+ focused: number | null;
+ selected: number | null;
+ hovered: number | null;
menuOpen: boolean;
}