diff --git a/src/app/core/core.reducers.ts b/src/app/core/core.reducers.ts index 077aa3dc95..448c1b8641 100644 --- a/src/app/core/core.reducers.ts +++ b/src/app/core/core.reducers.ts @@ -13,6 +13,7 @@ import { BitstreamFormatRegistryState } from '../+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; import { historyReducer, HistoryState } from './history/history.reducer'; +import { metaTagReducer, MetaTagState } from './metadata/meta-tag.reducer'; export interface CoreState { 'bitstreamFormats': BitstreamFormatRegistryState; @@ -24,6 +25,7 @@ export interface CoreState { 'index': MetaIndexState; 'auth': AuthState; 'json/patch': JsonPatchOperationsState; + 'metaTag': MetaTagState; 'route': RouteState; } @@ -37,5 +39,6 @@ export const coreReducers: ActionReducerMap = { 'index': indexReducer, 'auth': authReducer, 'json/patch': jsonPatchOperationsReducer, + 'metaTag': metaTagReducer, 'route': routeReducer }; diff --git a/src/app/core/metadata/meta-tag.actions.ts b/src/app/core/metadata/meta-tag.actions.ts new file mode 100644 index 0000000000..6451e58da2 --- /dev/null +++ b/src/app/core/metadata/meta-tag.actions.ts @@ -0,0 +1,24 @@ +import { type } from '../../shared/ngrx/type'; +import { Action } from '@ngrx/store'; +import { MetaDefinition } from '@angular/platform-browser'; + +// tslint:disable:max-classes-per-file +export const MetaTagTypes = { + ADD: type('dspace/meta-tag/ADD'), + CLEAR: type('dspace/meta-tag/CLEAR') +}; + +export class AddMetaTagAction implements Action { + type = MetaTagTypes.ADD; + payload: string; + + constructor(property: string) { + this.payload = property; + } +} + +export class ClearMetaTagAction implements Action { + type = MetaTagTypes.CLEAR; +} + +export type MetaTagAction = AddMetaTagAction | ClearMetaTagAction; diff --git a/src/app/core/metadata/meta-tag.reducer.ts b/src/app/core/metadata/meta-tag.reducer.ts new file mode 100644 index 0000000000..0af6fb0aab --- /dev/null +++ b/src/app/core/metadata/meta-tag.reducer.ts @@ -0,0 +1,38 @@ +import { + MetaTagAction, + MetaTagTypes, + AddMetaTagAction, + ClearMetaTagAction, +} from './meta-tag.actions'; + +export interface MetaTagState { + tagsInUse: string[]; +} + +const initialstate: MetaTagState = { + tagsInUse: [] +}; + +export const metaTagReducer = (state: MetaTagState = initialstate, action: MetaTagAction): MetaTagState => { + switch (action.type) { + case MetaTagTypes.ADD: { + return addMetaTag(state, action as AddMetaTagAction); + } + case MetaTagTypes.CLEAR: { + return clearMetaTags(state, action as ClearMetaTagAction); + } + default: { + return state; + } + } +}; + +const addMetaTag = (state: MetaTagState, action: AddMetaTagAction): MetaTagState => { + return { + tagsInUse: [...state.tagsInUse, action.payload] + }; +}; + +const clearMetaTags = (state: MetaTagState, action: ClearMetaTagAction): MetaTagState => { + return Object.assign({}, initialstate); +}; diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts index ed17fad2d8..8c1e1027dd 100644 --- a/src/app/core/metadata/metadata.service.ts +++ b/src/app/core/metadata/metadata.service.ts @@ -30,12 +30,33 @@ import { Bundle } from '../shared/bundle.model'; import { PaginatedList } from '../data/paginated-list.model'; import { URLCombiner } from '../url-combiner/url-combiner'; import { HardRedirectService } from '../services/hard-redirect.service'; +import { MetaTagState } from './meta-tag.reducer'; +import { Store, createSelector, select, MemoizedSelector } from '@ngrx/store'; +import { AddMetaTagAction, ClearMetaTagAction } from './meta-tag.actions'; +import { coreSelector } from '../core.selectors'; +import { CoreState } from '../core.reducers'; +import { ObjectCacheEntry, ObjectCacheState } from '../cache/object-cache.reducer'; + +/** + * The base selector function to select the metaTag section in the store + */ +const metaTagSelector = createSelector( + coreSelector, + (state: CoreState) => state.metaTag +); + +/** + * Selector function to select the tags in use from the MetaTagState + */ +const tagsInUseSelector = + createSelector( + metaTagSelector, + (state: MetaTagState) => state.tagsInUse, + ); @Injectable() export class MetadataService { - private tagStore: Map; - private currentObject: BehaviorSubject = new BehaviorSubject(undefined); /** @@ -63,11 +84,9 @@ export class MetadataService { private bitstreamDataService: BitstreamDataService, private bitstreamFormatDataService: BitstreamFormatDataService, private rootService: RootDataService, + private store: Store, private hardRedirectService: HardRedirectService, ) { - // TODO: determine what open graph meta tags are needed and whether - // the differ per route. potentially add image based on DSpaceObject - this.tagStore = new Map(); } public listenForRouteChange(): void { @@ -442,7 +461,7 @@ export class MetadataService { if (content) { const tag = { property, content } as MetaDefinition; this.meta.addTag(tag); - this.storeTag(property, tag); + this.storeTag(property); } } @@ -452,33 +471,21 @@ export class MetadataService { } } - private storeTag(key: string, tag: MetaDefinition): void { - const tags: MetaDefinition[] = this.getTags(key); - tags.push(tag); - this.setTags(key, tags); - } - - private getTags(key: string): MetaDefinition[] { - let tags: MetaDefinition[] = this.tagStore.get(key); - if (tags === undefined) { - tags = []; - } - return tags; - } - - private setTags(key: string, tags: MetaDefinition[]): void { - this.tagStore.set(key, tags); + private storeTag(key: string): void { + this.store.dispatch(new AddMetaTagAction(key)); } public clearMetaTags() { - this.tagStore.forEach((tags: MetaDefinition[], property: string) => { - this.meta.removeTag('property=\'' + property + '\''); + this.store.pipe( + select(tagsInUseSelector), + take(1) + ).subscribe((tagsInUse: string[]) => { + for (const property of tagsInUse) { + this.meta.removeTag('property=\'' + property + '\''); + } + this.store.dispatch(new ClearMetaTagAction()); }); - this.tagStore.clear(); } - public getTagStore(): Map { - return this.tagStore; - } }