diff --git a/src/app/core/shared/client-math.service.ts b/src/app/core/shared/client-math.service.ts index 1dbfa7e4e5..2fde521ba9 100644 --- a/src/app/core/shared/client-math.service.ts +++ b/src/app/core/shared/client-math.service.ts @@ -1,4 +1,8 @@ -import { Injectable } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { + Inject, + Injectable, +} from '@angular/core'; import { BehaviorSubject, Observable, @@ -6,6 +10,10 @@ import { } from 'rxjs'; import { environment } from 'src/environments/environment'; +import { + NativeWindowRef, + NativeWindowService, +} from '../services/window.service'; import { MathJaxConfig, MathService, @@ -14,6 +22,9 @@ import { @Injectable({ providedIn: 'root', }) +/** + * Provide the MathService for CSR + */ export class ClientMathService extends MathService { protected isReady$: Subject; @@ -39,7 +50,10 @@ export class ClientMathService extends MathService { id: 'MathJaxBackupScript', }; - constructor() { + constructor( + @Inject(DOCUMENT) private _document: Document, + @Inject(NativeWindowService) protected _window: NativeWindowRef, + ) { super(); this.isReady$ = new BehaviorSubject(false); @@ -52,16 +66,21 @@ export class ClientMathService extends MathService { }); } + /** + * Register the specified MathJax script in the document + * + * @param config The configuration object for the script + */ protected async registerMathJaxAsync(config: MathJaxConfig): Promise { if (environment.markdown.mathjax) { return new Promise((resolve, reject) => { - const optionsScript: HTMLScriptElement = document.createElement('script'); + const optionsScript: HTMLScriptElement = this._document.createElement('script'); optionsScript.type = 'text/javascript'; optionsScript.text = `MathJax = ${JSON.stringify(this.mathJaxOptions)};`; - document.head.appendChild(optionsScript); + this._document.head.appendChild(optionsScript); - const script: HTMLScriptElement = document.createElement('script'); + const script: HTMLScriptElement = this._document.createElement('script'); script.id = config.id; script.type = 'text/javascript'; script.src = config.source; @@ -69,19 +88,27 @@ export class ClientMathService extends MathService { script.async = true; script.onload = () => resolve(); script.onerror = error => reject(error); - document.head.appendChild(script); + this._document.head.appendChild(script); }); } return Promise.resolve(); } + /** + * Return the status of the script registration + */ ready(): Observable { return this.isReady$; } + /** + * Render the specified element using the MathJax JavaScript + * + * @param element The element to render with MathJax + */ render(element: HTMLElement) { if (environment.markdown.mathjax) { - (window as any).MathJax.typesetPromise([element]); + this._window.nativeWindow.MathJax.typesetPromise([element]); } } } diff --git a/src/app/core/shared/math.service.ts b/src/app/core/shared/math.service.ts index 1d5271f7a7..c06ce06220 100644 --- a/src/app/core/shared/math.service.ts +++ b/src/app/core/shared/math.service.ts @@ -5,6 +5,9 @@ export interface MathJaxConfig { id: string; } +/** + * This service is used to provide the MathJax library with the ability to render markdown code + */ export abstract class MathService { protected abstract mathJaxOptions: any; protected abstract mathJax: MathJaxConfig; diff --git a/src/app/core/shared/server-math.service.ts b/src/app/core/shared/server-math.service.ts index 51664b142a..75fa775fee 100644 --- a/src/app/core/shared/server-math.service.ts +++ b/src/app/core/shared/server-math.service.ts @@ -13,6 +13,9 @@ import { @Injectable({ providedIn: 'root', }) +/** + * Provide the MathService for SSR + */ export class ServerMathService extends MathService { protected isReady$: Subject; diff --git a/src/app/shared/utils/markdown.directive.ts b/src/app/shared/utils/markdown.directive.ts index cece57ae11..a38b079ffd 100644 --- a/src/app/shared/utils/markdown.directive.ts +++ b/src/app/shared/utils/markdown.directive.ts @@ -14,6 +14,7 @@ import { } from '@angular/platform-browser'; import { Subject } from 'rxjs'; import { + filter, take, takeUntil, } from 'rxjs/operators'; @@ -41,8 +42,8 @@ export class MarkdownDirective implements OnInit, OnDestroy { el: HTMLElement; constructor( - protected sanitizer: DomSanitizer, @Inject(MARKDOWN_IT) private markdownIt: LazyMarkdownIt, + protected sanitizer: DomSanitizer, private mathService: MathService, private elementRef: ElementRef) { this.el = elementRef.nativeElement; @@ -72,6 +73,7 @@ export class MarkdownDirective implements OnInit, OnDestroy { private renderMathjax() { this.mathService.ready().pipe( + filter((ready) => ready), take(1), takeUntil(this.alive$), ).subscribe(() => {