"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/app/shared/theme-support/theme.service.ts" between
dspace-angular-dspace-7.0.tar.gz and dspace-angular-dspace-7.1.tar.gz

About: dspace-angular is the Angular-based frontend of DSpace, a digital repository system to capture, store, index, preserve and redistribute an organization’s research material in digital formats.

theme.service.ts  (dspace-angular-dspace-7.0):theme.service.ts  (dspace-angular-dspace-7.1)
import { Injectable } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { Store, createFeatureSelector, createSelector, select } from '@ngrx/stor e'; import { Store, createFeatureSelector, createSelector, select } from '@ngrx/stor e';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { ThemeState } from './theme.reducer'; import { ThemeState } from './theme.reducer';
import { SetThemeAction } from './theme.actions'; import { SetThemeAction, ThemeActionTypes } from './theme.actions';
import { take } from 'rxjs/operators'; import { expand, filter, map, switchMap, take, toArray } from 'rxjs/operators';
import { hasValue } from '../empty.util'; import { hasValue, isNotEmpty } from '../empty.util';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import {
getFirstCompletedRemoteData,
getFirstSucceededRemoteData,
getRemoteDataPayload
} from '../../core/shared/operators';
import { EMPTY, of as observableOf } from 'rxjs';
import { Theme, ThemeConfig, themeFactory } from '../../../config/theme.model';
import { NO_OP_ACTION_TYPE, NoOpAction } from '../ngrx/no-op.action';
import { followLink } from '../utils/follow-link-config.model';
import { LinkService } from '../../core/cache/builders/link.service';
import { environment } from '../../../environments/environment';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
ice';
import { ActivatedRouteSnapshot } from '@angular/router';
import { GET_THEME_CONFIG_FOR_FACTORY } from '../object-collection/shared/listab
le-object/listable-object.decorator';
export const themeStateSelector = createFeatureSelector<ThemeState>('theme'); export const themeStateSelector = createFeatureSelector<ThemeState>('theme');
export const currentThemeSelector = createSelector( export const currentThemeSelector = createSelector(
themeStateSelector, themeStateSelector,
(state: ThemeState): string => hasValue(state) ? state.currentTheme : undefine d (state: ThemeState): string => hasValue(state) ? state.currentTheme : undefine d
); );
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class ThemeService { export class ThemeService {
/**
* The list of configured themes
*/
themes: Theme[];
/**
* True if at least one theme depends on the route
*/
hasDynamicTheme: boolean;
constructor( constructor(
private store: Store<ThemeState>, private store: Store<ThemeState>,
private linkService: LinkService,
private dSpaceObjectDataService: DSpaceObjectDataService,
@Inject(GET_THEME_CONFIG_FOR_FACTORY) private gtcf: (str) => ThemeConfig
) { ) {
// Create objects from the theme configs in the environment file
this.themes = environment.themes.map((themeConfig: ThemeConfig) => themeFact
ory(themeConfig));
this.hasDynamicTheme = environment.themes.some((themeConfig: any) =>
hasValue(themeConfig.regex) ||
hasValue(themeConfig.handle) ||
hasValue(themeConfig.uuid)
);
} }
setTheme(newName: string) { setTheme(newName: string) {
this.store.dispatch(new SetThemeAction(newName)); this.store.dispatch(new SetThemeAction(newName));
} }
getThemeName(): string { getThemeName(): string {
let currentTheme: string; let currentTheme: string;
this.store.pipe( this.store.pipe(
select(currentThemeSelector), select(currentThemeSelector),
skipping to change at line 46 skipping to change at line 82
); );
return currentTheme; return currentTheme;
} }
getThemeName$(): Observable<string> { getThemeName$(): Observable<string> {
return this.store.pipe( return this.store.pipe(
select(currentThemeSelector) select(currentThemeSelector)
); );
} }
/**
* Determine whether or not the theme needs to change depending on the current
route's URL and snapshot data
* If the snapshot contains a dso, this will be used to match a theme
* If the snapshot contains a scope parameters, this will be used to match a t
heme
* Otherwise the URL is matched against
* If none of the above find a match, the theme doesn't change
* @param currentRouteUrl
* @param activatedRouteSnapshot
* @return Observable boolean emitting whether or not the theme has been chang
ed
*/
updateThemeOnRouteChange$(currentRouteUrl: string, activatedRouteSnapshot: Act
ivatedRouteSnapshot): Observable<boolean> {
// and the current theme from the store
const currentTheme$: Observable<string> = this.store.pipe(select(currentThem
eSelector));
const action$ = currentTheme$.pipe(
switchMap((currentTheme: string) => {
const snapshotWithData = this.findRouteData(activatedRouteSnapshot);
if (this.hasDynamicTheme === true && isNotEmpty(this.themes)) {
if (hasValue(snapshotWithData) && hasValue(snapshotWithData.data) && h
asValue(snapshotWithData.data.dso)) {
const dsoRD: RemoteData<DSpaceObject> = snapshotWithData.data.dso;
if (dsoRD.hasSucceeded) {
// Start with the resolved dso and go recursively through its pare
nts until you reach the top-level community
return observableOf(dsoRD.payload).pipe(
this.getAncestorDSOs(),
map((dsos: DSpaceObject[]) => {
const dsoMatch = this.matchThemeToDSOs(dsos, currentRouteUrl);
return this.getActionForMatch(dsoMatch, currentTheme);
})
);
}
}
if (hasValue(activatedRouteSnapshot.queryParams) && hasValue(activated
RouteSnapshot.queryParams.scope)) {
const dsoFromScope$: Observable<RemoteData<DSpaceObject>> = this.dSp
aceObjectDataService.findById(activatedRouteSnapshot.queryParams.scope);
// Start with the resolved dso and go recursively through its parent
s until you reach the top-level community
return dsoFromScope$.pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
this.getAncestorDSOs(),
map((dsos: DSpaceObject[]) => {
const dsoMatch = this.matchThemeToDSOs(dsos, currentRouteUrl);
return this.getActionForMatch(dsoMatch, currentTheme);
})
);
}
// check whether the route itself matches
const routeMatch = this.themes.find((theme: Theme) => theme.matches(cu
rrentRouteUrl, undefined));
return [this.getActionForMatch(routeMatch, currentTheme)];
}
// If there are no themes configured, do nothing
return [new NoOpAction()];
}),
take(1),
);
action$.pipe(
filter((action) => action.type !== NO_OP_ACTION_TYPE),
).subscribe((action) => {
this.store.dispatch(action);
});
return action$.pipe(
map((action) => action.type === ThemeActionTypes.SET),
);
}
/**
* Find a DSpaceObject in one of the provided route snapshots their data
* Recursively looks for the dso in the routes their child routes until it rea
ches a dead end or finds one
* @param routes
*/
findRouteData(...routes: ActivatedRouteSnapshot[]) {
const result = routes.find((route) => hasValue(route.data) && hasValue(route
.data.dso));
if (hasValue(result)) {
return result;
} else {
const nextLevelRoutes = routes
.map((route: ActivatedRouteSnapshot) => route.children)
.reduce((combined: ActivatedRouteSnapshot[], current: ActivatedRouteSnap
shot[]) => [...combined, ...current]);
if (isNotEmpty(nextLevelRoutes)) {
return this.findRouteData(...nextLevelRoutes);
} else {
return undefined;
}
}
}
/**
* An rxjs operator that will return an array of all the ancestors of the DSpa
ceObject used as
* input. The initial DSpaceObject will be the first element of the output arr
ay, followed by
* its parent, its grandparent etc
*
* @private
*/
private getAncestorDSOs() {
return (source: Observable<DSpaceObject>): Observable<DSpaceObject[]> =>
source.pipe(
expand((dso: DSpaceObject) => {
// Check if the dso exists and has a parent link
if (hasValue(dso) && typeof (dso as any).getParentLinkKey === 'functio
n') {
const linkName = (dso as any).getParentLinkKey();
// If it does, retrieve it.
return this.linkService.resolveLinkWithoutAttaching<DSpaceObject, DS
paceObject>(dso, followLink(linkName)).pipe(
getFirstCompletedRemoteData(),
map((rd: RemoteData<DSpaceObject>) => {
if (hasValue(rd.payload)) {
// If there's a parent, use it for the next iteration
return rd.payload;
} else {
// If there's no parent, or an error, return null, which will
stop recursion
// in the next iteration
return null;
}
}),
);
}
// The current dso has no value, or no parent. Return EMPTY to stop re
cursion
return EMPTY;
}),
// only allow through DSOs that have a value
filter((dso: DSpaceObject) => hasValue(dso)),
// Wait for recursion to complete, and emit all results at once, in an a
rray
toArray()
);
}
/**
* return the action to dispatch based on the given matching theme
*
* @param newTheme The theme to create an action for
* @param currentThemeName The name of the currently active theme
* @private
*/
private getActionForMatch(newTheme: Theme, currentThemeName: string): SetTheme
Action | NoOpAction {
if (hasValue(newTheme) && newTheme.config.name !== currentThemeName) {
// If we have a match, and it isn't already the active theme, set it as th
e new theme
return new SetThemeAction(newTheme.config.name);
} else {
// Otherwise, do nothing
return new NoOpAction();
}
}
/**
* Check the given DSpaceObjects in order to see if they match the configured
themes in order.
* If a match is found, the matching theme is returned
*
* @param dsos The DSpaceObjects to check
* @param currentRouteUrl The url for the current route
* @private
*/
private matchThemeToDSOs(dsos: DSpaceObject[], currentRouteUrl: string): Theme
{
// iterate over the themes in order, and return the first one that matches
return this.themes.find((theme: Theme) => {
// iterate over the dsos's in order (most specific one first, so Item, Col
lection,
// Community), and return the first one that matches the current theme
const match = dsos.find((dso: DSpaceObject) => theme.matches(currentRouteU
rl, dso));
return hasValue(match);
});
}
/**
* Searches for a ThemeConfig by its name;
*/
getThemeConfigFor(themeName: string): ThemeConfig {
return this.gtcf(themeName);
}
} }
 End of changes. 6 change blocks. 
4 lines changed or deleted 240 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)