diff --git a/src/app/shared/theme-support/themed.component.spec.ts b/src/app/shared/theme-support/themed.component.spec.ts index 404e970a7a..7776e60379 100644 --- a/src/app/shared/theme-support/themed.component.spec.ts +++ b/src/app/shared/theme-support/themed.component.spec.ts @@ -71,6 +71,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('custom'); + }); + })); }); describe('when the current theme doesn\'t match a themed component', () => { @@ -92,6 +98,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the base theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('base'); + }); + })); }); describe('and it extends another theme', () => { @@ -117,6 +129,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the base theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('base'); + }); + })); }); describe('that does match it', () => { @@ -141,6 +159,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('custom'); + }); + })); }); describe('that extends another theme that doesn\'t match it either', () => { @@ -167,6 +191,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the base theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('base'); + }); + })); }); describe('that extends another theme that does match it', () => { @@ -193,6 +223,12 @@ describe('ThemedComponent', () => { expect((component as any).compRef.instance.testInput).toEqual('changed'); }); })); + + it(`should set usedTheme to the name of the matched theme`, waitForAsync(() => { + fixture.whenStable().then(() => { + expect(component.usedTheme).toEqual('custom'); + }); + })); }); }); }); diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 2a85dae402..995122d284 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -8,13 +8,15 @@ import { OnDestroy, ComponentFactoryResolver, ChangeDetectorRef, - OnChanges + OnChanges, + HostBinding } from '@angular/core'; import { hasValue, isNotEmpty } from '../empty.util'; import { from as fromPromise, Observable, of as observableOf, Subscription, BehaviorSubject } from 'rxjs'; import { ThemeService } from './theme.service'; -import { catchError, switchMap, map } from 'rxjs/operators'; +import { catchError, switchMap, map, tap } from 'rxjs/operators'; import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { BASE_THEME_NAME } from './theme.constants'; @Component({ selector: 'ds-themed', @@ -36,6 +38,11 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges protected inAndOutputNames: (keyof T & keyof this)[] = []; + /** + * A data attribute on the ThemedComponent to indicate which theme the rendered component came from. + */ + @HostBinding('attr.data-used-theme') usedTheme: string; + constructor( protected resolver: ComponentFactoryResolver, protected cdr: ChangeDetectorRef, @@ -86,6 +93,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges } else { // otherwise import and return the default component return fromPromise(this.importUnthemedComponent()).pipe( + tap(() => this.usedTheme = BASE_THEME_NAME), map((unthemedFile: any) => { return unthemedFile[this.getComponentName()]; }) @@ -130,6 +138,7 @@ export abstract class ThemedComponent implements OnInit, OnDestroy, OnChanges private resolveThemedComponent(themeName?: string, checkedThemeNames: string[] = []): Observable { if (isNotEmpty(themeName)) { return fromPromise(this.importThemedComponent(themeName)).pipe( + tap(() => this.usedTheme = themeName), catchError(() => { // Try the next ancestor theme instead const nextTheme = this.themeService.getThemeConfigFor(themeName)?.extends;