mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-2328] filtering support for facets and categories (#3293)
* filtering support for facets and categories * fix tests * update variable names
This commit is contained in:
committed by
Eugenio Romano
parent
440c666583
commit
7afcd24488
@@ -176,7 +176,8 @@
|
|||||||
"APPLY": "Apply",
|
"APPLY": "Apply",
|
||||||
"CLEAR-ALL": "Clear all",
|
"CLEAR-ALL": "Clear all",
|
||||||
"SHOW-MORE": "Show more",
|
"SHOW-MORE": "Show more",
|
||||||
"SHOW-LESS": "Show less"
|
"SHOW-LESS": "Show less",
|
||||||
|
"FILTER-CATEGORY": "Filter category"
|
||||||
},
|
},
|
||||||
"RANGE": {
|
"RANGE": {
|
||||||
"FROM": "From",
|
"FROM": "From",
|
||||||
|
@@ -19,17 +19,25 @@ import { ResponseFacetQuery } from '../../../facet-query.interface';
|
|||||||
import { SearchFilterList } from './search-filter-list.model';
|
import { SearchFilterList } from './search-filter-list.model';
|
||||||
|
|
||||||
export class ResponseFacetQueryList extends SearchFilterList<ResponseFacetQuery> {
|
export class ResponseFacetQueryList extends SearchFilterList<ResponseFacetQuery> {
|
||||||
|
|
||||||
constructor(items: ResponseFacetQuery[] = [], pageSize: number = 5) {
|
constructor(items: ResponseFacetQuery[] = [], pageSize: number = 5) {
|
||||||
const filtered = items
|
super(
|
||||||
.filter(item => {
|
items
|
||||||
return item.count > 0;
|
.filter(item => {
|
||||||
})
|
return item.count > 0;
|
||||||
.map(item => {
|
})
|
||||||
return <ResponseFacetQuery> { ...item };
|
.map(item => {
|
||||||
});
|
return <ResponseFacetQuery> { ...item };
|
||||||
|
}),
|
||||||
|
pageSize
|
||||||
|
);
|
||||||
|
|
||||||
super(filtered, pageSize);
|
this.filter = (query: ResponseFacetQuery) => {
|
||||||
|
if (this.filterText && query.label) {
|
||||||
|
const pattern = (this.filterText || '').toLowerCase();
|
||||||
|
const label = query.label.toLowerCase();
|
||||||
|
return label.startsWith(pattern);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,200 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SearchFilterList } from './search-filter-list.model';
|
||||||
|
|
||||||
|
export class Payload {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(public id: number) {
|
||||||
|
this.name = `Payload_${id}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('SearchFilterList', () => {
|
||||||
|
|
||||||
|
function generateItems(count: number): Payload[] {
|
||||||
|
return Array(count).fill(null).map((_, id) => new Payload(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should init with external items', () => {
|
||||||
|
const items = [
|
||||||
|
new Payload(1),
|
||||||
|
new Payload(2)
|
||||||
|
];
|
||||||
|
const list = new SearchFilterList<Payload>(items);
|
||||||
|
|
||||||
|
expect(list.length).toBe(2);
|
||||||
|
expect(list.items[0]).toBe(items[0]);
|
||||||
|
expect(list.items[1]).toBe(items[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should init with default values', () => {
|
||||||
|
const list = new SearchFilterList();
|
||||||
|
|
||||||
|
expect(list.items).toEqual([]);
|
||||||
|
expect(list.pageSize).toEqual(5);
|
||||||
|
expect(list.currentPageSize).toEqual(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should init with custom page size', () => {
|
||||||
|
const list = new SearchFilterList([], 10);
|
||||||
|
|
||||||
|
expect(list.pageSize).toEqual(10);
|
||||||
|
expect(list.currentPageSize).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow showing more items', () => {
|
||||||
|
const items = generateItems(6);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
|
||||||
|
expect(list.canShowMoreItems).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should now allow showing more items', () => {
|
||||||
|
const items = generateItems(6);
|
||||||
|
const list = new SearchFilterList(items, 6);
|
||||||
|
|
||||||
|
expect(list.canShowMoreItems).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show second page', () => {
|
||||||
|
const items = generateItems(6);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
|
||||||
|
expect(list.canShowMoreItems).toBeTruthy();
|
||||||
|
expect(list.visibleItems.length).toBe(4);
|
||||||
|
|
||||||
|
list.showMoreItems();
|
||||||
|
expect(list.currentPageSize).toBe(8);
|
||||||
|
expect(list.canShowMoreItems).toBeFalsy();
|
||||||
|
expect(list.visibleItems.length).toBe(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect if content fits single page', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 5);
|
||||||
|
|
||||||
|
expect(list.fitsPage).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect if content exceeds single page', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
|
||||||
|
expect(list.fitsPage).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow showing less items', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
list.showMoreItems();
|
||||||
|
|
||||||
|
expect(list.canShowMoreItems).toBeFalsy();
|
||||||
|
expect(list.canShowLessItems).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow showing less items for single page', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 5);
|
||||||
|
|
||||||
|
expect(list.canShowLessItems).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear the collection', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 5);
|
||||||
|
list.clear();
|
||||||
|
|
||||||
|
expect(list.items.length).toBe(0);
|
||||||
|
expect(list.visibleItems.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset page settings on clear', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
list.showMoreItems();
|
||||||
|
|
||||||
|
expect(list.pageSize).toBe(4);
|
||||||
|
expect(list.currentPageSize).toBe(8);
|
||||||
|
|
||||||
|
list.clear();
|
||||||
|
expect(list.pageSize).toEqual(4);
|
||||||
|
expect(list.currentPageSize).toEqual(4);
|
||||||
|
expect(list.items.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return visible portion of the page 1', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
const list = new SearchFilterList(items, 4);
|
||||||
|
|
||||||
|
expect(list.length).toBe(5);
|
||||||
|
expect(list.visibleItems.length).toBe(4);
|
||||||
|
|
||||||
|
expect(list.visibleItems[0].id).toBe(0);
|
||||||
|
expect(list.visibleItems[1].id).toBe(1);
|
||||||
|
expect(list.visibleItems[2].id).toBe(2);
|
||||||
|
expect(list.visibleItems[3].id).toBe(3);
|
||||||
|
|
||||||
|
expect(list.items[4].id).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom filter', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
items[0].name = 'custom';
|
||||||
|
|
||||||
|
const list = new SearchFilterList(items, 5);
|
||||||
|
expect(list.visibleItems.length).toBe(5);
|
||||||
|
|
||||||
|
list.filter = (item: Payload): boolean => {
|
||||||
|
return item.name === 'custom';
|
||||||
|
};
|
||||||
|
expect(list.visibleItems.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update filtered items on filter text change', () => {
|
||||||
|
const items = generateItems(5);
|
||||||
|
items[0].name = 'custom';
|
||||||
|
|
||||||
|
const list = new SearchFilterList(items, 5);
|
||||||
|
expect(list.visibleItems.length).toBe(5);
|
||||||
|
|
||||||
|
list.filter = (item: Payload): boolean => {
|
||||||
|
if (list.filterText) {
|
||||||
|
return item.name.startsWith(list.filterText);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
expect(list.visibleItems.length).toBe(5);
|
||||||
|
|
||||||
|
list.filterText = 'cus';
|
||||||
|
expect(list.visibleItems.length).toBe(1);
|
||||||
|
expect(list.visibleItems[0].name).toEqual('custom');
|
||||||
|
|
||||||
|
list.filterText = 'P';
|
||||||
|
expect(list.visibleItems.length).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset filter text on clear', () => {
|
||||||
|
const list = new SearchFilterList([], 5);
|
||||||
|
list.filterText = 'test';
|
||||||
|
list.clear();
|
||||||
|
|
||||||
|
expect(list.filterText).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@@ -16,51 +16,95 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export class SearchFilterList<T> implements Iterable<T> {
|
export class SearchFilterList<T> implements Iterable<T> {
|
||||||
|
|
||||||
|
private filteredItems: T[] = [];
|
||||||
|
private _filterText: string = '';
|
||||||
|
|
||||||
items: T[] = [];
|
items: T[] = [];
|
||||||
pageSize: number = 5;
|
pageSize: number = 5;
|
||||||
currentPageSize: number = 5;
|
currentPageSize: number = 5;
|
||||||
|
|
||||||
get visibleItems(): T[] {
|
get filterText(): string {
|
||||||
return this.items.slice(0, this.currentPageSize);
|
return this._filterText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set filterText(value: string) {
|
||||||
|
this._filterText = value;
|
||||||
|
this.applyFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filter: (item: T) => boolean = () => true;
|
||||||
|
|
||||||
|
get filter(): (item: T) => boolean {
|
||||||
|
return this._filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
set filter(value: (item: T) => boolean ) {
|
||||||
|
this._filter = value;
|
||||||
|
this.applyFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyFilter() {
|
||||||
|
if (this.filter) {
|
||||||
|
this.filteredItems = this.items.filter(this.filter);
|
||||||
|
} else {
|
||||||
|
this.filteredItems = this.items;
|
||||||
|
}
|
||||||
|
this.currentPageSize = this.pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns visible portion of the items. */
|
||||||
|
get visibleItems(): T[] {
|
||||||
|
return this.filteredItems.slice(0, this.currentPageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns entire collection length including items not displayed on the page. */
|
||||||
get length(): number {
|
get length(): number {
|
||||||
return this.items.length;
|
return this.items.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Detects whether more items can be displayed. */
|
||||||
get canShowMoreItems(): boolean {
|
get canShowMoreItems(): boolean {
|
||||||
return this.items.length > this.currentPageSize;
|
return this.filteredItems.length > this.currentPageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Detects whether less items can be displayed. */
|
||||||
get canShowLessItems(): boolean {
|
get canShowLessItems(): boolean {
|
||||||
return this.currentPageSize > this.pageSize;
|
return this.currentPageSize > this.pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Detects whether content fits single page. */
|
||||||
get fitsPage(): boolean {
|
get fitsPage(): boolean {
|
||||||
return this.pageSize > this.items.length;
|
return this.pageSize >= this.filteredItems.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(items: T[] = [], pageSize: number = 5) {
|
constructor(items: T[] = [], pageSize: number = 5) {
|
||||||
this.items = items;
|
this.items = items;
|
||||||
|
this.filteredItems = items;
|
||||||
this.pageSize = pageSize;
|
this.pageSize = pageSize;
|
||||||
this.currentPageSize = pageSize;
|
this.currentPageSize = pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Display more items. */
|
||||||
showMoreItems() {
|
showMoreItems() {
|
||||||
if (this.canShowMoreItems) {
|
if (this.canShowMoreItems) {
|
||||||
this.currentPageSize += this.pageSize;
|
this.currentPageSize += this.pageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Display less items. */
|
||||||
showLessItems() {
|
showLessItems() {
|
||||||
if (this.canShowLessItems) {
|
if (this.canShowLessItems) {
|
||||||
this.currentPageSize -= this.pageSize;
|
this.currentPageSize -= this.pageSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Reset entire collection and page settings. */
|
||||||
clear() {
|
clear() {
|
||||||
this.currentPageSize = this.pageSize;
|
this.currentPageSize = this.pageSize;
|
||||||
this.items = [];
|
this.items = [];
|
||||||
|
this.filteredItems = [];
|
||||||
|
this.filterText = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
[Symbol.iterator](): Iterator<T> {
|
[Symbol.iterator](): Iterator<T> {
|
||||||
|
@@ -21,12 +21,23 @@
|
|||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title>{{ facetQueriesLabel | translate }}</mat-panel-title>
|
<mat-panel-title>{{ facetQueriesLabel | translate }}</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
|
<mat-form-field class="facet-result-filter">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder="{{ 'SEARCH.FILTER.ACTIONS.FILTER-CATEGORY' | translate }}"
|
||||||
|
[(ngModel)]="responseFacetQueries.filterText">
|
||||||
|
<button *ngIf="responseFacetQueries.filterText"
|
||||||
|
mat-button matSuffix mat-icon-button
|
||||||
|
(click)="responseFacetQueries.filterText = ''">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-form-field>
|
||||||
<div class="checklist">
|
<div class="checklist">
|
||||||
<ng-container *ngFor="let query of responseFacetQueries">
|
<ng-container *ngFor="let query of responseFacetQueries">
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
[checked]="query.$checked"
|
[checked]="query.$checked"
|
||||||
(change)="onFacetQueryToggle($event, query)">
|
(change)="onFacetQueryToggle($event, query)">
|
||||||
{{ query.label | translate }} ({{ query.count }})
|
{{ query.label }} ({{ query.count }})
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,14 +63,27 @@
|
|||||||
(opened)="onFacetFieldExpanded(field)"
|
(opened)="onFacetFieldExpanded(field)"
|
||||||
(closed)="onFacetFieldCollapsed(field)">
|
(closed)="onFacetFieldCollapsed(field)">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title>{{ field.label | translate }}</mat-panel-title>
|
<mat-panel-title>{{ field.label }}</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<mat-form-field class="facet-result-filter">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder="{{ 'SEARCH.FILTER.ACTIONS.FILTER-CATEGORY' | translate }}"
|
||||||
|
[(ngModel)]="field.buckets.filterText">
|
||||||
|
<button *ngIf="field.buckets.filterText"
|
||||||
|
mat-button matSuffix mat-icon-button
|
||||||
|
(click)="field.buckets.filterText = ''">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<div class="checklist">
|
<div class="checklist">
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
*ngFor="let bucket of field.buckets"
|
*ngFor="let bucket of field.buckets"
|
||||||
[checked]="bucket.$checked"
|
[checked]="bucket.$checked"
|
||||||
(change)="onFacetToggle($event, field, bucket)">
|
(change)="onFacetToggle($event, field, bucket)">
|
||||||
{{ (bucket.display || bucket.label) | translate }} ({{ bucket.count }})
|
{{ bucket.display || bucket.label }} ({{ bucket.count }})
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -7,6 +7,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.facet-result-filter {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
input > {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.facet-buttons {
|
.facet-buttons {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
import { SearchFilterComponent } from './search-filter.component';
|
import { SearchFilterComponent } from './search-filter.component';
|
||||||
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
||||||
import { SearchConfiguration } from '../../search-configuration.interface';
|
import { SearchConfiguration } from '../../search-configuration.interface';
|
||||||
import { AppConfigService } from '@alfresco/adf-core';
|
import { AppConfigService, TranslationMock } from '@alfresco/adf-core';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
import { ResponseFacetQueryList } from './models/response-facet-query-list.model';
|
import { ResponseFacetQueryList } from './models/response-facet-query-list.model';
|
||||||
|
|
||||||
@@ -36,7 +36,8 @@ describe('SearchSettingsComponent', () => {
|
|||||||
const searchMock: any = {
|
const searchMock: any = {
|
||||||
dataLoaded: new Subject()
|
dataLoaded: new Subject()
|
||||||
};
|
};
|
||||||
component = new SearchFilterComponent(queryBuilder, searchMock);
|
const translationMock = new TranslationMock();
|
||||||
|
component = new SearchFilterComponent(queryBuilder, searchMock, translationMock);
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,6 +119,7 @@ describe('SearchSettingsComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should unselect facet query and update builder', () => {
|
it('should unselect facet query and update builder', () => {
|
||||||
|
const translationMock = new TranslationMock();
|
||||||
const config: SearchConfiguration = {
|
const config: SearchConfiguration = {
|
||||||
categories: [],
|
categories: [],
|
||||||
facetQueries: {
|
facetQueries: {
|
||||||
@@ -128,7 +130,7 @@ describe('SearchSettingsComponent', () => {
|
|||||||
};
|
};
|
||||||
appConfig.config.search = config;
|
appConfig.config.search = config;
|
||||||
queryBuilder = new SearchQueryBuilderService(appConfig, null);
|
queryBuilder = new SearchQueryBuilderService(appConfig, null);
|
||||||
component = new SearchFilterComponent(queryBuilder, null);
|
component = new SearchFilterComponent(queryBuilder, null, translationMock);
|
||||||
|
|
||||||
spyOn(queryBuilder, 'update').and.stub();
|
spyOn(queryBuilder, 'update').and.stub();
|
||||||
queryBuilder.filterQueries = [{ query: 'query1' }];
|
queryBuilder.filterQueries = [{ query: 'query1' }];
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||||
import { MatCheckboxChange } from '@angular/material';
|
import { MatCheckboxChange } from '@angular/material';
|
||||||
import { SearchService } from '@alfresco/adf-core';
|
import { SearchService, TranslationService } from '@alfresco/adf-core';
|
||||||
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
||||||
import { ResponseFacetField } from '../../response-facet-field.interface';
|
import { ResponseFacetField } from '../../response-facet-field.interface';
|
||||||
import { FacetFieldBucket } from '../../facet-field-bucket.interface';
|
import { FacetFieldBucket } from '../../facet-field-bucket.interface';
|
||||||
@@ -44,7 +44,9 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
facetQueriesPageSize = 5;
|
facetQueriesPageSize = 5;
|
||||||
facetQueriesExpanded = false;
|
facetQueriesExpanded = false;
|
||||||
|
|
||||||
constructor(public queryBuilder: SearchQueryBuilderService, private search: SearchService) {
|
constructor(public queryBuilder: SearchQueryBuilderService,
|
||||||
|
private searchService: SearchService,
|
||||||
|
private translationService: TranslationService) {
|
||||||
this.responseFacetQueries = new ResponseFacetQueryList();
|
this.responseFacetQueries = new ResponseFacetQueryList();
|
||||||
|
|
||||||
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
if (queryBuilder.config && queryBuilder.config.facetQueries) {
|
||||||
@@ -62,7 +64,7 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
if (this.queryBuilder) {
|
if (this.queryBuilder) {
|
||||||
this.queryBuilder.executed.subscribe(data => {
|
this.queryBuilder.executed.subscribe(data => {
|
||||||
this.onDataLoaded(data);
|
this.onDataLoaded(data);
|
||||||
this.search.dataLoaded.next(data);
|
this.searchService.dataLoaded.next(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
query.$checked = false;
|
query.$checked = false;
|
||||||
this.selectedFacetQueries = this.selectedFacetQueries.filter(q => q !== query.label);
|
this.selectedFacetQueries = this.selectedFacetQueries.filter(selectedQuery => selectedQuery !== query.label);
|
||||||
|
|
||||||
if (facetQuery) {
|
if (facetQuery) {
|
||||||
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
||||||
@@ -127,7 +129,7 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
|
|
||||||
unselectFacetQuery(label: string) {
|
unselectFacetQuery(label: string) {
|
||||||
const facetQuery = this.queryBuilder.getFacetQuery(label);
|
const facetQuery = this.queryBuilder.getFacetQuery(label);
|
||||||
this.selectedFacetQueries = this.selectedFacetQueries.filter(q => q !== label);
|
this.selectedFacetQueries = this.selectedFacetQueries.filter(selectedQuery => selectedQuery !== label);
|
||||||
|
|
||||||
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
this.queryBuilder.removeFilterQuery(facetQuery.query);
|
||||||
this.queryBuilder.update();
|
this.queryBuilder.update();
|
||||||
@@ -136,7 +138,7 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
unselectFacetBucket(bucket: FacetFieldBucket) {
|
unselectFacetBucket(bucket: FacetFieldBucket) {
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
const idx = this.selectedBuckets.findIndex(
|
const idx = this.selectedBuckets.findIndex(
|
||||||
b => b.$field === bucket.$field && b.label === bucket.label
|
selectedBucket => selectedBucket.$field === bucket.$field && selectedBucket.label === bucket.label
|
||||||
);
|
);
|
||||||
|
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
@@ -151,17 +153,19 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
const context = data.list.context;
|
const context = data.list.context;
|
||||||
|
|
||||||
if (context) {
|
if (context) {
|
||||||
const facetQueries = (context.facetQueries || []).map(q => {
|
const facetQueries = (context.facetQueries || []).map(query => {
|
||||||
q.$checked = this.selectedFacetQueries.includes(q.label);
|
query.label = this.translationService.instant(query.label);
|
||||||
return q;
|
query.$checked = this.selectedFacetQueries.includes(query.label);
|
||||||
|
return query;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.responseFacetQueries = new ResponseFacetQueryList(facetQueries, this.facetQueriesPageSize);
|
this.responseFacetQueries = new ResponseFacetQueryList(facetQueries, this.facetQueriesPageSize);
|
||||||
|
|
||||||
const expandedFields = this.responseFacetFields.filter(f => f.expanded).map(f => f.label);
|
const expandedFields = this.responseFacetFields.filter(field => field.expanded).map(field => field.label);
|
||||||
|
|
||||||
this.responseFacetFields = (context.facetsFields || []).map(
|
this.responseFacetFields = (context.facetsFields || []).map(
|
||||||
field => {
|
field => {
|
||||||
|
field.label = this.translationService.instant(field.label);
|
||||||
field.pageSize = field.pageSize || 5;
|
field.pageSize = field.pageSize || 5;
|
||||||
field.currentPageSize = field.pageSize;
|
field.currentPageSize = field.pageSize;
|
||||||
field.expanded = expandedFields.includes(field.label);
|
field.expanded = expandedFields.includes(field.label);
|
||||||
@@ -169,16 +173,29 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
const buckets = (field.buckets || []).map(bucket => {
|
const buckets = (field.buckets || []).map(bucket => {
|
||||||
bucket.$field = field.label;
|
bucket.$field = field.label;
|
||||||
bucket.$checked = false;
|
bucket.$checked = false;
|
||||||
|
bucket.display = this.translationService.instant(bucket.display);
|
||||||
|
bucket.label = this.translationService.instant(bucket.label);
|
||||||
|
|
||||||
const previousBucket = this.selectedBuckets.find(
|
const previousBucket = this.selectedBuckets.find(
|
||||||
b => b.$field === bucket.$field && b.label === bucket.label
|
selectedBucket => selectedBucket.$field === bucket.$field && selectedBucket.label === bucket.label
|
||||||
);
|
);
|
||||||
if (previousBucket) {
|
if (previousBucket) {
|
||||||
bucket.$checked = true;
|
bucket.$checked = true;
|
||||||
}
|
}
|
||||||
return bucket;
|
return bucket;
|
||||||
});
|
});
|
||||||
field.buckets = new SearchFilterList<FacetFieldBucket>(buckets, field.pageSize);
|
|
||||||
|
const bucketList = new SearchFilterList<FacetFieldBucket>(buckets, field.pageSize);
|
||||||
|
bucketList.filter = (bucket: FacetFieldBucket): boolean => {
|
||||||
|
if (bucket && bucketList.filterText) {
|
||||||
|
const pattern = (bucketList.filterText || '').toLowerCase();
|
||||||
|
const label = (bucket.display || bucket.label || '').toLowerCase();
|
||||||
|
return label.startsWith(pattern);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
field.buckets = bucketList;
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -105,4 +105,10 @@ describe('TranslationService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return empty string for missing key when getting instant translations', () => {
|
||||||
|
expect(translationService.instant(null)).toEqual('');
|
||||||
|
expect(translationService.instant('')).toEqual('');
|
||||||
|
expect(translationService.instant(undefined)).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -128,6 +128,6 @@ export class TranslationService {
|
|||||||
* @returns Translated text
|
* @returns Translated text
|
||||||
*/
|
*/
|
||||||
instant(key: string | Array<string>, interpolateParams?: Object): string | any {
|
instant(key: string | Array<string>, interpolateParams?: Object): string | any {
|
||||||
return this.translate.instant(key, interpolateParams);
|
return key ? this.translate.instant(key, interpolateParams) : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user