From e402ac482dcb03f57b88920ffad27e9c08bffe16 Mon Sep 17 00:00:00 2001 From: Andrea Barbasso <´andrea.barbasso@4science.com´> Date: Tue, 27 Feb 2024 10:21:42 +0100 Subject: [PATCH] [DURACOM-240] split service into SSR and CSR --- src/app/core/shared/client-math.service.ts | 88 ++++++++++++++++++++++ src/app/core/shared/math.service.ts | 83 +++----------------- src/app/core/shared/server-math.service.ts | 49 ++++++++++++ src/modules/app/browser-app.module.ts | 6 ++ src/modules/app/server-app.module.ts | 6 ++ 5 files changed, 158 insertions(+), 74 deletions(-) create mode 100644 src/app/core/shared/client-math.service.ts create mode 100644 src/app/core/shared/server-math.service.ts diff --git a/src/app/core/shared/client-math.service.ts b/src/app/core/shared/client-math.service.ts new file mode 100644 index 0000000000..a46d1694b3 --- /dev/null +++ b/src/app/core/shared/client-math.service.ts @@ -0,0 +1,88 @@ +import { Injectable } from '@angular/core'; +import { + Observable, + ReplaySubject, + Subject, +} from 'rxjs'; +import { environment } from 'src/environments/environment'; + +import { + MathJaxConfig, + MathService, +} from './math.service'; + +@Injectable({ + providedIn: 'root', +}) +export class ClientMathService extends MathService { + + protected signal: Subject; + + protected mathJaxOptions = { + tex: { + inlineMath: [['$', '$'], ['\\(', '\\)']], + }, + svg: { + fontCache: 'global', + }, + startup: { + typeset: false, + }, + }; + + protected mathJax: MathJaxConfig = { + source: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js', + id: 'MathJaxScript', + }; + protected mathJaxFallback: MathJaxConfig = { + source: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-chtml.min.js', + id: 'MathJaxBackupScript', + }; + + constructor() { + super(); + + this.signal = new ReplaySubject(1); + + void this.registerMathJaxAsync(this.mathJax) + .then(() => this.signal.next(true)) + .catch(_ => { + void this.registerMathJaxAsync(this.mathJaxFallback) + .then(() => this.signal.next(true)) + .catch((error) => console.log(error)); + }); + } + + protected async registerMathJaxAsync(config: MathJaxConfig): Promise { + if (environment.markdown.mathjax) { + return new Promise((resolve, reject) => { + + const optionsScript: HTMLScriptElement = document.createElement('script'); + optionsScript.type = 'text/javascript'; + optionsScript.text = `MathJax = ${JSON.stringify(this.mathJaxOptions)};`; + document.head.appendChild(optionsScript); + + const script: HTMLScriptElement = document.createElement('script'); + script.id = config.id; + script.type = 'text/javascript'; + script.src = config.source; + script.crossOrigin = 'anonymous'; + script.async = true; + script.onload = () => resolve(); + script.onerror = error => reject(error); + document.head.appendChild(script); + }); + } + return Promise.resolve(); + } + + ready(): Observable { + return this.signal; + } + + render(element: HTMLElement) { + if (environment.markdown.mathjax) { + (window as any).MathJax.typesetPromise([element]); + } + } +} diff --git a/src/app/core/shared/math.service.ts b/src/app/core/shared/math.service.ts index 7549b09680..1d5271f7a7 100644 --- a/src/app/core/shared/math.service.ts +++ b/src/app/core/shared/math.service.ts @@ -1,81 +1,16 @@ -import { Injectable } from '@angular/core'; -import { - Observable, - ReplaySubject, - Subject, -} from 'rxjs'; +import { Observable } from 'rxjs'; -interface MathJaxConfig { +export interface MathJaxConfig { source: string; id: string; } -@Injectable({ - providedIn: 'root', -}) -export class MathService { +export abstract class MathService { + protected abstract mathJaxOptions: any; + protected abstract mathJax: MathJaxConfig; + protected abstract mathJaxFallback: MathJaxConfig; - private signal: Subject; - - private mathJaxOptions = { - tex: { - inlineMath: [['$', '$'], ['\\(', '\\)']], - }, - svg: { - fontCache: 'global', - }, - startup: { - typeset: false, - }, - }; - - private mathJax: MathJaxConfig = { - source: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js', - id: 'MathJaxScript', - }; - private mathJaxFallback: MathJaxConfig = { - source: 'assets/mathjax/mml-chtml.js', - id: 'MathJaxBackupScript', - }; - - constructor() { - - this.signal = new ReplaySubject(1); - - void this.registerMathJaxAsync(this.mathJax) - .then(() => this.signal.next(true)) - .catch(_ => { - void this.registerMathJaxAsync(this.mathJaxFallback) - .then(() => this.signal.next(true)) - .catch((error) => console.log(error)); - }); - } - - private async registerMathJaxAsync(config: MathJaxConfig): Promise { - return new Promise((resolve, reject) => { - - const optionsScript: HTMLScriptElement = document.createElement('script'); - optionsScript.type = 'text/javascript'; - optionsScript.text = `MathJax = ${JSON.stringify(this.mathJaxOptions)};`; - document.head.appendChild(optionsScript); - - const script: HTMLScriptElement = document.createElement('script'); - script.id = config.id; - script.type = 'text/javascript'; - script.src = config.source; - script.crossOrigin = 'anonymous'; - script.async = true; - script.onload = () => resolve(); - script.onerror = error => reject(error); - document.head.appendChild(script); - }); - } - - ready(): Observable { - return this.signal; - } - - render(element: HTMLElement) { - (window as any).MathJax.typesetPromise([element]); - } + protected abstract registerMathJaxAsync(config: MathJaxConfig): Promise; + abstract ready(): Observable; + abstract render(element: HTMLElement): void; } diff --git a/src/app/core/shared/server-math.service.ts b/src/app/core/shared/server-math.service.ts new file mode 100644 index 0000000000..725658874d --- /dev/null +++ b/src/app/core/shared/server-math.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { + Observable, + ReplaySubject, + Subject, +} from 'rxjs'; + +import { + MathJaxConfig, + MathService, +} from './math.service'; + +@Injectable({ + providedIn: 'root', +}) +export class ServerMathService extends MathService { + + protected signal: Subject; + + protected mathJaxOptions = {}; + + protected mathJax: MathJaxConfig = { + source: '', + id: '', + }; + protected mathJaxFallback: MathJaxConfig = { + source: '', + id: '', + }; + + constructor() { + super(); + + this.signal = new ReplaySubject(1); + this.signal.next(true); + } + + protected async registerMathJaxAsync(config: MathJaxConfig): Promise { + return Promise.resolve(); + } + + ready(): Observable { + return this.signal; + } + + render(element: HTMLElement) { + return; + } +} diff --git a/src/modules/app/browser-app.module.ts b/src/modules/app/browser-app.module.ts index b3439d9f96..cccfa27ae2 100644 --- a/src/modules/app/browser-app.module.ts +++ b/src/modules/app/browser-app.module.ts @@ -46,6 +46,8 @@ import { ClientCookieService } from '../../app/core/services/client-cookie.servi import { CookieService } from '../../app/core/services/cookie.service'; import { HardRedirectService } from '../../app/core/services/hard-redirect.service'; import { ReferrerService } from '../../app/core/services/referrer.service'; +import { ClientMathService } from '../../app/core/shared/client-math.service'; +import { MathService } from '../../app/core/shared/math.service'; import { BrowserKlaroService } from '../../app/shared/cookies/browser-klaro.service'; import { KlaroService } from '../../app/shared/cookies/klaro.service'; import { MissingTranslationHelper } from '../../app/shared/translate/missing-translation.helper'; @@ -136,6 +138,10 @@ export function getRequest(transferState: TransferState): any { provide: LocationToken, useFactory: locationProvider, }, + { + provide: MathService, + useClass: ClientMathService, + }, ], }) export class BrowserAppModule { diff --git a/src/modules/app/server-app.module.ts b/src/modules/app/server-app.module.ts index eb99534513..27849ec8e0 100644 --- a/src/modules/app/server-app.module.ts +++ b/src/modules/app/server-app.module.ts @@ -43,6 +43,8 @@ import { ServerReferrerService } from '../../app/core/services/server.referrer.s import { ServerCookieService } from '../../app/core/services/server-cookie.service'; import { ServerHardRedirectService } from '../../app/core/services/server-hard-redirect.service'; import { ServerXhrService } from '../../app/core/services/server-xhr.service'; +import { MathService } from '../../app/core/shared/math.service'; +import { ServerMathService } from '../../app/core/shared/server-math.service'; import { AngularticsProviderMock } from '../../app/shared/mocks/angulartics-provider.service.mock'; import { Angulartics2Mock } from '../../app/shared/mocks/angulartics2.service.mock'; import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider'; @@ -128,6 +130,10 @@ export function createTranslateLoader(transferState: TransferState) { provide: ReferrerService, useClass: ServerReferrerService, }, + { + provide: MathService, + useClass: ServerMathService, + }, ], }) export class ServerAppModule {