Skip to content

Commit fad1a7a

Browse files
committed
Merge branch 'w2p-101127_browse-by-controlled-vocabulary' into w2p-101127_browse-by-controlled-vocabulary-7.6.0-next
Conflicts: src/app/browse-by/browse-by-routing.module.ts src/app/browse-by/browse-by.module.ts src/app/core/browse/browse-definition-data.service.ts src/app/core/core.module.ts
2 parents 0a2cc98 + 78d5116 commit fad1a7a

33 files changed

Lines changed: 549 additions & 99 deletions

src/app/browse-by/browse-by-guard.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { first } from 'rxjs/operators';
22
import { BrowseByGuard } from './browse-by-guard';
33
import { of as observableOf } from 'rxjs';
44
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
5-
import { BrowseDefinition } from '../core/shared/browse-definition.model';
65
import { BrowseByDataType } from './browse-by-switcher/browse-by-decorator';
6+
import { ValueListBrowseDefinition } from '../core/shared/value-list-browse-definition.model';
77

88
describe('BrowseByGuard', () => {
99
describe('canActivate', () => {
@@ -18,7 +18,7 @@ describe('BrowseByGuard', () => {
1818
const id = 'author';
1919
const scope = '1234-65487-12354-1235';
2020
const value = 'Filter';
21-
const browseDefinition = Object.assign(new BrowseDefinition(), { type: BrowseByDataType.Metadata, metadataKeys: ['dc.contributor'] });
21+
const browseDefinition = Object.assign(new ValueListBrowseDefinition(), { type: BrowseByDataType.Metadata, metadataKeys: ['dc.contributor'] });
2222

2323
beforeEach(() => {
2424
dsoService = {

src/app/browse-by/browse-by-routing.module.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { BrowseByDSOBreadcrumbResolver } from './browse-by-dso-breadcrumb.resolv
55
import { BrowseByI18nBreadcrumbResolver } from './browse-by-i18n-breadcrumb.resolver';
66
import { ThemedBrowseBySwitcherComponent } from './browse-by-switcher/themed-browse-by-switcher.component';
77
import { DSOEditMenuResolver } from '../shared/dso-page/dso-edit-menu.resolver';
8-
import { BrowseByTaxonomyPageComponent } from './browse-by-taxonomy-page/browse-by-taxonomy-page.component';
9-
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
108

119
@NgModule({
1210
imports: [
@@ -18,13 +16,6 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso
1816
menu: DSOEditMenuResolver
1917
},
2018
children: [
21-
{
22-
path: 'srsc',
23-
component: BrowseByTaxonomyPageComponent,
24-
canActivate: [BrowseByGuard],
25-
resolve: { breadcrumb: I18nBreadcrumbResolver },
26-
data: { title: 'browse.title.page', breadcrumbKey: 'browse.metadata.srsc' }
27-
},
2819
{
2920
path: ':id',
3021
component: ThemedBrowseBySwitcherComponent,

src/app/browse-by/browse-by-switcher/browse-by-decorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const map = new Map();
2626
* @param browseByType The type of page
2727
* @param theme The optional theme for the component
2828
*/
29-
export function rendersBrowseBy(browseByType: BrowseByDataType, theme = DEFAULT_THEME) {
29+
export function rendersBrowseBy(browseByType: string, theme = DEFAULT_THEME) {
3030
return function decorator(component: any) {
3131
if (hasNoValue(map.get(browseByType))) {
3232
map.set(browseByType, new Map());

src/app/browse-by/browse-by-switcher/browse-by-switcher.component.spec.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,45 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
33
import { NO_ERRORS_SCHEMA } from '@angular/core';
44
import { ActivatedRoute } from '@angular/router';
55
import { BROWSE_BY_COMPONENT_FACTORY, BrowseByDataType } from './browse-by-decorator';
6-
import { BrowseDefinition } from '../../core/shared/browse-definition.model';
76
import { BehaviorSubject } from 'rxjs';
87
import { ThemeService } from '../../shared/theme-support/theme.service';
8+
import { FlatBrowseDefinition } from '../../core/shared/flat-browse-definition.model';
9+
import { ValueListBrowseDefinition } from '../../core/shared/value-list-browse-definition.model';
10+
import { NonHierarchicalBrowseDefinition } from '../../core/shared/non-hierarchical-browse-definition';
911

1012
describe('BrowseBySwitcherComponent', () => {
1113
let comp: BrowseBySwitcherComponent;
1214
let fixture: ComponentFixture<BrowseBySwitcherComponent>;
1315

1416
const types = [
1517
Object.assign(
16-
new BrowseDefinition(), {
18+
new FlatBrowseDefinition(), {
1719
id: 'title',
1820
dataType: BrowseByDataType.Title,
1921
}
2022
),
2123
Object.assign(
22-
new BrowseDefinition(), {
24+
new FlatBrowseDefinition(), {
2325
id: 'dateissued',
2426
dataType: BrowseByDataType.Date,
2527
metadataKeys: ['dc.date.issued']
2628
}
2729
),
2830
Object.assign(
29-
new BrowseDefinition(), {
31+
new ValueListBrowseDefinition(), {
3032
id: 'author',
3133
dataType: BrowseByDataType.Metadata,
3234
}
3335
),
3436
Object.assign(
35-
new BrowseDefinition(), {
37+
new ValueListBrowseDefinition(), {
3638
id: 'subject',
3739
dataType: BrowseByDataType.Metadata,
3840
}
3941
),
4042
];
4143

42-
const data = new BehaviorSubject(createDataWithBrowseDefinition(new BrowseDefinition()));
44+
const data = new BehaviorSubject(createDataWithBrowseDefinition(new FlatBrowseDefinition()));
4345

4446
const activatedRouteStub = {
4547
data
@@ -70,7 +72,7 @@ describe('BrowseBySwitcherComponent', () => {
7072
comp = fixture.componentInstance;
7173
}));
7274

73-
types.forEach((type: BrowseDefinition) => {
75+
types.forEach((type: NonHierarchicalBrowseDefinition) => {
7476
describe(`when switching to a browse-by page for "${type.id}"`, () => {
7577
beforeEach(() => {
7678
data.next(createDataWithBrowseDefinition(type));

src/app/browse-by/browse-by-switcher/browse-by-switcher.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class BrowseBySwitcherComponent implements OnInit {
3131
*/
3232
ngOnInit(): void {
3333
this.browseByComponent = this.route.data.pipe(
34-
map((data: { browseDefinition: BrowseDefinition }) => this.getComponentByBrowseByType(data.browseDefinition.dataType, this.themeService.getThemeName()))
34+
map((data: { browseDefinition: BrowseDefinition }) => this.getComponentByBrowseByType(data.browseDefinition.getRenderType(), this.themeService.getThemeName()))
3535
);
3636
}
3737

src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
(deselect)="onDeselect($event)">
77
</ds-vocabulary-treeview>
88
</div>
9-
<a class="btn btn-primary" [routerLink]="['/search']" [queryParams]="{ 'f.subject': filterValues }">{{ 'browse.taxonomy.button' | translate }}</a>
9+
<a class="btn btn-primary" [routerLink]="['/search']" [queryParams]="queryParams">{{ 'browse.taxonomy.button' | translate }}</a>
1010
</div>

src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,36 @@ import { BrowseByTaxonomyPageComponent } from './browse-by-taxonomy-page.compone
44
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
55
import { TranslateModule } from '@ngx-translate/core';
66
import { NO_ERRORS_SCHEMA } from '@angular/core';
7+
import { ActivatedRoute } from '@angular/router';
8+
import { BehaviorSubject } from 'rxjs';
9+
import { createDataWithBrowseDefinition } from '../browse-by-switcher/browse-by-switcher.component.spec';
10+
import { HierarchicalBrowseDefinition } from '../../core/shared/hierarchical-browse-definition.model';
11+
import { ThemeService } from '../../shared/theme-support/theme.service';
712

813
describe('BrowseByTaxonomyPageComponent', () => {
914
let component: BrowseByTaxonomyPageComponent;
1015
let fixture: ComponentFixture<BrowseByTaxonomyPageComponent>;
16+
let themeService: ThemeService;
1117
let detail1: VocabularyEntryDetail;
1218
let detail2: VocabularyEntryDetail;
1319

20+
const data = new BehaviorSubject(createDataWithBrowseDefinition(new HierarchicalBrowseDefinition()));
21+
const activatedRouteStub = {
22+
data
23+
};
24+
1425
beforeEach(async () => {
26+
themeService = jasmine.createSpyObj('themeService', {
27+
getThemeName: 'dspace',
28+
});
29+
1530
await TestBed.configureTestingModule({
1631
imports: [ TranslateModule.forRoot() ],
1732
declarations: [ BrowseByTaxonomyPageComponent ],
33+
providers: [
34+
{ provide: ActivatedRoute, useValue: activatedRouteStub },
35+
{ provide: ThemeService, useValue: themeService },
36+
],
1837
schemas: [NO_ERRORS_SCHEMA]
1938
})
2039
.compileComponents();

src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.ts

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
import { Component, OnInit } from '@angular/core';
1+
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
22
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
33
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
4+
import { ActivatedRoute } from '@angular/router';
5+
import { Observable, Subscription } from 'rxjs';
6+
import { BrowseDefinition } from '../../core/shared/browse-definition.model';
7+
import { GenericConstructor } from '../../core/shared/generic-constructor';
8+
import { BROWSE_BY_COMPONENT_FACTORY } from '../browse-by-switcher/browse-by-decorator';
9+
import { map } from 'rxjs/operators';
10+
import { ThemeService } from 'src/app/shared/theme-support/theme.service';
11+
import { HierarchicalBrowseDefinition } from '../../core/shared/hierarchical-browse-definition.model';
412

513
@Component({
614
selector: 'ds-browse-by-taxonomy-page',
@@ -10,7 +18,7 @@ import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models
1018
/**
1119
* Component for browsing items by metadata in a hierarchical controlled vocabulary
1220
*/
13-
export class BrowseByTaxonomyPageComponent implements OnInit {
21+
export class BrowseByTaxonomyPageComponent implements OnInit, OnDestroy {
1422

1523
/**
1624
* The {@link VocabularyOptions} object
@@ -27,8 +35,48 @@ export class BrowseByTaxonomyPageComponent implements OnInit {
2735
*/
2836
filterValues: string[];
2937

30-
ngOnInit() {
31-
this.vocabularyOptions = { name: 'srsc', closed: true };
38+
/**
39+
* The facet the use when filtering
40+
*/
41+
facetType: string;
42+
43+
/**
44+
* The used vocabulary
45+
*/
46+
vocabularyName: string;
47+
48+
/**
49+
* The parameters used in the URL
50+
*/
51+
queryParams: any;
52+
53+
/**
54+
* Resolved browse-by component
55+
*/
56+
browseByComponent: Observable<any>;
57+
58+
/**
59+
* Subscriptions to track
60+
*/
61+
browseByComponentSubs: Subscription[] = [];
62+
63+
public constructor( protected route: ActivatedRoute,
64+
protected themeService: ThemeService,
65+
@Inject(BROWSE_BY_COMPONENT_FACTORY) private getComponentByBrowseByType: (browseByType, theme) => GenericConstructor<any>) {
66+
}
67+
68+
ngOnInit(): void {
69+
this.browseByComponent = this.route.data.pipe(
70+
map((data: { browseDefinition: BrowseDefinition }) => {
71+
this.getComponentByBrowseByType(data.browseDefinition.getRenderType(), this.themeService.getThemeName());
72+
return data.browseDefinition;
73+
})
74+
);
75+
this.browseByComponentSubs.push(this.browseByComponent.subscribe((browseDefinition: HierarchicalBrowseDefinition) => {
76+
this.facetType = browseDefinition.facetType;
77+
this.vocabularyName = browseDefinition.vocabulary;
78+
this.vocabularyOptions = { name: this.vocabularyName, closed: true };
79+
}));
3280
}
3381

3482
/**
@@ -41,10 +89,30 @@ export class BrowseByTaxonomyPageComponent implements OnInit {
4189
this.selectedItems.push(detail);
4290
this.filterValues = this.selectedItems
4391
.map((item: VocabularyEntryDetail) => `${item.value},equals`);
92+
this.updateQueryParams();
4493
}
4594

95+
/**
96+
* Removes detail from selectedItems and filterValues.
97+
*
98+
* @param detail VocabularyEntryDetail to be removed
99+
*/
46100
onDeselect(detail: VocabularyEntryDetail): void {
47101
this.selectedItems = this.selectedItems.filter((entry: VocabularyEntryDetail) => { return entry !== detail; });
48102
this.filterValues = this.filterValues.filter((value: string) => { return value !== `${detail.value},equals`; });
103+
this.updateQueryParams();
104+
}
105+
106+
/**
107+
* Updates queryParams based on the current facetType and filterValues.
108+
*/
109+
private updateQueryParams(): void {
110+
this.queryParams = {
111+
['f.' + this.facetType]: this.filterValues
112+
};
113+
}
114+
115+
ngOnDestroy(): void {
116+
this.browseByComponentSubs.forEach((sub: Subscription) => sub.unsubscribe());
49117
}
50118
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Component } from '@angular/core';
2+
import { ThemedComponent } from '../../shared/theme-support/themed.component';
3+
import { rendersBrowseBy } from '../browse-by-switcher/browse-by-decorator';
4+
import { BrowseByTaxonomyPageComponent } from './browse-by-taxonomy-page.component';
5+
6+
@Component({
7+
selector: 'ds-themed-browse-by-taxonomy-page',
8+
templateUrl: '../../shared/theme-support/themed.component.html',
9+
styleUrls: []
10+
})
11+
/**
12+
* Themed wrapper for BrowseByTaxonomyPageComponent
13+
*/
14+
@rendersBrowseBy('hierarchy')
15+
export class ThemedBrowseByTaxonomyPageComponent extends ThemedComponent<BrowseByTaxonomyPageComponent>{
16+
17+
protected getComponentName(): string {
18+
return 'BrowseByTaxonomyPageComponent';
19+
}
20+
21+
protected importThemedComponent(themeName: string): Promise<any> {
22+
return import(`../../../themes/${themeName}/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component`);
23+
}
24+
25+
protected importUnthemedComponent(): Promise<any> {
26+
return import(`./browse-by-taxonomy-page.component`);
27+
}
28+
}

src/app/browse-by/browse-by.module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ComcolModule } from '../shared/comcol/comcol.module';
1010
import { ThemedBrowseByMetadataPageComponent } from './browse-by-metadata-page/themed-browse-by-metadata-page.component';
1111
import { ThemedBrowseByDatePageComponent } from './browse-by-date-page/themed-browse-by-date-page.component';
1212
import { ThemedBrowseByTitlePageComponent } from './browse-by-title-page/themed-browse-by-title-page.component';
13+
import { ThemedBrowseByTaxonomyPageComponent } from './browse-by-taxonomy-page/themed-browse-by-taxonomy-page.component';
1314
import { SharedBrowseByModule } from '../shared/browse-by/shared-browse-by.module';
1415
import { DsoPageModule } from '../shared/dso-page/dso-page.module';
1516
import { FormModule } from '../shared/form/form.module';
@@ -19,11 +20,12 @@ const ENTRY_COMPONENTS = [
1920
BrowseByTitlePageComponent,
2021
BrowseByMetadataPageComponent,
2122
BrowseByDatePageComponent,
23+
BrowseByTaxonomyPageComponent,
2224

2325
ThemedBrowseByMetadataPageComponent,
2426
ThemedBrowseByDatePageComponent,
2527
ThemedBrowseByTitlePageComponent,
26-
28+
ThemedBrowseByTaxonomyPageComponent,
2729
];
2830

2931
@NgModule({
@@ -37,7 +39,6 @@ const ENTRY_COMPONENTS = [
3739
declarations: [
3840
BrowseBySwitcherComponent,
3941
ThemedBrowseBySwitcherComponent,
40-
BrowseByTaxonomyPageComponent,
4142
...ENTRY_COMPONENTS
4243
],
4344
exports: [

0 commit comments

Comments
 (0)