From e7054af1d55df52e8d912d42490c27cc0bdd6fce Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 28 Feb 2018 14:05:28 +0100 Subject: [PATCH 1/9] 49440: date widget with decorator --- package.json | 2 + ...search-facet-filter-wrapper.component.html | 1 + .../search-facet-filter-wrapper.component.ts | 36 +++++++++++++ .../search-facet-filter.component.ts | 13 ++--- .../search-filter-type-decorator.ts | 17 +++++++ .../search-filter.component.html | 2 +- .../search-range-filter.component.html | 21 ++++++++ .../search-range-filter.component.scss} | 0 .../search-range-filter.component.ts | 33 ++++++++++++ .../search-text-filter.component.html} | 0 .../search-text-filter.component.scss | 18 +++++++ .../search-text-filter.component.spec.ts} | 0 .../search-text-filter.component.ts | 51 +++++++++++++++++++ src/app/+search-page/search-page.module.ts | 10 +++- src/app/app.component.scss | 1 + src/app/shared/shared.module.ts | 5 +- yarn.lock | 8 +++ 17 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-filter-type-decorator.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html rename src/app/+search-page/search-filters/search-filter/{search-facet-filter/search-facet-filter.component.scss => search-range-filter/search-range-filter.component.scss} (100%) create mode 100644 src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts rename src/app/+search-page/search-filters/search-filter/{search-facet-filter/search-facet-filter.component.html => search-text-filter/search-text-filter.component.html} (100%) create mode 100644 src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss rename src/app/+search-page/search-filters/search-filter/{search-facet-filter/search-facet-filter.component.spec.ts => search-text-filter/search-text-filter.component.spec.ts} (100%) create mode 100644 src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts diff --git a/package.json b/package.json index ab875fd95e..c4194bf6f1 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,9 @@ "jsonschema": "1.2.2", "methods": "1.1.2", "morgan": "1.9.0", + "ng2-nouislider": "^1.7.7", "ngx-pagination": "3.0.3", + "nouislider": "^10.0.0", "pem": "1.12.3", "reflect-metadata": "0.1.12", "rxjs": "5.5.6", diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html new file mode 100644 index 0000000000..b7e03af473 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html @@ -0,0 +1 @@ + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts new file mode 100644 index 0000000000..1f8d4f1d52 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -0,0 +1,36 @@ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { renderFilterType } from '../search-filter-type-decorator'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; + +@Component({ + selector: 'ds-search-facet-filter-wrapper', + templateUrl: './search-facet-filter-wrapper.component.html' +}) +export class SearchFacetFilterWrapperComponent implements OnInit { + @Input() filterValues: FacetValue[]; + @Input() filterConfig: SearchFilterConfig; + @Input() selectedValues: string[]; + objectInjector: Injector; + + constructor(private injector: Injector) { + } + + ngOnInit(): void { + this.objectInjector = Injector.create({ + providers: [ + { provide: 'filterValues', useFactory: () => (this.filterValues), deps: [] }, + { provide: 'filterConfig', useFactory: () => (this.filterConfig), deps: [] }, + { provide: 'selectedValues', useFactory: () => (this.selectedValues), deps: [] }], + + parent: this.injector + }); + + } + + getSearchFilter(): string { + const type: FilterType = this.filterConfig.type; + return renderFilterType(type); + } +} diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index bf78bbe5ec..f4fa54c752 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { FacetValue } from '../../../search-service/facet-value.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { Router } from '@angular/router'; @@ -20,13 +20,10 @@ import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'ds-search-facet-filter', - styleUrls: ['./search-facet-filter.component.scss'], - templateUrl: './search-facet-filter.component.html' + template: ``, }) export class SearchFacetFilterComponent implements OnInit, OnDestroy { - @Input() filterConfig: SearchFilterConfig; - @Input() selectedValues: string[]; filterValues: Array>>> = []; filterValues$: BehaviorSubject = new BehaviorSubject(this.filterValues); currentPage: Observable; @@ -35,7 +32,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { pageChange = false; sub: Subscription; - constructor(private searchService: SearchService, private filterService: SearchFilterService, private router: Router) { + constructor(private searchService: SearchService, + private filterService: SearchFilterService, + private router: Router, + @Inject('filterConfig') public filterConfig: SearchFilterConfig, + @Inject('selectedValues') public selectedValues: string[]) { } ngOnInit(): void { diff --git a/src/app/+search-page/search-filters/search-filter/search-filter-type-decorator.ts b/src/app/+search-page/search-filters/search-filter/search-filter-type-decorator.ts new file mode 100644 index 0000000000..3169709466 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-filter-type-decorator.ts @@ -0,0 +1,17 @@ + +import { FilterType } from '../../search-service/filter-type.model'; + +const filterTypeMap = new Map(); + +export function renderFacetFor(type: FilterType) { + return function decorator(objectElement: any) { + if (!objectElement) { + return; + } + filterTypeMap.set(type, objectElement); + }; +} + +export function renderFilterType(type: FilterType) { + return filterTypeMap.get(type); +} diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html index 6cf9df9b05..9b5e312e6c 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html @@ -2,6 +2,6 @@
{{'search.filters.filter.' + filter.name + '.head'| translate}}
- +
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html new file mode 100644 index 0000000000..ee6ff2994c --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -0,0 +1,21 @@ +
+
+
+ + + +
+ + + + {{value}} + +
+
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss similarity index 100% rename from src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.scss rename to src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts new file mode 100644 index 0000000000..9bd7a93ca0 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -0,0 +1,33 @@ +import { Component } from '@angular/core'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { renderFacetFor } from '../search-filter-type-decorator'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; + +/** + * This component renders a simple item page. + * The route parameter 'id' is used to request the item it represents. + * All fields of the item that should be displayed, are defined in its template. + */ + +@Component({ + selector: 'ds-search-range-filter', + styleUrls: ['./search-range-filter.component.scss'], + templateUrl: './search-range-filter.component.html', +}) + +@renderFacetFor(FilterType.range) +export class SearchRangeFilterComponent extends SearchFacetFilterComponent { + min = 1950; + max = 1960; + rangeMin = 1900; // calculate using available values + rangeMax = 2000; + + get range() { + return [this.min, this.max]; + } + + set range(value: number[]) { + this.min = value[0]; + this.max = value[1]; + } +} diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html similarity index 100% rename from src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.html rename to src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss new file mode 100644 index 0000000000..595b2aefb8 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss @@ -0,0 +1,18 @@ +@import '../../../../../styles/variables.scss'; +@import '../../../../../styles/mixins.scss'; + +.filters { + margin-top: $spacer/2; + margin-bottom: $spacer/2; + a { + color: $body-color; + &:hover { + text-decoration: none; + } + } + .toggle-more-filters a { + color: $link-color; + text-decoration: underline; + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts similarity index 100% rename from src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts rename to src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts new file mode 100644 index 0000000000..ba355654e9 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { Observable } from 'rxjs/Observable'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { renderFacetFor } from '../search-filter-type-decorator'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; + +/** + * This component renders a simple item page. + * The route parameter 'id' is used to request the item it represents. + * All fields of the item that should be displayed, are defined in its template. + */ + +@Component({ + selector: 'ds-search-text-filter', + styleUrls: ['./search-text-filter.component.scss'], + templateUrl: './search-text-filter.component.html', +}) + +@renderFacetFor(FilterType.text) +export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit { + currentPage: Observable; + + ngOnInit(): void { + this.currentPage = this.filterService.getPage(this.filterConfig.name); + } + + isChecked(value: FacetValue): Observable { + return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, value.value); + } + + get facetCount(): Observable { + const resultCount = this.filterValues.length; + return this.currentPage.map((page: number) => { + const max = page * this.filterConfig.pageSize; + return max > resultCount ? resultCount : max; + }); + } + + showMore() { + this.filterService.incrementPage(this.filterConfig.name); + } + + showFirstPageOnly() { + this.filterService.resetPage(this.filterConfig.name); + } + + getCurrentPage(): Observable { + return this.filterService.getPage(this.filterConfig.name); + } +} diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 7c2001c909..3533a3e598 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -20,6 +20,9 @@ import { SearchFiltersComponent } from './search-filters/search-filters.componen import { SearchFilterComponent } from './search-filters/search-filter/search-filter.component'; import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-filter.component'; import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; +import { SearchDateFilterComponent } from './search-filters/search-filter/search-date-filter/search-date-filter.component'; +import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component'; +import { SearchFacetFilterWrapperComponent } from './search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component'; const effects = [ SearchSidebarEffects @@ -46,7 +49,10 @@ const effects = [ CommunitySearchResultListElementComponent, SearchFiltersComponent, SearchFilterComponent, - SearchFacetFilterComponent + SearchFacetFilterComponent, + SearchFacetFilterWrapperComponent, + SearchDateFilterComponent, + SearchTextFilterComponent, ], providers: [ SearchService, @@ -60,6 +66,8 @@ const effects = [ ItemSearchResultGridElementComponent, CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, + SearchDateFilterComponent, + SearchTextFilterComponent, ] }) export class SearchPageModule { diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 00a3e56121..e4c51ae37b 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,5 +1,6 @@ @import '../styles/variables.scss'; @import '../../node_modules/bootstrap/scss/bootstrap.scss'; +@import '../../node_modules/nouislider/distribute/nouislider.min.css'; @import "../../node_modules/font-awesome/scss/font-awesome.scss"; html { diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index c78c218fa9..ba877fcdd7 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - +import { NouisliderModule } from 'ng2-nouislider'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; @@ -54,7 +54,8 @@ const MODULES = [ NgxPaginationModule, ReactiveFormsModule, RouterModule, - TranslateModule + TranslateModule, + NouisliderModule ]; const PIPES = [ diff --git a/yarn.lock b/yarn.lock index e6e0aedf55..44d4dd54d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5581,6 +5581,10 @@ netmask@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" +ng2-nouislider@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.7.7.tgz#b841f4b313c8c9c8a763c80f3a59d5aa4c3a70c8" + ngrx-store-freeze@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ngrx-store-freeze/-/ngrx-store-freeze-0.2.1.tgz#04fb29db33cafda0f2d6ea32adeaac4891b1b27b" @@ -5800,6 +5804,10 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" +nouislider@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/nouislider/-/nouislider-10.1.0.tgz#7bdd0411fd62d4584bfe88cb92bb8d06e64c6b47" + npm-run-all@4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.2.tgz#90d62d078792d20669139e718621186656cea056" From fb8172af103bf9e4c60a15067ddfae2a32877679 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 1 Mar 2018 09:03:06 +0100 Subject: [PATCH 2/9] 49440: fixed naming bug --- src/app/+search-page/search-page.module.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 3533a3e598..d7a31b0aa0 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -20,7 +20,7 @@ import { SearchFiltersComponent } from './search-filters/search-filters.componen import { SearchFilterComponent } from './search-filters/search-filter/search-filter.component'; import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-filter.component'; import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; -import { SearchDateFilterComponent } from './search-filters/search-filter/search-date-filter/search-date-filter.component'; +import { SearchRangeFilterComponent } from './search-filters/search-filter/search-range-filter/search-range-filter.component'; import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component'; import { SearchFacetFilterWrapperComponent } from './search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component'; @@ -51,7 +51,7 @@ const effects = [ SearchFilterComponent, SearchFacetFilterComponent, SearchFacetFilterWrapperComponent, - SearchDateFilterComponent, + SearchRangeFilterComponent, SearchTextFilterComponent, ], providers: [ @@ -66,7 +66,7 @@ const effects = [ ItemSearchResultGridElementComponent, CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, - SearchDateFilterComponent, + SearchRangeFilterComponent, SearchTextFilterComponent, ] }) From 563cc019cfb1d4ea87ec6c7c166161adfd254622 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 26 Apr 2018 12:51:32 +0200 Subject: [PATCH 3/9] intermediate commit --- .../search-facet-filter-wrapper.component.ts | 3 -- .../search-facet-filter.component.ts | 6 +-- .../search-range-filter.component.html | 46 +++++++++++++------ .../search-text-filter.component.ts | 26 ----------- .../search-service/filter-type.model.ts | 8 ++-- 5 files changed, 40 insertions(+), 49 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index 1f8d4f1d52..1134d58bf0 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -1,7 +1,6 @@ import { Component, Injector, Input, OnInit } from '@angular/core'; import { renderFilterType } from '../search-filter-type-decorator'; import { FilterType } from '../../../search-service/filter-type.model'; -import { FacetValue } from '../../../search-service/facet-value.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; @Component({ @@ -9,7 +8,6 @@ import { SearchFilterConfig } from '../../../search-service/search-filter-config templateUrl: './search-facet-filter-wrapper.component.html' }) export class SearchFacetFilterWrapperComponent implements OnInit { - @Input() filterValues: FacetValue[]; @Input() filterConfig: SearchFilterConfig; @Input() selectedValues: string[]; objectInjector: Injector; @@ -20,7 +18,6 @@ export class SearchFacetFilterWrapperComponent implements OnInit { ngOnInit(): void { this.objectInjector = Injector.create({ providers: [ - { provide: 'filterValues', useFactory: () => (this.filterValues), deps: [] }, { provide: 'filterConfig', useFactory: () => (this.filterConfig), deps: [] }, { provide: 'selectedValues', useFactory: () => (this.selectedValues), deps: [] }], diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index f4fa54c752..8b48a1db39 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -32,9 +32,9 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { pageChange = false; sub: Subscription; - constructor(private searchService: SearchService, - private filterService: SearchFilterService, - private router: Router, + constructor(protected searchService: SearchService, + protected filterService: SearchFilterService, + protected router: Router, @Inject('filterConfig') public filterConfig: SearchFilterConfig, @Inject('selectedValues') public selectedValues: string[]) { } diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index ee6ff2994c..9fc58c98ba 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -2,20 +2,40 @@
- - +
+ +
+
+ +
- - - - {{value}} - + + + + + + + + + + + + {{value.value}} + + {{value.count}} + + + +
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts index ba355654e9..a0aa59471f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts @@ -21,31 +21,5 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet- export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit { currentPage: Observable; - ngOnInit(): void { - this.currentPage = this.filterService.getPage(this.filterConfig.name); - } - isChecked(value: FacetValue): Observable { - return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, value.value); - } - - get facetCount(): Observable { - const resultCount = this.filterValues.length; - return this.currentPage.map((page: number) => { - const max = page * this.filterConfig.pageSize; - return max > resultCount ? resultCount : max; - }); - } - - showMore() { - this.filterService.incrementPage(this.filterConfig.name); - } - - showFirstPageOnly() { - this.filterService.resetPage(this.filterConfig.name); - } - - getCurrentPage(): Observable { - return this.filterService.getPage(this.filterConfig.name); - } } diff --git a/src/app/+search-page/search-service/filter-type.model.ts b/src/app/+search-page/search-service/filter-type.model.ts index 354ca87f98..3c2966a778 100644 --- a/src/app/+search-page/search-service/filter-type.model.ts +++ b/src/app/+search-page/search-service/filter-type.model.ts @@ -1,6 +1,6 @@ export enum FilterType { - text, - date, - hierarchical, - standard + text = 'text', + range = 'date', + hierarchy = 'hierarchical', + boolean = 'standard' } From 307d9bf854a4935696afb40f587d3f942769ed85 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 2 May 2018 15:31:17 +0200 Subject: [PATCH 4/9] intermediate commit --- .../search-boolean-filter.component.html | 38 +++ .../search-boolean-filter.component.scss | 18 ++ .../search-boolean-filter.component.spec.ts | 242 ++++++++++++++++++ .../search-boolean-filter.component.ts | 22 ++ .../search-facet-filter-wrapper.component.ts | 20 +- .../search-facet-filter.component.ts | 6 +- .../search-filter.component.html | 2 +- .../search-filter/search-filter.service.ts | 5 +- .../search-hierarchy-filter.component.html | 38 +++ .../search-hierarchy-filter.component.scss | 18 ++ .../search-hierarchy-filter.component.spec.ts | 242 ++++++++++++++++++ .../search-hierarchy-filter.component.ts | 25 ++ .../search-range-filter.component.html | 4 +- .../search-range-filter.component.ts | 20 ++ .../search-text-filter.component.ts | 2 - src/app/+search-page/search-page.module.ts | 6 + 16 files changed, 691 insertions(+), 17 deletions(-) create mode 100644 src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss create mode 100644 src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss create mode 100644 src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html new file mode 100644 index 0000000000..074c5700d7 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html @@ -0,0 +1,38 @@ + diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss new file mode 100644 index 0000000000..595b2aefb8 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss @@ -0,0 +1,18 @@ +@import '../../../../../styles/variables.scss'; +@import '../../../../../styles/mixins.scss'; + +.filters { + margin-top: $spacer/2; + margin-bottom: $spacer/2; + a { + color: $body-color; + &:hover { + text-decoration: none; + } + } + .toggle-more-filters a { + color: $link-color; + text-decoration: underline; + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts new file mode 100644 index 0000000000..03b760318f --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts @@ -0,0 +1,242 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { SearchFacetFilterComponent } from './search-facet-filter.component'; +import { SearchFilterService } from '../search-filter.service'; +import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { FormsModule } from '@angular/forms'; +import { Observable } from 'rxjs/Observable'; +import { SearchService } from '../../../search-service/search.service'; +import { SearchServiceStub } from '../../../../shared/testing/search-service-stub'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { SearchOptions } from '../../../search-options.model'; +import { RouterStub } from '../../../../shared/testing/router-stub'; +import { Router } from '@angular/router'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { PageInfo } from '../../../../core/shared/page-info.model'; + +describe('SearchFacetFilterComponent', () => { + let comp: SearchFacetFilterComponent; + let fixture: ComponentFixture; + const filterName1 = 'test name'; + const value1 = 'testvalue1'; + const value2 = 'test2'; + const value3 = 'another value3'; + const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { + name: filterName1, + type: FilterType.text, + hasFacets: false, + isOpenByDefault: false, + pageSize: 2 + }); + const values: FacetValue[] = [ + { + value: value1, + count: 52, + search: '' + }, { + value: value2, + count: 20, + search: '' + }, { + value: value3, + count: 5, + search: '' + } + ]; + + const searchLink = '/search'; + const selectedValues = [value1, value2]; + let filterService; + let searchService; + let router; + const page = Observable.of(0); + + const mockValues = Observable.of(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values))); + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], + declarations: [SearchFacetFilterComponent], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, + { provide: Router, useValue: new RouterStub() }, + { + provide: SearchFilterService, useValue: { + isFilterActiveWithValue: (paramName: string, filterValue: string) => true, + getPage: (paramName: string) => page, + /* tslint:disable:no-empty */ + incrementPage: (filterName: string) => { + }, + resetPage: (filterName: string) => { + }, + getSearchOptions: () => Observable.of({}), + /* tslint:enable:no-empty */ + } + } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(SearchFacetFilterComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchFacetFilterComponent); + comp = fixture.componentInstance; // SearchPageComponent test instance + comp.filterConfig = mockFilterConfig; + comp.filterValues = [mockValues]; + comp.filterValues$ = new BehaviorSubject(comp.filterValues); + comp.selectedValues = selectedValues; + filterService = (comp as any).filterService; + searchService = (comp as any).searchService; + spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); + router = (comp as any).router; + fixture.detectChanges(); + }); + + describe('when the isChecked method is called with a value', () => { + beforeEach(() => { + spyOn(filterService, 'isFilterActiveWithValue'); + comp.isChecked(values[1]); + }); + + it('should call isFilterActiveWithValue on the filterService with the correct filter parameter name and the passed value', () => { + expect(filterService.isFilterActiveWithValue).toHaveBeenCalledWith(mockFilterConfig.paramName, values[1].value) + }); + }); + + describe('when the getSearchLink method is triggered', () => { + let link: string; + beforeEach(() => { + link = comp.getSearchLink(); + }); + + it('should return the value of the searchLink variable in the filter service', () => { + expect(link).toEqual(searchLink); + }); + }); + + describe('when the getAddParams method is called wih a value', () => { + it('should return the selectedValue list with the new parameter value', () => { + const result = comp.getAddParams(value3); + expect(result[mockFilterConfig.paramName]).toEqual([value1, value2, value3]); + }); + }); + + describe('when the getRemoveParams method is called wih a value', () => { + it('should return the selectedValue list with the parameter value left out', () => { + const result = comp.getRemoveParams(value1); + expect(result[mockFilterConfig.paramName]).toEqual([value2]); + }); + }); + + describe('when the showMore method is called', () => { + beforeEach(() => { + spyOn(filterService, 'incrementPage'); + comp.showMore(); + }); + + it('should call incrementPage on the filterService with the correct filter parameter name', () => { + expect(filterService.incrementPage).toHaveBeenCalledWith(mockFilterConfig.name) + }); + }); + + describe('when the showFirstPageOnly method is called', () => { + beforeEach(() => { + spyOn(filterService, 'resetPage'); + comp.showFirstPageOnly(); + }); + + it('should call resetPage on the filterService with the correct filter parameter name', () => { + expect(filterService.resetPage).toHaveBeenCalledWith(mockFilterConfig.name); + }); + }); + + describe('when the getCurrentPage method is called', () => { + beforeEach(() => { + spyOn(filterService, 'getPage'); + comp.getCurrentPage(); + }); + + it('should call getPage on the filterService with the correct filter parameter name', () => { + expect(filterService.getPage).toHaveBeenCalledWith(mockFilterConfig.name) + }); + }); + + describe('when the getCurrentUrl method is called', () => { + const url = 'test.url/test' + beforeEach(() => { + router.navigateByUrl(url); + }); + + it('should call getPage on the filterService with the correct filter parameter name', () => { + expect(router.url).toEqual(url); + }); + }); + + describe('when the onSubmit method is called with data', () => { + const searchUrl = '/search/path'; + const testValue = 'test'; + const data = { [mockFilterConfig.paramName]: testValue }; + beforeEach(() => { + spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); + comp.onSubmit(data); + }); + + it('should call navigate on the router with the right searchlink and parameters', () => { + expect(router.navigate).toHaveBeenCalledWith([searchUrl], { + queryParams: { [mockFilterConfig.paramName]: [...selectedValues, testValue] }, + queryParamsHandling: 'merge' + }); + }); + }); + + describe('when updateFilterValueList is called', () => { + const cPage = 10; + const searchOptions = new SearchOptions(); + beforeEach(() => { + // spyOn(searchService, 'getFacetValuesFor'); Already spied upon + comp.currentPage = Observable.of(cPage); + comp.updateFilterValueList(searchOptions); + }); + + it('should call getFacetValuesFor on the searchService with the correct parameters', () => { + expect(searchService.getFacetValuesFor).toHaveBeenCalledWith(mockFilterConfig, cPage, searchOptions); + }); + }); + + describe('when updateFilterValueList is called and pageChange is set to true', () => { + const searchOptions = new SearchOptions(); + beforeEach(() => { + comp.pageChange = true; + spyOn(comp, 'showFirstPageOnly'); + comp.updateFilterValueList(searchOptions); + }); + + it('should not call showFirstPageOnly on the component', () => { + expect(comp.showFirstPageOnly).not.toHaveBeenCalled(); + }); + + it('should set pageChange to false', () => { + expect(comp.pageChange).toBeFalsy(); + }); + }); + + describe('when updateFilterValueList is called and pageChange is set to false', () => { + const searchOptions = new SearchOptions(); + beforeEach(() => { + comp.pageChange = false; + spyOn(comp, 'showFirstPageOnly'); + comp.updateFilterValueList(searchOptions); + }); + + it('should call showFirstPageOnly on the component', () => { + expect(comp.showFirstPageOnly).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts new file mode 100644 index 0000000000..c80e7ce86a --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { renderFacetFor } from '../search-filter-type-decorator'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; + +/** + * This component renders a simple item page. + * The route parameter 'id' is used to request the item it represents. + * All fields of the item that should be displayed, are defined in its template. + */ + +@Component({ + selector: 'ds-search-boolean-filter', + styleUrls: ['./search-boolean-filter.component.scss'], + templateUrl: './search-boolean-filter.component.html', +}) + +@renderFacetFor(FilterType.boolean) +export class SearchBooleanFilterComponent extends SearchFacetFilterComponent implements OnInit { + currentPage: Observable; +} diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index 1134d58bf0..bac4a49d79 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -1,7 +1,10 @@ -import { Component, Injector, Input, OnInit } from '@angular/core'; +import { Component, InjectionToken, Injector, Input, OnInit } from '@angular/core'; import { renderFilterType } from '../search-filter-type-decorator'; import { FilterType } from '../../../search-service/filter-type.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; +import { GlobalConfig } from '../../../../../config/global-config.interface'; +import { FILTER_CONFIG, SELECTED_VALUES } from '../search-filter.service'; +import { Observable } from 'rxjs/Observable'; @Component({ selector: 'ds-search-facet-filter-wrapper', @@ -9,21 +12,22 @@ import { SearchFilterConfig } from '../../../search-service/search-filter-config }) export class SearchFacetFilterWrapperComponent implements OnInit { @Input() filterConfig: SearchFilterConfig; - @Input() selectedValues: string[]; + @Input() selectedValues: Observable; objectInjector: Injector; constructor(private injector: Injector) { } ngOnInit(): void { - this.objectInjector = Injector.create({ - providers: [ - { provide: 'filterConfig', useFactory: () => (this.filterConfig), deps: [] }, - { provide: 'selectedValues', useFactory: () => (this.selectedValues), deps: [] }], + this.selectedValues.subscribe((values) => { + this.objectInjector = Injector.create({ + providers: [ + { provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] }, + { provide: SELECTED_VALUES, useFactory: () => (values), deps: [] }], - parent: this.injector + parent: this.injector + }); }); - } getSearchFilter(): string { diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index dae4219309..4c7a7fd2d5 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -3,7 +3,7 @@ import { FacetValue } from '../../../search-service/facet-value.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { Router } from '@angular/router'; import { Observable } from 'rxjs/Observable'; -import { SearchFilterService } from '../search-filter.service'; +import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; import { hasNoValue, hasValue, isNotEmpty } from '../../../../shared/empty.util'; import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; @@ -35,8 +35,8 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { constructor(protected searchService: SearchService, protected filterService: SearchFilterService, protected router: Router, - @Inject('filterConfig') public filterConfig: SearchFilterConfig, - @Inject('selectedValues') public selectedValues: string[]) { + @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, + @Inject(SELECTED_VALUES) public selectedValues: string[]) { } ngOnInit(): void { diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html index 9b5e312e6c..857b03a38f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html @@ -2,6 +2,6 @@
{{'search.filters.filter.' + filter.name + '.head'| translate}}
- +
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts index cbe6d79dfc..0a612fa0f0 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, InjectionToken } from '@angular/core'; import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; import { SearchFiltersState, SearchFilterState } from './search-filter.reducer'; import { createSelector, MemoizedSelector, Store } from '@ngrx/store'; @@ -23,6 +23,9 @@ import { PaginatedSearchOptions } from '../../paginated-search-options.model'; const filterStateSelector = (state: SearchFiltersState) => state.searchFilter; +export const FILTER_CONFIG: InjectionToken = new InjectionToken('filterConfig'); +export const SELECTED_VALUES: InjectionToken = new InjectionToken('selectedValues'); + @Injectable() export class SearchFilterService { diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html new file mode 100644 index 0000000000..074c5700d7 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html @@ -0,0 +1,38 @@ + diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss new file mode 100644 index 0000000000..595b2aefb8 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss @@ -0,0 +1,18 @@ +@import '../../../../../styles/variables.scss'; +@import '../../../../../styles/mixins.scss'; + +.filters { + margin-top: $spacer/2; + margin-bottom: $spacer/2; + a { + color: $body-color; + &:hover { + text-decoration: none; + } + } + .toggle-more-filters a { + color: $link-color; + text-decoration: underline; + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts new file mode 100644 index 0000000000..03b760318f --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts @@ -0,0 +1,242 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { SearchFacetFilterComponent } from './search-facet-filter.component'; +import { SearchFilterService } from '../search-filter.service'; +import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { FormsModule } from '@angular/forms'; +import { Observable } from 'rxjs/Observable'; +import { SearchService } from '../../../search-service/search.service'; +import { SearchServiceStub } from '../../../../shared/testing/search-service-stub'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { SearchOptions } from '../../../search-options.model'; +import { RouterStub } from '../../../../shared/testing/router-stub'; +import { Router } from '@angular/router'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { PageInfo } from '../../../../core/shared/page-info.model'; + +describe('SearchFacetFilterComponent', () => { + let comp: SearchFacetFilterComponent; + let fixture: ComponentFixture; + const filterName1 = 'test name'; + const value1 = 'testvalue1'; + const value2 = 'test2'; + const value3 = 'another value3'; + const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { + name: filterName1, + type: FilterType.text, + hasFacets: false, + isOpenByDefault: false, + pageSize: 2 + }); + const values: FacetValue[] = [ + { + value: value1, + count: 52, + search: '' + }, { + value: value2, + count: 20, + search: '' + }, { + value: value3, + count: 5, + search: '' + } + ]; + + const searchLink = '/search'; + const selectedValues = [value1, value2]; + let filterService; + let searchService; + let router; + const page = Observable.of(0); + + const mockValues = Observable.of(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values))); + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], + declarations: [SearchFacetFilterComponent], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, + { provide: Router, useValue: new RouterStub() }, + { + provide: SearchFilterService, useValue: { + isFilterActiveWithValue: (paramName: string, filterValue: string) => true, + getPage: (paramName: string) => page, + /* tslint:disable:no-empty */ + incrementPage: (filterName: string) => { + }, + resetPage: (filterName: string) => { + }, + getSearchOptions: () => Observable.of({}), + /* tslint:enable:no-empty */ + } + } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(SearchFacetFilterComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchFacetFilterComponent); + comp = fixture.componentInstance; // SearchPageComponent test instance + comp.filterConfig = mockFilterConfig; + comp.filterValues = [mockValues]; + comp.filterValues$ = new BehaviorSubject(comp.filterValues); + comp.selectedValues = selectedValues; + filterService = (comp as any).filterService; + searchService = (comp as any).searchService; + spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); + router = (comp as any).router; + fixture.detectChanges(); + }); + + describe('when the isChecked method is called with a value', () => { + beforeEach(() => { + spyOn(filterService, 'isFilterActiveWithValue'); + comp.isChecked(values[1]); + }); + + it('should call isFilterActiveWithValue on the filterService with the correct filter parameter name and the passed value', () => { + expect(filterService.isFilterActiveWithValue).toHaveBeenCalledWith(mockFilterConfig.paramName, values[1].value) + }); + }); + + describe('when the getSearchLink method is triggered', () => { + let link: string; + beforeEach(() => { + link = comp.getSearchLink(); + }); + + it('should return the value of the searchLink variable in the filter service', () => { + expect(link).toEqual(searchLink); + }); + }); + + describe('when the getAddParams method is called wih a value', () => { + it('should return the selectedValue list with the new parameter value', () => { + const result = comp.getAddParams(value3); + expect(result[mockFilterConfig.paramName]).toEqual([value1, value2, value3]); + }); + }); + + describe('when the getRemoveParams method is called wih a value', () => { + it('should return the selectedValue list with the parameter value left out', () => { + const result = comp.getRemoveParams(value1); + expect(result[mockFilterConfig.paramName]).toEqual([value2]); + }); + }); + + describe('when the showMore method is called', () => { + beforeEach(() => { + spyOn(filterService, 'incrementPage'); + comp.showMore(); + }); + + it('should call incrementPage on the filterService with the correct filter parameter name', () => { + expect(filterService.incrementPage).toHaveBeenCalledWith(mockFilterConfig.name) + }); + }); + + describe('when the showFirstPageOnly method is called', () => { + beforeEach(() => { + spyOn(filterService, 'resetPage'); + comp.showFirstPageOnly(); + }); + + it('should call resetPage on the filterService with the correct filter parameter name', () => { + expect(filterService.resetPage).toHaveBeenCalledWith(mockFilterConfig.name); + }); + }); + + describe('when the getCurrentPage method is called', () => { + beforeEach(() => { + spyOn(filterService, 'getPage'); + comp.getCurrentPage(); + }); + + it('should call getPage on the filterService with the correct filter parameter name', () => { + expect(filterService.getPage).toHaveBeenCalledWith(mockFilterConfig.name) + }); + }); + + describe('when the getCurrentUrl method is called', () => { + const url = 'test.url/test' + beforeEach(() => { + router.navigateByUrl(url); + }); + + it('should call getPage on the filterService with the correct filter parameter name', () => { + expect(router.url).toEqual(url); + }); + }); + + describe('when the onSubmit method is called with data', () => { + const searchUrl = '/search/path'; + const testValue = 'test'; + const data = { [mockFilterConfig.paramName]: testValue }; + beforeEach(() => { + spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); + comp.onSubmit(data); + }); + + it('should call navigate on the router with the right searchlink and parameters', () => { + expect(router.navigate).toHaveBeenCalledWith([searchUrl], { + queryParams: { [mockFilterConfig.paramName]: [...selectedValues, testValue] }, + queryParamsHandling: 'merge' + }); + }); + }); + + describe('when updateFilterValueList is called', () => { + const cPage = 10; + const searchOptions = new SearchOptions(); + beforeEach(() => { + // spyOn(searchService, 'getFacetValuesFor'); Already spied upon + comp.currentPage = Observable.of(cPage); + comp.updateFilterValueList(searchOptions); + }); + + it('should call getFacetValuesFor on the searchService with the correct parameters', () => { + expect(searchService.getFacetValuesFor).toHaveBeenCalledWith(mockFilterConfig, cPage, searchOptions); + }); + }); + + describe('when updateFilterValueList is called and pageChange is set to true', () => { + const searchOptions = new SearchOptions(); + beforeEach(() => { + comp.pageChange = true; + spyOn(comp, 'showFirstPageOnly'); + comp.updateFilterValueList(searchOptions); + }); + + it('should not call showFirstPageOnly on the component', () => { + expect(comp.showFirstPageOnly).not.toHaveBeenCalled(); + }); + + it('should set pageChange to false', () => { + expect(comp.pageChange).toBeFalsy(); + }); + }); + + describe('when updateFilterValueList is called and pageChange is set to false', () => { + const searchOptions = new SearchOptions(); + beforeEach(() => { + comp.pageChange = false; + spyOn(comp, 'showFirstPageOnly'); + comp.updateFilterValueList(searchOptions); + }); + + it('should call showFirstPageOnly on the component', () => { + expect(comp.showFirstPageOnly).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts new file mode 100644 index 0000000000..23ac40fde1 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { Observable } from 'rxjs/Observable'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { renderFacetFor } from '../search-filter-type-decorator'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; + +/** + * This component renders a simple item page. + * The route parameter 'id' is used to request the item it represents. + * All fields of the item that should be displayed, are defined in its template. + */ + +@Component({ + selector: 'ds-search-hierarchy-filter', + styleUrls: ['./search-hierarchy-filter.component.scss'], + templateUrl: './search-hierarchy-filter.component.html', +}) + +@renderFacetFor(FilterType.hierarchy) +export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent implements OnInit { + currentPage: Observable; + + +} diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 9fc58c98ba..961e144c52 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -3,13 +3,13 @@
-
- diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 9bd7a93ca0..ceff8213c0 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -17,6 +17,7 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet- @renderFacetFor(FilterType.range) export class SearchRangeFilterComponent extends SearchFacetFilterComponent { + rangeDelimiter = '-'; min = 1950; max = 1960; rangeMin = 1900; // calculate using available values @@ -30,4 +31,23 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent { this.min = value[0]; this.max = value[1]; } + + getAddParams(value: string) { + const parts = value.split(this.rangeDelimiter); + const min = parts.length > 1 ? parts[0].trim() : value; + const max = parts.length > 1 ? parts[1].trim() : value; + return { + [this.filterConfig.paramName + '.min']: [min], + [this.filterConfig.paramName + '.max']: [max], + page: 1 + }; + } + + getRemoveParams(value: string) { + return { + [this.filterConfig.paramName + '.min']: null, + [this.filterConfig.paramName + '.max']: null, + page: 1 + }; + } } diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts index a0aa59471f..9d61696612 100644 --- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.ts @@ -20,6 +20,4 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet- @renderFacetFor(FilterType.text) export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit { currentPage: Observable; - - } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index da555b34af..4b28689910 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -24,6 +24,8 @@ import { SearchFilterService } from './search-filters/search-filter/search-filte import { SearchRangeFilterComponent } from './search-filters/search-filter/search-range-filter/search-range-filter.component'; import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component'; import { SearchFacetFilterWrapperComponent } from './search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component'; +import { SearchBooleanFilterComponent } from './search-filters/search-filter/search-boolean-filter/search-boolean-filter.component'; +import { SearchHierarchyFilterComponent } from './search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component'; const effects = [ SearchSidebarEffects @@ -55,6 +57,8 @@ const effects = [ SearchFacetFilterWrapperComponent, SearchRangeFilterComponent, SearchTextFilterComponent, + SearchHierarchyFilterComponent, + SearchBooleanFilterComponent, ], providers: [ SearchService, @@ -70,6 +74,8 @@ const effects = [ CommunitySearchResultGridElementComponent, SearchRangeFilterComponent, SearchTextFilterComponent, + SearchHierarchyFilterComponent, + SearchBooleanFilterComponent, ] }) export class SearchPageModule { From e1c407841c968435226c5bfb7573c0c5886f9108 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 2 May 2018 16:20:07 +0200 Subject: [PATCH 5/9] 49440: date widget progress --- .../search-range-filter.component.html | 13 ++++-------- .../search-range-filter.component.ts | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 961e144c52..ae51f3bcb1 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -3,13 +3,13 @@
-
- @@ -18,14 +18,9 @@ - - - - - - + - + diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index ceff8213c0..9cf763099c 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -1,7 +1,8 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FilterType } from '../../../search-service/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; +import { isNotEmpty } from '../../../../shared/empty.util'; /** * This component renders a simple item page. @@ -16,13 +17,16 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet- }) @renderFacetFor(FilterType.range) -export class SearchRangeFilterComponent extends SearchFacetFilterComponent { +export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit { rangeDelimiter = '-'; min = 1950; max = 1960; rangeMin = 1900; // calculate using available values rangeMax = 2000; + ngOnInit(): void { + + } get range() { return [this.min, this.max]; } @@ -50,4 +54,17 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent { page: 1 }; } + + onSubmit(data: any) { + if (isNotEmpty(data)) { + this.router.navigate([this.getSearchLink()], { + queryParams: + { [this.filterConfig.paramName + '.min']: [data[this.filterConfig.paramName + '.min']], + [this.filterConfig.paramName + '.max']: [data[this.filterConfig.paramName + '.max']]}, + queryParamsHandling: 'merge' + }); + this.filter = ''; + } + } + } From ce08f52b94caa81a0fa3a15fba3cbf71a0192bdc Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 9 May 2018 09:32:07 +0200 Subject: [PATCH 6/9] Finished date widget without tests and with AoT error --- package.json | 2 + resources/i18n/en.json | 7 +++- .../search-boolean-filter.component.spec.ts | 3 +- .../search-filter/search-filter.service.ts | 25 ++++++++++- .../search-hierarchy-filter.component.scss | 2 +- .../search-hierarchy-filter.component.spec.ts | 3 +- .../search-range-filter.component.html | 13 +++--- .../search-range-filter.component.scss | 14 +++---- .../search-range-filter.component.ts | 42 ++++++++++++------- .../search-text-filter.component.spec.ts | 2 +- .../search-filters.component.ts | 2 +- src/app/+search-page/search-page.component.ts | 2 +- .../search-filter-config.model.ts | 6 +++ .../data/search-response-parsing.service.ts | 1 + src/app/core/metadata/metadata.service.ts | 8 ++-- src/app/shared/shared.module.ts | 4 +- yarn.lock | 10 +++++ 17 files changed, 99 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index c4194bf6f1..e3e1d294d1 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "@ngx-translate/core": "9.1.1", "@ngx-translate/http-loader": "2.0.1", "angular-idle-preload": "2.0.4", + "angular2-moment": "^1.9.0", "body-parser": "1.18.2", "bootstrap": "^4.0.0", "cerialize": "0.1.18", @@ -101,6 +102,7 @@ "js.clone": "0.0.3", "jsonschema": "1.2.2", "methods": "1.1.2", + "moment": "^2.22.1", "morgan": "1.9.0", "ng2-nouislider": "^1.7.7", "ngx-pagination": "3.0.3", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 53ae9015f6..2cea867af6 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -123,7 +123,12 @@ "head": "Subject" }, "dateIssued": { - "placeholder": "Date", + "max": { + "placeholder": "Minimum Date" + }, + "min": { + "placeholder": "Maximum Date" + }, "head": "Date" }, "has_content_in_original_bundle": { diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts index 03b760318f..e1e34b47e6 100644 --- a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts @@ -1,9 +1,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFacetFilterComponent } from './search-facet-filter.component'; import { SearchFilterService } from '../search-filter.service'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { FilterType } from '../../../search-service/filter-type.model'; @@ -19,6 +17,7 @@ import { RouterStub } from '../../../../shared/testing/router-stub'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; describe('SearchFacetFilterComponent', () => { let comp: SearchFacetFilterComponent; diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts index a83312006c..e93a48330b 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts @@ -71,10 +71,31 @@ export class SearchFilterService { ); } - getCurrentFilters() { - return this.routeService.getQueryParamsWithPrefix('f.'); + getCurrentFilters(): Observable { + return this.routeService.getQueryParamsWithPrefix('f.').map((filterParams) => { + if (isNotEmpty(filterParams)) { + const params = {}; + Object.keys(filterParams).forEach((key) => { + if (key.endsWith('.min') || key.endsWith('.max')) { + const realKey = key.slice(0, -4); + if (isEmpty(params[realKey])) { + const min = filterParams[realKey + '.min'][0] || '*'; + const max = filterParams[realKey + '.max'][0] || '*'; + params[realKey] = ['[' + min + ' TO ' + max + ']']; + } + } else { + params[key] = filterParams[key]; + } + }); + return params; + } + return filterParams; + }); } + getCurrentFrontendFilters(): Observable { + return this.routeService.getQueryParamsWithPrefix('f.'); + } getCurrentView() { return this.routeService.getQueryParameterValue('view'); } diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss index 595b2aefb8..1297f1ae3a 100644 --- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss @@ -7,7 +7,7 @@ a { color: $body-color; &:hover { - text-decoration: none; + text-decoration: none; } } .toggle-more-filters a { diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts index 03b760318f..e1e34b47e6 100644 --- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts @@ -1,9 +1,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFacetFilterComponent } from './search-facet-filter.component'; import { SearchFilterService } from '../search-filter.service'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { FilterType } from '../../../search-service/filter-type.model'; @@ -19,6 +17,7 @@ import { RouterStub } from '../../../../shared/testing/router-stub'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; describe('SearchFacetFilterComponent', () => { let comp: SearchFacetFilterComponent; diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index ae51f3bcb1..06d084adf5 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -3,28 +3,27 @@
-
-
- +
- {{value.value}} {{value.count}} diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss index 595b2aefb8..ad36c7b8d3 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss @@ -2,17 +2,13 @@ @import '../../../../../styles/mixins.scss'; .filters { - margin-top: $spacer/2; - margin-bottom: $spacer/2; + a { - color: $body-color; + color: $link-color; &:hover { - text-decoration: none; + text-decoration: underline; + color: $link-hover-color; + } } - .toggle-more-filters a { - color: $link-color; - text-decoration: underline; - cursor: pointer; - } } \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 9cf763099c..1f0e16600f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -1,8 +1,13 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { FilterType } from '../../../search-service/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; import { isNotEmpty } from '../../../../shared/empty.util'; +import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; +import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; +import { SearchService } from '../../../search-service/search.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import * as moment from 'moment'; /** * This component renders a simple item page. @@ -20,21 +25,28 @@ import { isNotEmpty } from '../../../../shared/empty.util'; export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit { rangeDelimiter = '-'; min = 1950; - max = 1960; - rangeMin = 1900; // calculate using available values - rangeMax = 2000; + max = 2018; + range; + dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD'] + + constructor(protected searchService: SearchService, + protected filterService: SearchFilterService, + protected router: Router, + @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, + @Inject(SELECTED_VALUES) public selectedValues: string[], + private route: ActivatedRoute) { + super(searchService, filterService, router, filterConfig, selectedValues); + } ngOnInit(): void { + super.ngOnInit(); + this.min = moment(this.filterConfig.minValue, this.dateFormats).year() || this.min; + this.max = moment(this.filterConfig.maxValue, this.dateFormats).year() || this.max; + const iniMin = this.route.snapshot.queryParams[this.filterConfig.paramName + '.min'] || this.min; + const iniMax = this.route.snapshot.queryParams[this.filterConfig.paramName + '.max'] || this.max; + this.range = [iniMin, iniMax]; } - get range() { - return [this.min, this.max]; - } - - set range(value: number[]) { - this.min = value[0]; - this.max = value[1]; - } getAddParams(value: string) { const parts = value.split(this.rangeDelimiter); @@ -59,8 +71,10 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple if (isNotEmpty(data)) { this.router.navigate([this.getSearchLink()], { queryParams: - { [this.filterConfig.paramName + '.min']: [data[this.filterConfig.paramName + '.min']], - [this.filterConfig.paramName + '.max']: [data[this.filterConfig.paramName + '.max']]}, + { + [this.filterConfig.paramName + '.min']: [data[this.filterConfig.paramName + '.min']], + [this.filterConfig.paramName + '.max']: [data[this.filterConfig.paramName + '.max']] + }, queryParamsHandling: 'merge' }); this.filter = ''; diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts index 03b760318f..c44519743e 100644 --- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts @@ -3,7 +3,6 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFacetFilterComponent } from './search-facet-filter.component'; import { SearchFilterService } from '../search-filter.service'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { FilterType } from '../../../search-service/filter-type.model'; @@ -19,6 +18,7 @@ import { RouterStub } from '../../../../shared/testing/router-stub'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; describe('SearchFacetFilterComponent', () => { let comp: SearchFacetFilterComponent; diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index 517b2e1e59..b0c69ee5ce 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -22,7 +22,7 @@ export class SearchFiltersComponent { clearParams; constructor(private searchService: SearchService, private filterService: SearchFilterService) { this.filters = searchService.getConfig(); - this.clearParams = filterService.getCurrentFilters().map((filters) => {Object.keys(filters).forEach((f) => filters[f] = null); return filters;}); + this.clearParams = filterService.getCurrentFrontendFilters().map((filters) => {Object.keys(filters).forEach((f) => filters[f] = null); return filters;}); } getSearchLink() { diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 4f50723ced..1a71a70807 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { Observable } from 'rxjs/Observable'; -import { flatMap, } from 'rxjs/operators'; +import { flatMap, tap, } from 'rxjs/operators'; import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; import { CommunityDataService } from '../core/data/community-data.service'; import { PaginatedList } from '../core/data/paginated-list'; diff --git a/src/app/+search-page/search-service/search-filter-config.model.ts b/src/app/+search-page/search-service/search-filter-config.model.ts index 2b77ef6768..000e06e1a8 100644 --- a/src/app/+search-page/search-service/search-filter-config.model.ts +++ b/src/app/+search-page/search-service/search-filter-config.model.ts @@ -17,6 +17,12 @@ @autoserialize isOpenByDefault: boolean; + + @autoserialize + maxValue: string; + + @autoserialize + minValue: string; /** * Name of this configuration that can be used in a url * @returns Parameter name diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index c7456aa2f9..efecccf54a 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -17,6 +17,7 @@ export class SearchResponseParsingService implements ResponseParsingService { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; + console.log(payload); const hitHighlights = payload._embedded.objects .map((object) => object.hitHighlights) .map((hhObject) => { diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts index 39fb454ac5..cf597195e9 100644 --- a/src/app/core/metadata/metadata.service.ts +++ b/src/app/core/metadata/metadata.service.ts @@ -26,7 +26,7 @@ import { Metadatum } from '../shared/metadatum.model'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; import { BitstreamFormat } from '../shared/bitstream-format.model'; -import { hasValue } from '../../shared/empty.util'; +import { hasValue, isNotEmpty } from '../../shared/empty.util'; @Injectable() export class MetadataService { @@ -269,11 +269,9 @@ export class MetadataService { private setCitationPdfUrlTag(): void { if (this.currentObject.value instanceof Item) { const item = this.currentObject.value as Item; - // NOTE: Observable resolves many times with same data - // taking only two, fist one is empty array - item.getFiles().take(2).subscribe((bitstreams: Bitstream[]) => { + item.getFiles().filter((files) => isNotEmpty(files)).first().subscribe((bitstreams: Bitstream[]) => { for (const bitstream of bitstreams) { - bitstream.format.take(1) + bitstream.format.first() .map((rd: RemoteData) => rd.payload) .filter((format: BitstreamFormat) => hasValue(format)) .subscribe((format: BitstreamFormat) => { diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index ba877fcdd7..c26c0d03e8 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -45,6 +45,7 @@ import { TruncatePipe } from './utils/truncate.pipe'; import { TruncatableComponent } from './truncatable/truncatable.component'; import { TruncatableService } from './truncatable/truncatable.service'; import { TruncatablePartComponent } from './truncatable/truncatable-part/truncatable-part.component'; +import { MomentModule } from 'angular2-moment'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -55,7 +56,8 @@ const MODULES = [ ReactiveFormsModule, RouterModule, TranslateModule, - NouisliderModule + NouisliderModule, + MomentModule ]; const PIPES = [ diff --git a/yarn.lock b/yarn.lock index 44d4dd54d4..c67f761b40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -421,6 +421,12 @@ angular-idle-preload@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/angular-idle-preload/-/angular-idle-preload-2.0.4.tgz#7b177c0f52918c090e5c345480b922297cd59a0d" +angular2-moment@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/angular2-moment/-/angular2-moment-1.9.0.tgz#d198a4d9bc825f61de19106ac7ea07a78569f5a1" + dependencies: + moment "^2.19.3" + angular2-template-loader@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/angular2-template-loader/-/angular2-template-loader-0.6.2.tgz#c0d44e90fff0fac95e8b23f043acda7fd1c51d7c" @@ -5485,6 +5491,10 @@ module-deps@^4.0.8: through2 "^2.0.0" xtend "^4.0.0" +moment@^2.19.3, moment@^2.22.1: + version "2.22.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" + morgan@1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" From 95060ee573de4278bb7404b638201ca336a8e003 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 15 May 2018 11:03:18 +0200 Subject: [PATCH 7/9] almost finished date widget --- package.json | 4 +- .../search-facet-filter-wrapper.component.ts | 3 +- .../search-facet-filter.component.spec.ts} | 6 +- .../search-filter.component.html | 2 +- .../search-filter.component.scss | 2 +- .../search-hierarchy-filter.component.spec.ts | 241 ----------------- .../search-hierarchy-filter.component.ts | 2 - .../search-range-filter.component.html | 3 +- .../search-range-filter.component.scss | 34 ++- .../search-range-filter.component.spec.ts | 139 ++++++++++ .../search-range-filter.component.ts | 28 +- .../search-text-filter.component.spec.ts | 242 ------------------ .../search-filters.component.spec.ts | 2 +- src/app/+search-page/search-page.module.ts | 1 + .../search-filter-config.model.ts | 2 +- .../data/search-response-parsing.service.ts | 4 +- src/app/shared/mocks/mock-active-router.ts | 2 +- yarn.lock | 12 +- 18 files changed, 205 insertions(+), 524 deletions(-) rename src/app/+search-page/search-filters/search-filter/{search-boolean-filter/search-boolean-filter.component.spec.ts => search-facet-filter/search-facet-filter.component.spec.ts} (96%) delete mode 100644 src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts create mode 100644 src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts delete mode 100644 src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts diff --git a/package.json b/package.json index e3e1d294d1..f305f319ab 100644 --- a/package.json +++ b/package.json @@ -104,9 +104,9 @@ "methods": "1.1.2", "moment": "^2.22.1", "morgan": "1.9.0", - "ng2-nouislider": "^1.7.7", + "ng2-nouislider": "1.7.8", "ngx-pagination": "3.0.3", - "nouislider": "^10.0.0", + "nouislider": "^11.0.0", "pem": "1.12.3", "reflect-metadata": "0.1.12", "rxjs": "5.5.6", diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts index bac4a49d79..d1f7eeab5c 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts @@ -1,8 +1,7 @@ -import { Component, InjectionToken, Injector, Input, OnInit } from '@angular/core'; +import { Component, Injector, Input, OnInit } from '@angular/core'; import { renderFilterType } from '../search-filter-type-decorator'; import { FilterType } from '../../../search-service/filter-type.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; -import { GlobalConfig } from '../../../../../config/global-config.interface'; import { FILTER_CONFIG, SELECTED_VALUES } from '../search-filter.service'; import { Observable } from 'rxjs/Observable'; diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts similarity index 96% rename from src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts rename to src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index e1e34b47e6..0fddc58183 100644 --- a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFilterService } from '../search-filter.service'; +import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { FilterType } from '../../../search-service/filter-type.model'; import { FacetValue } from '../../../search-service/facet-value.model'; @@ -17,7 +17,7 @@ import { RouterStub } from '../../../../shared/testing/router-stub'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { PageInfo } from '../../../../core/shared/page-info.model'; -import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; +import { SearchFacetFilterComponent } from './search-facet-filter.component'; describe('SearchFacetFilterComponent', () => { let comp: SearchFacetFilterComponent; @@ -64,6 +64,8 @@ describe('SearchFacetFilterComponent', () => { providers: [ { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, { provide: Router, useValue: new RouterStub() }, + { provide: FILTER_CONFIG, useValue: new SearchFilterConfig()}, + { provide: SELECTED_VALUES, useValue: {} }, { provide: SearchFilterService, useValue: { isFilterActiveWithValue: (paramName: string, filterValue: string) => true, diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html index 857b03a38f..b0be42b215 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html @@ -1,7 +1,7 @@
{{'search.filters.filter.' + filter.name + '.head'| translate}}
-
+
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss index f694e9e167..6e49172a48 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss @@ -3,7 +3,7 @@ :host { border: 1px solid map-get($theme-colors, light); - .search-filter-wrapper { + .search-filter-wrapper.closed { overflow: hidden; } .filter-toggle { diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts deleted file mode 100644 index e1e34b47e6..0000000000 --- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFilterService } from '../search-filter.service'; -import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; -import { FilterType } from '../../../search-service/filter-type.model'; -import { FacetValue } from '../../../search-service/facet-value.model'; -import { FormsModule } from '@angular/forms'; -import { Observable } from 'rxjs/Observable'; -import { SearchService } from '../../../search-service/search.service'; -import { SearchServiceStub } from '../../../../shared/testing/search-service-stub'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { SearchOptions } from '../../../search-options.model'; -import { RouterStub } from '../../../../shared/testing/router-stub'; -import { Router } from '@angular/router'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { PageInfo } from '../../../../core/shared/page-info.model'; -import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; - -describe('SearchFacetFilterComponent', () => { - let comp: SearchFacetFilterComponent; - let fixture: ComponentFixture; - const filterName1 = 'test name'; - const value1 = 'testvalue1'; - const value2 = 'test2'; - const value3 = 'another value3'; - const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { - name: filterName1, - type: FilterType.text, - hasFacets: false, - isOpenByDefault: false, - pageSize: 2 - }); - const values: FacetValue[] = [ - { - value: value1, - count: 52, - search: '' - }, { - value: value2, - count: 20, - search: '' - }, { - value: value3, - count: 5, - search: '' - } - ]; - - const searchLink = '/search'; - const selectedValues = [value1, value2]; - let filterService; - let searchService; - let router; - const page = Observable.of(0); - - const mockValues = Observable.of(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values))); - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], - declarations: [SearchFacetFilterComponent], - providers: [ - { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, - { provide: Router, useValue: new RouterStub() }, - { - provide: SearchFilterService, useValue: { - isFilterActiveWithValue: (paramName: string, filterValue: string) => true, - getPage: (paramName: string) => page, - /* tslint:disable:no-empty */ - incrementPage: (filterName: string) => { - }, - resetPage: (filterName: string) => { - }, - getSearchOptions: () => Observable.of({}), - /* tslint:enable:no-empty */ - } - } - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(SearchFacetFilterComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SearchFacetFilterComponent); - comp = fixture.componentInstance; // SearchPageComponent test instance - comp.filterConfig = mockFilterConfig; - comp.filterValues = [mockValues]; - comp.filterValues$ = new BehaviorSubject(comp.filterValues); - comp.selectedValues = selectedValues; - filterService = (comp as any).filterService; - searchService = (comp as any).searchService; - spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); - router = (comp as any).router; - fixture.detectChanges(); - }); - - describe('when the isChecked method is called with a value', () => { - beforeEach(() => { - spyOn(filterService, 'isFilterActiveWithValue'); - comp.isChecked(values[1]); - }); - - it('should call isFilterActiveWithValue on the filterService with the correct filter parameter name and the passed value', () => { - expect(filterService.isFilterActiveWithValue).toHaveBeenCalledWith(mockFilterConfig.paramName, values[1].value) - }); - }); - - describe('when the getSearchLink method is triggered', () => { - let link: string; - beforeEach(() => { - link = comp.getSearchLink(); - }); - - it('should return the value of the searchLink variable in the filter service', () => { - expect(link).toEqual(searchLink); - }); - }); - - describe('when the getAddParams method is called wih a value', () => { - it('should return the selectedValue list with the new parameter value', () => { - const result = comp.getAddParams(value3); - expect(result[mockFilterConfig.paramName]).toEqual([value1, value2, value3]); - }); - }); - - describe('when the getRemoveParams method is called wih a value', () => { - it('should return the selectedValue list with the parameter value left out', () => { - const result = comp.getRemoveParams(value1); - expect(result[mockFilterConfig.paramName]).toEqual([value2]); - }); - }); - - describe('when the showMore method is called', () => { - beforeEach(() => { - spyOn(filterService, 'incrementPage'); - comp.showMore(); - }); - - it('should call incrementPage on the filterService with the correct filter parameter name', () => { - expect(filterService.incrementPage).toHaveBeenCalledWith(mockFilterConfig.name) - }); - }); - - describe('when the showFirstPageOnly method is called', () => { - beforeEach(() => { - spyOn(filterService, 'resetPage'); - comp.showFirstPageOnly(); - }); - - it('should call resetPage on the filterService with the correct filter parameter name', () => { - expect(filterService.resetPage).toHaveBeenCalledWith(mockFilterConfig.name); - }); - }); - - describe('when the getCurrentPage method is called', () => { - beforeEach(() => { - spyOn(filterService, 'getPage'); - comp.getCurrentPage(); - }); - - it('should call getPage on the filterService with the correct filter parameter name', () => { - expect(filterService.getPage).toHaveBeenCalledWith(mockFilterConfig.name) - }); - }); - - describe('when the getCurrentUrl method is called', () => { - const url = 'test.url/test' - beforeEach(() => { - router.navigateByUrl(url); - }); - - it('should call getPage on the filterService with the correct filter parameter name', () => { - expect(router.url).toEqual(url); - }); - }); - - describe('when the onSubmit method is called with data', () => { - const searchUrl = '/search/path'; - const testValue = 'test'; - const data = { [mockFilterConfig.paramName]: testValue }; - beforeEach(() => { - spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); - comp.onSubmit(data); - }); - - it('should call navigate on the router with the right searchlink and parameters', () => { - expect(router.navigate).toHaveBeenCalledWith([searchUrl], { - queryParams: { [mockFilterConfig.paramName]: [...selectedValues, testValue] }, - queryParamsHandling: 'merge' - }); - }); - }); - - describe('when updateFilterValueList is called', () => { - const cPage = 10; - const searchOptions = new SearchOptions(); - beforeEach(() => { - // spyOn(searchService, 'getFacetValuesFor'); Already spied upon - comp.currentPage = Observable.of(cPage); - comp.updateFilterValueList(searchOptions); - }); - - it('should call getFacetValuesFor on the searchService with the correct parameters', () => { - expect(searchService.getFacetValuesFor).toHaveBeenCalledWith(mockFilterConfig, cPage, searchOptions); - }); - }); - - describe('when updateFilterValueList is called and pageChange is set to true', () => { - const searchOptions = new SearchOptions(); - beforeEach(() => { - comp.pageChange = true; - spyOn(comp, 'showFirstPageOnly'); - comp.updateFilterValueList(searchOptions); - }); - - it('should not call showFirstPageOnly on the component', () => { - expect(comp.showFirstPageOnly).not.toHaveBeenCalled(); - }); - - it('should set pageChange to false', () => { - expect(comp.pageChange).toBeFalsy(); - }); - }); - - describe('when updateFilterValueList is called and pageChange is set to false', () => { - const searchOptions = new SearchOptions(); - beforeEach(() => { - comp.pageChange = false; - spyOn(comp, 'showFirstPageOnly'); - comp.updateFilterValueList(searchOptions); - }); - - it('should call showFirstPageOnly on the component', () => { - expect(comp.showFirstPageOnly).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts index 23ac40fde1..5e8966cdb4 100644 --- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts @@ -20,6 +20,4 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet- @renderFacetFor(FilterType.hierarchy) export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent implements OnInit { currentPage: Observable; - - } diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 06d084adf5..5760f20c5b 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -1,3 +1,4 @@ +
+ [(ngModel)]="range" (mouseup)="onSubmit(form.value)" ngDefaultControl> diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss index ad36c7b8d3..2bb89c0b14 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss @@ -1,14 +1,38 @@ @import '../../../../../styles/variables.scss'; @import '../../../../../styles/mixins.scss'; + .filters { + margin-top: $spacer/2; + margin-bottom: $spacer/2; + a { + color: $link-color; + &:hover { + text-decoration: underline; + color: $link-hover-color; - a { - color: $link-color; - &:hover { - text-decoration: underline; - color: $link-hover-color; + } + } + .toggle-more-filters a { + color: $link-color; + text-decoration: underline; + cursor: pointer; + } + } +$slider-handle-width: 18px; +::ng-deep +{ + html:not([dir=rtl]) .noUi-horizontal .noUi-handle { + right: -$slider-handle-width/2; + } + .noUi-horizontal .noUi-handle { + width: $slider-handle-width; + &:before { + left: ($slider-handle-width - 2)/2 - 2; + } + &:after { + left: ($slider-handle-width - 2)/2 + 2; } } } \ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts new file mode 100644 index 0000000000..e4aa887caa --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -0,0 +1,139 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; +import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; +import { FilterType } from '../../../search-service/filter-type.model'; +import { FacetValue } from '../../../search-service/facet-value.model'; +import { FormsModule } from '@angular/forms'; +import { Observable } from 'rxjs/Observable'; +import { SearchService } from '../../../search-service/search.service'; +import { SearchServiceStub } from '../../../../shared/testing/search-service-stub'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { RouterStub } from '../../../../shared/testing/router-stub'; +import { ActivatedRoute, Router } from '@angular/router'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { PageInfo } from '../../../../core/shared/page-info.model'; +import { SearchRangeFilterComponent } from './search-range-filter.component'; +import { MockActivatedRoute } from '../../../../shared/mocks/mock-active-router'; + +describe('SearchFacetFilterComponent', () => { + let comp: SearchRangeFilterComponent; + let fixture: ComponentFixture; + const minSuffix = '.min'; + const maxSuffix = '.max'; + const dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD']; + const filterName1 = 'test name'; + const value1 = '2000 - 2012'; + const value2 = '1992 - 2000'; + const value3 = '1990 - 1992'; + const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { + name: filterName1, + type: FilterType.range, + hasFacets: false, + isOpenByDefault: false, + pageSize: 2, + minValue: 200, + maxValue: 3000, + }); + const values: FacetValue[] = [ + { + value: value1, + count: 52, + search: '' + }, { + value: value2, + count: 20, + search: '' + }, { + value: value3, + count: 5, + search: '' + } + ]; + + const searchLink = '/search'; + const selectedValues = [value1]; + let filterService; + let searchService; + let router; + const page = Observable.of(0); + const activatedRouteStub = new MockActivatedRoute(); + + const mockValues = Observable.of(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values))); + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], + declarations: [SearchRangeFilterComponent], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, + { provide: Router, useValue: new RouterStub() }, + { provide: FILTER_CONFIG, useValue: mockFilterConfig}, + { provide: SELECTED_VALUES, useValue: selectedValues }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { + provide: SearchFilterService, useValue: { + isFilterActiveWithValue: (paramName: string, filterValue: string) => true, + getPage: (paramName: string) => page, + /* tslint:disable:no-empty */ + incrementPage: (filterName: string) => { + }, + resetPage: (filterName: string) => { + }, + getSearchOptions: () => Observable.of({}), + /* tslint:enable:no-empty */ + } + } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(SearchRangeFilterComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SearchRangeFilterComponent); + comp = fixture.componentInstance; // SearchPageComponent test instance + comp.filterValues = [mockValues]; + comp.filterValues$ = new BehaviorSubject(comp.filterValues); + filterService = (comp as any).filterService; + searchService = (comp as any).searchService; + spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); + router = (comp as any).router; + fixture.detectChanges(); + }); + + describe('when the getAddParams method is called wih a value', () => { + it('should return the selectedValue list with the new parameter value', () => { + const result = comp.getAddParams(value3); + expect(result[mockFilterConfig.paramName + minSuffix]).toEqual(['1990']); + expect(result[mockFilterConfig.paramName + maxSuffix]).toEqual(['1992']); + }); + }); + + describe('when the getRemoveParams method is called wih a value', () => { + it('should return the selectedValue list with the parameter value left out', () => { + const result = comp.getRemoveParams(value1); + expect(result[mockFilterConfig.paramName + minSuffix]).toBeNull(); + expect(result[mockFilterConfig.paramName + maxSuffix]).toBeNull(); + }); + }); + + describe('when the onSubmit method is called with data', () => { + const searchUrl = '/search/path'; + const data = { [mockFilterConfig.paramName + minSuffix]: '1900', [mockFilterConfig.paramName + maxSuffix]: '1950' }; + beforeEach(() => { + spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); + comp.onSubmit(data); + }); + + it('should call navigate on the router with the right searchlink and parameters', () => { + expect(router.navigate).toHaveBeenCalledWith([searchUrl], { + queryParams: { [mockFilterConfig.paramName + minSuffix]: ['1900'], [mockFilterConfig.paramName + maxSuffix]: ['1950']}, + queryParamsHandling: 'merge' + }); + }); + }); +}); diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 1f0e16600f..790ec93453 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -14,6 +14,10 @@ import * as moment from 'moment'; * The route parameter 'id' is used to request the item it represents. * All fields of the item that should be displayed, are defined in its template. */ +const minSuffix = '.min'; +const maxSuffix = '.max'; +const dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD']; +const rangeDelimiter = '-'; @Component({ selector: 'ds-search-range-filter', @@ -23,11 +27,9 @@ import * as moment from 'moment'; @renderFacetFor(FilterType.range) export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit { - rangeDelimiter = '-'; min = 1950; max = 2018; range; - dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD'] constructor(protected searchService: SearchService, protected filterService: SearchFilterService, @@ -40,29 +42,29 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple ngOnInit(): void { super.ngOnInit(); - this.min = moment(this.filterConfig.minValue, this.dateFormats).year() || this.min; - this.max = moment(this.filterConfig.maxValue, this.dateFormats).year() || this.max; - const iniMin = this.route.snapshot.queryParams[this.filterConfig.paramName + '.min'] || this.min; - const iniMax = this.route.snapshot.queryParams[this.filterConfig.paramName + '.max'] || this.max; + this.min = moment(this.filterConfig.minValue, dateFormats).year() || this.min; + this.max = moment(this.filterConfig.maxValue, dateFormats).year() || this.max; + const iniMin = this.route.snapshot.queryParams[this.filterConfig.paramName + minSuffix] || this.min; + const iniMax = this.route.snapshot.queryParams[this.filterConfig.paramName + maxSuffix] || this.max; this.range = [iniMin, iniMax]; } getAddParams(value: string) { - const parts = value.split(this.rangeDelimiter); + const parts = value.split(rangeDelimiter); const min = parts.length > 1 ? parts[0].trim() : value; const max = parts.length > 1 ? parts[1].trim() : value; return { - [this.filterConfig.paramName + '.min']: [min], - [this.filterConfig.paramName + '.max']: [max], + [this.filterConfig.paramName + minSuffix]: [min], + [this.filterConfig.paramName + maxSuffix]: [max], page: 1 }; } getRemoveParams(value: string) { return { - [this.filterConfig.paramName + '.min']: null, - [this.filterConfig.paramName + '.max']: null, + [this.filterConfig.paramName + minSuffix]: null, + [this.filterConfig.paramName + maxSuffix]: null, page: 1 }; } @@ -72,8 +74,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple this.router.navigate([this.getSearchLink()], { queryParams: { - [this.filterConfig.paramName + '.min']: [data[this.filterConfig.paramName + '.min']], - [this.filterConfig.paramName + '.max']: [data[this.filterConfig.paramName + '.max']] + [this.filterConfig.paramName + minSuffix]: [data[this.filterConfig.paramName + minSuffix]], + [this.filterConfig.paramName + maxSuffix]: [data[this.filterConfig.paramName + maxSuffix]] }, queryParamsHandling: 'merge' }); diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts deleted file mode 100644 index c44519743e..0000000000 --- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.spec.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFilterService } from '../search-filter.service'; -import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; -import { FilterType } from '../../../search-service/filter-type.model'; -import { FacetValue } from '../../../search-service/facet-value.model'; -import { FormsModule } from '@angular/forms'; -import { Observable } from 'rxjs/Observable'; -import { SearchService } from '../../../search-service/search.service'; -import { SearchServiceStub } from '../../../../shared/testing/search-service-stub'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { SearchOptions } from '../../../search-options.model'; -import { RouterStub } from '../../../../shared/testing/router-stub'; -import { Router } from '@angular/router'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { PageInfo } from '../../../../core/shared/page-info.model'; -import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; - -describe('SearchFacetFilterComponent', () => { - let comp: SearchFacetFilterComponent; - let fixture: ComponentFixture; - const filterName1 = 'test name'; - const value1 = 'testvalue1'; - const value2 = 'test2'; - const value3 = 'another value3'; - const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { - name: filterName1, - type: FilterType.text, - hasFacets: false, - isOpenByDefault: false, - pageSize: 2 - }); - const values: FacetValue[] = [ - { - value: value1, - count: 52, - search: '' - }, { - value: value2, - count: 20, - search: '' - }, { - value: value3, - count: 5, - search: '' - } - ]; - - const searchLink = '/search'; - const selectedValues = [value1, value2]; - let filterService; - let searchService; - let router; - const page = Observable.of(0); - - const mockValues = Observable.of(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values))); - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule], - declarations: [SearchFacetFilterComponent], - providers: [ - { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, - { provide: Router, useValue: new RouterStub() }, - { - provide: SearchFilterService, useValue: { - isFilterActiveWithValue: (paramName: string, filterValue: string) => true, - getPage: (paramName: string) => page, - /* tslint:disable:no-empty */ - incrementPage: (filterName: string) => { - }, - resetPage: (filterName: string) => { - }, - getSearchOptions: () => Observable.of({}), - /* tslint:enable:no-empty */ - } - } - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(SearchFacetFilterComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SearchFacetFilterComponent); - comp = fixture.componentInstance; // SearchPageComponent test instance - comp.filterConfig = mockFilterConfig; - comp.filterValues = [mockValues]; - comp.filterValues$ = new BehaviorSubject(comp.filterValues); - comp.selectedValues = selectedValues; - filterService = (comp as any).filterService; - searchService = (comp as any).searchService; - spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockValues); - router = (comp as any).router; - fixture.detectChanges(); - }); - - describe('when the isChecked method is called with a value', () => { - beforeEach(() => { - spyOn(filterService, 'isFilterActiveWithValue'); - comp.isChecked(values[1]); - }); - - it('should call isFilterActiveWithValue on the filterService with the correct filter parameter name and the passed value', () => { - expect(filterService.isFilterActiveWithValue).toHaveBeenCalledWith(mockFilterConfig.paramName, values[1].value) - }); - }); - - describe('when the getSearchLink method is triggered', () => { - let link: string; - beforeEach(() => { - link = comp.getSearchLink(); - }); - - it('should return the value of the searchLink variable in the filter service', () => { - expect(link).toEqual(searchLink); - }); - }); - - describe('when the getAddParams method is called wih a value', () => { - it('should return the selectedValue list with the new parameter value', () => { - const result = comp.getAddParams(value3); - expect(result[mockFilterConfig.paramName]).toEqual([value1, value2, value3]); - }); - }); - - describe('when the getRemoveParams method is called wih a value', () => { - it('should return the selectedValue list with the parameter value left out', () => { - const result = comp.getRemoveParams(value1); - expect(result[mockFilterConfig.paramName]).toEqual([value2]); - }); - }); - - describe('when the showMore method is called', () => { - beforeEach(() => { - spyOn(filterService, 'incrementPage'); - comp.showMore(); - }); - - it('should call incrementPage on the filterService with the correct filter parameter name', () => { - expect(filterService.incrementPage).toHaveBeenCalledWith(mockFilterConfig.name) - }); - }); - - describe('when the showFirstPageOnly method is called', () => { - beforeEach(() => { - spyOn(filterService, 'resetPage'); - comp.showFirstPageOnly(); - }); - - it('should call resetPage on the filterService with the correct filter parameter name', () => { - expect(filterService.resetPage).toHaveBeenCalledWith(mockFilterConfig.name); - }); - }); - - describe('when the getCurrentPage method is called', () => { - beforeEach(() => { - spyOn(filterService, 'getPage'); - comp.getCurrentPage(); - }); - - it('should call getPage on the filterService with the correct filter parameter name', () => { - expect(filterService.getPage).toHaveBeenCalledWith(mockFilterConfig.name) - }); - }); - - describe('when the getCurrentUrl method is called', () => { - const url = 'test.url/test' - beforeEach(() => { - router.navigateByUrl(url); - }); - - it('should call getPage on the filterService with the correct filter parameter name', () => { - expect(router.url).toEqual(url); - }); - }); - - describe('when the onSubmit method is called with data', () => { - const searchUrl = '/search/path'; - const testValue = 'test'; - const data = { [mockFilterConfig.paramName]: testValue }; - beforeEach(() => { - spyOn(comp, 'getSearchLink').and.returnValue(searchUrl); - comp.onSubmit(data); - }); - - it('should call navigate on the router with the right searchlink and parameters', () => { - expect(router.navigate).toHaveBeenCalledWith([searchUrl], { - queryParams: { [mockFilterConfig.paramName]: [...selectedValues, testValue] }, - queryParamsHandling: 'merge' - }); - }); - }); - - describe('when updateFilterValueList is called', () => { - const cPage = 10; - const searchOptions = new SearchOptions(); - beforeEach(() => { - // spyOn(searchService, 'getFacetValuesFor'); Already spied upon - comp.currentPage = Observable.of(cPage); - comp.updateFilterValueList(searchOptions); - }); - - it('should call getFacetValuesFor on the searchService with the correct parameters', () => { - expect(searchService.getFacetValuesFor).toHaveBeenCalledWith(mockFilterConfig, cPage, searchOptions); - }); - }); - - describe('when updateFilterValueList is called and pageChange is set to true', () => { - const searchOptions = new SearchOptions(); - beforeEach(() => { - comp.pageChange = true; - spyOn(comp, 'showFirstPageOnly'); - comp.updateFilterValueList(searchOptions); - }); - - it('should not call showFirstPageOnly on the component', () => { - expect(comp.showFirstPageOnly).not.toHaveBeenCalled(); - }); - - it('should set pageChange to false', () => { - expect(comp.pageChange).toBeFalsy(); - }); - }); - - describe('when updateFilterValueList is called and pageChange is set to false', () => { - const searchOptions = new SearchOptions(); - beforeEach(() => { - comp.pageChange = false; - spyOn(comp, 'showFirstPageOnly'); - comp.updateFilterValueList(searchOptions); - }); - - it('should call showFirstPageOnly on the component', () => { - expect(comp.showFirstPageOnly).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/app/+search-page/search-filters/search-filters.component.spec.ts b/src/app/+search-page/search-filters/search-filters.component.spec.ts index 64c2ea5332..6557c5e55f 100644 --- a/src/app/+search-page/search-filters/search-filters.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filters.component.spec.ts @@ -24,7 +24,7 @@ describe('SearchFiltersComponent', () => { /* tslint:enable:no-empty */ }; const searchFilterServiceStub = jasmine.createSpyObj('SearchFilterService', { - getCurrentFilters: Observable.of({}) + getCurrentFrontendFilters: Observable.of({}) }); beforeEach(async(() => { diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 4b28689910..94083d9936 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -72,6 +72,7 @@ const effects = [ ItemSearchResultGridElementComponent, CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, + SearchFacetFilterComponent, SearchRangeFilterComponent, SearchTextFilterComponent, SearchHierarchyFilterComponent, diff --git a/src/app/+search-page/search-service/search-filter-config.model.ts b/src/app/+search-page/search-service/search-filter-config.model.ts index 000e06e1a8..ced1f7a8eb 100644 --- a/src/app/+search-page/search-service/search-filter-config.model.ts +++ b/src/app/+search-page/search-service/search-filter-config.model.ts @@ -17,7 +17,7 @@ @autoserialize isOpenByDefault: boolean; - + @autoserialize maxValue: string; diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index efecccf54a..06e1d741b0 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -5,8 +5,7 @@ import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { PageInfo } from '../shared/page-info.model'; -import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { hasValue } from '../../shared/empty.util'; import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model'; import { Metadatum } from '../shared/metadatum.model'; @@ -17,7 +16,6 @@ export class SearchResponseParsingService implements ResponseParsingService { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; - console.log(payload); const hitHighlights = payload._embedded.objects .map((object) => object.hitHighlights) .map((hhObject) => { diff --git a/src/app/shared/mocks/mock-active-router.ts b/src/app/shared/mocks/mock-active-router.ts index 391b9c3426..183d6c13d0 100644 --- a/src/app/shared/mocks/mock-active-router.ts +++ b/src/app/shared/mocks/mock-active-router.ts @@ -29,6 +29,6 @@ export class MockActivatedRoute { // ActivatedRoute.snapshot.params get snapshot() { - return { params: this.testParams }; + return { params: this.testParams, queryParams: this.testParams }; } } diff --git a/yarn.lock b/yarn.lock index c67f761b40..fd03a7c8ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5591,9 +5591,9 @@ netmask@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" -ng2-nouislider@^1.7.7: - version "1.7.7" - resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.7.7.tgz#b841f4b313c8c9c8a763c80f3a59d5aa4c3a70c8" +ng2-nouislider@1.7.8: + version "1.7.8" + resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.7.8.tgz#5fd6de120f9ca5b5d9c4b377f884944b74c06855" ngrx-store-freeze@^0.2.1: version "0.2.1" @@ -5814,9 +5814,9 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" -nouislider@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/nouislider/-/nouislider-10.1.0.tgz#7bdd0411fd62d4584bfe88cb92bb8d06e64c6b47" +nouislider@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/nouislider/-/nouislider-11.1.0.tgz#1768eb5b854917325d41b96f2dc4eb3757d73381" npm-run-all@4.1.2: version "4.1.2" From 0ad4edb5232d7c9bd4a9426df6f2659b760196fb Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Mon, 28 May 2018 10:05:52 +0200 Subject: [PATCH 8/9] small css fixes --- .../search-filters/search-filter/search-filter.component.html | 4 ++-- .../search-filters/search-filter/search-filter.component.scss | 2 +- .../search-range-filter/search-range-filter.component.html | 1 - .../search-range-filter/search-range-filter.component.scss | 3 +++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html index b0be42b215..d0ddce8bcb 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html @@ -1,7 +1,7 @@
{{'search.filters.filter.' + filter.name + '.head'| translate}}
-
- +
+
\ No newline at end of file diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss index 6e49172a48..f694e9e167 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss @@ -3,7 +3,7 @@ :host { border: 1px solid map-get($theme-colors, light); - .search-filter-wrapper.closed { + .search-filter-wrapper { overflow: hidden; } .filter-toggle { diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 5760f20c5b..a3ee3e436b 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -1,4 +1,3 @@ -
Date: Fri, 13 Jul 2018 16:36:36 +0200 Subject: [PATCH 9/9] fixed an issue where the server-side would crash if the page contained nouislider --- package.json | 2 +- .../search-range-filter.component.html | 5 ++++- .../search-range-filter.component.ts | 11 ++++++++++- yarn.lock | 6 +++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f305f319ab..5fa2713295 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "methods": "1.1.2", "moment": "^2.22.1", "morgan": "1.9.0", - "ng2-nouislider": "1.7.8", + "ng2-nouislider": "^1.7.11", "ngx-pagination": "3.0.3", "nouislider": "^11.0.0", "pem": "1.12.3", diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html index a3ee3e436b..c20cc750b7 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -16,8 +16,11 @@
+ + + @@ -32,4 +35,4 @@
-
\ No newline at end of file +
diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 790ec93453..c8ea8c7587 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -1,4 +1,5 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; +import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core'; import { FilterType } from '../../../search-service/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; @@ -36,6 +37,7 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple protected router: Router, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @Inject(SELECTED_VALUES) public selectedValues: string[], + @Inject(PLATFORM_ID) private platformId: any, private route: ActivatedRoute) { super(searchService, filterService, router, filterConfig, selectedValues); } @@ -83,4 +85,11 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple } } + /** + * TODO when upgrading nouislider, verify that this check is still needed. + */ + shouldShowSlider(): boolean { + return isPlatformBrowser(this.platformId); + } + } diff --git a/yarn.lock b/yarn.lock index fd03a7c8ed..14db817837 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5591,9 +5591,9 @@ netmask@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" -ng2-nouislider@1.7.8: - version "1.7.8" - resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.7.8.tgz#5fd6de120f9ca5b5d9c4b377f884944b74c06855" +ng2-nouislider@^1.7.11: + version "1.7.11" + resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.7.11.tgz#b8ba5e3d2ffc23e1e32dfe54dd1726e2b4be316b" ngrx-store-freeze@^0.2.1: version "0.2.1"