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"