diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 615c2b3977..3c34e5ec35 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -162,6 +162,7 @@ import { UsageReport } from './statistics/models/usage-report.model';
import { RootDataService } from './data/root-data.service';
import { Root } from './data/root.model';
import { SearchConfig } from './shared/search/search-filters/search-config.model';
+import { SequenceService } from './shared/sequence.service';
/**
* When not in production, endpoint responses can be mocked for testing purposes
@@ -282,7 +283,8 @@ const PROVIDERS = [
FilteredDiscoveryPageResponseParsingService,
{ provide: NativeWindowService, useFactory: NativeWindowFactory },
VocabularyService,
- VocabularyTreeviewService
+ VocabularyTreeviewService,
+ SequenceService,
];
/**
diff --git a/src/app/core/shared/sequence.service.spec.ts b/src/app/core/shared/sequence.service.spec.ts
new file mode 100644
index 0000000000..e48ad3efcc
--- /dev/null
+++ b/src/app/core/shared/sequence.service.spec.ts
@@ -0,0 +1,22 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+import { SequenceService } from './sequence.service';
+
+let service: SequenceService;
+
+describe('SequenceService', () => {
+ beforeEach(() => {
+ service = new SequenceService();
+ });
+
+ it('should return sequential numbers on next(), starting with 1', () => {
+ const NUMBERS = [1,2,3,4,5];
+ const sequence = NUMBERS.map(() => service.next());
+ expect(sequence).toEqual(NUMBERS);
+ });
+});
diff --git a/src/app/core/shared/sequence.service.ts b/src/app/core/shared/sequence.service.ts
new file mode 100644
index 0000000000..2340ffb259
--- /dev/null
+++ b/src/app/core/shared/sequence.service.ts
@@ -0,0 +1,24 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+import { Injectable } from '@angular/core';
+
+@Injectable()
+/**
+ * Provides unique sequential numbers
+ */
+export class SequenceService {
+ private value: number;
+
+ constructor() {
+ this.value = 0;
+ }
+
+ public next(): number {
+ return ++this.value;
+ }
+}
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html
index e177b2b561..87a422e7db 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html
@@ -21,4 +21,4 @@
-
\ No newline at end of file
+
diff --git a/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html b/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html
index 7a9481f2f1..886c8f31c0 100644
--- a/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html
+++ b/src/app/shared/input-suggestions/filter-suggestions/filter-input-suggestions.component.html
@@ -3,13 +3,27 @@
(keydown.arrowdown)="shiftFocusDown($event)"
(keydown.arrowup)="shiftFocusUp($event)" (keydown.esc)="close()"
(dsClickOutside)="close();">
-
-
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/app/shared/input-suggestions/input-suggestions.component.ts b/src/app/shared/input-suggestions/input-suggestions.component.ts
index c48dcfb831..7b5c9f34f2 100644
--- a/src/app/shared/input-suggestions/input-suggestions.component.ts
+++ b/src/app/shared/input-suggestions/input-suggestions.component.ts
@@ -53,6 +53,11 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange
*/
@Input() valid = true;
+ /**
+ * Label for the input field. Used for screen readers.
+ */
+ @Input() label? = '';
+
/**
* Output for when the form is submitted
*/
diff --git a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html
index 5e6bcfaf8b..44aed494e3 100644
--- a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html
+++ b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html
@@ -8,15 +8,18 @@
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
index cf4876e34f..e2e57e7370 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
@@ -1,10 +1,13 @@
-
-
+
+
{{filterValue.count}}
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
index 4bcfc02966..d6cb7a3d79 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
@@ -1,8 +1,11 @@
+
diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-filter.component.html
index eb2105f4e7..230f072772 100644
--- a/src/app/shared/search/search-filters/search-filter/search-filter.component.html
+++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.html
@@ -1,17 +1,21 @@
-
-
+
+
+
+ class="search-filter-wrapper" [ngClass]="{ 'closed' : closed, 'notab': notab }">
diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.scss b/src/app/shared/search/search-filters/search-filter/search-filter.component.scss
index 518e7c9d5f..7e2631b55f 100644
--- a/src/app/shared/search/search-filters/search-filter/search-filter.component.scss
+++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.scss
@@ -1,10 +1,36 @@
:host .facet-filter {
- border: 1px solid var(--bs-light);
- cursor: pointer;
- .search-filter-wrapper.closed {
- overflow: hidden;
+ border: 1px solid var(--bs-light);
+ cursor: pointer;
+ line-height: 0;
+
+ .search-filter-wrapper {
+ line-height: var(--bs-line-height-base);
+ &.closed {
+ overflow: hidden;
}
- .filter-toggle {
- line-height: var(--bs-line-height-base);
+ &.notab {
+ visibility: hidden;
}
+ }
+
+ .filter-toggle {
+ line-height: var(--bs-line-height-base);
+ text-align: right;
+ position: relative;
+ top: -0.125rem; // Fix weird outline shape in Chrome
+ }
+
+ > button {
+ appearance: none;
+ border: 0;
+ padding: 0;
+ background: transparent;
+ width: 100%;
+ outline: none !important;
+ }
+
+ &.focus {
+ outline: none;
+ box-shadow: var(--bs-input-btn-focus-box-shadow);
+ }
}
diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts
index 228eef9a20..5e0077e11d 100644
--- a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts
@@ -12,6 +12,7 @@ import { SearchFilterConfig } from '../../search-filter-config.model';
import { FilterType } from '../../filter-type.model';
import { SearchConfigurationServiceStub } from '../../../testing/search-configuration-service.stub';
import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component';
+import { SequenceService } from '../../../../core/shared/sequence.service';
describe('SearchFilterComponent', () => {
let comp: SearchFilterComponent;
@@ -50,12 +51,15 @@ describe('SearchFilterComponent', () => {
};
let filterService;
+ let sequenceService;
const mockResults = observableOf(['test', 'data']);
const searchServiceStub = {
getFacetValuesFor: (filter) => mockResults
};
beforeEach(waitForAsync(() => {
+ sequenceService = jasmine.createSpyObj('sequenceService', { next: 17 });
+
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule],
declarations: [SearchFilterComponent],
@@ -65,7 +69,8 @@ describe('SearchFilterComponent', () => {
provide: SearchFilterService,
useValue: mockFilterService
},
- { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }
+ { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() },
+ { provide: SequenceService, useValue: sequenceService },
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(SearchFilterComponent, {
@@ -81,6 +86,12 @@ describe('SearchFilterComponent', () => {
filterService = (comp as any).filterService;
});
+ it('should generate unique IDs', () => {
+ expect(sequenceService.next).toHaveBeenCalled();
+ expect(comp.toggleId).toContain('17');
+ expect(comp.regionId).toContain('17');
+ });
+
describe('when the toggle method is triggered', () => {
beforeEach(() => {
spyOn(filterService, 'toggle');
diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts
index 31ace10a7d..0f7f763b45 100644
--- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts
@@ -10,6 +10,7 @@ import { isNotEmpty } from '../../../empty.util';
import { SearchService } from '../../../../core/shared/search/search.service';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component';
+import { SequenceService } from '../../../../core/shared/sequence.service';
@Component({
selector: 'ds-search-filter',
@@ -37,6 +38,16 @@ export class SearchFilterComponent implements OnInit {
*/
closed: boolean;
+ /**
+ * True when the filter controls should be hidden & removed from the tablist
+ */
+ notab: boolean;
+
+ /**
+ * True when the filter toggle button is focused
+ */
+ focusBox = false;
+
/**
* Emits true when the filter is currently collapsed in the store
*/
@@ -52,10 +63,15 @@ export class SearchFilterComponent implements OnInit {
*/
active$: Observable;
+ private readonly sequenceId: number;
+
constructor(
private filterService: SearchFilterService,
private searchService: SearchService,
- @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) {
+ @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService,
+ private sequenceService: SequenceService,
+ ) {
+ this.sequenceId = this.sequenceService.next();
}
/**
@@ -112,6 +128,9 @@ export class SearchFilterComponent implements OnInit {
if (event.fromState === 'collapsed') {
this.closed = false;
}
+ if (event.toState === 'collapsed') {
+ this.notab = true;
+ }
}
/**
@@ -122,6 +141,17 @@ export class SearchFilterComponent implements OnInit {
if (event.toState === 'collapsed') {
this.closed = true;
}
+ if (event.fromState === 'collapsed') {
+ this.notab = false;
+ }
+ }
+
+ get regionId(): string {
+ return `search-filter-region-${this.sequenceId}`;
+ }
+
+ get toggleId(): string {
+ return `search-filter-toggle-${this.sequenceId}`;
}
/**
diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
index 06b60b5ecd..49ca6fe3fd 100644
--- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
+++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
@@ -8,15 +8,18 @@