mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
49440: date widget with decorator
This commit is contained in:
@@ -102,7 +102,9 @@
|
|||||||
"jsonschema": "1.2.2",
|
"jsonschema": "1.2.2",
|
||||||
"methods": "1.1.2",
|
"methods": "1.1.2",
|
||||||
"morgan": "1.9.0",
|
"morgan": "1.9.0",
|
||||||
|
"ng2-nouislider": "^1.7.7",
|
||||||
"ngx-pagination": "3.0.3",
|
"ngx-pagination": "3.0.3",
|
||||||
|
"nouislider": "^10.0.0",
|
||||||
"pem": "1.12.3",
|
"pem": "1.12.3",
|
||||||
"reflect-metadata": "0.1.12",
|
"reflect-metadata": "0.1.12",
|
||||||
"rxjs": "5.5.6",
|
"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 { FacetValue } from '../../../search-service/facet-value.model';
|
||||||
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
|
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
@@ -20,13 +20,10 @@ import { Subscription } from 'rxjs/Subscription';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-facet-filter',
|
selector: 'ds-search-facet-filter',
|
||||||
styleUrls: ['./search-facet-filter.component.scss'],
|
template: ``,
|
||||||
templateUrl: './search-facet-filter.component.html'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
||||||
@Input() filterConfig: SearchFilterConfig;
|
|
||||||
@Input() selectedValues: string[];
|
|
||||||
filterValues: Array<Observable<RemoteData<PaginatedList<FacetValue>>>> = [];
|
filterValues: Array<Observable<RemoteData<PaginatedList<FacetValue>>>> = [];
|
||||||
filterValues$: BehaviorSubject<any> = new BehaviorSubject(this.filterValues);
|
filterValues$: BehaviorSubject<any> = new BehaviorSubject(this.filterValues);
|
||||||
currentPage: Observable<number>;
|
currentPage: Observable<number>;
|
||||||
@@ -35,7 +32,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
|||||||
pageChange = false;
|
pageChange = false;
|
||||||
sub: Subscription;
|
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 {
|
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"
|
<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>
|
[ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div>
|
||||||
<div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" class="search-filter-wrapper">
|
<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>
|
||||||
</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 { SearchFilterComponent } from './search-filters/search-filter/search-filter.component';
|
||||||
import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-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 { 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 = [
|
const effects = [
|
||||||
SearchSidebarEffects
|
SearchSidebarEffects
|
||||||
@@ -46,7 +49,10 @@ const effects = [
|
|||||||
CommunitySearchResultListElementComponent,
|
CommunitySearchResultListElementComponent,
|
||||||
SearchFiltersComponent,
|
SearchFiltersComponent,
|
||||||
SearchFilterComponent,
|
SearchFilterComponent,
|
||||||
SearchFacetFilterComponent
|
SearchFacetFilterComponent,
|
||||||
|
SearchFacetFilterWrapperComponent,
|
||||||
|
SearchDateFilterComponent,
|
||||||
|
SearchTextFilterComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SearchService,
|
SearchService,
|
||||||
@@ -60,6 +66,8 @@ const effects = [
|
|||||||
ItemSearchResultGridElementComponent,
|
ItemSearchResultGridElementComponent,
|
||||||
CollectionSearchResultGridElementComponent,
|
CollectionSearchResultGridElementComponent,
|
||||||
CommunitySearchResultGridElementComponent,
|
CommunitySearchResultGridElementComponent,
|
||||||
|
SearchDateFilterComponent,
|
||||||
|
SearchTextFilterComponent,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SearchPageModule {
|
export class SearchPageModule {
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
@import '../styles/variables.scss';
|
@import '../styles/variables.scss';
|
||||||
@import '../../node_modules/bootstrap/scss/bootstrap.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";
|
@import "../../node_modules/font-awesome/scss/font-awesome.scss";
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { NouisliderModule } from 'ng2-nouislider';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
@@ -54,7 +54,8 @@ const MODULES = [
|
|||||||
NgxPaginationModule,
|
NgxPaginationModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
TranslateModule
|
TranslateModule,
|
||||||
|
NouisliderModule
|
||||||
];
|
];
|
||||||
|
|
||||||
const PIPES = [
|
const PIPES = [
|
||||||
|
@@ -5581,6 +5581,10 @@ netmask@~1.0.4:
|
|||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
|
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:
|
ngrx-store-freeze@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ngrx-store-freeze/-/ngrx-store-freeze-0.2.1.tgz#04fb29db33cafda0f2d6ea32adeaac4891b1b27b"
|
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"
|
query-string "^4.1.0"
|
||||||
sort-keys "^1.0.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:
|
npm-run-all@4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.2.tgz#90d62d078792d20669139e718621186656cea056"
|
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.2.tgz#90d62d078792d20669139e718621186656cea056"
|
||||||
|
Reference in New Issue
Block a user