mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
49440: date widget with decorator
This commit is contained in:
@@ -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",
|
||||
|
@@ -0,0 +1 @@
|
||||
<ng-container *ngComponentOutlet="getSearchFilter(); injector: objectInjector;"></ng-container>
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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<Observable<RemoteData<PaginatedList<FacetValue>>>> = [];
|
||||
filterValues$: BehaviorSubject<any> = new BehaviorSubject(this.filterValues);
|
||||
currentPage: Observable<number>;
|
||||
@@ -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 {
|
||||
|
@@ -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);
|
||||
}
|
@@ -2,6 +2,6 @@
|
||||
<div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fa float-right"
|
||||
[ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div>
|
||||
<div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" class="search-filter-wrapper">
|
||||
<ds-search-facet-filter [filterConfig]="filter" [selectedValues]="getSelectedValues() | async"></ds-search-facet-filter>
|
||||
<ds-search-facet-filter-wrapper [filterConfig]="filter" [selectedValues]="getSelectedValues() | async"></ds-search-facet-filter-wrapper>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,21 @@
|
||||
<div>
|
||||
<div class="filters">
|
||||
<form #form="ngForm" (ngSubmit)="onSubmit(form.value)" class="add-filter row"
|
||||
[action]="getCurrentUrl()">
|
||||
<input type="text" [(ngModel)]="min" [name]="filterConfig.paramName + 'min'" class="form-control col-6"
|
||||
aria-label="Mininum value"
|
||||
[placeholder]="'search.filters.filter.' + filterConfig.name + '.min.placeholder'| translate"/>
|
||||
<input type="text" [(ngModel)]="max" [name]="filterConfig.paramName + 'max'" class="form-control col-6"
|
||||
aria-label="Maximum value"
|
||||
[placeholder]="'search.filters.filter.' + filterConfig.name + '.max.placeholder'| translate"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
</form>
|
||||
<nouislider [connect]="true" [min]="rangeMin" [max]="rangeMax" [step]="1" [(ngModel)]="range"></nouislider>
|
||||
<a *ngFor="let value of selectedValues" class="d-block"
|
||||
[routerLink]="[getSearchLink()]"
|
||||
[queryParams]="getQueryParamsWithout(value) | async">
|
||||
<input type="checkbox" [checked]="true"/>
|
||||
<span class="filter-value">{{value}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
@@ -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];
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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<number>;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.currentPage = this.filterService.getPage(this.filterConfig.name);
|
||||
}
|
||||
|
||||
isChecked(value: FacetValue): Observable<boolean> {
|
||||
return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, value.value);
|
||||
}
|
||||
|
||||
get facetCount(): Observable<number> {
|
||||
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<number> {
|
||||
return this.filterService.getPage(this.filterConfig.name);
|
||||
}
|
||||
}
|
@@ -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 {
|
||||
|
@@ -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 {
|
||||
|
@@ -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 = [
|
||||
|
@@ -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"
|
||||
|
Reference in New Issue
Block a user