@@ -21,7 +21,6 @@ import { CoreText } from '@singletons/text';
2121import { CorePromiseUtils } from '@singletons/promise-utils' ;
2222import { CoreSite } from '@classes/sites/site' ;
2323import { makeSingleton } from '@singletons' ;
24- import { CoreWait } from '@singletons/wait' ;
2524import { CoreDom } from '@singletons/dom' ;
2625import { CoreLogger } from '@singletons/logger' ;
2726
@@ -40,32 +39,52 @@ export class AddonFilterMathJaxLoaderHandlerService extends CoreFilterDefaultHan
4039 /**
4140 * Initialize MathJax.
4241 */
43- initialize ( ) : void {
42+ async initialize ( ) : Promise < void > {
4443 if ( document . head . querySelector ( '#core-filter-mathjax-script' ) ) {
4544 // Script already added, don't add it again.
45+ await this . window . MathJax ?. startup . promise ;
46+
4647 return ;
4748 }
4849
4950 // The MathJax configuration needs to be created before loading the MathJax script. Changing the options
5051 // after MathJax is initialized doesn't work (e.g. chaning window.MathJax.options or window.MathJax.config.options).
52+ // @todo : Obtain mathjaxconfig from the site.
5153 this . window . MathJax = {
5254 options : {
5355 enableMenu : false , // Disable right-click menu on equations.
5456 } ,
5557 startup : {
5658 typeset : false , // Don't run typeset automatically on the whole page when MathJax is loaded.
5759 } ,
60+ loader : {
61+ load : [ 'ui/safe' ] , // Prevent XSS.
62+ } ,
5863 } ;
5964
6065 // Add the script to the header.
61- const script = document . createElement ( 'script' ) ;
62- script . id = 'core-filter-mathjax-script' ;
63- script . src = 'assets/lib/mathjax/tex-mml-chtml.js' ;
64- document . head . appendChild ( script ) ;
66+ await this . loadMathJax ( ) ;
67+
68+ await this . window . MathJax ?. startup . promise ;
6569
6670 // @todo : Once MathJax supports locale, set current language and listen for CoreEvents.LANGUAGE_CHANGED events.
6771 }
6872
73+ /**
74+ * Load the MathJax script.
75+ */
76+ protected loadMathJax ( ) : Promise < void > {
77+ return new Promise ( ( resolve , reject ) => {
78+ const script = document . createElement ( 'script' ) ;
79+ script . onload = ( ) => resolve ( ) ;
80+ script . onerror = ( error ) => reject ( error ) ;
81+ script . id = 'core-filter-mathjax-script' ;
82+ script . src = 'assets/lib/mathjax/tex-mml-chtml.js' ;
83+ script . type = 'text/javascript' ;
84+ document . head . appendChild ( script ) ;
85+ } ) ;
86+ }
87+
6988 /**
7089 * @inheritdoc
7190 */
@@ -152,8 +171,7 @@ export class AddonFilterMathJaxLoaderHandlerService extends CoreFilterDefaultHan
152171 return ;
153172 }
154173
155- this . initialize ( ) ;
156- await this . waitForReady ( ) ;
174+ await this . initialize ( ) ;
157175
158176 await Promise . all ( equations . map ( ( node ) => this . typesetNode ( node ) ) ) ;
159177 }
@@ -183,22 +201,6 @@ export class AddonFilterMathJaxLoaderHandlerService extends CoreFilterDefaultHan
183201 }
184202 }
185203
186- /**
187- * Wait for the MathJax library and our JS object to be loaded.
188- *
189- * @param retries Number of times this has been retried.
190- * @returns Promise resolved when ready or if it took too long to load.
191- */
192- protected async waitForReady ( retries : number = 0 ) : Promise < void > {
193- if ( this . window . MathJax ?. typesetPromise || retries >= 25 ) {
194- // Loaded or too many retries, stop.
195- return ;
196- }
197-
198- await CoreWait . wait ( 20 + 10 * retries ) ;
199- await CorePromiseUtils . ignoreErrors ( this . waitForReady ( retries + 1 ) ) ;
200- }
201-
202204 /**
203205 * Find math environments in the $text and wrap them in no link spans
204206 * (<span class="nolink"></span>). If math environments are nested, only
0 commit comments