themed.component.ts (dspace-angular-dspace-7.0) | : | themed.component.ts (dspace-angular-dspace-7.1) | ||
---|---|---|---|---|
skipping to change at line 14 | skipping to change at line 14 | |||
ViewContainerRef, | ViewContainerRef, | |||
ComponentRef, | ComponentRef, | |||
SimpleChanges, | SimpleChanges, | |||
OnInit, | OnInit, | |||
OnDestroy, | OnDestroy, | |||
ComponentFactoryResolver, | ComponentFactoryResolver, | |||
ChangeDetectorRef, | ChangeDetectorRef, | |||
OnChanges | OnChanges | |||
} from '@angular/core'; | } from '@angular/core'; | |||
import { hasValue, isNotEmpty } from '../empty.util'; | import { hasValue, isNotEmpty } from '../empty.util'; | |||
import { Subscription } from 'rxjs'; | import { Observable, of as observableOf, Subscription } from 'rxjs'; | |||
import { ThemeService } from './theme.service'; | import { ThemeService } from './theme.service'; | |||
import { fromPromise } from 'rxjs/internal-compatibility'; | import { fromPromise } from 'rxjs/internal-compatibility'; | |||
import { catchError, switchMap, map } from 'rxjs/operators'; | import { catchError, switchMap, map } from 'rxjs/operators'; | |||
import { GenericConstructor } from '../../core/shared/generic-constructor'; | import { GenericConstructor } from '../../core/shared/generic-constructor'; | |||
@Component({ | @Component({ | |||
selector: 'ds-themed', | selector: 'ds-themed', | |||
styleUrls: ['./themed.component.scss'], | styleUrls: ['./themed.component.scss'], | |||
templateUrl: './themed.component.html', | templateUrl: './themed.component.html', | |||
}) | }) | |||
skipping to change at line 72 | skipping to change at line 72 | |||
this.destroyComponentInstance(); | this.destroyComponentInstance(); | |||
} | } | |||
protected renderComponentInstance(): void { | protected renderComponentInstance(): void { | |||
this.destroyComponentInstance(); | this.destroyComponentInstance(); | |||
if (hasValue(this.lazyLoadSub)) { | if (hasValue(this.lazyLoadSub)) { | |||
this.lazyLoadSub.unsubscribe(); | this.lazyLoadSub.unsubscribe(); | |||
} | } | |||
this.lazyLoadSub = | this.lazyLoadSub = this.resolveThemedComponent(this.themeService.getThemeNam | |||
fromPromise(this.importThemedComponent(this.themeService.getThemeName())). | e()).pipe( | |||
pipe( | switchMap((themedFile: any) => { | |||
// if there is no themed version of the component an exception is thrown | if (hasValue(themedFile) && hasValue(themedFile[this.getComponentName()] | |||
, | )) { | |||
// catch it and return null instead | // if the file is not null, and exports a component with the specified | |||
catchError(() => [null]), | name, | |||
switchMap((themedFile: any) => { | // return that component | |||
if (hasValue(themedFile) && hasValue(themedFile[this.getComponentName( | return [themedFile[this.getComponentName()]]; | |||
)])) { | } else { | |||
// if the file is not null, and exports a component with the specifi | // otherwise import and return the default component | |||
ed name, | return fromPromise(this.importUnthemedComponent()).pipe( | |||
// return that component | map((unthemedFile: any) => { | |||
return [themedFile[this.getComponentName()]]; | return unthemedFile[this.getComponentName()]; | |||
} else { | }) | |||
// otherwise import and return the default component | ); | |||
return fromPromise(this.importUnthemedComponent()).pipe( | } | |||
map((unthemedFile: any) => { | }), | |||
return unthemedFile[this.getComponentName()]; | ).subscribe((constructor: GenericConstructor<T>) => { | |||
}) | const factory = this.resolver.resolveComponentFactory(constructor); | |||
); | this.compRef = this.vcr.createComponent(factory); | |||
} | this.connectInputsAndOutputs(); | |||
}), | this.cdr.markForCheck(); | |||
).subscribe((constructor: GenericConstructor<T>) => { | }); | |||
const factory = this.resolver.resolveComponentFactory(constructor); | ||||
this.compRef = this.vcr.createComponent(factory); | ||||
this.connectInputsAndOutputs(); | ||||
this.cdr.markForCheck(); | ||||
}); | ||||
} | } | |||
protected destroyComponentInstance(): void { | protected destroyComponentInstance(): void { | |||
if (hasValue(this.compRef)) { | if (hasValue(this.compRef)) { | |||
this.compRef.destroy(); | this.compRef.destroy(); | |||
this.compRef = null; | this.compRef = null; | |||
} | } | |||
if (hasValue(this.vcr)) { | if (hasValue(this.vcr)) { | |||
this.vcr.clear(); | this.vcr.clear(); | |||
} | } | |||
} | } | |||
protected connectInputsAndOutputs(): void { | protected connectInputsAndOutputs(): void { | |||
if (isNotEmpty(this.inAndOutputNames) && hasValue(this.compRef) && hasValue( this.compRef.instance)) { | if (isNotEmpty(this.inAndOutputNames) && hasValue(this.compRef) && hasValue( this.compRef.instance)) { | |||
this.inAndOutputNames.forEach((name: any) => { | this.inAndOutputNames.forEach((name: any) => { | |||
this.compRef.instance[name] = this[name]; | this.compRef.instance[name] = this[name]; | |||
}); | }); | |||
} | } | |||
} | } | |||
/** | ||||
* Attempt to import this component from the current theme or a theme it {@lin | ||||
k NamedThemeConfig.extends}. | ||||
* Recurse until we succeed or when until we run out of themes to fall back to | ||||
. | ||||
* | ||||
* @param themeName The name of the theme to check | ||||
* @param checkedThemeNames The list of theme names that are already checked | ||||
* @private | ||||
*/ | ||||
private resolveThemedComponent(themeName?: string, checkedThemeNames: string[] | ||||
= []): Observable<any> { | ||||
if (isNotEmpty(themeName)) { | ||||
return fromPromise(this.importThemedComponent(themeName)).pipe( | ||||
catchError(() => { | ||||
// Try the next ancestor theme instead | ||||
const nextTheme = this.themeService.getThemeConfigFor(themeName)?.exte | ||||
nds; | ||||
const nextCheckedThemeNames = [...checkedThemeNames, themeName]; | ||||
if (checkedThemeNames.includes(nextTheme)) { | ||||
throw new Error('Theme extension cycle detected: ' + [...nextChecked | ||||
ThemeNames, nextTheme].join(' -> ')); | ||||
} else { | ||||
return this.resolveThemedComponent(nextTheme, nextCheckedThemeNames) | ||||
; | ||||
} | ||||
}), | ||||
); | ||||
} else { | ||||
// If we got here, we've failed to import this component from any ancestor | ||||
theme → fall back to unthemed | ||||
return observableOf(null); | ||||
} | ||||
} | ||||
} | } | |||
End of changes. 3 change blocks. | ||||
30 lines changed or deleted | 60 lines changed or added |