62355: replaced all method calls in templates (except for metadata values...)

This commit is contained in:
lotte
2019-06-14 16:15:45 +02:00
parent e179596ac2
commit 37fd04593b
35 changed files with 166 additions and 130 deletions

View File

@@ -17,7 +17,7 @@
</div> </div>
<ds-input-suggestions [suggestions]="(filterSearchResults | async)" <ds-input-suggestions [suggestions]="(filterSearchResults | async)"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate" [placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
[action]="getCurrentUrl()" [action]="currentUrl"
[name]="filterConfig.paramName" [name]="filterConfig.paramName"
[(ngModel)]="filter" [(ngModel)]="filter"
(submitSuggestion)="onSubmit($event)" (submitSuggestion)="onSubmit($event)"

View File

@@ -1,5 +1,5 @@
<a *ngIf="isVisible | async" class="d-flex flex-row" <a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[searchLink]"
[queryParams]="addQueryParams" queryParamsHandling="merge"> [queryParams]="addQueryParams" queryParamsHandling="merge">
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
<span class="filter-value px-1">{{filterValue.value}}</span> <span class="filter-value px-1">{{filterValue.value}}</span>

View File

@@ -50,6 +50,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
*/ */
addQueryParams; addQueryParams;
searchLink: string;
/** /**
* Subscription to unsubscribe from on destroy * Subscription to unsubscribe from on destroy
*/ */
@@ -66,6 +67,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
* Initializes all observable instance variables and starts listening to them * Initializes all observable instance variables and starts listening to them
*/ */
ngOnInit(): void { ngOnInit(): void {
this.searchLink = this.getSearchLink();
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked)); this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
this.sub = observableCombineLatest(this.selectedValues$, this.searchConfigService.searchOptions) this.sub = observableCombineLatest(this.selectedValues$, this.searchConfigService.searchOptions)
.subscribe(([selectedValues, searchOptions]) => { .subscribe(([selectedValues, searchOptions]) => {
@@ -83,7 +85,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
public getSearchLink(): string { private getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -1,5 +1,5 @@
<a *ngIf="isVisible | async" class="d-flex flex-row" <a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[searchLink]"
[queryParams]="changeQueryParams" queryParamsHandling="merge"> [queryParams]="changeQueryParams" queryParamsHandling="merge">
<span class="filter-value px-1">{{filterValue.label}}</span> <span class="filter-value px-1">{{filterValue.label}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">

View File

@@ -55,6 +55,8 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
*/ */
sub: Subscription; sub: Subscription;
searchLink: string;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
protected filterService: SearchFilterService, protected filterService: SearchFilterService,
protected searchConfigService: SearchConfigurationService, protected searchConfigService: SearchConfigurationService,
@@ -66,6 +68,7 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
* Initializes all observable instance variables and starts listening to them * Initializes all observable instance variables and starts listening to them
*/ */
ngOnInit(): void { ngOnInit(): void {
this.searchLink = this.getSearchLink();
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked)); this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
this.sub = this.searchConfigService.searchOptions.subscribe(() => { this.sub = this.searchConfigService.searchOptions.subscribe(() => {
this.updateChangeParams() this.updateChangeParams()
@@ -82,7 +85,7 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
public getSearchLink(): string { private getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -1,5 +1,5 @@
<a class="d-flex flex-row" <a class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[searchLink]"
[queryParams]="removeQueryParams" queryParamsHandling="merge"> [queryParams]="removeQueryParams" queryParamsHandling="merge">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
<span class="filter-value pl-1 text-capitalize">{{selectedValue.label}}</span> <span class="filter-value pl-1 text-capitalize">{{selectedValue.label}}</span>

View File

@@ -49,6 +49,8 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
*/ */
sub: Subscription; sub: Subscription;
searchLink: string;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
protected filterService: SearchFilterService, protected filterService: SearchFilterService,
protected searchConfigService: SearchConfigurationService, protected searchConfigService: SearchConfigurationService,
@@ -64,12 +66,13 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
.subscribe(([selectedValues, searchOptions]) => { .subscribe(([selectedValues, searchOptions]) => {
this.updateRemoveParams(selectedValues) this.updateRemoveParams(selectedValues)
}); });
this.searchLink = this.getSearchLink();
} }
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
public getSearchLink(): string { private getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -80,6 +80,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
*/ */
searchOptions$: Observable<SearchOptions>; searchOptions$: Observable<SearchOptions>;
/**
* The current URL
*/
currentUrl: string;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
protected filterService: SearchFilterService, protected filterService: SearchFilterService,
protected rdbs: RemoteDataBuildService, protected rdbs: RemoteDataBuildService,
@@ -93,6 +98,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
* Initializes all observable instance variables and starts listening to them * Initializes all observable instance variables and starts listening to them
*/ */
ngOnInit(): void { ngOnInit(): void {
this.currentUrl = this.router.url;
this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined)); this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined));
this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged()); this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged());
@@ -215,13 +221,6 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
return this.filterService.getPage(this.filterConfig.name); return this.filterService.getPage(this.filterConfig.name);
} }
/**
* @returns {string} the current URL
*/
getCurrentUrl() {
return this.router.url;
}
/** /**
* Submits a new active custom value to the filter from the input field * Submits a new active custom value to the filter from the input field
* @param data The string from the input field * @param data The string from the input field

View File

@@ -1,5 +1,5 @@
import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
import { mergeMap, map, distinctUntilChanged } from 'rxjs/operators'; import { distinctUntilChanged, map, mergeMap } from 'rxjs/operators';
import { Injectable, InjectionToken } from '@angular/core'; import { Injectable, InjectionToken } from '@angular/core';
import { SearchFiltersState, SearchFilterState } from './search-filter.reducer'; import { SearchFiltersState, SearchFilterState } from './search-filter.reducer';
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
@@ -17,12 +17,8 @@ import { SearchFilterConfig } from '../../search-service/search-filter-config.mo
import { RouteService } from '../../../shared/services/route.service'; import { RouteService } from '../../../shared/services/route.service';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { SearchOptions } from '../../search-options.model';
import { PaginatedSearchOptions } from '../../paginated-search-options.model';
import { SearchFixedFilterService } from './search-fixed-filter.service'; import { SearchFixedFilterService } from './search-fixed-filter.service';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import * as postcss from 'postcss';
import prefix = postcss.vendor.prefix;
// const spy = create(); // const spy = create();
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter; const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;

View File

@@ -17,7 +17,7 @@
</div> </div>
<ds-input-suggestions [suggestions]="(filterSearchResults | async)" <ds-input-suggestions [suggestions]="(filterSearchResults | async)"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate" [placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
[action]="getCurrentUrl()" [action]="currentUrl"
[name]="filterConfig.paramName" [name]="filterConfig.paramName"
[(ngModel)]="filter" [(ngModel)]="filter"
(submitSuggestion)="onSubmit($event)" (submitSuggestion)="onSubmit($event)"

View File

@@ -1,7 +1,7 @@
<div> <div>
<div class="filters py-2"> <div class="filters py-2">
<form #form="ngForm" (ngSubmit)="onSubmit()" class="add-filter row" <form #form="ngForm" (ngSubmit)="onSubmit()" class="add-filter row"
[action]="getCurrentUrl()"> [action]="currentUrl">
<div class="col-6"> <div class="col-6">
<input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'" <input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'"
class="form-control" (blur)="onSubmit()" class="form-control" (blur)="onSubmit()"

View File

@@ -17,7 +17,7 @@
</div> </div>
<ds-input-suggestions [suggestions]="(filterSearchResults | async)" <ds-input-suggestions [suggestions]="(filterSearchResults | async)"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate" [placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
[action]="getCurrentUrl()" [action]="currentUrl"
[name]="filterConfig.paramName" [name]="filterConfig.paramName"
[(ngModel)]="filter" [(ngModel)]="filter"
(submitSuggestion)="onSubmit($event)" (submitSuggestion)="onSubmit($event)"

View File

@@ -4,4 +4,4 @@
<ds-search-filter [filter]="filter" [inPlaceSearch]="inPlaceSearch"></ds-search-filter> <ds-search-filter [filter]="filter" [inPlaceSearch]="inPlaceSearch"></ds-search-filter>
</div> </div>
</div> </div>
<a class="btn btn-primary" [routerLink]="[getSearchLink()]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a> <a class="btn btn-primary" [routerLink]="[searchLink]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a>

View File

@@ -37,6 +37,8 @@ export class SearchFiltersComponent implements OnInit {
*/ */
@Input() inPlaceSearch; @Input() inPlaceSearch;
searchLink: string;
/** /**
* Initialize instance variables * Initialize instance variables
* @param {SearchService} searchService * @param {SearchService} searchService
@@ -60,12 +62,13 @@ export class SearchFiltersComponent implements OnInit {
Object.keys(filters).forEach((f) => filters[f] = null); Object.keys(filters).forEach((f) => filters[f] = null);
return filters; return filters;
})); }));
this.searchLink = this.getSearchLink();
} }
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
public getSearchLink(): string { private getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -0,0 +1,6 @@
<a class="badge badge-primary mr-1 mb-1 text-capitalize"
[routerLink]="searchLink"
[queryParams]="(removeParameters | async)" queryParamsHandling="merge">
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(value)}}
<span> ×</span>
</a>

View File

@@ -0,0 +1,75 @@
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Params } from '@angular/router';
import { SearchService } from '../../search-service/search.service';
import { map } from 'rxjs/operators';
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
@Component({
selector: 'ds-search-label',
templateUrl: './search-label.component.html',
})
/**
* Component that represents the labels containing the currently active filters
*/
export class SearchLabelComponent implements OnInit {
@Input() key: string;
@Input() value: string;
@Input() inPlaceSearch: boolean;
@Input() appliedFilters: Observable<Params>;
searchLink: string;
removeParameters: Observable<Params>;
/**
* Initialize the instance variable
*/
constructor(
private searchService: SearchService) {
}
ngOnInit(): void {
this.searchLink = this.getSearchLink();
this.removeParameters = this.getRemoveParams();
}
/**
* Calculates the parameters that should change if a given value for the given filter would be removed from the active filters
* @returns {Observable<Params>} The changed filter parameters
*/
getRemoveParams(): Observable<Params> {
return this.appliedFilters.pipe(
map((filters) => {
const field: string = Object.keys(filters).find((f) => f === this.key);
const newValues = hasValue(filters[field]) ? filters[field].filter((v) => v !== this.value) : null;
return {
[field]: isNotEmpty(newValues) ? newValues : null,
page: 1
};
})
)
}
/**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/
private getSearchLink(): string {
if (this.inPlaceSearch) {
return './';
}
return this.searchService.getSearchLink();
}
/**
* TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved
* Strips authority operator from filter value
* e.g. 'test ,authority' => 'test'
*
* @param value
*/
normalizeFilterValue(value: string) {
// const pattern = /,[^,]*$/g;
const pattern = /,authority*$/g;
return value.replace(pattern, '');
}
}

View File

@@ -1,13 +1,7 @@
<div class="row mb-3 mb-md-1"> <div class="row mb-3 mb-md-1">
<div class="labels col-sm-9 offset-sm-3"> <div class="labels col-sm-9 offset-sm-3">
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)"><!--Do not remove this to prevent uneven spacing <ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)">
--><a *ngFor="let values of (appliedFilters | async)[key]" <ds-search-label *ngFor="let value of (appliedFilters | async)[key]" [inPlaceSearch]="inPlaceSearch" [key]="key" [value]="value" [appliedFilters]="appliedFilters"></ds-search-label>
class="badge badge-primary mr-1 mb-1 text-capitalize" </ng-container>
[routerLink]="getSearchLink()"
[queryParams]="(getRemoveParams(key, values) | async)" queryParamsHandling="merge">
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(values)}}
<span> ×</span>
</a><!--Do not remove this to prevent uneven spacing
--></ng-container>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { Component, Inject, Input } from '@angular/core'; import { Component, Inject, Input, OnInit } from '@angular/core';
import { SearchService } from '../search-service/search.service'; import { SearchService } from '../search-service/search.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
@@ -31,50 +31,7 @@ export class SearchLabelsComponent {
* Initialize the instance variable * Initialize the instance variable
*/ */
constructor( constructor(
private searchService: SearchService,
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) { @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters(); this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters();
} }
/**
* Calculates the parameters that should change if a given value for the given filter would be removed from the active filters
* @param {string} filterField The filter field parameter name from which the value should be removed
* @param {string} filterValue The value that is removed for this given filter field
* @returns {Observable<Params>} The changed filter parameters
*/
getRemoveParams(filterField: string, filterValue: string): Observable<Params> {
return this.appliedFilters.pipe(
map((filters) => {
const field: string = Object.keys(filters).find((f) => f === filterField);
const newValues = hasValue(filters[field]) ? filters[field].filter((v) => v !== filterValue) : null;
return {
[field]: isNotEmpty(newValues) ? newValues : null,
page: 1
};
})
)
}
/**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/
public getSearchLink(): string {
if (this.inPlaceSearch) {
return './';
}
return this.searchService.getSearchLink();
}
/**
* TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved
* Strips authority operator from filter value
* e.g. 'test ,authority' => 'test'
*
* @param value
*/
normalizeFilterValue(value: string) {
// const pattern = /,[^,]*$/g;
const pattern = /,authority*$/g;
return value.replace(pattern, '');
}
} }

View File

@@ -7,7 +7,7 @@
<ds-search-form *ngIf="searchEnabled" id="search-form" <ds-search-form *ngIf="searchEnabled" id="search-form"
[query]="(searchOptions$ | async)?.query" [query]="(searchOptions$ | async)?.query"
[scope]="(searchOptions$ | async)?.scope" [scope]="(searchOptions$ | async)?.scope"
[currentUrl]="getSearchLink()" [currentUrl]="searchLink"
[scopes]="(scopeListRD$ | async)" [scopes]="(scopeListRD$ | async)"
[inPlaceSearch]="inPlaceSearch"> [inPlaceSearch]="inPlaceSearch">
</ds-search-form> </ds-search-form>
@@ -15,12 +15,12 @@
<div class="row"> <div class="row">
<div id="search-body" <div id="search-body"
class="row-offcanvas row-offcanvas-left" class="row-offcanvas row-offcanvas-left"
[@pushInOut]="(isSidebarCollapsed() | async) ? 'collapsed' : 'expanded'"> [@pushInOut]="(isSidebarCollapsed$ | async) ? 'collapsed' : 'expanded'">
<ds-search-sidebar *ngIf="(isXsOrSm$ | async)" class="col-12" <ds-search-sidebar *ngIf="(isXsOrSm$ | async)" class="col-12"
id="search-sidebar-sm" id="search-sidebar-sm"
[resultCount]="(resultsRD$ | async)?.payload.totalElements" [resultCount]="(resultsRD$ | async)?.payload.totalElements"
(toggleSidebar)="closeSidebar()" (toggleSidebar)="closeSidebar()"
[ngClass]="{'active': !(isSidebarCollapsed() | async)}"> [ngClass]="{'active': !(isSidebarCollapsed$ | async)}">
</ds-search-sidebar> </ds-search-sidebar>
<div id="search-content" class="col-12"> <div id="search-content" class="col-12">
<div class="d-block d-md-none search-controls clearfix"> <div class="d-block d-md-none search-controls clearfix">

View File

@@ -91,6 +91,9 @@ export class SearchPageComponent implements OnInit {
@Input() @Input()
fixedFilter$: Observable<string>; fixedFilter$: Observable<string>;
searchLink: string;
isSidebarCollapsed$: Observable<boolean>;
constructor(protected service: SearchService, constructor(protected service: SearchService,
protected sidebarService: SearchSidebarService, protected sidebarService: SearchSidebarService,
protected windowService: HostWindowService, protected windowService: HostWindowService,
@@ -107,6 +110,8 @@ export class SearchPageComponent implements OnInit {
* If something changes, update the list of scopes for the dropdown * If something changes, update the list of scopes for the dropdown
*/ */
ngOnInit(): void { ngOnInit(): void {
this.isSidebarCollapsed$ = this.isSidebarCollapsed();
this.searchLink = this.getSearchLink();
this.searchOptions$ = this.getSearchOptions(); this.searchOptions$ = this.getSearchOptions();
this.sub = this.searchOptions$.pipe( this.sub = this.searchOptions$.pipe(
switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData(), startWith(observableOf(undefined))))) switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData(), startWith(observableOf(undefined)))))
@@ -147,14 +152,14 @@ export class SearchPageComponent implements OnInit {
* Check if the sidebar is collapsed * Check if the sidebar is collapsed
* @returns {Observable<boolean>} emits true if the sidebar is currently collapsed, false if it is expanded * @returns {Observable<boolean>} emits true if the sidebar is currently collapsed, false if it is expanded
*/ */
public isSidebarCollapsed(): Observable<boolean> { private isSidebarCollapsed(): Observable<boolean> {
return this.sidebarService.isCollapsed; return this.sidebarService.isCollapsed;
} }
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
public getSearchLink(): string { private getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -32,6 +32,7 @@ import { SearchFacetSelectedOptionComponent } from './search-filters/search-filt
import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component'; import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component';
import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component'; import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component';
import { SearchAuthorityFilterComponent } from './search-filters/search-filter/search-authority-filter/search-authority-filter.component'; import { SearchAuthorityFilterComponent } from './search-filters/search-filter/search-authority-filter/search-authority-filter.component';
import { SearchLabelComponent } from './search-labels/search-label/search-label.component';
const effects = [ const effects = [
SearchSidebarEffects SearchSidebarEffects
@@ -49,6 +50,7 @@ const components = [
SearchFilterComponent, SearchFilterComponent,
SearchFacetFilterComponent, SearchFacetFilterComponent,
SearchLabelsComponent, SearchLabelsComponent,
SearchLabelComponent,
SearchFacetFilterComponent, SearchFacetFilterComponent,
SearchFacetFilterWrapperComponent, SearchFacetFilterWrapperComponent,
SearchRangeFilterComponent, SearchRangeFilterComponent,

View File

@@ -1 +1 @@
<ng-container *ngComponentOutlet="getComponent(); injector: objectInjector;"></ng-container> <ng-container *ngComponentOutlet="component; injector: objectInjector;"></ng-container>

View File

@@ -32,6 +32,8 @@ export class ItemTypeSwitcherComponent implements OnInit {
*/ */
objectInjector: Injector; objectInjector: Injector;
component: any;
constructor(private injector: Injector) { constructor(private injector: Injector) {
} }
@@ -40,14 +42,14 @@ export class ItemTypeSwitcherComponent implements OnInit {
providers: [{ provide: ITEM, useFactory: () => this.object, deps:[] }], providers: [{ provide: ITEM, useFactory: () => this.object, deps:[] }],
parent: this.injector parent: this.injector
}); });
this.component = this.getComponent();
} }
/** /**
* Fetch the component depending on the item's relationship type * Fetch the component depending on the item's relationship type
* @returns {string} * @returns {string}
*/ */
getComponent(): string { private getComponent(): string {
if (hasValue((this.object as any).representationType)) { if (hasValue((this.object as any).representationType)) {
const metadataRepresentation = this.object as MetadataRepresentation; const metadataRepresentation = this.object as MetadataRepresentation;
return getComponentByItemType(metadataRepresentation.itemType, this.viewMode, metadataRepresentation.representationType); return getComponentByItemType(metadataRepresentation.itemType, this.viewMode, metadataRepresentation.representationType);

View File

@@ -8,7 +8,7 @@
(pageSizeChange)="onPageSizeChange($event)" (pageSizeChange)="onPageSizeChange($event)"
(sortDirectionChange)="onSortDirectionChange($event)" (sortDirectionChange)="onSortDirectionChange($event)"
(sortFieldChange)="onSortFieldChange($event)" (sortFieldChange)="onSortFieldChange($event)"
*ngIf="getViewMode()===viewModeEnum.List"> *ngIf="(currentMode$ | async) === viewModeEnum.List">
</ds-object-list> </ds-object-list>
<ds-object-grid [config]="config" <ds-object-grid [config]="config"
@@ -20,14 +20,14 @@
(pageSizeChange)="onPageSizeChange($event)" (pageSizeChange)="onPageSizeChange($event)"
(sortDirectionChange)="onSortDirectionChange($event)" (sortDirectionChange)="onSortDirectionChange($event)"
(sortFieldChange)="onSortFieldChange($event)" (sortFieldChange)="onSortFieldChange($event)"
*ngIf="getViewMode()===viewModeEnum.Grid"> *ngIf="(currentMode$ | async) === viewModeEnum.Grid">
</ds-object-grid> </ds-object-grid>
<ds-object-detail [config]="config" <ds-object-detail [config]="config"
[sortConfig]="sortConfig" [sortConfig]="sortConfig"
[objects]="objects" [objects]="objects"
[hideGear]="hideGear" [hideGear]="hideGear"
*ngIf="getViewMode()===viewModeEnum.Detail"> *ngIf="(currentMode$ | async) === viewModeEnum.Detail">
</ds-object-detail> </ds-object-detail>

View File

@@ -1,10 +1,8 @@
import { ObjectCollectionComponent } from './object-collection.component'; import { ObjectCollectionComponent } from './object-collection.component';
import { SetViewMode } from '../view-mode'; import { SetViewMode } from '../view-mode';
import { element } from 'protractor';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Config } from '../../../config/config.interface'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { RouterStub } from '../testing/router-stub'; import { RouterStub } from '../testing/router-stub';
@@ -38,14 +36,14 @@ describe('ObjectCollectionComponent', () => {
})); }));
it('should only show the grid component when the viewmode is set to grid', () => { it('should only show the grid component when the viewmode is set to grid', () => {
objectCollectionComponent.currentMode = SetViewMode.Grid; objectCollectionComponent.currentMode$ = observableOf(SetViewMode.Grid);
expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeDefined(); expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeDefined();
expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeNull(); expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeNull();
}); });
it('should only show the list component when the viewmode is set to list', () => { it('should only show the list component when the viewmode is set to list', () => {
objectCollectionComponent.currentMode = SetViewMode.List; objectCollectionComponent.currentMode$ = observableOf(SetViewMode.List);
expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeDefined(); expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeDefined();
expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeNull(); expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeNull();

View File

@@ -11,7 +11,7 @@ import {
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { filter, map, startWith } from 'rxjs/operators';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { PageInfo } from '../../core/shared/page-info.model'; import { PageInfo } from '../../core/shared/page-info.model';
@@ -19,14 +19,14 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { ListableObject } from './shared/listable-object.model'; import { ListableObject } from './shared/listable-object.model';
import { SetViewMode } from '../view-mode'; import { SetViewMode } from '../view-mode';
import { hasValue, isNotEmpty } from '../empty.util'; import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
@Component({ @Component({
selector: 'ds-viewable-collection', selector: 'ds-viewable-collection',
styleUrls: ['./object-collection.component.scss'], styleUrls: ['./object-collection.component.scss'],
templateUrl: './object-collection.component.html', templateUrl: './object-collection.component.html',
}) })
export class ObjectCollectionComponent implements OnChanges, OnInit { export class ObjectCollectionComponent implements OnInit {
@Input() objects: RemoteData<ListableObject[]>; @Input() objects: RemoteData<ListableObject[]>;
@Input() config?: PaginationComponentOptions; @Input() config?: PaginationComponentOptions;
@@ -34,7 +34,6 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
@Input() hasBorder = false; @Input() hasBorder = false;
@Input() hideGear = false; @Input() hideGear = false;
pageInfo: Observable<PageInfo>; pageInfo: Observable<PageInfo>;
private sub;
/** /**
* An event fired when the page is changed. * An event fired when the page is changed.
* Event's payload equals to the newly selected page. * Event's payload equals to the newly selected page.
@@ -61,25 +60,17 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
*/ */
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>(); @Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
data: any = {}; data: any = {};
currentMode: SetViewMode = SetViewMode.List; currentMode$: Observable<SetViewMode>;
viewModeEnum = SetViewMode; viewModeEnum = SetViewMode;
ngOnChanges(changes: SimpleChanges) {
if (changes.objects && !changes.objects.isFirstChange()) {
// this.pageInfo = this.objects.pageInfo;
}
}
ngOnInit(): void { ngOnInit(): void {
// this.pageInfo = this.objects.pageInfo; this.currentMode$ = this.route
this.sub = this.route
.queryParams .queryParams
.subscribe((params) => { .pipe(
if (isNotEmpty(params.view)) { filter((params) => isNotEmpty(params.view)),
this.currentMode = params.view; map((params) => params.view),
} startWith(SetViewMode.List)
}); );
} }
/** /**
@@ -96,15 +87,6 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
private router: Router) { private router: Router) {
} }
getViewMode(): SetViewMode {
this.route.queryParams.pipe(map((params) => {
if (isNotEmpty(params.view) && hasValue(params.view)) {
this.currentMode = params.view;
}
}));
return this.currentMode;
}
onPageChange(event) { onPageChange(event) {
this.pageChange.emit(event); this.pageChange.emit(event);
} }

View File

@@ -1 +1 @@
<ng-container *ngComponentOutlet="getDetailElement(); injector: objectInjector;"></ng-container> <ng-container *ngComponentOutlet="detailElement; injector: objectInjector;"></ng-container>

View File

@@ -26,6 +26,8 @@ export class WrapperDetailElementComponent implements OnInit {
*/ */
objectInjector: Injector; objectInjector: Injector;
detailElement: any;
/** /**
* Initialize instance variables * Initialize instance variables
* *
@@ -42,13 +44,13 @@ export class WrapperDetailElementComponent implements OnInit {
providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }], providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }],
parent: this.injector parent: this.injector
}); });
this.detailElement = this.getDetailElement();
} }
/** /**
* Return class name for the object to inject * Return class name for the object to inject
*/ */
getDetailElement(): string { private getDetailElement(): string {
const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>; const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>;
return rendersDSOType(f, SetViewMode.Detail); return rendersDSOType(f, SetViewMode.Detail);
} }

View File

@@ -1,5 +1,5 @@
<ds-truncatable [id]="dso.id"> <ds-truncatable [id]="dso.id">
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'"> <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width"> <a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div> <div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail()"> <ds-grid-thumbnail [thumbnail]="dso.getThumbnail()">

View File

@@ -15,10 +15,12 @@ import { Metadata } from '../../../core/shared/metadata.utils';
export class SearchResultGridElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> { export class SearchResultGridElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> {
dso: K; dso: K;
isCollapsed$: Observable<boolean>;
public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, private truncatableService: TruncatableService) { public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, private truncatableService: TruncatableService) {
super(listableObject); super(listableObject);
this.dso = this.object.indexableObject; this.dso = this.object.indexableObject;
this.isCollapsed$ = this.isCollapsed();
} }
/** /**
@@ -41,7 +43,7 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
} }
isCollapsed(): Observable<boolean> { private isCollapsed(): Observable<boolean> {
return this.truncatableService.isCollapsed(this.dso.id); return this.truncatableService.isCollapsed(this.dso.id);
} }

View File

@@ -1 +1 @@
<ng-container *ngComponentOutlet="getGridElement(); injector: objectInjector;"></ng-container> <ng-container *ngComponentOutlet="gridElement; injector: objectInjector;"></ng-container>

View File

@@ -12,6 +12,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m
export class WrapperGridElementComponent implements OnInit { export class WrapperGridElementComponent implements OnInit {
@Input() object: ListableObject; @Input() object: ListableObject;
objectInjector: Injector; objectInjector: Injector;
gridElement: any;
constructor(private injector: Injector) { constructor(private injector: Injector) {
} }
@@ -21,7 +22,7 @@ export class WrapperGridElementComponent implements OnInit {
providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }], providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }],
parent: this.injector parent: this.injector
}); });
this.gridElement = this.getGridElement();
} }
getGridElement(): string { getGridElement(): string {

View File

@@ -8,6 +8,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
import { TruncatableService } from '../../truncatable/truncatable.service'; import { TruncatableService } from '../../truncatable/truncatable.service';
import { Metadata } from '../../../core/shared/metadata.utils'; import { Metadata } from '../../../core/shared/metadata.utils';
import { MetadataMap } from '../../../core/shared/metadata.models';
@Component({ @Component({
selector: 'ds-search-result-list-element', selector: 'ds-search-result-list-element',
@@ -16,6 +17,7 @@ import { Metadata } from '../../../core/shared/metadata.utils';
export class SearchResultListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> { export class SearchResultListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> {
dso: K; dso: K;
metadata: MetadataMap;
public constructor(@Inject('objectElementProvider') public listable: ListableObject, protected truncatableService: TruncatableService) { public constructor(@Inject('objectElementProvider') public listable: ListableObject, protected truncatableService: TruncatableService) {
super(listable); super(listable);

View File

@@ -1 +1 @@
<ng-container *ngComponentOutlet="getListElement(); injector: objectInjector;"></ng-container> <ng-container *ngComponentOutlet="listElement; injector: objectInjector;"></ng-container>

View File

@@ -13,6 +13,7 @@ export class WrapperListElementComponent implements OnInit {
@Input() object: ListableObject; @Input() object: ListableObject;
@Input() index: number; @Input() index: number;
objectInjector: Injector; objectInjector: Injector;
listElement: any;
constructor(private injector: Injector) {} constructor(private injector: Injector) {}
@@ -24,9 +25,10 @@ export class WrapperListElementComponent implements OnInit {
], ],
parent: this.injector parent: this.injector
}); });
this.listElement = this.getListElement();
} }
getListElement(): string { private getListElement(): string {
const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>; const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>;
return rendersDSOType(f, SetViewMode.List); return rendersDSOType(f, SetViewMode.List);
} }