MDL-85488 mathjax: refactor loader to enhance configuration and loading
This commit is contained in:
committed by
Huong Nguyen
parent
7ac6e421ab
commit
db8f7fc95a
+9
-1
@@ -1,3 +1,11 @@
|
||||
define("filter_mathjaxloader/loader",["exports","core_filters/events"],(function(_exports,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.typeset=_exports.contentUpdated=_exports.configure=void 0;_exports.configure=params=>{loadMathJax(params.mathjaxurl,(()=>{window.MathJax&&(window.MathJax.config.locale=params.lang),document.addEventListener(_events.eventTypes.filterContentUpdated,contentUpdated)}))};const typesetNode=node=>{node instanceof HTMLElement&&window.MathJax&&window.MathJax.typesetPromise([node]).then((()=>{(0,_events.notifyFilterContentRenderingComplete)([node])})).catch((e=>{window.console.log(e)}))};_exports.typeset=()=>{const elements=document.getElementsByClassName("filter_mathjaxloader_equation");for(const element of elements)void 0!==window.MathJax&&typesetNode(element)};const contentUpdated=event=>{if(void 0===window.MathJax)return;let listOfElementContainMathJax=[],hasMathJax=!1;event.detail.nodes.forEach((node=>{if(!(node instanceof HTMLElement))return;const mathjaxElements=node.querySelectorAll(".filter_mathjaxloader_equation");mathjaxElements.length>0&&(hasMathJax=!0),listOfElementContainMathJax.push(mathjaxElements)})),hasMathJax&&listOfElementContainMathJax.forEach((mathjaxElements=>{mathjaxElements.forEach((node=>typesetNode(node)))}))};_exports.contentUpdated=contentUpdated;const loadMathJax=(url,callback)=>{const script=document.createElement("script");script.type="text/javascript",script.onload=()=>{callback()},script.src=url,document.getElementsByTagName("head")[0].appendChild(script)}}));
|
||||
define("filter_mathjaxloader/loader",["exports","core_filters/events"],(function(_exports,_events){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.typeset=_exports.loadMathJax=_exports.contentUpdated=_exports.configure=void 0;
|
||||
/**
|
||||
* Mathjax JS Loader.
|
||||
*
|
||||
* @module filter_mathjaxloader/loader
|
||||
* @copyright 2014 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
let mathJaxUrl=null,mathJaxLoaded=null;_exports.configure=params=>{let config={};try{""!==params.mathjaxconfig&&(config=JSON.parse(params.mathjaxconfig))}catch(e){window.console.error("Invalid JSON in mathjaxconfig.",e)}"object"!=typeof config&&(config={}),"object"!=typeof config.loader&&(config.loader={}),Array.isArray(config.loader.load)||(config.loader.load=[]),"object"!=typeof config.startup&&(config.startup={}),config.loader.load.includes("ui/safe")||config.loader.load.push("ui/safe"),config.startup.typeset=!1,config.locale=params.lang,mathJaxUrl=params.mathjaxurl,window.MathJax=config,document.addEventListener(_events.eventTypes.filterContentUpdated,contentUpdated)};const typesetNode=node=>{node instanceof HTMLElement&&loadMathJax().then((()=>{window.MathJax.startup.promise=window.MathJax.startup.promise.then((()=>window.MathJax.typesetPromise([node]))).then((()=>{(0,_events.notifyFilterContentRenderingComplete)([node])})).catch((e=>{window.console.log(e)}))}))};_exports.typeset=()=>{const elements=document.getElementsByClassName("filter_mathjaxloader_equation");for(const element of elements)typesetNode(element)};const contentUpdated=event=>{let listOfElementContainMathJax=[],hasMathJax=!1;event.detail.nodes.forEach((node=>{if(!(node instanceof HTMLElement))return;const mathjaxElements=node.querySelectorAll(".filter_mathjaxloader_equation");mathjaxElements.length>0&&(hasMathJax=!0),listOfElementContainMathJax.push(mathjaxElements)})),hasMathJax&&listOfElementContainMathJax.forEach((mathjaxElements=>{mathjaxElements.forEach((node=>typesetNode(node)))}))};_exports.contentUpdated=contentUpdated;const loadMathJax=()=>{if(!mathJaxLoaded){if(!mathJaxUrl)return Promise.reject(new Error("URL to MathJax not set."));mathJaxLoaded=new Promise(((resolve,reject)=>{const script=document.createElement("script");script.type="text/javascript",script.onload=resolve,script.onerror=reject,script.src=mathJaxUrl,document.getElementsByTagName("head")[0].appendChild(script)}))}return mathJaxLoaded};_exports.loadMathJax=loadMathJax}));
|
||||
|
||||
//# sourceMappingURL=loader.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -24,25 +24,67 @@ import {
|
||||
notifyFilterContentRenderingComplete,
|
||||
} from 'core_filters/events';
|
||||
|
||||
/**
|
||||
* URL to MathJax.
|
||||
* @type {string|null}
|
||||
*/
|
||||
let mathJaxUrl = null;
|
||||
|
||||
/**
|
||||
* Promise that is resolved when MathJax was loaded.
|
||||
* @type {Promise|null}
|
||||
*/
|
||||
let mathJaxLoaded = null;
|
||||
|
||||
/**
|
||||
* Called by the filter when it is active on any page.
|
||||
* This does not load MathJAX yet - it addes the configuration to the head incase it gets loaded later.
|
||||
* This does not load MathJAX yet - it adds the configuration in case it gets loaded later.
|
||||
* It also subscribes to the filter-content-updated event so MathJax can respond to content loaded by Ajax.
|
||||
*
|
||||
* @param {Object} params List of configuration params containing mathjaxurl, mathjaxconfig (text) and lang
|
||||
*/
|
||||
export const configure = (params) => {
|
||||
loadMathJax(params.mathjaxurl, () => {
|
||||
if (window.MathJax) {
|
||||
// Let's still set the locale even if the localization is not yet ported to version 3.2.2
|
||||
// https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html#not-yet-ported-to-version-3.
|
||||
window.MathJax.config.locale = params.lang;
|
||||
let config = {};
|
||||
try {
|
||||
if (params.mathjaxconfig !== '') {
|
||||
config = JSON.parse(params.mathjaxconfig);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
window.console.error('Invalid JSON in mathjaxconfig.', e);
|
||||
}
|
||||
if (typeof config != 'object') {
|
||||
config = {};
|
||||
}
|
||||
if (typeof config.loader !== 'object') {
|
||||
config.loader = {};
|
||||
}
|
||||
if (!Array.isArray(config.loader.load)) {
|
||||
config.loader.load = [];
|
||||
}
|
||||
if (typeof config.startup !== 'object') {
|
||||
config.startup = {};
|
||||
}
|
||||
|
||||
// Listen for events triggered when new text is added to a page that needs
|
||||
// processing by a filter.
|
||||
document.addEventListener(eventTypes.filterContentUpdated, contentUpdated);
|
||||
});
|
||||
// Always ensure that ui/safe is in the list. Otherwise, there is a risk of XSS.
|
||||
// https://docs.mathjax.org/en/v3.2-latest/options/safe.html.
|
||||
if (!config.loader.load.includes('ui/safe')) {
|
||||
config.loader.load.push('ui/safe');
|
||||
}
|
||||
|
||||
// This filter controls what elements to typeset.
|
||||
config.startup.typeset = false;
|
||||
|
||||
// Let's still set the locale even if the localization is not yet ported to version 3.2.2
|
||||
// https://docs.mathjax.org/en/v3.2-latest/upgrading/v2.html#not-yet-ported-to-version-3.
|
||||
config.locale = params.lang;
|
||||
|
||||
mathJaxUrl = params.mathjaxurl;
|
||||
window.MathJax = config;
|
||||
|
||||
// Listen for events triggered when new text is added to a page that needs
|
||||
// processing by a filter.
|
||||
document.addEventListener(eventTypes.filterContentUpdated, contentUpdated);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -58,15 +100,18 @@ const typesetNode = (node) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.MathJax) {
|
||||
window.MathJax.typesetPromise([node]).then(() => {
|
||||
notifyFilterContentRenderingComplete([node]);
|
||||
return;
|
||||
})
|
||||
.catch(e => {
|
||||
window.console.log(e);
|
||||
});
|
||||
}
|
||||
loadMathJax().then(() => {
|
||||
// Chain the calls to typesetPromise as it is recommended.
|
||||
// https://docs.mathjax.org/en/v3.2-latest/web/typeset.html#handling-asynchronous-typesetting.
|
||||
window.MathJax.startup.promise = window.MathJax.startup.promise
|
||||
.then(() => window.MathJax.typesetPromise([node]))
|
||||
.then(() => {
|
||||
notifyFilterContentRenderingComplete([node]);
|
||||
})
|
||||
.catch(e => {
|
||||
window.console.log(e);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -75,9 +120,7 @@ const typesetNode = (node) => {
|
||||
export const typeset = () => {
|
||||
const elements = document.getElementsByClassName('filter_mathjaxloader_equation');
|
||||
for (const element of elements) {
|
||||
if (typeof window.MathJax !== "undefined") {
|
||||
typesetNode(element);
|
||||
}
|
||||
typesetNode(element);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -87,10 +130,6 @@ export const typeset = () => {
|
||||
* @param {CustomEvent} event - Custom event with "nodes" indicating the root of the updated nodes.
|
||||
*/
|
||||
export const contentUpdated = (event) => {
|
||||
if (typeof window.MathJax === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
let listOfElementContainMathJax = [];
|
||||
let hasMathJax = false;
|
||||
// The list of HTMLElements in an Array.
|
||||
@@ -118,15 +157,22 @@ export const contentUpdated = (event) => {
|
||||
/**
|
||||
* Load the MathJax script.
|
||||
*
|
||||
* @param {String} url The URL of the MathJax script to load.
|
||||
* @param {function} callback The function to call when the script has loaded.
|
||||
* @return Promise that is resolved when MathJax was loaded.
|
||||
*/
|
||||
const loadMathJax = (url, callback) => {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.onload = () => {
|
||||
callback();
|
||||
};
|
||||
script.src = url;
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
export const loadMathJax = () => {
|
||||
if (!mathJaxLoaded) {
|
||||
if (!mathJaxUrl) {
|
||||
return Promise.reject(new Error('URL to MathJax not set.'));
|
||||
}
|
||||
|
||||
mathJaxLoaded = new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
script.src = mathJaxUrl;
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
});
|
||||
}
|
||||
return mathJaxLoaded;
|
||||
};
|
||||
|
||||
@@ -147,7 +147,9 @@ class text_filter extends \core_filters\text_filter {
|
||||
}
|
||||
|
||||
if ($hasdisplayorinline || $hasextra) {
|
||||
$PAGE->requires->js_call_amd('filter_mathjaxloader/loader', 'typeset');
|
||||
if ($PAGE->requires->should_create_one_time_item_now('filter_mathjaxloader-typeset')) {
|
||||
$PAGE->requires->js_call_amd('filter_mathjaxloader/loader', 'typeset');
|
||||
}
|
||||
return '<span class="filter_mathjaxloader_equation">' . $text . '</span>';
|
||||
}
|
||||
return $text;
|
||||
|
||||
@@ -40,5 +40,11 @@ This can be useful to save on bandwidth or because of local proxy restrictions.
|
||||
|
||||
To use a local installation of MathJax, first download the full MathJax library from https://www.mathjax.org/. Then install it on a web server. Finally update the MathJax filter settings httpurl and/or httpsurl to point to the local MathJax.js URL.';
|
||||
$string['mathjaxsettings'] = 'MathJax configuration';
|
||||
$string['mathjaxsettings_desc'] = 'The default MathJax configuration should be appropriate for most users, but MathJax is highly configurable and any of the standard MathJax configuration options can be added here.';
|
||||
$string['mathjaxsettings_desc'] = 'The default MathJax configuration should be appropriate for most users, but MathJax is highly configurable and any of the standard MathJax configuration options can be added here as JSON. This field must be empty or contain a valid JSON object! For example, to enable AsciiMath and the zoom feature, set this field to:
|
||||
<pre>
|
||||
{
|
||||
"loader": {"load": ["input/asciimath"]},
|
||||
"options": {"menuOptions": {"settings": {"zoom": "DoubleClick"}}}
|
||||
}
|
||||
</pre>';
|
||||
$string['privacy:metadata'] = 'The MathJax plugin does not store any personal data.';
|
||||
|
||||
Reference in New Issue
Block a user